diff --git a/.changeset/backstage-changelog.js b/.changeset/backstage-changelog.js index 45ed53afe4..22038b348b 100644 --- a/.changeset/backstage-changelog.js +++ b/.changeset/backstage-changelog.js @@ -16,7 +16,7 @@ const { default: defaultChangelogFunctions, -} = require('@changesets/changelog-github'); +} = require('@changesets/cli/changelog'); // Custom CHANGELOG generation for changesets, stolen from here with one minor change: // https://github.com/atlassian/changesets/blob/main/packages/cli/src/changelog/index.ts @@ -32,34 +32,7 @@ async function getDependencyReleaseLine(changesets, dependenciesUpdated) { return ['- Updated dependencies', ...updatedDependenciesList].join('\n'); } -async function getReleaseLine(changeset, type, options) { - const { ignoreUserThanks = [], ...rest } = options ?? {}; - const releaseLine = await defaultChangelogFunctions.getReleaseLine( - changeset, - type, - rest, - ); - - const ignoredUsers = new Set(ignoreUserThanks); - return releaseLine.replace(/Thanks\s(.*)!\s/g, (_, text) => { - // extracts user name and profile url from the markdown link - const regex = /\[@(\w+)\]\((https:\/\/github\.com\/[^\)]+)\)/g; - - let matches; - const links = []; - - while ((matches = regex.exec(text)) !== null) { - const [, user, url] = matches; - if (!ignoredUsers.has(user)) { - links.push(`[@${user}](${url})`); - } - } - - return links.length ? `Thanks ${links.join(', ')}! ` : ''; - }); -} - module.exports = { - getReleaseLine, + getReleaseLine: defaultChangelogFunctions.getReleaseLine, getDependencyReleaseLine, }; diff --git a/.changeset/beige-stingrays-tap.md b/.changeset/beige-stingrays-tap.md deleted file mode 100644 index ae7f2f709e..0000000000 --- a/.changeset/beige-stingrays-tap.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-api-docs': minor ---- - -Replace GraphiQL playground with DocExplorer diff --git a/.changeset/big-roses-stare.md b/.changeset/big-roses-stare.md deleted file mode 100644 index 442e53522e..0000000000 --- a/.changeset/big-roses-stare.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-msgraph': patch ---- - -export the function to read ms graph provider config diff --git a/.changeset/blue-bags-warn.md b/.changeset/blue-bags-warn.md deleted file mode 100644 index 17fa5e89d6..0000000000 --- a/.changeset/blue-bags-warn.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': minor -'@backstage/plugin-catalog-node': minor ---- - -Support adding location analyzers in new catalog analysis extension point and move `AnalyzeOptions` and `ScmLocationAnalyzer` types to `@backstage/plugin-catalog-node` diff --git a/.changeset/breezy-dogs-serve.md b/.changeset/breezy-dogs-serve.md deleted file mode 100644 index a92e5cdb0c..0000000000 --- a/.changeset/breezy-dogs-serve.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Cleaned up cases where deprecated code was being used but had a new location they should be imported from diff --git a/.changeset/brown-poets-join.md b/.changeset/brown-poets-join.md deleted file mode 100644 index bc6ccbaa70..0000000000 --- a/.changeset/brown-poets-join.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -`knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. - -You can do the same in your own Backstage repository to ensure that you get future node 18+ relevant updates, by having the following lines in your `packages/backend/package.json`: - -``` -"dependencies": { - // ... - "knex": "^3.0.0" -}, -"devDependencies": { - // ... - "better-sqlite3": "^9.0.0", -``` diff --git a/.changeset/chatty-cobras-cheer.md b/.changeset/chatty-cobras-cheer.md deleted file mode 100644 index c8203e58c0..0000000000 --- a/.changeset/chatty-cobras-cheer.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/config-loader': patch ---- - -Correctly resolve config targets into absolute paths diff --git a/.changeset/chatty-countries-refuse.md b/.changeset/chatty-countries-refuse.md deleted file mode 100644 index d29d1a453b..0000000000 --- a/.changeset/chatty-countries-refuse.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-bazaar': patch ---- - -Updated Readme document in bazaar plugin diff --git a/.changeset/chilled-knives-rule.md b/.changeset/chilled-knives-rule.md deleted file mode 100644 index f246beabbd..0000000000 --- a/.changeset/chilled-knives-rule.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-import': patch ---- - -Create an experimental plugin that is compatible with the declarative integration system, it is exported from the `/alpha` subpath. diff --git a/.changeset/chilly-books-sneeze.md b/.changeset/chilly-books-sneeze.md deleted file mode 100644 index a2d3ca1e04..0000000000 --- a/.changeset/chilly-books-sneeze.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/cli-node': minor -'@backstage/cli': minor ---- - -Removed support for the `publishConfig.alphaTypes` and `.betaTypes` fields that were used together with `--experimental-type-build` to generate `/alpha` and `/beta` entry points. Use the `exports` field to achieve this instead. diff --git a/.changeset/chilly-terms-behave.md b/.changeset/chilly-terms-behave.md deleted file mode 100644 index 8ee1ad8375..0000000000 --- a/.changeset/chilly-terms-behave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-search-backend-module-stack-overflow-collator': minor ---- - -Extract a package for the Stack Overflow new backend system plugin. diff --git a/.changeset/clever-houses-scream.md b/.changeset/clever-houses-scream.md deleted file mode 100644 index 14a2427dea..0000000000 --- a/.changeset/clever-houses-scream.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs-node': patch ---- - -Switch to `@smithy/node-http-handler` instead of the `@aws-sdk/node-http-handler` diff --git a/.changeset/config.json b/.changeset/config.json index 94e435bd93..283caa6ac4 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -1,19 +1,6 @@ { "$schema": "https://unpkg.com/@changesets/config@1.3.0/schema.json", - "changelog": [ - "./backstage-changelog.js", - { - "repo": "backstage/backstage", - "ignoreUserThanks": [ - "benjdlambert", - "freben", - "jhaals", - "Rugvip", - "renovate", - "dependabot" - ] - } - ], + "changelog": "./backstage-changelog.js", "commit": false, "linked": [], "access": "public", diff --git a/.changeset/cool-bulldogs-itch.md b/.changeset/cool-bulldogs-itch.md deleted file mode 100644 index 8f48befee2..0000000000 --- a/.changeset/cool-bulldogs-itch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-react': patch ---- - -Add EntityRef to Entity Inspector UI diff --git a/.changeset/create-app-1698763033.md b/.changeset/create-app-1698763033.md deleted file mode 100644 index b50d431d4b..0000000000 --- a/.changeset/create-app-1698763033.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Bumped create-app version. diff --git a/.changeset/curvy-carpets-kneel.md b/.changeset/curvy-carpets-kneel.md deleted file mode 100644 index e6b0019edb..0000000000 --- a/.changeset/curvy-carpets-kneel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-shortcuts': patch ---- - -Ensure that shortcuts aren't duplicate-checked against themselves diff --git a/.changeset/curvy-carrots-thank.md b/.changeset/curvy-carrots-thank.md deleted file mode 100644 index 6303125314..0000000000 --- a/.changeset/curvy-carrots-thank.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-home': patch ---- - -Fix bug where `retrieveAll` method wasn't fetching visits diff --git a/.changeset/curvy-ladybugs-impress.md b/.changeset/curvy-ladybugs-impress.md new file mode 100644 index 0000000000..ab799e4888 --- /dev/null +++ b/.changeset/curvy-ladybugs-impress.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-adr': patch +--- + +Updated README diff --git a/.changeset/cyan-bats-lick.md b/.changeset/cyan-bats-lick.md new file mode 100644 index 0000000000..0683d806b0 --- /dev/null +++ b/.changeset/cyan-bats-lick.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-azure-devops-backend': patch +--- + +Added a note about Service Principles diff --git a/.changeset/dirty-ducks-behave.md b/.changeset/dirty-ducks-behave.md deleted file mode 100644 index c7bea8ea0a..0000000000 --- a/.changeset/dirty-ducks-behave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -Fix `RoutedTabs` so that it does not explode without tabs. diff --git a/.changeset/dry-days-invite.md b/.changeset/dry-days-invite.md deleted file mode 100644 index dcf052acd2..0000000000 --- a/.changeset/dry-days-invite.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Switch from using deprecated `@esbuild-kit/*` packages to using `tsx`. This also switches to using the new module loader `register` API when available, avoiding the experimental warning when starting backends. diff --git a/.changeset/eighty-chairs-camp.md b/.changeset/eighty-chairs-camp.md deleted file mode 100644 index 6a240609d4..0000000000 --- a/.changeset/eighty-chairs-camp.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-plugin-api': minor ---- - -Added `RouteRef`, `SubRouteRef`, `ExternalRouteRef`, and related types. All exports from this package that previously relied on the types with the same name from `@backstage/core-plugin-api` now use the new types instead. To convert and existing legacy route ref to be compatible with the APIs from this package, use the `convertLegacyRouteRef` utility from `@backstage/core-plugin-api/alpha`. diff --git a/.changeset/eighty-chairs-care.md b/.changeset/eighty-chairs-care.md deleted file mode 100644 index 6d14bb0f18..0000000000 --- a/.changeset/eighty-chairs-care.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-search-backend-module-pg': patch ---- - -Optimize outdated documents deletion logic in PgSearchEngine DatabaseDocumentStore which significantly reduces cost on large tables diff --git a/.changeset/eleven-students-brake.md b/.changeset/eleven-students-brake.md deleted file mode 100644 index b2cad0bfd6..0000000000 --- a/.changeset/eleven-students-brake.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-gcp': patch ---- - -Allow integration with kubernetes dashboard diff --git a/.changeset/fair-parrots-lick.md b/.changeset/fair-parrots-lick.md deleted file mode 100644 index dffe6be1e2..0000000000 --- a/.changeset/fair-parrots-lick.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-home': patch ---- - -Remove the duplicate versions of `@rjsf/*` as they're no longer needed diff --git a/.changeset/fair-tools-bake.md b/.changeset/fair-tools-bake.md deleted file mode 100644 index fd7b21bbc8..0000000000 --- a/.changeset/fair-tools-bake.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-kubernetes-backend': patch -'@backstage/plugin-kubernetes-common': patch ---- - -Allow storing dashboard parameters for kubernetes in catalog diff --git a/.changeset/famous-plums-sit.md b/.changeset/famous-plums-sit.md deleted file mode 100644 index b85e26b87e..0000000000 --- a/.changeset/famous-plums-sit.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/core-components': patch -'@backstage/plugin-catalog': patch ---- - -Fix spacing inconsistency with links and labels in headers diff --git a/.changeset/fast-bears-lick.md b/.changeset/fast-bears-lick.md deleted file mode 100644 index 8e0dc8e60b..0000000000 --- a/.changeset/fast-bears-lick.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog': patch ---- - -Migrate catalog entity cards to new frontend system extension format. diff --git a/.changeset/fifty-taxis-allow.md b/.changeset/fifty-taxis-allow.md deleted file mode 100644 index 1b818f45e7..0000000000 --- a/.changeset/fifty-taxis-allow.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-common': patch ---- - -Add missing required property `type` in `Template.v1beta3.schema.json` schema diff --git a/.changeset/flat-ducks-buy.md b/.changeset/flat-ducks-buy.md deleted file mode 100644 index 5c952faaf1..0000000000 --- a/.changeset/flat-ducks-buy.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-search-backend-node': patch ---- - -Fix highlighting for non-string fields on the `Lunr` search engine implementation. diff --git a/.changeset/fluffy-years-shake.md b/.changeset/fluffy-years-shake.md deleted file mode 100644 index 9612690d62..0000000000 --- a/.changeset/fluffy-years-shake.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog': patch ---- - -Use default extensions boundary and suspense on the alpha declarative `createCatalogFilterExtension` extension factory. diff --git a/.changeset/forty-monkeys-lay.md b/.changeset/forty-monkeys-lay.md deleted file mode 100644 index b5fda56bf4..0000000000 --- a/.changeset/forty-monkeys-lay.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-auth-backend-module-microsoft-provider': patch -'@backstage/plugin-auth-backend-module-gitlab-provider': patch ---- - -Fix link to the repository in `README.md`. diff --git a/.changeset/four-files-behave.md b/.changeset/four-files-behave.md deleted file mode 100644 index 0430bd98d8..0000000000 --- a/.changeset/four-files-behave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-graphiql': minor ---- - -Upgrade to GraphiQL to 3.0.6 diff --git a/.changeset/four-pears-swim.md b/.changeset/four-pears-swim.md deleted file mode 100644 index b091dad598..0000000000 --- a/.changeset/four-pears-swim.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-vault-node': minor ---- - -Initial version of the `plugin-vault-node`` package. It contains the extension point definitions -for the vault backend, as well as some types that will be deprecated in the backend plugin. diff --git a/.changeset/fresh-camels-give.md b/.changeset/fresh-camels-give.md deleted file mode 100644 index 723733e45e..0000000000 --- a/.changeset/fresh-camels-give.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-msgraph': patch -'@backstage/integration': patch -'@backstage/plugin-auth-backend': patch ---- - -JSDoc and Error message updates to handle `Azure Active Directory` re-brand to `Entra ID` diff --git a/.changeset/fresh-crews-promise.md b/.changeset/fresh-crews-promise.md deleted file mode 100644 index fc9859086a..0000000000 --- a/.changeset/fresh-crews-promise.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-techdocs-module-addons-contrib': patch -'@backstage/plugin-techdocs': patch ---- - -Fixed navigation bug that caused users to not be scrolled to the top of a new page. Fixed navigation bug where using backwards and forwards browser navigation did not scroll users to the correct place on the TechDoc page. diff --git a/.changeset/fresh-penguins-cry.md b/.changeset/fresh-penguins-cry.md deleted file mode 100644 index 457025a518..0000000000 --- a/.changeset/fresh-penguins-cry.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-common': patch ---- - -Limit the database creation concurrency to one, defensively diff --git a/.changeset/fresh-schools-thank.md b/.changeset/fresh-schools-thank.md deleted file mode 100644 index 1e32f82051..0000000000 --- a/.changeset/fresh-schools-thank.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-gitlab': patch ---- - -Added try catch around fetching gitlab group users to prevent refresh from failing completely while only a select number of groups might not be able to load correctly. diff --git a/.changeset/friendly-jars-obey.md b/.changeset/friendly-jars-obey.md deleted file mode 100644 index 032fcff3f9..0000000000 --- a/.changeset/friendly-jars-obey.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-cloudbuild': patch ---- - -Added Installation Steps so that it is clear what is needed to install and use the Google Cloud Plugin. diff --git a/.changeset/gentle-elephants-look.md b/.changeset/gentle-elephants-look.md deleted file mode 100644 index 44263fb8a9..0000000000 --- a/.changeset/gentle-elephants-look.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/core-components': patch -'@backstage/plugin-scaffolder': minor ---- - -Add a possibility to use a formatter on a warning panel. Applied it for a scaffolder template diff --git a/.changeset/gentle-pears-camp.md b/.changeset/gentle-pears-camp.md deleted file mode 100644 index 6d96958a76..0000000000 --- a/.changeset/gentle-pears-camp.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-backstage-openapi': minor ---- - -Adds a new catalog module for ingesting Backstage plugin OpenAPI specs into the catalog for display as an API entity. diff --git a/.changeset/gentle-pumpkins-carry.md b/.changeset/gentle-pumpkins-carry.md deleted file mode 100644 index 721fbe8195..0000000000 --- a/.changeset/gentle-pumpkins-carry.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-backend-module-microsoft-provider': patch ---- - -Added support for specifying a domain hint on the Microsoft authentication provider configuration. diff --git a/.changeset/giant-cars-walk.md b/.changeset/giant-cars-walk.md deleted file mode 100644 index 5e313faa3b..0000000000 --- a/.changeset/giant-cars-walk.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs': patch ---- - -Export alpha routes and nav item extension, only available for applications that uses the new Frontend system. diff --git a/.changeset/giant-cycles-end.md b/.changeset/giant-cycles-end.md deleted file mode 100644 index f69938ea25..0000000000 --- a/.changeset/giant-cycles-end.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-stack-overflow-backend': patch ---- - -Deprecate package in favor of the new `@backstage/plugin-search-backend-module-stack-overflow-collator` module. - -The search collator `requestParams` option is optional now, so its default value is `{ order: 'desc', sort: 'activity', site: 'stackoverflow' }` as defined in the `Try It` section on the [official Stack Overflow API documentation](https://api.stackexchange.com/docs/questions). diff --git a/.changeset/good-plums-confess.md b/.changeset/good-plums-confess.md deleted file mode 100644 index 941adec8b3..0000000000 --- a/.changeset/good-plums-confess.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-app-api': patch ---- - -Refactor internal extension instance system into an app graph. diff --git a/.changeset/great-baboons-allow.md b/.changeset/great-baboons-allow.md deleted file mode 100644 index 47e410d8a4..0000000000 --- a/.changeset/great-baboons-allow.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -'@backstage/plugin-vault-backend': minor ---- - -Added support for the [new backend system](https://backstage.io/docs/backend-system/). - -In your `packages/backend/src/index.ts` make the following changes: - -```diff - import { createBackend } from '@backstage/backend-defaults'; - const backend = createBackend(); - // ... other feature additions -+ backend.add(import('@backstage/plugin-vault-backend'); - backend.start(); -``` - -If you use the new backend system, the token renewal task can be defined via configuration file: - -```diff -vault: - baseUrl: - token: - schedule: -+ frequency: ... -+ timeout: ... -+ # Other schedule options, such as scope or initialDelay -``` - -If the `schedule` is omitted or set to `false` no token renewal task will be scheduled. -If the value of `schedule` is set to `true` the renew will be scheduled hourly (the default). -In other cases (like in the diff above), the defined schedule will be used. - -**DEPRECATIONS**: The interface `VaultApi` and the type `VaultSecret` are now deprecated. Import them from `@backstage/plugin-vault-node`. diff --git a/.changeset/green-experts-happen.md b/.changeset/green-experts-happen.md deleted file mode 100644 index 6c892a2038..0000000000 --- a/.changeset/green-experts-happen.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-bazaar': patch ---- - -Added alert popup for link and unlink entity in bazaar project diff --git a/.changeset/healthy-dancers-dream.md b/.changeset/healthy-dancers-dream.md deleted file mode 100644 index 6a9869f03a..0000000000 --- a/.changeset/healthy-dancers-dream.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-app-api': patch ---- - -The options parameter of `createApp` is now optional. diff --git a/.changeset/healthy-shirts-fold.md b/.changeset/healthy-shirts-fold.md deleted file mode 100644 index f2ac0a9e83..0000000000 --- a/.changeset/healthy-shirts-fold.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-catalog': patch -'@backstage/plugin-techdocs': patch ---- - -The `spec.lifecycle' field in entities will now always be rendered as a string. diff --git a/.changeset/heavy-experts-accept.md b/.changeset/heavy-experts-accept.md deleted file mode 100644 index e6f2f435b8..0000000000 --- a/.changeset/heavy-experts-accept.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -'@backstage/plugin-catalog-react': minor ---- - -Added an `EntityPresentationApi` and associated `entityPresentationApiRef`. This -API lets you control how references to entities (e.g. in links, headings, -iconography etc) are represented in the user interface. - -Usage of this API is initially added to the `EntityRefLink` and `EntityRefLinks` -components, so that they can render richer, more correct representation of -entity refs. There's also a new `EntityDisplayName` component, which works just like -the `EntityRefLink` but without the link. - -Along with that change, the `fetchEntities` and `getTitle` props of -`EntityRefLinksProps` are deprecated and no longer used, since the same need -instead is fulfilled (and by default always enabled) by the -`entityPresentationApiRef`. diff --git a/.changeset/heavy-rings-play.md b/.changeset/heavy-rings-play.md deleted file mode 100644 index bbed4c3fa3..0000000000 --- a/.changeset/heavy-rings-play.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-bazaar': patch ---- - -Adding descending sort in a bazaar plugin diff --git a/.changeset/hip-moose-boil.md b/.changeset/hip-moose-boil.md deleted file mode 100644 index e14c557c62..0000000000 --- a/.changeset/hip-moose-boil.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-kubernetes-react': patch ---- - -Internal refactor to avoid a null pointer problem diff --git a/.changeset/hip-mugs-camp.md b/.changeset/hip-mugs-camp.md deleted file mode 100644 index 3413b5ac0a..0000000000 --- a/.changeset/hip-mugs-camp.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs-backend': patch ---- - -Add info about the entity when tech docs fail to build diff --git a/.changeset/hungry-paws-dress.md b/.changeset/hungry-paws-dress.md deleted file mode 100644 index b227a77e72..0000000000 --- a/.changeset/hungry-paws-dress.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@backstage/plugin-user-settings': patch -'@backstage/plugin-techdocs': patch -'@backstage/plugin-tech-radar': patch -'@backstage/plugin-graphiql': patch -'@backstage/plugin-search': patch ---- - -Updated alpha exports according to routing changes in `@backstage/frontend-plugin-api`. diff --git a/.changeset/hungry-radios-play.md b/.changeset/hungry-radios-play.md deleted file mode 100644 index ce7f524f4a..0000000000 --- a/.changeset/hungry-radios-play.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-user-settings-backend': patch ---- - -Added dependency on `@backstage/config` diff --git a/.changeset/kind-beers-chew.md b/.changeset/kind-beers-chew.md deleted file mode 100644 index 5fb939ea6b..0000000000 --- a/.changeset/kind-beers-chew.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-api-docs': minor ---- - -Define a default for oauth2RedirectUrl option of swagger-ui-react to match documentation diff --git a/.changeset/large-forks-arrive.md b/.changeset/large-forks-arrive.md deleted file mode 100644 index 3490a87128..0000000000 --- a/.changeset/large-forks-arrive.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-code-coverage-backend': patch ---- - -Added support for new backend system diff --git a/.changeset/late-forks-fetch.md b/.changeset/late-forks-fetch.md deleted file mode 100644 index 3ba15885e2..0000000000 --- a/.changeset/late-forks-fetch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs-backend': patch ---- - -Fix potential memory leak by not creating a build log transport if not given via `RouterOptions`. diff --git a/.changeset/lazy-hotels-wait.md b/.changeset/lazy-hotels-wait.md deleted file mode 100644 index 85879880f5..0000000000 --- a/.changeset/lazy-hotels-wait.md +++ /dev/null @@ -1,109 +0,0 @@ ---- -'@backstage/plugin-analytics-module-newrelic-browser': patch -'@backstage/plugin-api-docs-module-protoc-gen-doc': patch -'@backstage/plugin-techdocs-module-addons-contrib': patch -'@backstage/plugin-cicd-statistics-module-gitlab': patch -'@backstage/plugin-catalog-unprocessed-entities': patch -'@backstage/plugin-github-pull-requests-board': patch -'@backstage/plugin-techdocs-addons-test-utils': patch -'@backstage/frontend-plugin-api': patch -'@backstage/plugin-analytics-module-ga4': patch -'@backstage/plugin-analytics-module-ga': patch -'@backstage/plugin-git-release-manager': patch -'@backstage/integration-react': patch -'@backstage/plugin-github-deployments': patch -'@backstage/plugin-kubernetes-cluster': patch -'@backstage/plugin-microsoft-calendar': patch -'@backstage/plugin-newrelic-dashboard': patch -'@backstage/frontend-app-api': patch -'@backstage/plugin-entity-validation': patch -'@backstage/core-components': patch -'@backstage/core-plugin-api': patch -'@backstage/plugin-kubernetes-react': patch -'@backstage/plugin-permission-react': patch -'@backstage/plugin-scaffolder-react': patch -'@backstage/version-bridge': patch -'@backstage/plugin-apollo-explorer': patch -'@backstage/plugin-catalog-graphql': patch -'@backstage/plugin-cicd-statistics': patch -'@backstage/plugin-entity-feedback': patch -'@backstage/plugin-gitops-profiles': patch -'@backstage/plugin-graphql-voyager': patch -'@backstage/plugin-sonarqube-react': patch -'@backstage/plugin-apache-airflow': patch -'@backstage/plugin-catalog-import': patch -'@backstage/plugin-github-actions': patch -'@backstage/plugin-octopus-deploy': patch -'@backstage/plugin-splunk-on-call': patch -'@backstage/plugin-stack-overflow': patch -'@backstage/plugin-techdocs-react': patch -'@backstage/app-defaults': patch -'@backstage/core-app-api': patch -'@backstage/plugin-catalog-graph': patch -'@backstage/plugin-catalog-react': patch -'@backstage/plugin-code-coverage': patch -'@backstage/plugin-config-schema': patch -'@backstage/plugin-cost-insights': patch -'@backstage/plugin-explore-react': patch -'@backstage/plugin-github-issues': patch -'@backstage/plugin-tech-insights': patch -'@backstage/plugin-user-settings': patch -'@backstage/plugin-azure-devops': patch -'@backstage/plugin-code-climate': patch -'@backstage/plugin-gcp-projects': patch -'@backstage/plugin-search-react': patch -'@backstage/create-app': patch -'@backstage/test-utils': patch -'@backstage/plugin-azure-sites': patch -'@backstage/plugin-firehydrant': patch -'@backstage/plugin-cloudbuild': patch -'@backstage/plugin-home-react': patch -'@backstage/plugin-kubernetes': patch -'@backstage/plugin-lighthouse': patch -'@backstage/plugin-scaffolder': patch -'@backstage/plugin-stackstorm': patch -'@backstage/plugin-tech-radar': patch -'@backstage/plugin-codescene': patch -'@backstage/plugin-dynatrace': patch -'@backstage/plugin-gcalendar': patch -'@backstage/plugin-org-react': patch -'@backstage/plugin-pagerduty': patch -'@backstage/plugin-shortcuts': patch -'@backstage/plugin-sonarqube': patch -'@backstage/plugin-xcmetrics': patch -'@backstage/plugin-airbrake': patch -'@backstage/plugin-api-docs': patch -'@backstage/plugin-circleci': patch -'@backstage/plugin-devtools': patch -'@backstage/plugin-graphiql': patch -'@backstage/plugin-linguist': patch -'@backstage/plugin-newrelic': patch -'@backstage/plugin-opencost': patch -'@backstage/plugin-periskop': patch -'@backstage/plugin-playlist': patch -'@backstage/plugin-puppetdb': patch -'@backstage/plugin-techdocs': patch -'@backstage/plugin-bitrise': patch -'@backstage/plugin-catalog': patch -'@backstage/plugin-explore': patch -'@backstage/plugin-jenkins': patch -'@backstage/plugin-rollbar': patch -'@backstage/theme': patch -'@backstage/plugin-allure': patch -'@backstage/plugin-badges': patch -'@backstage/plugin-bazaar': patch -'@backstage/plugin-search': patch -'@backstage/plugin-sentry': patch -'@backstage/plugin-fossa': patch -'@backstage/plugin-ilert': patch -'@backstage/plugin-kafka': patch -'@backstage/plugin-nomad': patch -'@backstage/plugin-vault': patch -'@backstage/plugin-gocd': patch -'@backstage/plugin-home': patch -'@backstage/plugin-todo': patch -'@backstage/plugin-adr': patch -'@backstage/plugin-org': patch ---- - -Add official support for React 18. diff --git a/.changeset/long-sheep-exercise.md b/.changeset/long-sheep-exercise.md deleted file mode 100644 index f5e692f55e..0000000000 --- a/.changeset/long-sheep-exercise.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -'@backstage/plugin-catalog-graph': minor ---- - -Add the entire `Entity` to `EntityNodeData` and deprecate `name`, `kind`, `title`, `namespace` and `spec`. - -To get the deprecated properties in your custom component you can use: - -```typescript -import { DEFAULT_NAMESPACE } from '@backstage/catalog-model'; - -const { - kind, - metadata: { name, namespace = DEFAULT_NAMESPACE, title }, -} = entity; -``` diff --git a/.changeset/long-turkeys-argue.md b/.changeset/long-turkeys-argue.md deleted file mode 100644 index f051d42478..0000000000 --- a/.changeset/long-turkeys-argue.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Add examples for `github:environment:create` scaffolder action & improve related tests diff --git a/.changeset/loud-ghosts-deny.md b/.changeset/loud-ghosts-deny.md deleted file mode 100644 index e66b052c4e..0000000000 --- a/.changeset/loud-ghosts-deny.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': minor ---- - -Introduce a new optional config parameter `catalog.stitchingStrategy.mode`, -which can have the values `'immediate'` (default) and `'deferred'`. The default -is for stitching to work as it did before this change, which means that it -happens "in-band" (blocking) immediately when each processing task finishes. -When set to `'deferred'`, stitching is instead deferred to happen on a separate -asynchronous worker queue just like processing. - -Deferred stitching should make performance smoother when ingesting large amounts -of entities, and reduce p99 processing times and repeated over-stitching of -hot spot entities when fan-out/fan-in in terms of relations is very large. It -does however also come with some performance cost due to the queuing with how -much wall-clock time some types of task take. diff --git a/.changeset/lovely-turtles-remain.md b/.changeset/lovely-turtles-remain.md deleted file mode 100644 index 711a397baa..0000000000 --- a/.changeset/lovely-turtles-remain.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Added description for publish:gerrit scaffolder actions diff --git a/.changeset/many-masks-smoke.md b/.changeset/many-masks-smoke.md deleted file mode 100644 index 6d249eeb15..0000000000 --- a/.changeset/many-masks-smoke.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/repo-tools': minor -'@backstage/cli': minor ---- - -Remove support for the deprecated `--experimental-type-build` option for `package build`. diff --git a/.changeset/metal-students-drive.md b/.changeset/metal-students-drive.md new file mode 100644 index 0000000000..04f338c64e --- /dev/null +++ b/.changeset/metal-students-drive.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-entity-validation': patch +--- + +Improves UX of the EntityValidationPage: Moves the validate button below the EntityTextArea which is actually validated, the location TextField can now be hidden to prevent confusion about what is validated and additional content can be added to the top of the validation page. diff --git a/.changeset/mighty-crews-attack.md b/.changeset/mighty-crews-attack.md deleted file mode 100644 index c0b8587fe0..0000000000 --- a/.changeset/mighty-crews-attack.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog': patch ---- - -Initial entity page implementation for new frontend system at `/alpha`, with an overview page enabled by default and the about card available as an optional card. diff --git a/.changeset/mighty-humans-shave.md b/.changeset/mighty-humans-shave.md deleted file mode 100644 index 7a4971e021..0000000000 --- a/.changeset/mighty-humans-shave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-search-backend-module-elasticsearch': patch ---- - -Support AWS OpenSearch Serverless search backend. Does not support `_refresh` endpoint. diff --git a/.changeset/modern-ducks-battle.md b/.changeset/modern-ducks-battle.md deleted file mode 100644 index e8359cf4ac..0000000000 --- a/.changeset/modern-ducks-battle.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-app-api': minor ---- - -Added the ability to configure bound routes through `app.routes.bindings`. The routing system used by `createApp` has been replaced by one that only supports route refs of the new format from `@backstage/frontend-plugin-api`. The requirement for route refs to have the same ID as their associated extension has been removed. diff --git a/.changeset/nasty-colts-tickle.md b/.changeset/nasty-colts-tickle.md deleted file mode 100644 index 5a6194c14d..0000000000 --- a/.changeset/nasty-colts-tickle.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': patch -'@backstage/plugin-search-backend': patch ---- - -Update the OpenAPI spec with more complete error responses and request bodies using Optic. Also, updates the test cases to use the new `supertest` pass through from `@backstage/backend-openapi-utils`. diff --git a/.changeset/neat-hotels-wink.md b/.changeset/neat-hotels-wink.md new file mode 100644 index 0000000000..fca82e38fa --- /dev/null +++ b/.changeset/neat-hotels-wink.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-gitlab': patch +--- + +Added the option to provide custom `groupTransformer`, `userTransformer` and `groupNameTransformer` to allow custom transformations of groups and users diff --git a/.changeset/new-beers-drive.md b/.changeset/new-beers-drive.md deleted file mode 100644 index 370734b7c5..0000000000 --- a/.changeset/new-beers-drive.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-catalog': patch ---- - -Create declarative extensions for the `Catalog` plugin; this initial plugin preset contains sidebar item, index page and filter extensions, all distributed via `/alpha` subpath. - -The `EntityPage` will be migrated in a follow-up patch. diff --git a/.changeset/new-kangaroos-train.md b/.changeset/new-kangaroos-train.md deleted file mode 100644 index 2e7a14f127..0000000000 --- a/.changeset/new-kangaroos-train.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-unprocessed-entities': patch ---- - -Added filtering and sorting to unprocessed entities tables. diff --git a/.changeset/nice-apes-kneel.md b/.changeset/nice-apes-kneel.md deleted file mode 100644 index 1ecff9d223..0000000000 --- a/.changeset/nice-apes-kneel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs': patch ---- - -Added entity page content for the new plugin exported via `/alpha`. diff --git a/.changeset/nice-pillows-poke.md b/.changeset/nice-pillows-poke.md deleted file mode 100644 index 64034c39d2..0000000000 --- a/.changeset/nice-pillows-poke.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-stack-overflow': patch ---- - -Migrate package to the new Frontend system, the new module is distributed with a `/alpha` subpath. diff --git a/.changeset/ninety-numbers-study.md b/.changeset/ninety-numbers-study.md deleted file mode 100644 index e77131fab9..0000000000 --- a/.changeset/ninety-numbers-study.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -Fixed compatibility with Safari <16.3 by eliminating RegEx lookbehind in `extractInitials`. - -This PR also changed how initials are generated resulting in _John Jonathan Doe_ => _JD_ instead of _JJ_. diff --git a/.changeset/old-apricots-taste.md b/.changeset/old-apricots-taste.md deleted file mode 100644 index 544ba11536..0000000000 --- a/.changeset/old-apricots-taste.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-react': patch ---- - -Added new APIs at the `/alpha` subpath for creating entity page cards and content for the new frontend system. diff --git a/.changeset/old-chairs-switch.md b/.changeset/old-chairs-switch.md deleted file mode 100644 index 2e9251e06f..0000000000 --- a/.changeset/old-chairs-switch.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/repo-tools': minor ---- - -Adds a new command `schema openapi test` that performs runtime validation of your OpenAPI specs using your test data. Under the hood, we're using Optic to perform this check, really cool work by them! - -To use this new command, you will have to run `yarn add @useoptic/optic` in the root of your repo. diff --git a/.changeset/old-coats-doubt.md b/.changeset/old-coats-doubt.md deleted file mode 100644 index 2b98acbd87..0000000000 --- a/.changeset/old-coats-doubt.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/plugin-kubernetes-react': patch ---- - -Make sure types exported by other `kubernetes` plugins in the past are exported again after the creation -of the react package. - -Some types have been moved to this new package but the export was missing, so they were not available anymore for developers. diff --git a/.changeset/old-cows-buy.md b/.changeset/old-cows-buy.md deleted file mode 100644 index 14c9cf6eda..0000000000 --- a/.changeset/old-cows-buy.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-search-react': patch ---- - -Emit search analytics in the search hook instead of in a dedicated component diff --git a/.changeset/olive-doors-begin.md b/.changeset/olive-doors-begin.md deleted file mode 100644 index 5d8978964c..0000000000 --- a/.changeset/olive-doors-begin.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-incremental-ingestion': patch -'@backstage/plugin-catalog-backend-module-unprocessed': patch -'@backstage/plugin-search-backend-module-pg': patch -'@backstage/plugin-entity-feedback-backend': patch -'@backstage/plugin-code-coverage-backend': patch -'@backstage/plugin-tech-insights-backend': patch -'@backstage/plugin-user-settings-backend': patch -'@backstage/backend-plugin-api': patch -'@backstage/backend-test-utils': patch -'@backstage/plugin-scaffolder-backend': patch -'@backstage/plugin-linguist-backend': patch -'@backstage/plugin-playlist-backend': patch -'@backstage/plugin-techdocs-backend': patch -'@backstage/backend-common': patch -'@backstage/plugin-catalog-backend': patch -'@backstage/backend-tasks': patch -'@backstage/plugin-badges-backend': patch -'@backstage/plugin-bazaar-backend': patch -'@backstage/plugin-auth-backend': patch -'@backstage/plugin-app-backend': patch ---- - -`knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. diff --git a/.changeset/olive-paws-divide.md b/.changeset/olive-paws-divide.md deleted file mode 100644 index 688b6025bf..0000000000 --- a/.changeset/olive-paws-divide.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-app-api': patch ---- - -Updated `app.extensions` configuration schema. diff --git a/.changeset/orange-ears-kiss.md b/.changeset/orange-ears-kiss.md deleted file mode 100644 index 1620127c20..0000000000 --- a/.changeset/orange-ears-kiss.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@backstage/plugin-auth-backend-module-microsoft-provider': patch ---- - -Re-add the missing profile photo -as well as access token retrieval for foreign scopes. - -Additionally, we switch from previously 48x48 to 96x96 -which is the size used at the profile card. diff --git a/.changeset/orange-jokes-tap.md b/.changeset/orange-jokes-tap.md deleted file mode 100644 index 0fd9e14a46..0000000000 --- a/.changeset/orange-jokes-tap.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-app-api': patch ---- - -Implement new `AppTreeApi` diff --git a/.changeset/orange-planes-crash.md b/.changeset/orange-planes-crash.md deleted file mode 100644 index a8e828e912..0000000000 --- a/.changeset/orange-planes-crash.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-bazaar': patch ---- - -Added alert popup in the bazaar plugin diff --git a/.changeset/pink-eyes-reflect.md b/.changeset/pink-eyes-reflect.md deleted file mode 100644 index 11ea54e052..0000000000 --- a/.changeset/pink-eyes-reflect.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': minor ---- - -Made shut down stale tasks configurable. - -There are two properties exposed: - -- `scaffolder.processingInterval` - sets the processing interval for staled tasks. -- `scaffolder.taskTimeoutJanitorFrequency` - sets the task's heartbeat timeout, when to consider a task to be staled. diff --git a/.changeset/plenty-buckets-float.md b/.changeset/plenty-buckets-float.md deleted file mode 100644 index c1dbb54e87..0000000000 --- a/.changeset/plenty-buckets-float.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-bazaar': patch ---- - -Removed unnecessary dependency on `@backstage/cli`. diff --git a/.changeset/plenty-tigers-argue.md b/.changeset/plenty-tigers-argue.md deleted file mode 100644 index ef9e58d63b..0000000000 --- a/.changeset/plenty-tigers-argue.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-tech-insights-backend': patch ---- - -Add `factRetrieverId` to the fact retriever's logger metadata. diff --git a/.changeset/polite-meals-hug.md b/.changeset/polite-meals-hug.md new file mode 100644 index 0000000000..664f450c6d --- /dev/null +++ b/.changeset/polite-meals-hug.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-stack-overflow': patch +--- + +Fixes a bug that made the API return questions not related to the tags provided diff --git a/.changeset/poor-roses-hang.md b/.changeset/poor-roses-hang.md deleted file mode 100644 index 028df6a7c6..0000000000 --- a/.changeset/poor-roses-hang.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -Make the `options.titleFormat` prop of `` apply to all keys including nested ones. Previously, this option would only apply to the root keys of the `metadata` prop. - -Document and improve the props of ``. Previously, the `options` prop was `any`. diff --git a/.changeset/poor-seahorses-rush.md b/.changeset/poor-seahorses-rush.md deleted file mode 100644 index 55313f706d..0000000000 --- a/.changeset/poor-seahorses-rush.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-azure-devops': patch ---- - -Consolidated getting the annotation values into a single function to help with future changes diff --git a/.changeset/popular-bikes-do.md b/.changeset/popular-bikes-do.md deleted file mode 100644 index b1cc5c2cdd..0000000000 --- a/.changeset/popular-bikes-do.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-code-coverage': patch ---- - -The warning for missing code coverage will now render the entity as a reference. diff --git a/.changeset/pre.json b/.changeset/pre.json index 94ee1cdd09..1e62c27268 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -1,399 +1,268 @@ { - "mode": "exit", + "mode": "pre", "tag": "next", "initialVersions": { - "example-app": "0.2.88", - "@backstage/app-defaults": "1.4.4", - "example-app-next": "0.0.2", - "app-next-example-plugin": "0.0.2", - "example-backend": "0.2.88", - "@backstage/backend-app-api": "0.5.6", - "@backstage/backend-common": "0.19.8", - "@backstage/backend-defaults": "0.2.6", - "@backstage/backend-dev-utils": "0.1.2", - "example-backend-next": "0.0.16", - "@backstage/backend-openapi-utils": "0.0.5", - "@backstage/backend-plugin-api": "0.6.6", - "@backstage/backend-plugin-manager": "0.0.2", - "@backstage/backend-tasks": "0.5.11", - "@backstage/backend-test-utils": "0.2.7", - "@backstage/catalog-client": "1.4.5", + "example-app": "0.2.91", + "@backstage/app-defaults": "1.4.7", + "example-app-next": "0.0.5", + "app-next-example-plugin": "0.0.5", + "example-backend": "0.2.91", + "@backstage/backend-app-api": "0.5.10", + "@backstage/backend-common": "0.20.1", + "@backstage/backend-defaults": "0.2.9", + "@backstage/backend-dev-utils": "0.1.3", + "@backstage/backend-dynamic-feature-service": "0.1.0", + "example-backend-next": "0.0.19", + "@backstage/backend-openapi-utils": "0.1.2", + "@backstage/backend-plugin-api": "0.6.9", + "@backstage/backend-tasks": "0.5.14", + "@backstage/backend-test-utils": "0.2.10", + "@backstage/catalog-client": "1.5.2", "@backstage/catalog-model": "1.4.3", - "@backstage/cli": "0.23.0", + "@backstage/cli": "0.25.1", "@backstage/cli-common": "0.1.13", - "@backstage/cli-node": "0.1.5", + "@backstage/cli-node": "0.2.2", "@backstage/codemods": "0.1.46", "@backstage/config": "1.1.1", - "@backstage/config-loader": "1.5.1", - "@backstage/core-app-api": "1.11.0", - "@backstage/core-components": "0.13.6", - "@backstage/core-plugin-api": "1.7.0", - "@backstage/create-app": "0.5.6", - "@backstage/dev-utils": "1.0.22", - "e2e-test": "0.2.8", + "@backstage/config-loader": "1.6.1", + "@backstage/core-app-api": "1.11.3", + "@backstage/core-compat-api": "0.1.1", + "@backstage/core-components": "0.13.10", + "@backstage/core-plugin-api": "1.8.2", + "@backstage/create-app": "0.5.9", + "@backstage/dev-utils": "1.0.26", + "e2e-test": "0.2.11", "@backstage/e2e-test-utils": "0.1.0", "@backstage/errors": "1.2.3", - "@backstage/eslint-plugin": "0.1.3", - "@backstage/frontend-app-api": "0.2.0", - "@backstage/frontend-plugin-api": "0.2.0", - "@backstage/integration": "1.7.1", - "@backstage/integration-aws-node": "0.1.7", - "@backstage/integration-react": "1.1.20", - "@backstage/release-manifests": "0.0.10", - "@backstage/repo-tools": "0.3.5", - "@techdocs/cli": "1.6.0", - "techdocs-cli-embedded-app": "0.2.87", - "@backstage/test-utils": "1.4.4", - "@backstage/theme": "0.4.3", + "@backstage/eslint-plugin": "0.1.4", + "@backstage/frontend-app-api": "0.5.0", + "@backstage/frontend-plugin-api": "0.5.0", + "@backstage/frontend-test-utils": "0.1.1", + "@backstage/integration": "1.8.0", + "@backstage/integration-aws-node": "0.1.8", + "@backstage/integration-react": "1.1.23", + "@backstage/release-manifests": "0.0.11", + "@backstage/repo-tools": "0.5.2", + "@techdocs/cli": "1.8.1", + "techdocs-cli-embedded-app": "0.2.90", + "@backstage/test-utils": "1.4.7", + "@backstage/theme": "0.5.0", "@backstage/types": "1.1.1", - "@backstage/version-bridge": "1.0.6", - "@backstage/plugin-adr": "0.6.8", - "@backstage/plugin-adr-backend": "0.4.3", - "@backstage/plugin-adr-common": "0.2.16", - "@backstage/plugin-airbrake": "0.3.25", - "@backstage/plugin-airbrake-backend": "0.3.3", - "@backstage/plugin-allure": "0.1.41", - "@backstage/plugin-analytics-module-ga": "0.1.34", - "@backstage/plugin-analytics-module-ga4": "0.1.5", - "@backstage/plugin-analytics-module-newrelic-browser": "0.0.3", - "@backstage/plugin-apache-airflow": "0.2.16", - "@backstage/plugin-api-docs": "0.9.12", - "@backstage/plugin-api-docs-module-protoc-gen-doc": "0.1.4", - "@backstage/plugin-apollo-explorer": "0.1.16", - "@backstage/plugin-app-backend": "0.3.54", - "@backstage/plugin-app-node": "0.1.6", - "@backstage/plugin-auth-backend": "0.19.3", - "@backstage/plugin-auth-backend-module-gcp-iap-provider": "0.2.0", - "@backstage/plugin-auth-backend-module-github-provider": "0.1.3", - "@backstage/plugin-auth-backend-module-gitlab-provider": "0.1.3", - "@backstage/plugin-auth-backend-module-google-provider": "0.1.3", - "@backstage/plugin-auth-backend-module-microsoft-provider": "0.1.0", - "@backstage/plugin-auth-backend-module-oauth2-provider": "0.1.3", - "@backstage/plugin-auth-backend-module-pinniped-provider": "0.1.0", - "@backstage/plugin-auth-node": "0.4.0", - "@backstage/plugin-azure-devops": "0.3.7", - "@backstage/plugin-azure-devops-backend": "0.4.3", - "@backstage/plugin-azure-devops-common": "0.3.1", - "@backstage/plugin-azure-sites": "0.1.14", - "@backstage/plugin-azure-sites-backend": "0.1.16", + "@backstage/version-bridge": "1.0.7", + "@backstage/plugin-adr": "0.6.12", + "@backstage/plugin-adr-backend": "0.4.6", + "@backstage/plugin-adr-common": "0.2.19", + "@backstage/plugin-airbrake": "0.3.29", + "@backstage/plugin-airbrake-backend": "0.3.6", + "@backstage/plugin-allure": "0.1.45", + "@backstage/plugin-analytics-module-ga": "0.1.37", + "@backstage/plugin-analytics-module-ga4": "0.1.8", + "@backstage/plugin-analytics-module-newrelic-browser": "0.0.6", + "@backstage/plugin-apache-airflow": "0.2.19", + "@backstage/plugin-api-docs": "0.10.3", + "@backstage/plugin-api-docs-module-protoc-gen-doc": "0.1.5", + "@backstage/plugin-apollo-explorer": "0.1.19", + "@backstage/plugin-app-backend": "0.3.57", + "@backstage/plugin-app-node": "0.1.9", + "@backstage/plugin-app-visualizer": "0.1.0", + "@backstage/plugin-auth-backend": "0.20.3", + "@backstage/plugin-auth-backend-module-atlassian-provider": "0.1.1", + "@backstage/plugin-auth-backend-module-gcp-iap-provider": "0.2.3", + "@backstage/plugin-auth-backend-module-github-provider": "0.1.6", + "@backstage/plugin-auth-backend-module-gitlab-provider": "0.1.6", + "@backstage/plugin-auth-backend-module-google-provider": "0.1.6", + "@backstage/plugin-auth-backend-module-microsoft-provider": "0.1.4", + "@backstage/plugin-auth-backend-module-oauth2-provider": "0.1.6", + "@backstage/plugin-auth-backend-module-oauth2-proxy-provider": "0.1.1", + "@backstage/plugin-auth-backend-module-okta-provider": "0.0.2", + "@backstage/plugin-auth-backend-module-pinniped-provider": "0.1.3", + "@backstage/plugin-auth-backend-module-vmware-cloud-provider": "0.1.1", + "@backstage/plugin-auth-node": "0.4.3", + "@backstage/plugin-azure-devops": "0.3.11", + "@backstage/plugin-azure-devops-backend": "0.5.1", + "@backstage/plugin-azure-devops-common": "0.3.2", + "@backstage/plugin-azure-sites": "0.1.18", + "@backstage/plugin-azure-sites-backend": "0.1.19", "@backstage/plugin-azure-sites-common": "0.1.1", - "@backstage/plugin-badges": "0.2.49", - "@backstage/plugin-badges-backend": "0.3.3", - "@backstage/plugin-bazaar": "0.2.17", - "@backstage/plugin-bazaar-backend": "0.3.3", - "@backstage/plugin-bitbucket-cloud-common": "0.2.13", - "@backstage/plugin-bitrise": "0.1.52", - "@backstage/plugin-catalog": "1.14.0", - "@backstage/plugin-catalog-backend": "1.14.0", - "@backstage/plugin-catalog-backend-module-aws": "0.3.0", - "@backstage/plugin-catalog-backend-module-azure": "0.1.25", - "@backstage/plugin-catalog-backend-module-bitbucket": "0.2.21", - "@backstage/plugin-catalog-backend-module-bitbucket-cloud": "0.1.21", - "@backstage/plugin-catalog-backend-module-bitbucket-server": "0.1.19", - "@backstage/plugin-catalog-backend-module-gcp": "0.1.6", - "@backstage/plugin-catalog-backend-module-gerrit": "0.1.22", - "@backstage/plugin-catalog-backend-module-github": "0.4.4", - "@backstage/plugin-catalog-backend-module-github-org": "0.1.0", - "@backstage/plugin-catalog-backend-module-gitlab": "0.3.3", - "@backstage/plugin-catalog-backend-module-incremental-ingestion": "0.4.10", - "@backstage/plugin-catalog-backend-module-ldap": "0.5.21", - "@backstage/plugin-catalog-backend-module-msgraph": "0.5.13", - "@backstage/plugin-catalog-backend-module-openapi": "0.1.23", - "@backstage/plugin-catalog-backend-module-puppetdb": "0.1.11", - "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "0.1.3", - "@backstage/plugin-catalog-backend-module-unprocessed": "0.3.3", - "@backstage/plugin-catalog-common": "1.0.17", - "@backstage/plugin-catalog-graph": "0.2.37", - "@backstage/plugin-catalog-graphql": "0.4.0", - "@backstage/plugin-catalog-import": "0.10.1", - "@backstage/plugin-catalog-node": "1.4.7", - "@backstage/plugin-catalog-react": "1.8.5", - "@backstage/plugin-catalog-unprocessed-entities": "0.1.4", - "@backstage/plugin-cicd-statistics": "0.1.27", - "@backstage/plugin-cicd-statistics-module-gitlab": "0.1.21", - "@backstage/plugin-circleci": "0.3.25", - "@backstage/plugin-cloudbuild": "0.3.25", - "@backstage/plugin-code-climate": "0.1.25", - "@backstage/plugin-code-coverage": "0.2.18", - "@backstage/plugin-code-coverage-backend": "0.2.20", - "@backstage/plugin-codescene": "0.1.18", - "@backstage/plugin-config-schema": "0.1.46", - "@backstage/plugin-cost-insights": "0.12.14", + "@backstage/plugin-badges": "0.2.53", + "@backstage/plugin-badges-backend": "0.3.6", + "@backstage/plugin-bazaar": "0.2.21", + "@backstage/plugin-bazaar-backend": "0.3.7", + "@backstage/plugin-bitbucket-cloud-common": "0.2.15", + "@backstage/plugin-bitrise": "0.1.56", + "@backstage/plugin-catalog": "1.16.1", + "@backstage/plugin-catalog-backend": "1.16.1", + "@backstage/plugin-catalog-backend-module-aws": "0.3.3", + "@backstage/plugin-catalog-backend-module-azure": "0.1.28", + "@backstage/plugin-catalog-backend-module-backstage-openapi": "0.1.2", + "@backstage/plugin-catalog-backend-module-bitbucket": "0.2.24", + "@backstage/plugin-catalog-backend-module-bitbucket-cloud": "0.1.24", + "@backstage/plugin-catalog-backend-module-bitbucket-server": "0.1.22", + "@backstage/plugin-catalog-backend-module-gcp": "0.1.9", + "@backstage/plugin-catalog-backend-module-gerrit": "0.1.25", + "@backstage/plugin-catalog-backend-module-github": "0.4.7", + "@backstage/plugin-catalog-backend-module-github-org": "0.1.3", + "@backstage/plugin-catalog-backend-module-gitlab": "0.3.6", + "@backstage/plugin-catalog-backend-module-incremental-ingestion": "0.4.13", + "@backstage/plugin-catalog-backend-module-ldap": "0.5.24", + "@backstage/plugin-catalog-backend-module-msgraph": "0.5.16", + "@backstage/plugin-catalog-backend-module-openapi": "0.1.26", + "@backstage/plugin-catalog-backend-module-puppetdb": "0.1.14", + "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "0.1.6", + "@backstage/plugin-catalog-backend-module-unprocessed": "0.3.6", + "@backstage/plugin-catalog-common": "1.0.20", + "@backstage/plugin-catalog-graph": "0.3.3", + "@backstage/plugin-catalog-import": "0.10.5", + "@backstage/plugin-catalog-node": "1.6.1", + "@backstage/plugin-catalog-react": "1.9.3", + "@backstage/plugin-catalog-unprocessed-entities": "0.1.7", + "@backstage/plugin-cicd-statistics": "0.1.31", + "@backstage/plugin-cicd-statistics-module-gitlab": "0.1.25", + "@backstage/plugin-circleci": "0.3.29", + "@backstage/plugin-cloudbuild": "0.3.29", + "@backstage/plugin-code-climate": "0.1.29", + "@backstage/plugin-code-coverage": "0.2.22", + "@backstage/plugin-code-coverage-backend": "0.2.23", + "@backstage/plugin-codescene": "0.1.21", + "@backstage/plugin-config-schema": "0.1.49", + "@backstage/plugin-cost-insights": "0.12.18", "@backstage/plugin-cost-insights-common": "0.1.2", - "@backstage/plugin-devtools": "0.1.5", - "@backstage/plugin-devtools-backend": "0.2.3", - "@backstage/plugin-devtools-common": "0.1.5", - "@backstage/plugin-dynatrace": "7.0.5", - "@backstage/plugin-entity-feedback": "0.2.8", - "@backstage/plugin-entity-feedback-backend": "0.2.3", + "@backstage/plugin-devtools": "0.1.8", + "@backstage/plugin-devtools-backend": "0.2.6", + "@backstage/plugin-devtools-common": "0.1.8", + "@backstage/plugin-dynatrace": "8.0.3", + "@backstage/plugin-entity-feedback": "0.2.12", + "@backstage/plugin-entity-feedback-backend": "0.2.6", "@backstage/plugin-entity-feedback-common": "0.1.3", - "@backstage/plugin-entity-validation": "0.1.10", - "@backstage/plugin-events-backend": "0.2.15", - "@backstage/plugin-events-backend-module-aws-sqs": "0.2.9", - "@backstage/plugin-events-backend-module-azure": "0.1.16", - "@backstage/plugin-events-backend-module-bitbucket-cloud": "0.1.16", - "@backstage/plugin-events-backend-module-gerrit": "0.1.16", - "@backstage/plugin-events-backend-module-github": "0.1.16", - "@backstage/plugin-events-backend-module-gitlab": "0.1.16", - "@backstage/plugin-events-backend-test-utils": "0.1.16", - "@backstage/plugin-events-node": "0.2.15", - "@internal/plugin-todo-list": "1.0.18", - "@internal/plugin-todo-list-backend": "1.0.18", - "@internal/plugin-todo-list-common": "1.0.14", - "@backstage/plugin-explore": "0.4.11", - "@backstage/plugin-explore-backend": "0.0.16", + "@backstage/plugin-entity-validation": "0.1.14", + "@backstage/plugin-events-backend": "0.2.18", + "@backstage/plugin-events-backend-module-aws-sqs": "0.2.12", + "@backstage/plugin-events-backend-module-azure": "0.1.19", + "@backstage/plugin-events-backend-module-bitbucket-cloud": "0.1.19", + "@backstage/plugin-events-backend-module-gerrit": "0.1.19", + "@backstage/plugin-events-backend-module-github": "0.1.19", + "@backstage/plugin-events-backend-module-gitlab": "0.1.19", + "@backstage/plugin-events-backend-test-utils": "0.1.19", + "@backstage/plugin-events-node": "0.2.18", + "@internal/plugin-todo-list": "1.0.21", + "@internal/plugin-todo-list-backend": "1.0.21", + "@internal/plugin-todo-list-common": "1.0.17", + "@backstage/plugin-explore": "0.4.15", + "@backstage/plugin-explore-backend": "0.0.19", "@backstage/plugin-explore-common": "0.0.2", - "@backstage/plugin-explore-react": "0.0.32", - "@backstage/plugin-firehydrant": "0.2.9", - "@backstage/plugin-fossa": "0.2.57", - "@backstage/plugin-gcalendar": "0.3.19", - "@backstage/plugin-gcp-projects": "0.3.42", - "@backstage/plugin-git-release-manager": "0.3.38", - "@backstage/plugin-github-actions": "0.6.6", - "@backstage/plugin-github-deployments": "0.1.56", - "@backstage/plugin-github-issues": "0.2.14", - "@backstage/plugin-github-pull-requests-board": "0.1.19", - "@backstage/plugin-gitops-profiles": "0.3.41", - "@backstage/plugin-gocd": "0.1.31", - "@backstage/plugin-graphiql": "0.2.55", - "@backstage/plugin-graphql-backend": "0.2.0", - "@backstage/plugin-graphql-voyager": "0.1.8", - "@backstage/plugin-home": "0.5.9", - "@backstage/plugin-home-react": "0.1.4", - "@backstage/plugin-ilert": "0.2.14", - "@backstage/plugin-jenkins": "0.9.0", - "@backstage/plugin-jenkins-backend": "0.3.0", - "@backstage/plugin-jenkins-common": "0.1.20", - "@backstage/plugin-kafka": "0.3.25", - "@backstage/plugin-kafka-backend": "0.3.3", - "@backstage/plugin-kubernetes": "0.11.0", - "@backstage/plugin-kubernetes-backend": "0.13.0", - "@backstage/plugin-kubernetes-cluster": "0.0.1", - "@backstage/plugin-kubernetes-common": "0.7.0", - "@backstage/plugin-kubernetes-node": "0.1.0", - "@backstage/plugin-kubernetes-react": "0.1.0", - "@backstage/plugin-lighthouse": "0.4.10", - "@backstage/plugin-lighthouse-backend": "0.3.3", + "@backstage/plugin-explore-react": "0.0.35", + "@backstage/plugin-firehydrant": "0.2.13", + "@backstage/plugin-fossa": "0.2.61", + "@backstage/plugin-gcalendar": "0.3.22", + "@backstage/plugin-gcp-projects": "0.3.45", + "@backstage/plugin-git-release-manager": "0.3.41", + "@backstage/plugin-github-actions": "0.6.10", + "@backstage/plugin-github-deployments": "0.1.60", + "@backstage/plugin-github-issues": "0.2.18", + "@backstage/plugin-github-pull-requests-board": "0.1.23", + "@backstage/plugin-gitops-profiles": "0.3.44", + "@backstage/plugin-gocd": "0.1.35", + "@backstage/plugin-graphiql": "0.3.2", + "@backstage/plugin-graphql-voyager": "0.1.11", + "@backstage/plugin-home": "0.6.1", + "@backstage/plugin-home-react": "0.1.7", + "@backstage/plugin-ilert": "0.2.18", + "@backstage/plugin-jenkins": "0.9.4", + "@backstage/plugin-jenkins-backend": "0.3.3", + "@backstage/plugin-jenkins-common": "0.1.23", + "@backstage/plugin-kafka": "0.3.29", + "@backstage/plugin-kafka-backend": "0.3.7", + "@backstage/plugin-kubernetes": "0.11.4", + "@backstage/plugin-kubernetes-backend": "0.14.1", + "@backstage/plugin-kubernetes-cluster": "0.0.5", + "@backstage/plugin-kubernetes-common": "0.7.3", + "@backstage/plugin-kubernetes-node": "0.1.3", + "@backstage/plugin-kubernetes-react": "0.2.1", + "@backstage/plugin-lighthouse": "0.4.14", + "@backstage/plugin-lighthouse-backend": "0.4.1", "@backstage/plugin-lighthouse-common": "0.1.4", - "@backstage/plugin-linguist": "0.1.10", - "@backstage/plugin-linguist-backend": "0.5.3", + "@backstage/plugin-linguist": "0.1.14", + "@backstage/plugin-linguist-backend": "0.5.6", "@backstage/plugin-linguist-common": "0.1.2", - "@backstage/plugin-microsoft-calendar": "0.1.8", - "@backstage/plugin-newrelic": "0.3.41", - "@backstage/plugin-newrelic-dashboard": "0.3.0", - "@backstage/plugin-nomad": "0.1.6", - "@backstage/plugin-nomad-backend": "0.1.8", - "@backstage/plugin-octopus-deploy": "0.2.7", - "@backstage/plugin-opencost": "0.2.1", - "@backstage/plugin-org": "0.6.15", - "@backstage/plugin-org-react": "0.1.14", - "@backstage/plugin-pagerduty": "0.6.6", - "@backstage/plugin-periskop": "0.1.23", - "@backstage/plugin-periskop-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-common": "0.7.9", - "@backstage/plugin-permission-node": "0.7.17", - "@backstage/plugin-permission-react": "0.4.16", - "@backstage/plugin-playlist": "0.1.17", - "@backstage/plugin-playlist-backend": "0.3.10", - "@backstage/plugin-playlist-common": "0.1.11", - "@backstage/plugin-proxy-backend": "0.4.3", - "@backstage/plugin-puppetdb": "0.1.8", - "@backstage/plugin-rollbar": "0.4.25", - "@backstage/plugin-rollbar-backend": "0.1.51", - "@backstage/plugin-scaffolder": "1.15.1", - "@backstage/plugin-scaffolder-backend": "1.18.0", - "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown": "0.2.7", - "@backstage/plugin-scaffolder-backend-module-cookiecutter": "0.2.30", - "@backstage/plugin-scaffolder-backend-module-gitlab": "0.2.9", - "@backstage/plugin-scaffolder-backend-module-rails": "0.4.23", - "@backstage/plugin-scaffolder-backend-module-sentry": "0.1.14", - "@backstage/plugin-scaffolder-backend-module-yeoman": "0.2.27", - "@backstage/plugin-scaffolder-common": "1.4.2", - "@backstage/plugin-scaffolder-node": "0.2.6", - "@backstage/plugin-scaffolder-react": "1.5.6", - "@backstage/plugin-search": "1.4.1", - "@backstage/plugin-search-backend": "1.4.6", - "@backstage/plugin-search-backend-module-catalog": "0.1.10", - "@backstage/plugin-search-backend-module-elasticsearch": "1.3.9", - "@backstage/plugin-search-backend-module-explore": "0.1.10", - "@backstage/plugin-search-backend-module-pg": "0.5.15", - "@backstage/plugin-search-backend-module-techdocs": "0.1.10", - "@backstage/plugin-search-backend-node": "1.2.10", - "@backstage/plugin-search-common": "1.2.7", - "@backstage/plugin-search-react": "1.7.1", - "@backstage/plugin-sentry": "0.5.10", - "@backstage/plugin-shortcuts": "0.3.15", - "@backstage/plugin-sonarqube": "0.7.6", - "@backstage/plugin-sonarqube-backend": "0.2.8", - "@backstage/plugin-sonarqube-react": "0.1.9", - "@backstage/plugin-splunk-on-call": "0.4.14", - "@backstage/plugin-stack-overflow": "0.1.21", - "@backstage/plugin-stack-overflow-backend": "0.2.10", - "@backstage/plugin-stackstorm": "0.1.7", - "@backstage/plugin-tech-insights": "0.3.17", - "@backstage/plugin-tech-insights-backend": "0.5.20", - "@backstage/plugin-tech-insights-backend-module-jsonfc": "0.1.38", + "@backstage/plugin-microsoft-calendar": "0.1.11", + "@backstage/plugin-newrelic": "0.3.44", + "@backstage/plugin-newrelic-dashboard": "0.3.4", + "@backstage/plugin-nomad": "0.1.10", + "@backstage/plugin-nomad-backend": "0.1.11", + "@backstage/plugin-octopus-deploy": "0.2.11", + "@backstage/plugin-opencost": "0.2.4", + "@backstage/plugin-org": "0.6.19", + "@backstage/plugin-org-react": "0.1.18", + "@backstage/plugin-pagerduty": "0.7.1", + "@backstage/plugin-periskop": "0.1.27", + "@backstage/plugin-periskop-backend": "0.2.7", + "@backstage/plugin-permission-backend": "0.5.32", + "@backstage/plugin-permission-backend-module-allow-all-policy": "0.1.6", + "@backstage/plugin-permission-common": "0.7.12", + "@backstage/plugin-permission-node": "0.7.20", + "@backstage/plugin-permission-react": "0.4.19", + "@backstage/plugin-playlist": "0.2.3", + "@backstage/plugin-playlist-backend": "0.3.13", + "@backstage/plugin-playlist-common": "0.1.14", + "@backstage/plugin-proxy-backend": "0.4.7", + "@backstage/plugin-puppetdb": "0.1.12", + "@backstage/plugin-rollbar": "0.4.29", + "@backstage/plugin-rollbar-backend": "0.1.54", + "@backstage/plugin-scaffolder": "1.17.1", + "@backstage/plugin-scaffolder-backend": "1.20.0", + "@backstage/plugin-scaffolder-backend-module-azure": "0.1.1", + "@backstage/plugin-scaffolder-backend-module-bitbucket": "0.1.1", + "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown": "0.2.10", + "@backstage/plugin-scaffolder-backend-module-cookiecutter": "0.2.33", + "@backstage/plugin-scaffolder-backend-module-gerrit": "0.1.1", + "@backstage/plugin-scaffolder-backend-module-github": "0.1.1", + "@backstage/plugin-scaffolder-backend-module-gitlab": "0.2.12", + "@backstage/plugin-scaffolder-backend-module-rails": "0.4.26", + "@backstage/plugin-scaffolder-backend-module-sentry": "0.1.17", + "@backstage/plugin-scaffolder-backend-module-yeoman": "0.2.30", + "@backstage/plugin-scaffolder-common": "1.4.5", + "@backstage/plugin-scaffolder-node": "0.2.10", + "@backstage/plugin-scaffolder-react": "1.7.1", + "@backstage/plugin-search": "1.4.5", + "@backstage/plugin-search-backend": "1.4.9", + "@backstage/plugin-search-backend-module-catalog": "0.1.13", + "@backstage/plugin-search-backend-module-elasticsearch": "1.3.12", + "@backstage/plugin-search-backend-module-explore": "0.1.13", + "@backstage/plugin-search-backend-module-pg": "0.5.18", + "@backstage/plugin-search-backend-module-stack-overflow-collator": "0.1.2", + "@backstage/plugin-search-backend-module-techdocs": "0.1.13", + "@backstage/plugin-search-backend-node": "1.2.13", + "@backstage/plugin-search-common": "1.2.10", + "@backstage/plugin-search-react": "1.7.5", + "@backstage/plugin-sentry": "0.5.14", + "@backstage/plugin-shortcuts": "0.3.18", + "@backstage/plugin-sonarqube": "0.7.11", + "@backstage/plugin-sonarqube-backend": "0.2.11", + "@backstage/plugin-sonarqube-react": "0.1.12", + "@backstage/plugin-splunk-on-call": "0.4.18", + "@backstage/plugin-stack-overflow": "0.1.24", + "@backstage/plugin-stack-overflow-backend": "0.2.13", + "@backstage/plugin-stackstorm": "0.1.10", + "@backstage/plugin-tech-insights": "0.3.21", + "@backstage/plugin-tech-insights-backend": "0.5.23", + "@backstage/plugin-tech-insights-backend-module-jsonfc": "0.1.41", "@backstage/plugin-tech-insights-common": "0.2.12", - "@backstage/plugin-tech-insights-node": "0.4.12", - "@backstage/plugin-tech-radar": "0.6.9", - "@backstage/plugin-techdocs": "1.8.0", - "@backstage/plugin-techdocs-addons-test-utils": "1.0.22", - "@backstage/plugin-techdocs-backend": "1.8.0", - "@backstage/plugin-techdocs-module-addons-contrib": "1.1.1", - "@backstage/plugin-techdocs-node": "1.9.0", - "@backstage/plugin-techdocs-react": "1.1.12", - "@backstage/plugin-todo": "0.2.28", - "@backstage/plugin-todo-backend": "0.3.4", - "@backstage/plugin-user-settings": "0.7.11", - "@backstage/plugin-user-settings-backend": "0.2.4", - "@backstage/plugin-vault": "0.1.20", - "@backstage/plugin-vault-backend": "0.3.11", - "@backstage/plugin-xcmetrics": "0.2.44", - "@backstage/core-compat-api": "0.0.0", - "@backstage/plugin-catalog-backend-module-backstage-openapi": "0.0.0", - "@backstage/plugin-search-backend-module-stack-overflow-collator": "0.0.0", - "@backstage/plugin-vault-node": "0.0.0" + "@backstage/plugin-tech-insights-node": "0.4.15", + "@backstage/plugin-tech-radar": "0.6.12", + "@backstage/plugin-techdocs": "1.9.3", + "@backstage/plugin-techdocs-addons-test-utils": "1.0.26", + "@backstage/plugin-techdocs-backend": "1.9.2", + "@backstage/plugin-techdocs-module-addons-contrib": "1.1.4", + "@backstage/plugin-techdocs-node": "1.11.1", + "@backstage/plugin-techdocs-react": "1.1.15", + "@backstage/plugin-todo": "0.2.33", + "@backstage/plugin-todo-backend": "0.3.7", + "@backstage/plugin-user-settings": "0.8.0", + "@backstage/plugin-user-settings-backend": "0.2.8", + "@backstage/plugin-vault": "0.1.24", + "@backstage/plugin-vault-backend": "0.4.2", + "@backstage/plugin-vault-node": "0.1.2", + "@backstage/plugin-xcmetrics": "0.2.47" }, - "changesets": [ - "beige-stingrays-tap", - "big-roses-stare", - "blue-bags-warn", - "breezy-dogs-serve", - "brown-poets-join", - "chatty-cobras-cheer", - "chatty-countries-refuse", - "chilled-knives-rule", - "chilly-books-sneeze", - "chilly-terms-behave", - "clever-houses-scream", - "create-app-1698763033", - "curvy-carpets-kneel", - "curvy-carrots-thank", - "dirty-ducks-behave", - "dry-days-invite", - "eighty-chairs-camp", - "eleven-students-brake", - "fair-parrots-lick", - "fair-tools-bake", - "famous-plums-sit", - "fast-bears-lick", - "fifty-taxis-allow", - "flat-ducks-buy", - "fluffy-years-shake", - "four-files-behave", - "four-pears-swim", - "fresh-camels-give", - "fresh-crews-promise", - "fresh-schools-thank", - "gentle-elephants-look", - "gentle-pears-camp", - "gentle-pumpkins-carry", - "giant-cars-walk", - "giant-cycles-end", - "good-plums-confess", - "great-baboons-allow", - "healthy-dancers-dream", - "healthy-shirts-fold", - "heavy-experts-accept", - "heavy-rings-play", - "hip-moose-boil", - "hip-mugs-camp", - "hungry-paws-dress", - "hungry-radios-play", - "large-forks-arrive", - "late-forks-fetch", - "lazy-hotels-wait", - "long-turkeys-argue", - "loud-ghosts-deny", - "lovely-turtles-remain", - "many-masks-smoke", - "mighty-crews-attack", - "mighty-humans-shave", - "modern-ducks-battle", - "nasty-colts-tickle", - "new-beers-drive", - "new-kangaroos-train", - "nice-apes-kneel", - "nice-pillows-poke", - "ninety-numbers-study", - "old-apricots-taste", - "old-chairs-switch", - "old-coats-doubt", - "olive-doors-begin", - "olive-paws-divide", - "orange-ears-kiss", - "orange-jokes-tap", - "orange-planes-crash", - "plenty-buckets-float", - "plenty-tigers-argue", - "poor-seahorses-rush", - "popular-bikes-do", - "pretty-bats-end", - "pretty-swans-worry", - "quick-pumpkins-shave", - "quick-roses-move", - "real-apes-build", - "real-carrots-brake", - "real-jars-yawn", - "real-pears-study", - "red-beers-roll", - "red-yaks-press", - "renovate-dacadfa", - "rich-pugs-chew", - "rude-penguins-press", - "rude-tomatoes-itch", - "selfish-flies-kneel", - "shaggy-beers-collect", - "shaggy-buses-beg", - "sharp-chefs-attend", - "sharp-falcons-clean", - "shiny-geese-watch", - "shiny-goats-flash", - "silent-chairs-smoke", - "silver-kiwis-float", - "six-books-arrive", - "sixty-tips-argue", - "small-buckets-roll", - "smart-dancers-watch", - "sour-toes-joke", - "stale-horses-obey", - "stale-rice-count", - "strange-gifts-try", - "strange-queens-deliver", - "strange-taxis-explode", - "strong-taxis-wait", - "sweet-buckets-fry", - "sweet-countries-share", - "swift-badgers-hide", - "swift-mice-care", - "tall-colts-roll", - "tame-spies-hunt", - "tender-lies-wonder", - "tender-maps-type", - "thick-boats-decide", - "thick-dolphins-boil", - "thirty-stingrays-grin", - "three-moles-mix", - "tidy-camels-boil", - "tidy-planets-trade", - "tiny-files-judge", - "tricky-cups-hammer", - "tricky-vans-behave", - "twelve-donkeys-smash", - "two-jars-melt", - "unlucky-houses-end", - "violet-falcons-leave", - "violet-lamps-appear", - "weak-zebras-cover", - "wet-cows-brake", - "wet-shrimps-approve", - "wicked-ties-knock", - "wild-cows-watch", - "wild-geese-occur", - "wise-waves-approve", - "wise-weeks-design", - "young-days-talk" - ] + "changesets": [] } diff --git a/.changeset/pretty-bats-end.md b/.changeset/pretty-bats-end.md deleted file mode 100644 index 8b08c5b00f..0000000000 --- a/.changeset/pretty-bats-end.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-gitlab': patch ---- - -Resolved a bug affecting the retrieval of users from group members. By appending '/all' to the API call, we now include members from all inherited groups, as per Gitlab's API specifications. This change is reflected in the listSaaSUsers function. diff --git a/.changeset/pretty-swans-worry.md b/.changeset/pretty-swans-worry.md deleted file mode 100644 index 621ae98fe5..0000000000 --- a/.changeset/pretty-swans-worry.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -Fixed the type declaration of `DependencyGraphProps`, the `defs` prop now expects `JSX.Element`s. diff --git a/.changeset/quick-pumpkins-shave.md b/.changeset/quick-pumpkins-shave.md deleted file mode 100644 index cbb4c48dce..0000000000 --- a/.changeset/quick-pumpkins-shave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-home': patch ---- - -Added experimental support for declarative integration via the `/alpha` subpath. diff --git a/.changeset/quick-roses-move.md b/.changeset/quick-roses-move.md deleted file mode 100644 index 767ad0919e..0000000000 --- a/.changeset/quick-roses-move.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/dev-utils': patch -'@backstage/plugin-techdocs': patch ---- - -Switched the conditional `react-dom/client` import to use `import(...)` rather than `require(...)`. diff --git a/.changeset/real-apes-build.md b/.changeset/real-apes-build.md deleted file mode 100644 index 5481bebf3a..0000000000 --- a/.changeset/real-apes-build.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-backend-module-microsoft-provider': patch ---- - -Correctly mark the client secret in configuration as secret diff --git a/.changeset/real-carrots-brake.md b/.changeset/real-carrots-brake.md deleted file mode 100644 index e9ae1f0c27..0000000000 --- a/.changeset/real-carrots-brake.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-search-react': patch ---- - -Fixed a rare occurrence where a race in the search bar could throw away user input or cause the clear button not to work. diff --git a/.changeset/real-jars-yawn.md b/.changeset/real-jars-yawn.md deleted file mode 100644 index a89a687971..0000000000 --- a/.changeset/real-jars-yawn.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -If create app installs dependencies, don't suggest to user that they also need to do it. diff --git a/.changeset/real-pears-study.md b/.changeset/real-pears-study.md deleted file mode 100644 index 9cbf9d8a28..0000000000 --- a/.changeset/real-pears-study.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -Reverting the `MissingAnnotationEmptyState` component due to cyclical dependency. This component is now deprecated, please use the import from `@backstage/plugin-catalog-react` instead to use the new functionality diff --git a/.changeset/red-beers-roll.md b/.changeset/red-beers-roll.md deleted file mode 100644 index 3c061ce377..0000000000 --- a/.changeset/red-beers-roll.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-search-backend-module-techdocs': patch ---- - -The process of adding or modifying fields in the techdocs search index has been simplified. For more details, see [How to customize fields in the Software Catalog or TechDocs index](https://backstage.io/docs/features/search/how-to-guides.md#how-to-customize-fields-in-the-software-catalog-or-techdocs-index). diff --git a/.changeset/red-yaks-press.md b/.changeset/red-yaks-press.md deleted file mode 100644 index 7166ac345e..0000000000 --- a/.changeset/red-yaks-press.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-app-api': patch ---- - -Add current and default scopes when refreshing session diff --git a/.changeset/renovate-051a797.md b/.changeset/renovate-051a797.md deleted file mode 100644 index 76759f6173..0000000000 --- a/.changeset/renovate-051a797.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/integration-aws-node': patch -'@backstage/plugin-catalog-backend-module-aws': patch ---- - -Updated dependency `aws-sdk-client-mock-jest` to `^3.0.0`. diff --git a/.changeset/renovate-151ed0c.md b/.changeset/renovate-151ed0c.md deleted file mode 100644 index ee974fac52..0000000000 --- a/.changeset/renovate-151ed0c.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-cost-insights': patch ---- - -Updated dependency `@types/pluralize` to `^0.0.33`. diff --git a/.changeset/renovate-1693d3d.md b/.changeset/renovate-1693d3d.md deleted file mode 100644 index 2787ba12e4..0000000000 --- a/.changeset/renovate-1693d3d.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -Updated dependency `linkify-react` to `4.1.2`. diff --git a/.changeset/renovate-1fce036.md b/.changeset/renovate-1fce036.md deleted file mode 100644 index 6cb8980aea..0000000000 --- a/.changeset/renovate-1fce036.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -Updated dependency `linkifyjs` to `4.1.2`. diff --git a/.changeset/renovate-4d6eab0.md b/.changeset/renovate-4d6eab0.md deleted file mode 100644 index 6d3b498d88..0000000000 --- a/.changeset/renovate-4d6eab0.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.13.6`. -Updated dependency `@rjsf/core` to `5.13.6`. -Updated dependency `@rjsf/material-ui` to `5.13.6`. -Updated dependency `@rjsf/validator-ajv8` to `5.13.6`. diff --git a/.changeset/renovate-70e4741.md b/.changeset/renovate-70e4741.md deleted file mode 100644 index 47c572ca6a..0000000000 --- a/.changeset/renovate-70e4741.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@backstage/backend-common': patch -'@backstage/integration-aws-node': patch -'@backstage/plugin-catalog-backend-module-aws': patch -'@backstage/plugin-events-backend-module-aws-sqs': patch -'@backstage/plugin-techdocs-node': patch ---- - -Updated dependency `aws-sdk-client-mock` to `^3.0.0`. diff --git a/.changeset/renovate-788120b.md b/.changeset/renovate-788120b.md deleted file mode 100644 index 28bcf33b6f..0000000000 --- a/.changeset/renovate-788120b.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-analytics-module-ga4': patch ---- - -Updated dependency `@types/jest` to `^29.0.0`. diff --git a/.changeset/renovate-851933d.md b/.changeset/renovate-851933d.md deleted file mode 100644 index b2de30e2b2..0000000000 --- a/.changeset/renovate-851933d.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Updated dependency `vite-plugin-node-polyfills` to `^0.16.0`. diff --git a/.changeset/renovate-9bd0bec.md b/.changeset/renovate-9bd0bec.md deleted file mode 100644 index f254a55ca9..0000000000 --- a/.changeset/renovate-9bd0bec.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -'@backstage/catalog-client': patch -'@backstage/cli': patch -'@backstage/core-components': patch -'@backstage/integration': patch -'@backstage/release-manifests': patch -'@backstage/test-utils': patch -'@backstage/plugin-adr': patch -'@backstage/plugin-apache-airflow': patch -'@backstage/plugin-api-docs': patch -'@backstage/plugin-badges-backend': patch -'@backstage/plugin-bitbucket-cloud-common': patch -'@backstage/plugin-catalog-backend-module-backstage-openapi': patch -'@backstage/plugin-circleci': patch -'@backstage/plugin-cloudbuild': patch -'@backstage/plugin-cost-insights': patch -'@backstage/plugin-devtools': patch -'@backstage/plugin-explore-react': patch -'@backstage/plugin-explore': patch -'@backstage/plugin-fossa': patch -'@backstage/plugin-gcalendar': patch -'@backstage/plugin-gcp-projects': patch -'@backstage/plugin-github-actions': patch -'@backstage/plugin-gitops-profiles': patch -'@backstage/plugin-graphiql': patch -'@backstage/plugin-home-react': patch -'@backstage/plugin-jenkins': patch -'@backstage/plugin-newrelic': patch -'@backstage/plugin-nomad': patch -'@backstage/plugin-opencost': patch -'@backstage/plugin-permission-common': patch -'@backstage/plugin-permission-react': patch -'@backstage/plugin-rollbar': patch -'@backstage/plugin-sentry': patch -'@backstage/plugin-sonarqube': patch -'@backstage/plugin-stack-overflow': patch -'@backstage/plugin-tech-radar': patch -'@backstage/plugin-techdocs': patch -'@backstage/plugin-user-settings': patch ---- - -Updated dependency `cross-fetch` to `^4.0.0`. diff --git a/.changeset/renovate-a09b29c.md b/.changeset/renovate-a09b29c.md deleted file mode 100644 index 34765f733d..0000000000 --- a/.changeset/renovate-a09b29c.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/config-loader': patch ---- - -Updated dependency `typescript-json-schema` to `^0.62.0`. diff --git a/.changeset/renovate-abcaea1.md b/.changeset/renovate-abcaea1.md deleted file mode 100644 index 7413c5c546..0000000000 --- a/.changeset/renovate-abcaea1.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-api-docs': patch ---- - -Updated dependency `graphiql` to `3.0.9`. diff --git a/.changeset/renovate-c0b4ae6.md b/.changeset/renovate-c0b4ae6.md deleted file mode 100644 index d7ab8ff515..0000000000 --- a/.changeset/renovate-c0b4ae6.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-api-docs': patch ---- - -Updated dependency `@graphiql/react` to `^0.20.0`. diff --git a/.changeset/renovate-c1b681b.md b/.changeset/renovate-c1b681b.md deleted file mode 100644 index a128ace434..0000000000 --- a/.changeset/renovate-c1b681b.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-jenkins-backend': patch ---- - -Updated dependency `@types/jenkins` to `^1.0.0`. diff --git a/.changeset/renovate-c30c1cd.md b/.changeset/renovate-c30c1cd.md deleted file mode 100644 index 07d65b3e0c..0000000000 --- a/.changeset/renovate-c30c1cd.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-adr-backend': patch ---- - -Updated dependency `@types/marked` to `^5.0.0`. diff --git a/.changeset/renovate-d81ca26.md b/.changeset/renovate-d81ca26.md deleted file mode 100644 index 23b8354ea1..0000000000 --- a/.changeset/renovate-d81ca26.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Updated dependency `@typescript-eslint/eslint-plugin` to `6.10.0`. diff --git a/.changeset/renovate-dacadfa.md b/.changeset/renovate-dacadfa.md deleted file mode 100644 index a450dc06a9..0000000000 --- a/.changeset/renovate-dacadfa.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-cost-insights': patch ---- - -Updated dependency `@types/pluralize` to `^0.0.32`. diff --git a/.changeset/rich-pugs-chew.md b/.changeset/rich-pugs-chew.md deleted file mode 100644 index 6c5aa0af62..0000000000 --- a/.changeset/rich-pugs-chew.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -The experimental package detection will now ignore packages that don't make `package.json` available. diff --git a/.changeset/rude-penguins-press.md b/.changeset/rude-penguins-press.md deleted file mode 100644 index 967b04bc19..0000000000 --- a/.changeset/rude-penguins-press.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder': patch ---- - -Title and description in RepoUrlPicker are now correctly displayed. diff --git a/.changeset/rude-tomatoes-itch.md b/.changeset/rude-tomatoes-itch.md deleted file mode 100644 index 1071f65756..0000000000 --- a/.changeset/rude-tomatoes-itch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-app-api': patch ---- - -Installed features are now deduplicated both by reference and ID when available. Features passed to `createApp` now override both discovered and loaded features. diff --git a/.changeset/selfish-flies-kneel.md b/.changeset/selfish-flies-kneel.md deleted file mode 100644 index 0f13f11d11..0000000000 --- a/.changeset/selfish-flies-kneel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-app-api': patch ---- - -No longer throw error on invalid input if the child is disabled. diff --git a/.changeset/selfish-geese-mix.md b/.changeset/selfish-geese-mix.md deleted file mode 100644 index 69e34e1b2b..0000000000 --- a/.changeset/selfish-geese-mix.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-scaffolder-react': patch -'@backstage/plugin-scaffolder': patch -'@backstage/plugin-catalog': patch ---- - -Use `EntityRefLinks` with `hideIcons` property to avoid double icons diff --git a/.changeset/shaggy-beers-collect.md b/.changeset/shaggy-beers-collect.md deleted file mode 100644 index 471368d6f2..0000000000 --- a/.changeset/shaggy-beers-collect.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/dev-utils': patch -'@backstage/plugin-techdocs': patch ---- - -Added support for React 18. The new `createRoot` API from `react-dom/client` will now be used if present. diff --git a/.changeset/shaggy-buses-beg.md b/.changeset/shaggy-buses-beg.md deleted file mode 100644 index d2c9351b5e..0000000000 --- a/.changeset/shaggy-buses-beg.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@backstage/plugin-catalog-react': minor ---- - -The `UserListPicker` component has undergone improvements to enhance its performance. - -The previous implementation inferred the number of owned and starred entities based on the entities available in the `EntityListContext`. The updated version no longer relies on the `EntityListContext` for inference, allowing for better decoupling. - -The component now loads the entities' count asynchronously, resulting in improved performance and responsiveness. For this purpose, some of the exported filters such as `EntityTagFilter`, `EntityOwnerFilter`, `EntityLifecycleFilter` and `EntityNamespaceFilter` have now the `getCatalogFilters` method implemented. diff --git a/.changeset/sharp-chefs-attend.md b/.changeset/sharp-chefs-attend.md deleted file mode 100644 index 2334344928..0000000000 --- a/.changeset/sharp-chefs-attend.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-test-utils': patch ---- - -Ensure recursive deletion of temporary directories in tests diff --git a/.changeset/sharp-falcons-clean.md b/.changeset/sharp-falcons-clean.md deleted file mode 100644 index bc247be451..0000000000 --- a/.changeset/sharp-falcons-clean.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-app-api': patch ---- - -Register default implementation for the `Translation API` on the new `createApp`. diff --git a/.changeset/shiny-geese-watch.md b/.changeset/shiny-geese-watch.md deleted file mode 100644 index 5394a0776d..0000000000 --- a/.changeset/shiny-geese-watch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-backend-module-microsoft-provider': patch ---- - -Removed `prompt=consent` from start method to fix #20641 diff --git a/.changeset/shiny-goats-flash.md b/.changeset/shiny-goats-flash.md deleted file mode 100644 index 35a7ce0697..0000000000 --- a/.changeset/shiny-goats-flash.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-plugin-api': patch ---- - -Add new `AppTreeApi`. diff --git a/.changeset/silent-chairs-smoke.md b/.changeset/silent-chairs-smoke.md deleted file mode 100644 index bfd3a4d7cb..0000000000 --- a/.changeset/silent-chairs-smoke.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-app-api': patch ---- - -Fix for app node output IDs not being serialized correctly. diff --git a/.changeset/silent-pillows-reflect.md b/.changeset/silent-pillows-reflect.md deleted file mode 100644 index fe755056cc..0000000000 --- a/.changeset/silent-pillows-reflect.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Refactoring the runner to generate minimally informative task log per iteration and properly validate iterated actions. diff --git a/.changeset/silver-kiwis-float.md b/.changeset/silver-kiwis-float.md deleted file mode 100644 index 6a45dfb1a6..0000000000 --- a/.changeset/silver-kiwis-float.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-plugin-api': minor ---- - -Extensions now return their output from the factory function rather than calling `bind(...)`. diff --git a/.changeset/silver-yaks-bow.md b/.changeset/silver-yaks-bow.md deleted file mode 100644 index bd1aefd376..0000000000 --- a/.changeset/silver-yaks-bow.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-import': patch ---- - -Fix missing children key warning on the default catalog import page. diff --git a/.changeset/six-books-arrive.md b/.changeset/six-books-arrive.md deleted file mode 100644 index 785424f635..0000000000 --- a/.changeset/six-books-arrive.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -'@backstage/plugin-techdocs-module-addons-contrib': patch -'@backstage/plugin-microsoft-calendar': patch -'@backstage/plugin-scaffolder-react': patch -'@backstage/plugin-catalog-graph': patch -'@backstage/plugin-cost-insights': patch -'@backstage/plugin-tech-insights': patch -'@backstage/plugin-code-climate': patch -'@backstage/plugin-scaffolder': patch -'@backstage/plugin-gcalendar': patch -'@backstage/plugin-org-react': patch -'@backstage/plugin-sonarqube': patch -'@backstage/plugin-xcmetrics': patch -'@backstage/plugin-api-docs': patch -'@backstage/plugin-playlist': patch -'@backstage/plugin-catalog': patch -'@backstage/plugin-explore': patch -'@backstage/plugin-bazaar': patch -'@backstage/plugin-search': patch -'@backstage/plugin-org': patch ---- - -Internal theme type updates diff --git a/.changeset/sixty-tips-argue.md b/.changeset/sixty-tips-argue.md deleted file mode 100644 index 9fc965a281..0000000000 --- a/.changeset/sixty-tips-argue.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-plugin-api': patch ---- - -Improve the extension boundary component and create a default extension suspense component. diff --git a/.changeset/small-buckets-roll.md b/.changeset/small-buckets-roll.md deleted file mode 100644 index 5cd9b23678..0000000000 --- a/.changeset/small-buckets-roll.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-home': patch ---- - -Temporarily pin the `react-grid-layout` sub-dependency to version `1.3.4` while the horizontal resizing of the latest version is not fixed. For more details, see [#20712](https://github.com/backstage/backstage/issues/20712). diff --git a/.changeset/smart-dancers-watch.md b/.changeset/smart-dancers-watch.md deleted file mode 100644 index b47a6ae5c2..0000000000 --- a/.changeset/smart-dancers-watch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-plugin-api': minor ---- - -`IconComponent` can now have a `fontSize` of `inherit`, which is useful for in-line icons. diff --git a/.changeset/soft-oranges-act.md b/.changeset/soft-oranges-act.md deleted file mode 100644 index 99ff63395f..0000000000 --- a/.changeset/soft-oranges-act.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-react': patch ---- - -Preserve step's time execution for a non-running task. diff --git a/.changeset/sour-toes-joke.md b/.changeset/sour-toes-joke.md deleted file mode 100644 index 4e380f4ded..0000000000 --- a/.changeset/sour-toes-joke.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -'@backstage/plugin-user-settings-backend': patch -'@backstage/plugin-scaffolder-backend': patch -'@backstage/plugin-periskop-backend': patch -'@backstage/plugin-scaffolder-node': patch -'@backstage/plugin-bazaar-backend': patch -'@backstage/plugin-kafka-backend': patch -'@backstage/plugin-proxy-backend': patch -'@backstage/plugin-sonarqube': patch -'@backstage/plugin-todo': patch ---- - -Switched to using `"exports"` field for `/alpha` subpath export. diff --git a/.changeset/stale-horses-obey.md b/.changeset/stale-horses-obey.md deleted file mode 100644 index 671844c1b7..0000000000 --- a/.changeset/stale-horses-obey.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -'@backstage/plugin-github-deployments': patch -'@backstage/plugin-kubernetes-cluster': patch -'@backstage/plugin-newrelic-dashboard': patch -'@backstage/plugin-github-actions': patch -'@backstage/plugin-splunk-on-call': patch -'@backstage/plugin-code-coverage': patch -'@backstage/plugin-code-climate': patch -'@backstage/plugin-azure-sites': patch -'@backstage/plugin-cloudbuild': patch -'@backstage/plugin-kubernetes': patch -'@backstage/plugin-lighthouse': patch -'@backstage/plugin-dynatrace': patch -'@backstage/plugin-sonarqube': patch -'@backstage/plugin-airbrake': patch -'@backstage/plugin-circleci': patch -'@backstage/plugin-puppetdb': patch -'@backstage/plugin-techdocs': patch -'@backstage/plugin-bitrise': patch -'@backstage/plugin-jenkins': patch -'@backstage/plugin-rollbar': patch -'@backstage/plugin-allure': patch -'@backstage/plugin-sentry': patch -'@backstage/plugin-fossa': patch -'@backstage/plugin-kafka': patch -'@backstage/plugin-nomad': patch -'@backstage/plugin-vault': patch -'@backstage/plugin-gocd': patch -'@backstage/plugin-adr': patch ---- - -Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency diff --git a/.changeset/stale-rice-count.md b/.changeset/stale-rice-count.md deleted file mode 100644 index 3d2caf168d..0000000000 --- a/.changeset/stale-rice-count.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-plugin-api': patch ---- - -Deprecated several types related to the routing system that are scheduled to be removed, as well as several fields on the route ref types themselves. diff --git a/.changeset/strange-gifts-try.md b/.changeset/strange-gifts-try.md deleted file mode 100644 index 7f9aa89ad4..0000000000 --- a/.changeset/strange-gifts-try.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@backstage/frontend-app-api': patch -'@backstage/plugin-catalog': patch -'@backstage/plugin-catalog-react': patch -'@backstage/plugin-graphiql': patch -'@backstage/plugin-search-react': patch ---- - -Internal updates to match changes in the experimental `@backstage/frontend-plugin-api`. diff --git a/.changeset/strange-queens-deliver.md b/.changeset/strange-queens-deliver.md deleted file mode 100644 index ed1d4d0b5b..0000000000 --- a/.changeset/strange-queens-deliver.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-backend': patch ---- - -Reverted the Microsoft auth provider to the previous implementation. diff --git a/.changeset/strange-taxis-explode.md b/.changeset/strange-taxis-explode.md deleted file mode 100644 index 41bcf1895c..0000000000 --- a/.changeset/strange-taxis-explode.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-kubernetes-backend': patch -'@backstage/plugin-kubernetes-common': patch ---- - -Fixed the lack of `resourcequotas` as part of the Default Objects to fetch from the kubernetes api diff --git a/.changeset/strong-sloths-push.md b/.changeset/strong-sloths-push.md deleted file mode 100644 index 52ae7698a3..0000000000 --- a/.changeset/strong-sloths-push.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': minor ---- - -Allow using `globby`'s negative matching with `copyWithoutTemplating`/`copyWithoutRender`. This allows including an entire subdirectory while excluding a single file so that it will still be templated instead of needing to list every other file and ensure the list is updated when new files are added. diff --git a/.changeset/strong-taxis-wait.md b/.changeset/strong-taxis-wait.md deleted file mode 100644 index 13cfa9a1ba..0000000000 --- a/.changeset/strong-taxis-wait.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-app-api': patch ---- - -Added a workaround for double `default` wrapping when dynamically importing CommonJS modules with default exports. diff --git a/.changeset/sweet-buckets-fry.md b/.changeset/sweet-buckets-fry.md deleted file mode 100644 index 8f17617645..0000000000 --- a/.changeset/sweet-buckets-fry.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-react': patch ---- - -The `spec.type` field in entities will now always be rendered as a string. diff --git a/.changeset/sweet-countries-share.md b/.changeset/sweet-countries-share.md deleted file mode 100644 index e1327a74b8..0000000000 --- a/.changeset/sweet-countries-share.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Add examples for `github:webhook` scaffolder action & improve related tests diff --git a/.changeset/swift-badgers-hide.md b/.changeset/swift-badgers-hide.md deleted file mode 100644 index 217253370e..0000000000 --- a/.changeset/swift-badgers-hide.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-app-api': patch ---- - -Internal refactor to rename the app graph to app tree diff --git a/.changeset/swift-mice-care.md b/.changeset/swift-mice-care.md deleted file mode 100644 index 1d0d7d8703..0000000000 --- a/.changeset/swift-mice-care.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Added `EXPERIMENTAL_VITE` flag for using [vite](https://vitejs.dev) as dev server instead of Webpack diff --git a/.changeset/tall-colts-roll.md b/.changeset/tall-colts-roll.md deleted file mode 100644 index 914a09cdac..0000000000 --- a/.changeset/tall-colts-roll.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': minor ---- - -Allow setting `update: true` in `publish:github:pull-request` scaffolder action diff --git a/.changeset/tame-spies-hunt.md b/.changeset/tame-spies-hunt.md deleted file mode 100644 index 5a45defb7e..0000000000 --- a/.changeset/tame-spies-hunt.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Add examples for `github:deployKey:create` scaffolder action & improve related tests diff --git a/.changeset/tender-lies-wonder.md b/.changeset/tender-lies-wonder.md deleted file mode 100644 index 43124bb41c..0000000000 --- a/.changeset/tender-lies-wonder.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-backend': minor ---- - -Adds the StaticTokenIssuer and StaticKeyStore, an alternative token issuer that can be used to sign the Authorization header using a predefined public/private key pair. diff --git a/.changeset/tender-maps-type.md b/.changeset/tender-maps-type.md deleted file mode 100644 index 11aa814a17..0000000000 --- a/.changeset/tender-maps-type.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-plugin-api': minor ---- - -Introduced `AnyRouteRefParams` as a replacement for `AnyParams`, which is now deprecated. diff --git a/.changeset/thick-boats-decide.md b/.changeset/thick-boats-decide.md deleted file mode 100644 index e258962ecd..0000000000 --- a/.changeset/thick-boats-decide.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Added missing node-gyp dependency to fix Docker image build diff --git a/.changeset/thick-dolphins-boil.md b/.changeset/thick-dolphins-boil.md deleted file mode 100644 index dd562e620c..0000000000 --- a/.changeset/thick-dolphins-boil.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-import': patch ---- - -The `app.title` configuration is now properly required to be a string. diff --git a/.changeset/thick-tigers-call.md b/.changeset/thick-tigers-call.md deleted file mode 100644 index 4a9c66a354..0000000000 --- a/.changeset/thick-tigers-call.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -'@backstage/plugin-playlist': minor ---- - -Support being able to define custom composable Playlist index pages - -**BREAKING** The individual `PlaylistPage` route must now be manually hooked up by making the following change to your setup: - -```diff --import { PlaylistIndexPage } from '@backstage/plugin-playlist'; -+import { PlaylistIndexPage, PlaylistPage } from '@backstage/plugin-playlist'; - -// ... - - } /> -+} /> -``` diff --git a/.changeset/thirty-stingrays-grin.md b/.changeset/thirty-stingrays-grin.md deleted file mode 100644 index 6dcb4bbd50..0000000000 --- a/.changeset/thirty-stingrays-grin.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-openapi-utils': minor ---- - -Adds a new route, `/openapi.json` to validated routers for displaying their full OpenAPI spec in a standard endpoint. diff --git a/.changeset/three-moles-mix.md b/.changeset/three-moles-mix.md deleted file mode 100644 index d1e48194a1..0000000000 --- a/.changeset/three-moles-mix.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-search': patch ---- - -Fixed incorrect plugin ID in `/alpha` export. diff --git a/.changeset/tidy-camels-boil.md b/.changeset/tidy-camels-boil.md deleted file mode 100644 index 6e59f96f34..0000000000 --- a/.changeset/tidy-camels-boil.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-app-api': patch ---- - -Add component data `core.type` marker for `AppRouter` and `FlatRoutes`. diff --git a/.changeset/tidy-gorillas-carry.md b/.changeset/tidy-gorillas-carry.md deleted file mode 100644 index 47d8de8f30..0000000000 --- a/.changeset/tidy-gorillas-carry.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-react': patch ---- - -Move the `EntityRefLink` icon to the left hand side as per Material-UI guidelines diff --git a/.changeset/tidy-planets-trade.md b/.changeset/tidy-planets-trade.md deleted file mode 100644 index 49c1643e55..0000000000 --- a/.changeset/tidy-planets-trade.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch -'@backstage/plugin-scaffolder-common': patch -'@backstage/plugin-scaffolder-react': patch ---- - -Make it possible to define control buttons text (Back, Create, Review) per template diff --git a/.changeset/tiny-files-judge.md b/.changeset/tiny-files-judge.md deleted file mode 100644 index 781adef3c7..0000000000 --- a/.changeset/tiny-files-judge.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs': minor ---- - -A new analytics event `not-found` will be published when a user visits a documentation site that does not exist diff --git a/.changeset/tricky-cups-hammer.md b/.changeset/tricky-cups-hammer.md deleted file mode 100644 index 4e1b6fe9ce..0000000000 --- a/.changeset/tricky-cups-hammer.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-plugin-api': patch ---- - -Added a new `/alpha` export `convertLegacyRouteRef`, which is a temporary utility to allow existing route refs to be used with the new experimental packages. diff --git a/.changeset/tricky-vans-behave.md b/.changeset/tricky-vans-behave.md deleted file mode 100644 index 89592e5e8f..0000000000 --- a/.changeset/tricky-vans-behave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-openapi-utils': patch ---- - -Adds a new function `wrapInOpenApiTestServer` that allows for proxied requests at runtime. This will support the new `yarn backstage-repo-tools schema openapi test` command. diff --git a/.changeset/twelve-donkeys-smash.md b/.changeset/twelve-donkeys-smash.md deleted file mode 100644 index 3cbdea388b..0000000000 --- a/.changeset/twelve-donkeys-smash.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-github-actions': patch ---- - -Fixed an issue that was preventing the sorting of workflow runs by their status. diff --git a/.changeset/two-jars-melt.md b/.changeset/two-jars-melt.md deleted file mode 100644 index 2789157065..0000000000 --- a/.changeset/two-jars-melt.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-techdocs-backend': minor -'@backstage/plugin-techdocs-node': minor ---- - -Expose an extension point to set a custom build strategy. Also move `DocsBuildStrategy` type to `@backstage/plugin-techdocs-node` and deprecate `ShouldBuildParameters` type. diff --git a/.changeset/unlucky-houses-end.md b/.changeset/unlucky-houses-end.md deleted file mode 100644 index 48f5849002..0000000000 --- a/.changeset/unlucky-houses-end.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-github': patch ---- - -Import `AnalyzeOptions` and `ScmLocationAnalyzer` types from `@backstage/plugin-catalog-node` diff --git a/.changeset/violet-falcons-leave.md b/.changeset/violet-falcons-leave.md deleted file mode 100644 index 03b91957b1..0000000000 --- a/.changeset/violet-falcons-leave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-react': patch ---- - -Removed unnecessary `@backstage/integration` dependency, replaced by `@backstage/integration-react`. diff --git a/.changeset/violet-lamps-appear.md b/.changeset/violet-lamps-appear.md deleted file mode 100644 index 23536fb728..0000000000 --- a/.changeset/violet-lamps-appear.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -'@backstage/plugin-scaffolder': minor -'@backstage/plugin-scaffolder-react': minor ---- - -Release design improvements for the `Scaffolder` plugin and support v5 of `@rjsf/*` libraries. - -This change should be non-breaking. If you're seeing typescript issues after migrating please [open an issue](https://github.com/backstage/backstage/issues/new/choose) - -The `next` versions like `createNextFieldExtension` and `NextScaffolderPage` have been promoted to the public interface under `createScaffolderFieldExtension` and `ScaffolderPage`, so any older imports which are no longer found will need updating from `@backstage/plugin-scaffolder/alpha` or `@backstage/plugin-scaffolder-react/alpha` will need to be imported from `@backstage/plugin-scaffolder` and `@backstage/plugin-scaffolder-react` respectively. - -The legacy versions are now available in `/alpha` under `createLegacyFieldExtension` and `LegacyScaffolderPage` if you're running into issues, but be aware that these will be removed in a next mainline release. diff --git a/.changeset/warm-maps-scream.md b/.changeset/warm-maps-scream.md new file mode 100644 index 0000000000..3ea5d93b03 --- /dev/null +++ b/.changeset/warm-maps-scream.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-azure-devops': patch +'@backstage/plugin-devtools': patch +'@backstage/plugin-linguist': patch +--- + +Updated imports from named to default imports to help with the Material UI v4 to v5 migration diff --git a/.changeset/weak-zebras-cover.md b/.changeset/weak-zebras-cover.md deleted file mode 100644 index f3290683e2..0000000000 --- a/.changeset/weak-zebras-cover.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-search-react': patch ---- - -Minor refactor of search bar analytics capture diff --git a/.changeset/wet-cows-brake.md b/.changeset/wet-cows-brake.md deleted file mode 100644 index 9e694d8452..0000000000 --- a/.changeset/wet-cows-brake.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-search-react': patch ---- - -The filter options passed to `SearchResultGroupLayout` are now always explicitly rendered as strings by default. diff --git a/.changeset/wet-shrimps-approve.md b/.changeset/wet-shrimps-approve.md deleted file mode 100644 index b75a28f355..0000000000 --- a/.changeset/wet-shrimps-approve.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-react': patch ---- - -Export `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` diff --git a/.changeset/wicked-ties-knock.md b/.changeset/wicked-ties-knock.md deleted file mode 100644 index 582cb905d0..0000000000 --- a/.changeset/wicked-ties-knock.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-gitlab': patch ---- - -Add examples for `gitlab:projectAccessToken:create` scaffolder action & improve related tests diff --git a/.changeset/wild-cows-watch.md b/.changeset/wild-cows-watch.md deleted file mode 100644 index 770fb1a692..0000000000 --- a/.changeset/wild-cows-watch.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -'@backstage/plugin-catalog': minor ---- - -Added the `DefaultEntityPresentationApi`, which is an implementation of the -`EntityPresentationApi` that `@backstage/plugin-catalog-react` exposes through -its `entityPresentationApiRef`. This implementation is also by default made -available automatically by the catalog plugin, unless you replace it with a -custom one. It batch fetches and caches data from the catalog as needed for -display, and is customizable by adopters to add their own rendering functions. diff --git a/.changeset/wild-geese-occur.md b/.changeset/wild-geese-occur.md deleted file mode 100644 index b97620e7f5..0000000000 --- a/.changeset/wild-geese-occur.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-search': patch ---- - -Minor internal code cleanup. diff --git a/.changeset/wise-waves-approve.md b/.changeset/wise-waves-approve.md deleted file mode 100644 index f543f8918c..0000000000 --- a/.changeset/wise-waves-approve.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Ignore `stdin` when spawning backend child process for the `start` command. Fixing an issue where backend startup would hang. diff --git a/.changeset/wise-weeks-design.md b/.changeset/wise-weeks-design.md deleted file mode 100644 index 657a8e23d5..0000000000 --- a/.changeset/wise-weeks-design.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Add examples for `publish:github:pull-request` scaffolder action & improve related tests diff --git a/.changeset/young-days-talk.md b/.changeset/young-days-talk.md deleted file mode 100644 index b7420c7894..0000000000 --- a/.changeset/young-days-talk.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-search-react': patch ---- - -Use default extensions boundary and suspense on the alpha declarative `createSearchResultListItem` extension factory. diff --git a/.changeset/young-rules-repeat.md b/.changeset/young-rules-repeat.md new file mode 100644 index 0000000000..6fb17f0608 --- /dev/null +++ b/.changeset/young-rules-repeat.md @@ -0,0 +1,5 @@ +--- +'@backstage/eslint-plugin': patch +--- + +Added new `@backstage/no-top-level-material-ui-4-imports` rule that forbids top level imports from Material UI v4 packages diff --git a/.github/labeler.yml b/.github/labeler.yml index dc048b1744..add66d7b28 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -2,7 +2,7 @@ area:catalog: - plugins/catalog/**/* - plugins/catalog-*/**/* - packages/catalog-*/**/* -scaffolder: +area:scaffolder: - plugins/scaffolder/**/* - plugins/scaffolder-*/**/* search: diff --git a/.github/uffizzi/k8s/manifests/backstage-deploy.yaml b/.github/uffizzi/k8s/manifests/backstage-deploy.yaml index 9bf62e991a..2c1458cfea 100644 --- a/.github/uffizzi/k8s/manifests/backstage-deploy.yaml +++ b/.github/uffizzi/k8s/manifests/backstage-deploy.yaml @@ -35,3 +35,10 @@ spec: 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/pg-deploy.yaml b/.github/uffizzi/k8s/manifests/pg-deploy.yaml index 354acd8e87..950e64283f 100644 --- a/.github/uffizzi/k8s/manifests/pg-deploy.yaml +++ b/.github/uffizzi/k8s/manifests/pg-deploy.yaml @@ -15,15 +15,25 @@ spec: spec: containers: - name: postgres - image: postgres:13.2-alpine + 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: /var/lib/postgresql + - mountPath: /data name: postgresdb volumes: - name: postgresdb diff --git a/.github/uffizzi/uffizzi.production.app-config.yaml b/.github/uffizzi/uffizzi.production.app-config.yaml index fb6638295e..53944256e1 100644 --- a/.github/uffizzi/uffizzi.production.app-config.yaml +++ b/.github/uffizzi/uffizzi.production.app-config.yaml @@ -38,6 +38,14 @@ auth: 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 diff --git a/.github/vale/Vocab/Backstage/accept.txt b/.github/vale/Vocab/Backstage/accept.txt index 73f6d56bb4..d557434d78 100644 --- a/.github/vale/Vocab/Backstage/accept.txt +++ b/.github/vale/Vocab/Backstage/accept.txt @@ -323,6 +323,7 @@ reusability Reusability roadmaps rollbar +Roboto Rollbar Rollup routable @@ -462,3 +463,4 @@ zod Zolotusky zoomable zsh +scrollable \ No newline at end of file diff --git a/.github/workflows/automate_area-labels.yml b/.github/workflows/automate_area-labels.yml index 1ba3b1d6c3..5d12e4ca89 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@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit diff --git a/.github/workflows/automate_changeset_feedback.yml b/.github/workflows/automate_changeset_feedback.yml index 1768cb670e..bf58b4b49d 100644 --- a/.github/workflows/automate_changeset_feedback.yml +++ b/.github/workflows/automate_changeset_feedback.yml @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit diff --git a/.github/workflows/automate_merge_message.yml b/.github/workflows/automate_merge_message.yml index d967e4404c..71e3450235 100644 --- a/.github/workflows/automate_merge_message.yml +++ b/.github/workflows/automate_merge_message.yml @@ -24,7 +24,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit @@ -44,7 +44,7 @@ jobs: node generate.js ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }} > message.txt - name: Post Message - uses: actions/github-script@v6.4.1 + uses: actions/github-script@v7.0.1 env: ISSUE_NUMBER: ${{ github.event.pull_request.number }} with: diff --git a/.github/workflows/automate_stale.yml b/.github/workflows/automate_stale.yml index b888471254..6d6fd65c0d 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@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit diff --git a/.github/workflows/ci-noop.yml b/.github/workflows/ci-noop.yml index 648386873b..6918db4be5 100644 --- a/.github/workflows/ci-noop.yml +++ b/.github/workflows/ci-noop.yml @@ -39,7 +39,7 @@ jobs: name: Test ${{ matrix.node-version }} steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b77983db04..ada4233f18 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,14 +27,14 @@ jobs: name: Install ${{ matrix.node-version }} steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit - uses: actions/checkout@v4.1.1 - name: use node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.0 + uses: actions/setup-node@v4.0.1 with: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth @@ -63,14 +63,14 @@ jobs: name: Verify ${{ matrix.node-version }} steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit - uses: actions/checkout@v4.1.1 - name: use node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.0 + uses: actions/setup-node@v4.0.1 with: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth @@ -153,8 +153,8 @@ jobs: name: Test ${{ matrix.node-version }} services: - postgres13: - image: postgres:13 + postgres16: + image: postgres:16 env: POSTGRES_PASSWORD: postgres options: >- @@ -164,8 +164,8 @@ jobs: --health-retries 5 ports: - 5432/tcp - postgres9: - image: postgres:9 + postgres12: + image: postgres:12 env: POSTGRES_PASSWORD: postgres options: >- @@ -201,7 +201,7 @@ jobs: run: git fetch origin master - name: use node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.0 + uses: actions/setup-node@v4.0.1 with: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth @@ -218,8 +218,8 @@ jobs: run: yarn backstage-cli repo test --maxWorkers=2 --workerIdleMemoryLimit=1300M --since origin/master env: BACKSTAGE_TEST_DISABLE_DOCKER: 1 - BACKSTAGE_TEST_DATABASE_POSTGRES13_CONNECTION_STRING: postgresql://postgres:postgres@localhost:${{ job.services.postgres13.ports[5432] }} - BACKSTAGE_TEST_DATABASE_POSTGRES9_CONNECTION_STRING: postgresql://postgres:postgres@localhost:${{ job.services.postgres9.ports[5432] }} + 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 # We run the test cases before verifying the specs to prevent any failing tests from causing errors. diff --git a/.github/workflows/cron.yml b/.github/workflows/cron.yml index f1a1dbd0b0..4a9e4522f4 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@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit diff --git a/.github/workflows/deploy_docker-image.yml b/.github/workflows/deploy_docker-image.yml index 89177b971f..037d4a88d7 100644 --- a/.github/workflows/deploy_docker-image.yml +++ b/.github/workflows/deploy_docker-image.yml @@ -16,7 +16,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit @@ -27,7 +27,7 @@ jobs: ref: v${{ github.event.client_payload.version }} - name: use node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.0 + uses: actions/setup-node@v4.0.1 with: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth @@ -47,21 +47,21 @@ jobs: working-directory: ./example-app - name: Login to GitHub Container Registry - uses: docker/login-action@v2.2.0 + uses: docker/login-action@v3.0.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2.10.0 + uses: docker/setup-buildx-action@v3.0.0 - name: Build and push - uses: docker/build-push-action@v4.2.1 + uses: docker/build-push-action@v5.1.0 with: context: './example-app' file: ./example-app/packages/backend/Dockerfile - push: ${{ github.event_name == "repository_dispatch" && github.event.action == "release-published" }} + push: ${{ (github.event_name == "repository_dispatch") && (github.event.action == "release-published") }} platforms: linux/amd64,linux/arm64 tags: | ghcr.io/${{ github.repository_owner }}/backstage:latest diff --git a/.github/workflows/deploy_microsite.yml b/.github/workflows/deploy_microsite.yml index c7b621f8fe..8343b92a66 100644 --- a/.github/workflows/deploy_microsite.yml +++ b/.github/workflows/deploy_microsite.yml @@ -24,14 +24,14 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit - uses: actions/checkout@v4.1.1 - name: use node.js 18.x - uses: actions/setup-node@v4.0.0 + uses: actions/setup-node@v4.0.1 with: node-version: 18.x registry-url: https://registry.npmjs.org/ # Needed for auth @@ -66,7 +66,7 @@ jobs: run: ls microsite/build && ls microsite/build/storybook - name: Deploy both microsite and storybook to gh-pages - uses: JamesIves/github-pages-deploy-action@a1ea191d508feb8485aceba848389d49f80ca2dc # v4.4.3 + uses: JamesIves/github-pages-deploy-action@65b5dfd4f5bcd3a7403bbc2959c144256167464e # v4.5.0 with: branch: gh-pages folder: microsite/build diff --git a/.github/workflows/deploy_nightly.yml b/.github/workflows/deploy_nightly.yml index 39bf38f907..33dc17f867 100644 --- a/.github/workflows/deploy_nightly.yml +++ b/.github/workflows/deploy_nightly.yml @@ -15,14 +15,14 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: use node.js 18.x - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 + uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1 with: node-version: 18.x registry-url: https://registry.npmjs.org/ # Needed for auth diff --git a/.github/workflows/deploy_packages.yml b/.github/workflows/deploy_packages.yml index 5b2acbdd3b..0d81f1c40a 100644 --- a/.github/workflows/deploy_packages.yml +++ b/.github/workflows/deploy_packages.yml @@ -17,8 +17,8 @@ jobs: node-version: [18.x, 20.x] services: - postgres13: - image: postgres:13 + postgres16: + image: postgres:16 env: POSTGRES_PASSWORD: postgres options: >- @@ -28,8 +28,8 @@ jobs: --health-retries 5 ports: - 5432/tcp - postgres9: - image: postgres:9 + postgres12: + image: postgres:12 env: POSTGRES_PASSWORD: postgres options: >- @@ -63,7 +63,7 @@ jobs: - uses: actions/checkout@v4.1.1 - name: use node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.0 + uses: actions/setup-node@v4.0.1 with: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth @@ -106,8 +106,8 @@ jobs: 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_POSTGRES13_CONNECTION_STRING: postgresql://postgres:postgres@localhost:${{ job.services.postgres13.ports[5432] }} - BACKSTAGE_TEST_DATABASE_POSTGRES9_CONNECTION_STRING: postgresql://postgres:postgres@localhost:${{ job.services.postgres9.ports[5432] }} + 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 - name: Discord notification @@ -138,14 +138,14 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit - uses: actions/checkout@v4.1.1 - name: use node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.0 + uses: actions/setup-node@v4.0.1 with: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth @@ -171,7 +171,7 @@ jobs: if [ -f ".changeset/pre.json" ]; then yarn workspaces foreach -v --no-private npm publish --access public --tolerate-republish --tag next else - yarn workspaces foreach -p -j 10 -v --no-private npm publish --access public --tolerate-republish + yarn workspaces foreach -v --no-private npm publish --access public --tolerate-republish fi env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/issue.yaml b/.github/workflows/issue.yaml index 8ef339efc7..c81447e9c0 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@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit diff --git a/.github/workflows/pr-review-comment-trigger.yaml b/.github/workflows/pr-review-comment-trigger.yaml index 60129eee82..bfd1ffef3d 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@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit diff --git a/.github/workflows/pr-review-comment.yaml b/.github/workflows/pr-review-comment.yaml index d85bb26f60..7d9869d378 100644 --- a/.github/workflows/pr-review-comment.yaml +++ b/.github/workflows/pr-review-comment.yaml @@ -17,13 +17,13 @@ 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@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit - name: Read PR Number id: pr-number - uses: actions/github-script@v6.4.1 + uses: actions/github-script@v7.0.1 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index cfa0738332..6c2ffcfe77 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@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 74ed8fe49f..64472e71c6 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -29,7 +29,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit @@ -66,6 +66,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: 'Upload to code-scanning' - uses: github/codeql-action/upload-sarif@74483a38d39275f33fcff5f35b679b5ca4a26a99 # v2.22.5 + uses: github/codeql-action/upload-sarif@1500a131381b66de0c52ac28abb13cd79f4b7ecc # v2.22.12 with: sarif_file: results.sarif diff --git a/.github/workflows/sync_code-formatting.yml b/.github/workflows/sync_code-formatting.yml index 2421d62211..9b5a04198a 100644 --- a/.github/workflows/sync_code-formatting.yml +++ b/.github/workflows/sync_code-formatting.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit @@ -20,7 +20,7 @@ jobs: fetch-depth: 0 - name: use node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.0 + uses: actions/setup-node@v4.0.1 with: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth diff --git a/.github/workflows/sync_dependabot-changesets.yml b/.github/workflows/sync_dependabot-changesets.yml index 5450ffba0b..f61d8709a5 100644 --- a/.github/workflows/sync_dependabot-changesets.yml +++ b/.github/workflows/sync_dependabot-changesets.yml @@ -11,7 +11,7 @@ jobs: if: github.actor == 'dependabot[bot]' && github.repository == 'backstage/backstage' steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit @@ -26,7 +26,7 @@ jobs: git config --global user.email noreply@backstage.io git config --global user.name 'Github changeset workflow' - name: Generate changeset - uses: actions/github-script@v6.4.1 + uses: actions/github-script@v7.0.1 with: script: | const { promises: fs } = require('fs'); diff --git a/.github/workflows/sync_release-manifest.yml b/.github/workflows/sync_release-manifest.yml index 2f841df6f9..1cab7797e6 100644 --- a/.github/workflows/sync_release-manifest.yml +++ b/.github/workflows/sync_release-manifest.yml @@ -8,12 +8,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit # Setup node & install deps before checkout, keeping install quick - - uses: actions/setup-node@v4.0.0 + - uses: actions/setup-node@v4.0.1 with: node-version: 18.x - name: Install dependencies @@ -53,7 +53,7 @@ jobs: git push - name: Dispatch update-helper update - uses: actions/github-script@v6.4.1 + uses: actions/github-script@v7.0.1 with: github-token: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }} # TODO(Rugvip): Remove the create-app dispatch once we've been on the release version for a while diff --git a/.github/workflows/sync_renovate-changesets.yml b/.github/workflows/sync_renovate-changesets.yml index f116a3b609..1e93a12f85 100644 --- a/.github/workflows/sync_renovate-changesets.yml +++ b/.github/workflows/sync_renovate-changesets.yml @@ -11,7 +11,7 @@ jobs: if: github.actor == 'renovate[bot]' && github.repository == 'backstage/backstage' steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit @@ -26,7 +26,7 @@ jobs: git config --global user.email noreply@backstage.io git config --global user.name 'Github changeset workflow' - name: Generate changeset - uses: actions/github-script@v6.4.1 + uses: actions/github-script@v7.0.1 with: script: | const { promises: fs } = require("fs"); diff --git a/.github/workflows/sync_snyk-github-issues.yml b/.github/workflows/sync_snyk-github-issues.yml index c030ad124a..f1a91ed7e6 100644 --- a/.github/workflows/sync_snyk-github-issues.yml +++ b/.github/workflows/sync_snyk-github-issues.yml @@ -12,14 +12,14 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit - uses: actions/checkout@v4.1.1 - name: use node.js 18.x - uses: actions/setup-node@v4.0.0 + uses: actions/setup-node@v4.0.1 with: node-version: 18.x registry-url: https://registry.npmjs.org/ # Needed for auth diff --git a/.github/workflows/sync_snyk-monitor.yml b/.github/workflows/sync_snyk-monitor.yml index 20639b24bf..c3f7af1550 100644 --- a/.github/workflows/sync_snyk-monitor.yml +++ b/.github/workflows/sync_snyk-monitor.yml @@ -25,7 +25,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit @@ -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@v2.22.5 + uses: github/codeql-action/upload-sarif@v2.22.12 with: sarif_file: snyk.sarif diff --git a/.github/workflows/sync_version-packages.yml b/.github/workflows/sync_version-packages.yml index 6529017198..fc1d7a68f1 100644 --- a/.github/workflows/sync_version-packages.yml +++ b/.github/workflows/sync_version-packages.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit diff --git a/.github/workflows/uffizzi-build.yml b/.github/workflows/uffizzi-build.yml index 1d9f4e4f2c..c0bbde49f3 100644 --- a/.github/workflows/uffizzi-build.yml +++ b/.github/workflows/uffizzi-build.yml @@ -3,9 +3,14 @@ on: pull_request: types: [opened, synchronize, reopened, closed] paths-ignore: - - 'microsite/**' - - 'storybook/**' + - '.changeset/**' - 'contrib/**' + - 'docs/**' + - 'microsite/**' + - 'scripts/**' + - 'storybook/**' + - '**/*.test.*' + - '**/package.json' - '*.md' jobs: @@ -20,7 +25,7 @@ jobs: tags: ${{ steps.meta.outputs.tags }} steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit @@ -28,7 +33,7 @@ jobs: uses: actions/checkout@v4.1.1 - name: setup-node - uses: actions/setup-node@v4.0.0 + uses: actions/setup-node@v4.0.1 with: node-version: 18.x registry-url: https://registry.npmjs.org/ @@ -42,30 +47,26 @@ jobs: run: | cp -f ./.github/uffizzi/uffizzi.production.app-config.yaml ./app-config.yaml - - name: typescript build - run: | - yarn tsc - - name: backstage build run: | yarn workspace example-backend build - name: Set up Docker Buildx - uses: docker/setup-buildx-action@885d1462b80bc1c1c7f0b00334ad271f09369c55 # v2.10.0 + uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 - name: Generate UUID image name id: uuid - run: echo "UUID_TAG_APP=$(uuidgen)" >> $GITHUB_ENV + run: echo "UUID_TAG_APP=backstage-$(uuidgen --time)" >> $GITHUB_ENV - name: Docker metadata id: meta - uses: docker/metadata-action@818d4b7b91585d195f67373fd9cb0332e31a7175 # v4.6.0 + uses: docker/metadata-action@e6428a5c4e294a61438ed7f43155db912025b6b3 # v5.2.0 with: images: registry.uffizzi.com/${{ env.UUID_TAG_APP }} tags: type=raw,value=60d - name: Build Image - uses: docker/build-push-action@0a97817b6ade9f46837855d676c4cca3a2471fc9 # v4.2.1 + uses: docker/build-push-action@4a13e500e55cf31b7a5d59a38ab2040ab0f42f56 # v5.1.0 with: context: . file: packages/backend/Dockerfile @@ -82,7 +83,7 @@ jobs: - build-backstage steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit @@ -114,7 +115,7 @@ jobs: if: ${{ github.event.action == 'closed' }} steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit diff --git a/.github/workflows/uffizzi-preview.yaml b/.github/workflows/uffizzi-preview.yaml index 9599ff4877..9591af3a23 100644 --- a/.github/workflows/uffizzi-preview.yaml +++ b/.github/workflows/uffizzi-preview.yaml @@ -12,20 +12,27 @@ jobs: 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: ${{ env.MANIFESTS_FILE_HASH }} - git-ref: ${{ env.GIT_REF }} - pr-number: ${{ env.PR_NUMBER }} - action: ${{ env.ACTION }} + 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@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: - egress-policy: audit + 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@v6.4.1 + uses: actions/github-script@v7.0.1 with: script: | let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({ @@ -48,59 +55,50 @@ jobs: let fs = require('fs'); fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/preview-spec.zip`, Buffer.from(download.data)); - - name: 'Unzip artifact' - run: unzip preview-spec.zip + - name: 'Accept event from first stage' + run: unzip preview-spec.zip event.json - name: Read Event into ENV + id: event run: | - echo 'EVENT_JSON<> $GITHUB_ENV - cat event.json >> $GITHUB_ENV - echo -e '\nEOF' >> $GITHUB_ENV + 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: ${{ fromJSON(env.EVENT_JSON).action != 'closed' }} + 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_ENV + echo "MANIFESTS_FILE_HASH=$(md5sum manifests.rendered.yml | awk '{ print $1 }')" >> $GITHUB_OUTPUT - name: Cache Manifests File - if: ${{ fromJSON(env.EVENT_JSON).action != 'closed' }} - uses: actions/cache@v3.3.2 + if: ${{ steps.event.outputs.ACTION != 'closed' }} + uses: actions/cache@v3.3.3 with: path: manifests.rendered.yml - key: ${{ env.MANIFESTS_FILE_HASH }} - - - name: Read PR Number From Event Object - id: pr - run: echo "PR_NUMBER=${{ fromJSON(env.EVENT_JSON).number }}" >> $GITHUB_ENV - - - name: Read Event Type from Event Object - id: action - run: echo "ACTION=${{ fromJSON(env.EVENT_JSON).action }}" >> $GITHUB_ENV - - - name: Read Git Ref From Event Object - id: ref - run: echo "GIT_REF=${{ fromJSON(env.EVENT_JSON).pull_request.head.sha }}" >> $GITHUB_ENV + key: ${{ steps.hash.outputs.MANIFESTS_FILE_HASH }} - name: DEBUG - Print Job Outputs if: ${{ runner.debug }} run: | - echo "PR number: ${{ env.PR_NUMBER }}" - echo "Git Ref: ${{ env.GIT_REF }}" - echo "Manifests file hash: ${{ env.MANIFESTS_FILE_HASH }}" + 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: - permissions: - contents: read - pull-requests: write - id-token: write 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 @@ -119,7 +117,7 @@ jobs: # Create/Update comment with action deployment status - name: Create or Update Comment with Deployment Notification id: notification - uses: peter-evans/create-or-update-comment@v2 + uses: peter-evans/create-or-update-comment@v3 with: comment-id: ${{ steps.find-comment.outputs.comment-id }} issue-number: ${{ needs.cache-manifests-file.outputs.pr-number }} @@ -142,7 +140,6 @@ jobs: - name: Fetch cached Manifests File id: cache - # if: ${{ contains(fromJSON('["create", "update"]'), env.UFFIZZI_ACTION) }} uses: actions/cache@v3 with: path: manifests.rendered.yml @@ -168,7 +165,7 @@ jobs: 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@v2 + uses: peter-evans/create-or-update-comment@v3 with: comment-id: ${{ steps.notification.outputs.comment-id }} issue-number: ${{ github.event.pull_request.number }} @@ -232,7 +229,7 @@ jobs: direction: last - name: Update Comment with Deletion - uses: peter-evans/create-or-update-comment@v2 + uses: peter-evans/create-or-update-comment@v3 with: comment-id: ${{ steps.find-comment.outputs.comment-id }} issue-number: ${{ needs.cache-manifests-file.outputs.pr-number }} diff --git a/.github/workflows/verify_accessibility-noop.yml b/.github/workflows/verify_accessibility-noop.yml index ab438681bb..79c9962fce 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@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit diff --git a/.github/workflows/verify_accessibility.yml b/.github/workflows/verify_accessibility.yml index 57aec1298a..1310fc15f4 100644 --- a/.github/workflows/verify_accessibility.yml +++ b/.github/workflows/verify_accessibility.yml @@ -20,13 +20,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit - uses: actions/checkout@v4.1.1 - name: Use Node.js 18.x - uses: actions/setup-node@v4.0.0 + uses: actions/setup-node@v4.0.1 with: node-version: 18.x - name: yarn install diff --git a/.github/workflows/verify_codeql.yml b/.github/workflows/verify_codeql.yml index e6c78cdb33..61be150ff8 100644 --- a/.github/workflows/verify_codeql.yml +++ b/.github/workflows/verify_codeql.yml @@ -42,7 +42,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit @@ -55,7 +55,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2.22.5 + uses: github/codeql-action/init@v2.22.12 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@v2.22.5 + uses: github/codeql-action/autobuild@v2.22.12 # ℹ️ 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@v2.22.5 + uses: github/codeql-action/analyze@v2.22.12 diff --git a/.github/workflows/verify_docs-quality.yml b/.github/workflows/verify_docs-quality.yml index 8e11a53fb7..8e3b333dd3 100644 --- a/.github/workflows/verify_docs-quality.yml +++ b/.github/workflows/verify_docs-quality.yml @@ -12,7 +12,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit @@ -30,5 +30,6 @@ jobs: with: # This also contains --config=.github/vale/config.ini ... :/ files: '${{ steps.generate.outputs.args }}' + version: 2.30.0 # TODO: migrate to v3 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/verify_e2e-kubernetes-noop.yml b/.github/workflows/verify_e2e-kubernetes-noop.yml index 72b1c57f19..7606f78f07 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@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit diff --git a/.github/workflows/verify_e2e-kubernetes.yml b/.github/workflows/verify_e2e-kubernetes.yml index fcc75b6264..db3651cfe1 100644 --- a/.github/workflows/verify_e2e-kubernetes.yml +++ b/.github/workflows/verify_e2e-kubernetes.yml @@ -22,14 +22,14 @@ jobs: name: Kubernetes ${{ matrix.node-version }} steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit - uses: actions/checkout@v4.1.1 - name: use node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.0 + uses: actions/setup-node@v4.0.1 with: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth diff --git a/.github/workflows/verify_e2e-linux-noop.yml b/.github/workflows/verify_e2e-linux-noop.yml index b451c5d75e..c1ac6ecf89 100644 --- a/.github/workflows/verify_e2e-linux-noop.yml +++ b/.github/workflows/verify_e2e-linux-noop.yml @@ -28,7 +28,7 @@ jobs: name: E2E Linux ${{ matrix.node-version }} steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit diff --git a/.github/workflows/verify_e2e-linux.yml b/.github/workflows/verify_e2e-linux.yml index 925f593ba7..0e335b8fe0 100644 --- a/.github/workflows/verify_e2e-linux.yml +++ b/.github/workflows/verify_e2e-linux.yml @@ -18,7 +18,7 @@ jobs: services: postgres: - image: postgres:latest + image: postgres:12 env: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres @@ -40,7 +40,7 @@ jobs: name: E2E Linux ${{ matrix.node-version }} steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit @@ -52,7 +52,7 @@ jobs: git config --global user.name 'GitHub e2e user' - name: use node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.0 + uses: actions/setup-node@v4.0.1 with: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth diff --git a/.github/workflows/verify_e2e-techdocs.yml b/.github/workflows/verify_e2e-techdocs.yml index 3b7b42e905..e2ca1db16e 100644 --- a/.github/workflows/verify_e2e-techdocs.yml +++ b/.github/workflows/verify_e2e-techdocs.yml @@ -30,12 +30,12 @@ jobs: name: Techdocs steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit - uses: actions/checkout@v4.1.1 - - uses: actions/setup-python@v4.7.1 + - uses: actions/setup-python@v4.8.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 d8119f8363..e24f7820fe 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@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit diff --git a/.github/workflows/verify_e2e-windows.yml b/.github/workflows/verify_e2e-windows.yml index cfb7014224..d3c9d58ba6 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@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit @@ -50,13 +50,13 @@ jobs: git config --global user.name 'GitHub e2e user' - name: use node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.0 + uses: actions/setup-node@v4.0.1 with: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth - name: setup python - uses: actions/setup-python@v4.7.1 + uses: actions/setup-python@v4.8.0 with: python-version: '3.10' diff --git a/.github/workflows/verify_fossa.yml b/.github/workflows/verify_fossa.yml index 85dbc46afa..e91a04d6ed 100644 --- a/.github/workflows/verify_fossa.yml +++ b/.github/workflows/verify_fossa.yml @@ -14,7 +14,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit diff --git a/.github/workflows/verify_microsite-noop.yml b/.github/workflows/verify_microsite-noop.yml index 020ecbcfd5..ac0e397127 100644 --- a/.github/workflows/verify_microsite-noop.yml +++ b/.github/workflows/verify_microsite-noop.yml @@ -5,7 +5,6 @@ name: Microsite Void on: pull_request: paths-ignore: - - '.github/workflows/verify_microsite-next.yml' - '.github/workflows/verify_microsite.yml' - 'microsite/**' - 'mkdocs.yml' @@ -21,7 +20,7 @@ jobs: name: Microsite steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit diff --git a/.github/workflows/verify_microsite.yml b/.github/workflows/verify_microsite.yml index a3be6c4c69..42a6663e59 100644 --- a/.github/workflows/verify_microsite.yml +++ b/.github/workflows/verify_microsite.yml @@ -3,7 +3,6 @@ on: # NOTE: If you change these you must update verify_microsite-noop.yml as well pull_request: paths: - - '.github/workflows/verify_microsite-next.yml' - '.github/workflows/verify_microsite.yml' - 'microsite/**' - 'mkdocs.yml' @@ -24,14 +23,14 @@ jobs: name: Microsite steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit - uses: actions/checkout@v4.1.1 - name: use node.js 18.x - uses: actions/setup-node@v4.0.0 + uses: actions/setup-node@v4.0.1 with: node-version: 18.x diff --git a/.github/workflows/verify_storybook-noop.yml b/.github/workflows/verify_storybook-noop.yml index b60aa18362..3c92f0eaa2 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@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit diff --git a/.github/workflows/verify_storybook.yml b/.github/workflows/verify_storybook.yml index 5ebce61da2..d7f90118de 100644 --- a/.github/workflows/verify_storybook.yml +++ b/.github/workflows/verify_storybook.yml @@ -28,7 +28,7 @@ jobs: name: Storybook steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit @@ -37,7 +37,7 @@ jobs: fetch-depth: 0 # Required to retrieve git history - name: use node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.0 + uses: actions/setup-node@v4.0.1 with: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth @@ -51,7 +51,7 @@ jobs: - run: yarn build-storybook - - uses: chromaui/action@b52e14dd333579901e7099e0094b652e8284dea9 # v1 + - uses: chromaui/action@722516a3934360dac82cdef8dbab38e824fc6fa1 # v1 with: token: ${{ secrets.GITHUB_TOKEN }} # projectToken intentionally shared to allow collaborators to run Chromatic on forks diff --git a/.github/workflows/verify_windows.yml b/.github/workflows/verify_windows.yml index 22d4f0af3b..4cffa959da 100644 --- a/.github/workflows/verify_windows.yml +++ b/.github/workflows/verify_windows.yml @@ -29,14 +29,14 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: egress-policy: audit - uses: actions/checkout@v4.1.1 - name: use node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.0 + uses: actions/setup-node@v4.0.1 with: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth diff --git a/.prettierignore b/.prettierignore index ad2bd355ed..c54ee5d821 100644 --- a/.prettierignore +++ b/.prettierignore @@ -5,7 +5,7 @@ coverage *.hbs templates api-report.md -*-api-report.md +api-report-*.md cli-report.md plugins/scaffolder-backend/sample-templates .vscode diff --git a/.yarn/patches/mock-fs-npm-5.2.0-5103a7b507.patch b/.yarn/patches/mock-fs-npm-5.2.0-5103a7b507.patch deleted file mode 100644 index ed5555203b..0000000000 --- a/.yarn/patches/mock-fs-npm-5.2.0-5103a7b507.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/lib/binding.js b/lib/binding.js -index a4a3e6cdc197bd0f12fe2d060640e91ac58ab457..ab04ce3115fe93073a3e25008730272b6fa21bd7 100644 ---- a/lib/binding.js -+++ b/lib/binding.js -@@ -165,6 +165,8 @@ function Binding(system) { - this.trackDescriptor(stderr); - } - -+Binding.prototype.readFileSync = path => require('fs').readFileSync(path).toString('utf8'); -+ - /** - * Get the file system underlying this binding. - * @return {FileSystem} The underlying file system. diff --git a/ADOPTERS.md b/ADOPTERS.md index eaec1cc2d1..8f3f93658b 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -261,3 +261,5 @@ _You can do this by using the [Adopter form](https://info.backstage.spotify.com/ | [AppsFlyer](https://www.appsflyer.com/) | [Shahar Shmaram](https://github.com/shmaram) | Internal Developer Portal, a catalog of all company resources, custom providers and processors, scaffolder for generating new resources. | [Gynzy](https://gynzy.com) | [Stef Louwers](https://github.com/fhp) | We are building an internal developer portal to get an overview of all our software components. | | [Cielo](https://www.cielo.com.br) | [@Alex Silva](https://github.com/narokwq) | We are using as our Internal Developer Portal, it provides developers with the resources, information, and tools they need to build high-quality applications and adhere to organizational standards and security practices. | +| [Giant Swarm](https://giantswarm.io) | [Lucas Weatherhog](https://github.com/weatherhog) | At Giant Swarm we are using Backstage as our internal developer portal. Heavily using the service catalog and the TechDocs plugin. Further looking into adopting functionalities of our Web UI into Backstage to have a single pane of glass for our core business, managing all our components, and helping developers to be more productive. | +| [WD Studios](https://wdstudios.tech) | [Mikael Aboagye](https://github.com/JailbreakPapa) | We are using Backstage as our main internal developer portal for our Programmers and Studio Partners. It's really proven its worth at our studio with on-boarding new programmers! diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 7597dd437c..464519e792 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,3 +1,3 @@ # Community Code of Conduct -Backstage follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md). +Backstage follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/main/code-of-conduct.md). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6c645ab524..527957677b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,6 +12,21 @@ You can find out more about the types of contributions over at [getting involved If you need help, just jump into our [Discord chatroom](https://discord.gg/backstage-687207715902193673). +## Table of Contents + +- [Code of Conduct](#code-of-conduct) +- [Security Issues?](#security-issues) +- [Accessibility](#accessibility) +- [Get Started!](#get-started) +- [Coding Guidelines](#coding-guidelines) +- [Package Scripts](#package-scripts) +- [Local configuration](#local-configuration) +- [Creating Changesets](#creating-changesets) +- [Developer Certificate of Origin](#developer-certificate-of-origin) +- [API Reports](#api-reports) +- [Submitting a Pull Request](#submitting-a-pull-request) +- [Review Process](#review-process) + ## Code of Conduct This project adheres to the [CNCF Code of Conduct][code-of-conduct]. By participating, you are expected to honor this code. @@ -98,7 +113,7 @@ If you're contributing to the backend or CLI tooling, be mindful of cross-platfo Also be sure to skim through our [ADRs](docs/architecture-decisions) to see if they cover what you're working on. In particular [ADR006: Avoid React.FC and React.SFC](docs/architecture-decisions/adr006-avoid-react-fc.md) is one to look out for. -If there are any updates in `markdown` file please make sure to run `yarn run lint:docs`. Though it is checked on `lint-staged`. It is required to install [vale](https://docs.errata.ai/vale/install) separately and make sure it is accessed by global command. +If there are any updates in `markdown` file please make sure to run `yarn run lint:docs`. Though it is checked on `lint-staged`. It is required to install [vale](https://vale.sh/docs/vale-cli/installation/) separately and make sure it is accessed by global command. ### Editor @@ -124,7 +139,7 @@ yarn build:api-reports # Build API Reports used for documentation yarn lint # lint packages that have changed since later commit on origin/master yarn lint:all # lint all packages -yarn lind:docs # lint all the Markdown files +yarn lint:docs # lint all the Markdown files yarn lint:type-deps # verify that @types/* dependencies are placed correctly in packages yarn test # test packages that have changed since later commit on origin/master @@ -273,6 +288,13 @@ Awesome commit message Signed-off-by: Jane Smith ``` +> Note: this assumes you have setup your git name and email, if you have not you can use these commands to set that up: +> +> ```shell +> git config --global user.name "Your Name" +> git config --global user.email "youremail@example.com" +> ``` + - In case you forgot to add it to the most recent commit, use `git commit --amend --signoff` - In case you forgot to add it to the last N commits in your branch, use `git rebase --signoff HEAD~N` and replace N with the number of new commits you created in your branch. - If you have a very deep branch with a lot of commits, run `git rebase -i --signoff $(git merge-base -a master HEAD)`, double check to make sense of the commits (keep all lines as `pick`) and save and close the editor. This should bulk sign all the commits in your PR. Do be careful though. If you have a complex flow with a lot of branching and re-merging of work branches and stuff, merge-base may not be the right solution for you. @@ -283,7 +305,7 @@ Note: If you have already pushed your branch to a remote, you might have to forc If you are using the GitHub Desktop client, you need to manually add the `Signed-off-by` line to the Description field on the Changes tab before committing: -``` +```text Awesome description (commit message) Signed-off-by: Jane Smith @@ -291,6 +313,16 @@ Signed-off-by: Jane Smith In case you forgot to add the line to your most recent commit, you can amend the commit message from the History tab before pushing your branch (GitHub Desktop 2.9 or later). +### Using VS Code? + +If you are using VS Code you can enable always signing your commits by setting the following in your `settings.json` file: + +```json +"git.alwaysSignOff": true, +``` + +Or from the Settings UI look for the "Git: Always Sign Off" setting and check the "Controls the signoff flag for all commits" box. + ## API Reports Backstage uses [API Extractor](https://api-extractor.com/) and TSDoc comments to generate API Reports in Markdown format. These reports are what drive the [API Reference documentation](https://backstage.io/docs/reference/). What this means is that if you are making changes to the API or adding a new plugin then you will need either generate a new API Report or update an existing API Report. If you don't do this the CI build will fail when you create your Pull Request. diff --git a/OWNERS.md b/OWNERS.md index b3f9d7bef9..4d6fb21a80 100644 --- a/OWNERS.md +++ b/OWNERS.md @@ -78,7 +78,6 @@ Scope: The Permission Framework and plugins integrating with the permission fram | Name | Organization | Team | GitHub | Discord | | -------------------- | ------------ | --------------- | ----------------------------------------------- | ---------------- | | Ainhoa Larumbe | Spotify | Imaginary Goats | [ainhoaL](http://github.com/ainhoaL) | ainhoa#8085 | -| Aramis Sennyey | Spotify | Imaginary Goats | [sennyeya](https://github.com/sennyeya) | Aramis#7984 | | Claire Casey | Spotify | Imaginary Goats | [clairelcasey](http://github.com/clairelcasey) | clairecasey#2710 | | Eric Peterson | Spotify | Imaginary Goats | [iamEAP](http://github.com/iamEAP) | iamEAP#3058 | | Harry Hogg | Spotify | Imaginary Goats | [HHogg](http://github.com/HHogg) | simplex#3451 | @@ -118,7 +117,7 @@ Scope: Tooling for frontend and backend schema-first OpenAPI development. | Name | Organization | GitHub | Discord | | -------------- | ------------ | --------------------------------------- | ------------- | -| Aramis Sennyey | Spotify | [sennyeya](https://github.com/sennyeya) | `Aramis#7984` | +| Aramis Sennyey | | [sennyeya](https://github.com/sennyeya) | `Aramis#7984` | ### Scaffolder @@ -126,10 +125,9 @@ Team: @backstage/scaffolder-maintainers Scope: The Scaffolder frontend and backend plugins, and related tooling. -| Name | Organization | GitHub | Discord | -| ------------------- | -------------- | ------------------------------------- | ---------------- | -| Bogdan Nechyporenko | Bol.com | [acierto](https://github.com/acierto) | `bogdan_haarlem` | -| Paul Cowan | frontendrescue | [dagda1](https://github.com/dagda1) | `dagda1` | +| Name | Organization | GitHub | Discord | +| ------------------- | ------------ | ------------------------------------- | ---------------- | +| Bogdan Nechyporenko | Bol.com | [acierto](https://github.com/acierto) | `bogdan_haarlem` | ## Sponsors @@ -147,7 +145,7 @@ Scope: The Scaffolder frontend and backend plugins, and related tooling. | Alex Crome | | [afscrome](https://github.com/afscrome) | `afscrome` | | Andre Wanlin | Spotify | [awanlin](https://github.com/awanlin) | `ahhhndre` | | Andrew Thauer | Wealthsimple | [andrewthauer](https://github.com/andrewthauer) | `andrewthauer#3060` | -| Aramis Sennyey | Spotify | [sennyeya](https://github.com/sennyeya) | `Aramis#7984` | +| Aramis Sennyey | | [sennyeya](https://github.com/sennyeya) | `Aramis#7984` | | Brian Fletcher | Roadie.io | [punkle](https://github.com/punkle) | `Brian Fletcher#7051` | | Carlos Esteban Lopez Jaramillo | VMWare | [luchillo17](https://github.com/luchillo17) | `luchillo17#8777` | | David Tuite | Roadie.io | [dtuite](https://github.com/dtuite) | `David Tuite (roadie.io)#1010` | @@ -173,3 +171,9 @@ Scope: The Scaffolder frontend and backend plugins, and related tooling. | Name | Organization | GitHub | Discord | | --------- | ------------ | ------------------------------------------- | -------------- | | Lee Mills | Spotify | [leemills83](https://github.com/leemills83) | `.binarypoint` | + +## Emeritus Project Area Maintainers + +| Maintainer | Organization | GitHub | Discord | +| ---------- | -------------- | ----------------------------------- | -------- | +| Paul Cowan | frontendrescue | [dagda1](https://github.com/dagda1) | `dagda1` | diff --git a/README-ko_kr.md b/README-ko_kr.md new file mode 100644 index 0000000000..f7bcba144b --- /dev/null +++ b/README-ko_kr.md @@ -0,0 +1,78 @@ +[![headline](docs/assets/headline.png)](https://backstage.io/) + +# [Backstage](https://backstage.io) + +[English](README.md) \| 한국어 + +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) +[![CNCF Status](https://img.shields.io/badge/cncf%20status-incubation-blue.svg)](https://www.cncf.io/projects) +[![Discord](https://img.shields.io/discord/687207715902193673?logo=discord&label=Discord&color=5865F2&logoColor=white)](https://discord.gg/backstage-687207715902193673) +![Code style](https://img.shields.io/badge/code_style-prettier-ff69b4.svg) +[![Codecov](https://img.shields.io/codecov/c/github/backstage/backstage)](https://codecov.io/gh/backstage/backstage) +[![](https://img.shields.io/github/v/release/backstage/backstage)](https://github.com/backstage/backstage/releases) +[![Uffizzi](https://img.shields.io/endpoint?url=https%3A%2F%2Fapp.uffizzi.com%2Fapi%2Fv1%2Fpublic%2Fshields%2Fgithub.com%2Fbackstage%2Fbackstage)](https://app.uffizzi.com/ephemeral-environments/backstage/backstage) +[![OpenSSF Best Practices](https://bestpractices.coreinfrastructure.org/projects/7678/badge)](https://bestpractices.coreinfrastructure.org/projects/7678) +[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/backstage/backstage/badge)](https://securityscorecards.dev/viewer/?uri=github.com/backstage/backstage) + +## 백스테이지(Backstage)란? + +[백스테이지(Backstage)](https://backstage.io/) 는 개발자 포털 구출을 위한 개방형 플랫폼입니다. 중앙 집중식 소프트웨어 카탈로그를 기반으로하는 Backstage는 마이크로 서비스와 인프라의 질서를 복원하고 제품팀이 자율성을 훼손하지 않고 고품질 코드를 신속하게 출시할 수 있도록 지원합니다. + +Backstage 는 모든 인프라 도구, 서비스 및 문서를 통합하여 처음부터 끝까지 간소화된 개발 환경을 만듭니다. + +![software-catalog](docs/assets/header.png) + +Backstage 다음을 포함합니다: + +- [Backstage Software Catalog](https://backstage.io/docs/features/software-catalog/) 마이크로 서비스, 라이브러리, 데이터 파이프라인, 웹 사이트, ML 모델 등 모든 소프트웨어 관리 +- [Backstage Software Templates](https://backstage.io/docs/features/software-templates/) 새로운 프로젝트를 신속하게 시작하고 조직의 모밤 사례에따라 도구를 표준화 +- [Backstage TechDocs](https://backstage.io/docs/features/techdocs/) "docs like code" 접근 방식을 사용하여 기술 문서를 쉽게 작성, 유지 관리, 검색 및 사용 +- [open source plugins](https://github.com/backstage/backstage/tree/master/plugins) Backstage의 사용자 정의 가능성과 기능을 확장 + +Backstage는 Spotify에서 제작되었지만 현재는 [Cloud Native Computing Foundation(CNCF)](https://www.cncf.io)에서 인큐베이션 수준 프로젝트로 호스팅되고 있습니다. 추가적인 정보는 [announcement](https://backstage.io/blog/2022/03/16/backstage-turns-two#out-of-the-sandbox-and-into-incubation)를 참조하세요. + +## 프로젝트 로드맵 + +제공된 마일스톤을 포함한 자세한 프로젝트 로드맵에 대한 자세한 내용은 [the Roadmap](https://backstage.io/docs/overview/roadmap)을 참조하세요. + +## 시작하기 + +Backstage를 시작하기위해 [Getting Started documentation](https://backstage.io/docs/getting-started)를 참조하세요. + +## 문서 + +Backstage의 문서는 다음을 포함합니다: + +- [Main documentation](https://backstage.io/docs) +- [Software Catalog](https://backstage.io/docs/features/software-catalog/) +- [Architecture](https://backstage.io/docs/overview/architecture-overview) ([Decisions](https://backstage.io/docs/architecture-decisions/)) +- [Designing for Backstage](https://backstage.io/docs/dls/design) +- [Storybook - UI components](https://backstage.io/storybook) + +## 커뮤니티 + +커뮤니티에 참여하려면 다음 리소스를 사용하세요: + +- [Discord chatroom](https://discord.gg/backstage-687207715902193673) - 지원 및 프로젝트 토론 +- [Contributing to Backstage](https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md) - 프로젝트 기여 +- [RFCs](https://github.com/backstage/backstage/labels/rfc) - 기술 방향을 정하는 데 도움을 주세요. +- [FAQ](https://backstage.io/docs/FAQ) - 자주 묻는 질문들 +- [Code of Conduct](CODE_OF_CONDUCT.md) - 커뮤니티 운영 방식 +- [Adopters](ADOPTERS.md) - Backstage를 사용하고 있는 기업 +- [Blog](https://backstage.io/blog/) - 공지사항 및 업데이트 +- [Newsletter](https://spoti.fi/backstagenewsletter) - 이메일 뉴스레터 구독 +- [Backstage Community Sessions](https://github.com/backstage/community) - 월간 모임 참여 및 커뮤니티 톺아보기 +- Backstage를 사용중이거나 흥미로운 프로젝트라고 생각하신다면 별표를 눌러주세요. 별표는 사랑입니다 ❤️ + +## License + +Copyright 2020-2023 © The Backstage Authors. All rights reserved. The Linux Foundation has registered trademarks and uses trademarks. For a list of trademarks of The Linux Foundation, please see our Trademark Usage page: https://www.linuxfoundation.org/trademark-usage + +Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 + +## 보안 + +민감한 보안문제는 Github가 아닌 Spotify의 [bug-bounty program](https://hackerone.com/spotify) 통해 신고해주세요 +Please report sensitive security issues using Spotify's [bug-bounty program](https://hackerone.com/spotify) rather than GitHub. + +자세한 내용은 [security release process](SECURITY.md)를 참고하세요. diff --git a/README-zh_Hans.md b/README-zh_Hans.md new file mode 100644 index 0000000000..b1e5a16add --- /dev/null +++ b/README-zh_Hans.md @@ -0,0 +1,77 @@ +[![headline](docs/assets/headline.png)](https://backstage.io/) + +# [Backstage](https://backstage.io) + +简体中文\| [English](README.md) \| [한국어](README-ko_kr.md) + +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) +[![CNCF Status](https://img.shields.io/badge/cncf%20status-incubation-blue.svg)](https://www.cncf.io/projects) +[![Discord](https://img.shields.io/discord/687207715902193673?logo=discord&label=Discord&color=5865F2&logoColor=white)](https://discord.gg/backstage-687207715902193673) +![Code style](https://img.shields.io/badge/code_style-prettier-ff69b4.svg) +[![Codecov](https://img.shields.io/codecov/c/github/backstage/backstage)](https://codecov.io/gh/backstage/backstage) +[![](https://img.shields.io/github/v/release/backstage/backstage)](https://github.com/backstage/backstage/releases) +[![Uffizzi](https://img.shields.io/endpoint?url=https%3A%2F%2Fapp.uffizzi.com%2Fapi%2Fv1%2Fpublic%2Fshields%2Fgithub.com%2Fbackstage%2Fbackstage)](https://app.uffizzi.com/ephemeral-environments/backstage/backstage) +[![OpenSSF Best Practices](https://bestpractices.coreinfrastructure.org/projects/7678/badge)](https://bestpractices.coreinfrastructure.org/projects/7678) +[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/backstage/backstage/badge)](https://securityscorecards.dev/viewer/?uri=github.com/backstage/backstage) + +## Backstage 是什么? + +[Backstage](https://backstage.io/) 是一个用于构建开发者门户的开放平台。在集中式软件目录的支持下,Backstage 可以恢复微服务和基础设施的秩序,并使您的产品团队能够快速交付高质量的代码,而不会影响自主权。 + +Backstage 统一了所有基础设施工具、服务和文档,以创建端到端的流线型开发环境。 + +![software-catalog](docs/assets/header.png) + +开箱即用的 Backstage 包括: + +- [Backstage 软件目录](https://backstage.io/docs/features/software-catalog/) 用于管理所有软件,例如微服务、类库、数据管道、网站和机器学习模型 +- [Backstage 软件模板](https://backstage.io/docs/features/software-templates/) 用于快速启动新项目,并根据组织的最佳实践实现工具标准化 +- [Backstage 技术文档](https://backstage.io/docs/features/techdocs/) 采用 "像编写代码一样编写文档 "的方法,轻松创建、维护、查找和使用技术文档 +- 此外,[开源插件](https://github.com/backstage/backstage/tree/master/plugins) 生态系统不断发展壮大,进一步扩展了 Backstage 的可定制性和功能性 + +Backstage 由 Spotify 创建,但现在由 [云原生计算基金会 (CNCF)](https://www.cncf.io) 作为孵化级项目托管。更多信息请参见[公告](https://backstage.io/blog/2022/03/16/backstage-turns-two#out-of-the-sandbox-and-into-incubation)。 + +## 项目路线图 + +有关项目路线图(包括已交付的里程碑)的详细信息,请参阅[路线图](https://backstage.io/docs/overview/roadmap)。 + +## 开始上手 + +要开始使用 Backstage,请参阅[入门文档](https://backstage.io/docs/getting-started)。 + +## 文档 + +Backstage 的文档包括: + +- [主要文档](https://backstage.io/docs) +- [软件目录](https://backstage.io/docs/features/software-catalog/) +- [架构](https://backstage.io/docs/overview/architecture-overview) ([决策](https://backstage.io/docs/architecture-decisions/)) +- [Backstage 设计](https://backstage.io/docs/dls/design) +- [Storybook - UI 组件](https://backstage.io/storybook) + +## 社区 + +要参与我们的社区,您可以使用以下资源: + +- [Discord 聊天室](https://discord.gg/backstage-687207715902193673) - 获得支持或讨论项目 +- [参与贡献 Backstage](https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md) - 如果您想做出贡献,请从这里开始 +- [RFCs](https://github.com/backstage/backstage/labels/rfc) - 帮助制定技术方向 +- [FAQ](https://backstage.io/docs/FAQ) - n.: 常问问题 +- [行为准则](CODE_OF_CONDUCT.md) - 这是我们的行事方式 +- [采纳者](ADOPTERS.md) - 已经在使用 Backstage 的公司 +- [博客](https://backstage.io/blog/) - 公告和更新 +- [通讯](https://spoti.fi/backstagenewsletter) - 订阅我们的电子邮件通讯 +- [Backstage 社区会议](https://github.com/backstage/community) - 参加每月聚会,探索 Backstage 社区 +- 给我们点个星星吧 ⭐️ - 如果您正在使用 Backstage 或认为它是一个有趣的项目,我们希望获得你的一颗星星 ❤️ + +## 许可 + +版权所有 2020-2023 © Backstage 作者。版权所有。Linux 基金会已注册商标并使用商标。有关 Linux 基金会的商标列表,请参阅我们的商标使用页面:https://www.linuxfoundation.org/trademark-usage + +采用 Apache v2.0 许可:http://www.apache.org/licenses/LICENSE-2.0 + +## 安全 + +请使用 Spotify 的 [Bug 赏金计划](https://hackerone.com/spotify) 而不是 GitHub 报告敏感安全问题。 + +更多详细信息,请参阅完整的[安全发布流程](SECURITY.md)。 diff --git a/README.md b/README.md index 1175b4320c..a1c53e4c8d 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,11 @@ # [Backstage](https://backstage.io) -> 🏖️ From October 30th - November 5th, employees at Spotify will have a week to recharge, which means all core maintainers & some project area maintainers are out of office. Right after that, we will go into the week of BackstageCon + KubeCon in Chicago, hoping to see some of you there! Expect slower responses & reviews during the 2 weeks, but we're on it for urgent issues. We will be up to speed again on November 13th! 🏖️ +English \| [한국어](README-ko_kr.md) \| [中文版](README-zh_Hans.md) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![CNCF Status](https://img.shields.io/badge/cncf%20status-incubation-blue.svg)](https://www.cncf.io/projects) -[![Discord](https://img.shields.io/discord/687207715902193673)](https://discord.gg/backstage-687207715902193673) +[![Discord](https://img.shields.io/discord/687207715902193673?logo=discord&label=Discord&color=5865F2&logoColor=white)](https://discord.gg/backstage-687207715902193673) ![Code style](https://img.shields.io/badge/code_style-prettier-ff69b4.svg) [![Codecov](https://img.shields.io/codecov/c/github/backstage/backstage)](https://codecov.io/gh/backstage/backstage) [![](https://img.shields.io/github/v/release/backstage/backstage)](https://github.com/backstage/backstage/releases) diff --git a/REVIEWING.md b/REVIEWING.md index 7ed3fcda57..c443c15d77 100644 --- a/REVIEWING.md +++ b/REVIEWING.md @@ -349,3 +349,13 @@ type LabelStyle = 'normal' | 'thin'; // Output, since it's an exported constant const LABEL_SIZE: number; ``` + +## Plugin Directory Submissions + +When reviewing Plugin Directory submissions please consider the following: + +- Check to make sure they have the rights for any icon being used. This is mostly for clearly copyrighted logos, for example the Microsoft Azure DevOps logo +- Make sure the package has been published on the NPM registry. +- Make sure the package on NPM has a link back to the code repo, this helps provide confidence that it's the right package. +- If they use an [NPM scope](https://docs.npmjs.com/about-scopes) make sure it that matches either the Organization name or user name, this provides trust in the plugin +- If the plugin has both a frontend and backend make sure that the documentation notes that. diff --git a/beps/0001-notifications-system/README.md b/beps/0001-notifications-system/README.md new file mode 100644 index 0000000000..c7b0ffff64 --- /dev/null +++ b/beps/0001-notifications-system/README.md @@ -0,0 +1,255 @@ +--- +title: Backstage Notifications System +status: provisional +authors: + - Rugvip +project-areas: + - core +creation-date: 2023-01-12 +--- + +# BEP: Backstage Notifications System + +[**Discussion Issue**](https://github.com/backstage/backstage/issues/22213) + +- [Summary](#summary) +- [Motivation](#motivation) + - [Goals](#goals) + - [Non-Goals](#non-goals) +- [Proposal](#proposal) +- [Design Details](#design-details) +- [Release Plan](#release-plan) +- [Dependencies](#dependencies) +- [Alternatives](#alternatives) + +## Summary + +The Backstage Notifications System provides a way for Backstage plugins to send notifications to users. The notifications are displayed in the Backstage frontend UI, but future extensions can allow them to be sent via external channels such as email. The system includes a push mechanism to make sure that users receive notifications immediately, as well as persistence of notification history and read status. + +## Motivation + +Support for notifications is an old and common features request. See [#639](https://github.com/backstage/backstage/issues/639) and [#10652](https://github.com/backstage/backstage/issues/10652). There are also initiatives to implement notifications in [#20312](https://github.com/backstage/backstage/issues/20312) as well as the underlying infrastructure pieces, for example [#17997](https://github.com/backstage/backstage/issues/17997). + +This proposal assumes that further motivation for a notifications system as a whole is not needed. The focus is instead on the specific goals of an initial notifications system, and generally aiming to address the need to coordinate this work. + +### Goals + +We aim to build a system that would provide support for the following type of notifications, as listed in [#10652](https://github.com/backstage/backstage/issues/10652): + +- System-wide announcements or alerts +- Notifications for component owners (e.g. build failure, successful deployment, new vulnerabilities) +- Notifications for individuals (e.g. updates you have subscribed to, new required training courses) +- Notifications pertaining to a particular entity in the catalog (a given notification might apply to an entity and the owning team) + +Initially we only target a single way to send notifications: via a REST API call to the notifications backend, which in turn also provides an accompanying [backend service](https://backstage.io/docs/backend-system/architecture/services). + +The notifications system will need to support scaled deployments, where multiple backend instances may be deployed. + +In the future we aim to provide an extensible system that can be customized to send notifications to users via other channels. Notifications can be captured and processed in-band in order to trigger custom behavior such as sending an email. The goal is for this to be possible to build, but not necessarily part of the initial implementation. + +### Non-Goals + +The following features are out of scope for this BEP: + +- Building out specific support for channels such as email, Slack, and other external channels. +- Providing a fallback mechanisms when a notification cannot be delivered to a user. For example, if a user has not logged in for a long time, we will not attempt to send an email instead. + +## Proposal + +The notifications system is implemented through two net-new components, the `notifications` plugin, and the `signal` plugin. + +The `notifications` plugin in its simplest form provides the following: + +- A backend API for sending, reading, and interacting with notifications. +- Persistent storage of notification state. +- A frontend UI for viewing notifications. + +The `signal` plugin provides the following: + +- A backend API for pushing lightweight signals to online users. +- A connection between the frontend and backend that can be used to push messages to the client. +- A frontend API that lets plugins to subscribe to specific signals. + +### Signals Plugin + +In the backend the signal plugin implements a general purpose message bus for sending signals from backend plugins to connected users. It relies on the `EventBroker` from the [events plugin](https://github.com/backstage/backstage/blob/master/plugins/events-backend/README.md) for the actual message passing in the backend. In order to support scaled deployments, each signal backend instance has a separate subscription to the event broker so that each instance receives all events. It is then up to each backend instance to filter out events that are not relevant to it. For this reason, signals should be kept lightweight and not contain unnecessary data. + +In the frontend the signal plugin has a persistent connection to the signal backend. This is initially implemented as a WebSocket connection, but could in the future also receive fallback mechanisms such as Server Sent Events or long polling. It is important that this connection is authenticated as we will be routing signals to specific users. The exact implementation of the authentication is not part of this proposal, but it should use whatever the outcome of the discussion in issue [#19581](https://github.com/backstage/backstage/issues/19581) is. + +In order to route signals from the sender to the intended receiver the signal plugin uses the concept of signaling channels. They are just like the topics on the message bus, but we use separate terminology in order to avoid confusion. They also sit one layer beneath the even topic in the protocol stack, where the signal channel is communicated as part of the event payload. In the frontend, the signal plugin exposes an API to subscribe to a signal channel. Each time the user receives a signal on the specified channel, a listener is called with the signal payload. + +### Notifications Plugin + +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: + +- ID +- Payload +- Receivers +- Read status by user + +The receivers 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 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. + +The notification frontend plugin provides a UI for viewing notifications, which in the initial implementation can be as simple as needed. The only requirement is that a user is able to view recent notifications and distinguish between read and unread notifications. A notification as marked as read once it has been interacted with. The frontend plugin also subscribes to the notifications signal channel and alerts the user when a new notification is received. + +### Architecture Overview + +The diagram below show an overview of the notifications system architecture and the interaction between the different components. + +![notifications system architecture diagram](./notifications-architecture.drawio.svg) + +The components that are presented with dashed lines are not directly part of this proposal, but included to be considered as future extensions. + +Let's walk through the process of sending of a notification to a user: + +1. A backend plugin that wants to send a notification to a user uses the `NotificationService`, which in turn makes a POST request to the notification backend. The request contains a filter to select the target users, as well as the notification payload. + + 1b. As the notification backend handles the request it could optionally invoke a series of notification processors. These processors can be used to transform the notification payload, send the notification through other channels, and decide whether the regular notification flow should continue or not. This step is not in scope for this proposal. + +2. The notification backend stores the received notification in its database. At this point the notification is available from the notification backend's read API. +3. The notification backend published an event to the event bus on the `'signal'` topic. This event payload contains the signaling channel, in this case `'notifications'`, as well as the target user ID and the notification ID, but not the notification payload. +4. Each instance of the signal backend plugin subscribes to the `'signal'` topic and receives the event. +5. Each signal backend instance has a set of push channels set up to online users. The incoming event is filtered based on the target user ID and the signaling is pushed through all connections with a matching user ID. +6. The signal frontend plugin receives the signal and forwards it to all subscribers of the target channel. In this case, the notifications frontend plugin, who is subscribed to the `'notifications'` channel. +7. The notifications frontend plugin receives the signal with the notification ID. It then makes a request to the notification backend to fetch the notification payload and then displays the notification to the user. + + 7b. Rather than rendering the notification directly, the notifications frontend plugin leaves that to an extension installed by the frontend part of the backend plugin that sent the notification. This allows for a more customized notification experience which can also contain custom actions and data display. This step is not in scope for this proposal. + +## Design Details + +### Backend Services + +The following backend service interfaces are added as part of this proposal. + +#### `NotificationService` + +```ts +// TODO - We may want to add an additional wrapping here with interfaces for Notification and NotificationParameters + +interface SendNotificationRequest { + receivers: SignalReceivers; + + /* TODO - please contribute :) */ +} + +interface SendNotificationResponse { + id: string; + receivers: SignalReceivers; + + /* TODO - please contribute :) */ +} + +interface NotificationService { + sendNotification( + request: SendNotificationRequest, + ): Promise; +} +``` + +#### `SignalService` + +```ts +type SignalReceivers = + | { + type: 'entity'; + entityRef: string; // typically a user or group entity + } + | { + type: 'broadcast'; // all users + }; + +interface Signal { + channel: string; + receivers: SignalReceivers; + payload: JsonObject; +} + +interface SignalService { + signal(signal: Signal): Promise; +} +``` + +### Frontend API + +The following frontend API is added as part of this proposal. + +#### `SignalApi` + +> TODO - we likely need a slightly different approach here, since APIs are lazy loaded. + +```ts +interface SignalSubscriber { + unsubscribe(): void; +} + +interface SignalApi { + subscribe( + channel: string, + listener: (payload: JsonObject) => void, + ): SignalSubscriber; +} +``` + +> TODO: Add payload formats and API details + + + +## 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. + +For the notification plugin to reach a stable release we much reach the following: + +- A stable notifications payload format. +- A stable notifications receiver filter format. +- The event broker must have at least one implementation that supports scaled deployments. + +For the signal plugin to reach a stable release we much reach the following: + +- A stable signal receiver filter format. +- A stable signal channel API in the frontend. + +If any changes are required to the frontend framework to facilitate the implementation of notifications or signals, these will be released as experimental alpha features. They will stay in alpha until they are deemed stable enough, which must happen before a stable release of the notifications system. + +## Dependencies + +Since the signal plugin relies on the event broker for communication, it is a dependency for the notifications system as a whole. The event broker does not currently implement any transport for scaled deployments, which is a requirement for scaled deployments of the notification system. + +## Alternatives + +### Signal Plugin Separation + +One primary consideration for the notifications system was whether the notification plugin should set up its own frontend push connection rather than relying on the signal plugin. The signal plugin separation is done for three primary reasons: + +1. The use-case of sending signals from backend plugins to frontend plugins is not limited to only notifications, since not all signals should necessarily be displayed directly to the user. For example, the catalog backend may want to send a signal to the frontend when an entity is updated so that users that are currently viewing the entity in the frontend can trigger an update of the view. +2. We want to limit the number of WebSocket connections that the frontend needs to maintain. By using a separated signal abstraction it is easier to extend the implementation to support other messaging patterns in the future. For example, we may want to move the Scaffolder logs to be sent via the signal plugin instead. That is much more straightforward with a separate signal plugin compared to adding it to the notifications plugin. +3. The technical implementation of sending signals is sufficiently complex that it makes sense to separate out to its own solution in order to reduce the complexity of the notifications plugin. In particular when it comes to handling scaled deployments. + +### User-to-User Notifications + +The notification backend API for sending notifications is only available to other backend plugins, and is not accessible to end users in the frontend. If this were to be added it would likely be a separate backend module that you can install alongside the notification backend. That is unless the permission framework can be extended to support default policy handlers so that we can reject the permission to send user notifications by default. + +There are a few reasons we don't want to allow user-to-user notifications out of the box: + +- To limit the possibility of spam. Even if well-intended, a notification overload can quickly lead to a bad user experience and users disabling and ignoring notifications. +- From a security perspective it's beneficial to avoid user sent notifications since they could be used to trick users into clicking on malicious links, or other similar attacks. +- Our assumption is that this is a feature that most adopters will not want to use, and so by having it be disabled by default we can avoid additional configuration steps. diff --git a/beps/0001-notifications-system/notifications-architecture.drawio.svg b/beps/0001-notifications-system/notifications-architecture.drawio.svg new file mode 100644 index 0000000000..9f8194b499 --- /dev/null +++ b/beps/0001-notifications-system/notifications-architecture.drawio.svg @@ -0,0 +1,537 @@ + + + + + + + + + + +
+
+
+ Notification Backend +
+
+
+
+ + Notification Backend + +
+
+ + + + + + + + +
+
+
+ Notification Frontend +
+
+
+
+ + Notification Frontend + +
+
+ + + + +
+
+
+ Signal Backend +
+
+
+
+ + Signal Backend + +
+
+ + + + + + + + + + +
+
+
+ Signal Frontend +
+
+
+
+ + Signal Frontend + +
+
+ + + + + + +
+
+
+ Plugin X Backend +
+
+
+
+ + Plugin X Backend + +
+
+ + + + +
+
+
+ Plugin X Frontend +
+
+
+
+ + Plugin X Frontend + +
+
+ + + + + + + + + + + + +
+
+
+ Event Broker +
+
+
+
+ + Event Broker + +
+
+ + + + + + +
+
+
+ ... +
+
+
+
+ + ... + +
+
+ + + + +
+
+
+ ... +
+
+
+
+ + ... + +
+
+ + + + +
+
+
+ publish event +
+
+
+
+ + publish event + +
+
+ + + + +
+
+
+ broadcast +
+
+
+
+ + broadcast + +
+
+ + + + +
+
+
+ ??? +
+
+
+
+ + ??? + +
+
+ + + + +
+
+
+ server push +
+
+
+
+ + server push + +
+
+ + + + +
+
+
+ POST +
+
+
+
+ + POST + +
+
+ + + + + + +
+
+
+ External System +
+
+
+
+ + External System + +
+
+ + + + +
+
+
+ email/slack/teams, etc. +
+
+
+
+ + email/slack/teams, etc. + +
+
+ + + + +
+
+
+ Render +
+
+
+
+ + Render + +
+
+ + + + +
+
+
+ + Processor + +
+
+
+
+ + Processor + +
+
+ + + + +
+
+
+ GET +
+
+
+
+ + GET + +
+
+ + + + +
+
+
+ 1 +
+
+
+
+ + 1 + +
+
+ + + + +
+
+
+ 3 +
+
+
+
+ + 3 + +
+
+ + + + +
+
+
+ 1b +
+
+
+
+ + 1b + +
+
+ + + + +
+
+
+ 4 +
+
+
+
+ + 4 + +
+
+ + + + +
+
+
+ 5 +
+
+
+
+ + 5 + +
+
+ + + + +
+
+
+ 6 +
+
+
+
+ + 6 + +
+
+ + + + +
+
+
+ 7b +
+
+
+
+ + 7b + +
+
+ + + + +
+
+
+ 7 +
+
+
+
+ + 7 + +
+
+ + + + + + +
+
+
+ 2 +
+
+
+
+ + 2 + +
+
+ + + + +
+
+
+ Channel Callback +
+
+
+
+ + Channel Callback + +
+
+
+ + + + + Text is not SVG - cannot display + + + +
diff --git a/beps/NNNN-template/README.md b/beps/NNNN-template/README.md new file mode 100644 index 0000000000..40e2eb8f72 --- /dev/null +++ b/beps/NNNN-template/README.md @@ -0,0 +1,99 @@ +--- +title: BEP Title +status: provisional +authors: + - '@ghost' +owners: +project-areas: + - aaa + - bbb +creation-date: yyyy-mm-dd +--- + + + +# BEP: + + + +[**Discussion Issue**](https://github.com/backstage/backstage/issues/NNNNN) + +- [Summary](#summary) +- [Motivation](#motivation) + - [Goals](#goals) + - [Non-Goals](#non-goals) +- [Proposal](#proposal) +- [Design Details](#design-details) +- [Release Plan](#release-plan) +- [Dependencies](#dependencies) +- [Alternatives](#alternatives) + +## Summary + + + +## Motivation + + + +### Goals + + + +### Non-Goals + + + +## Proposal + + + +## Design Details + + + +## Release Plan + + + +## Dependencies + + + +## Alternatives + + diff --git a/beps/README.md b/beps/README.md new file mode 100644 index 0000000000..531bd15f50 --- /dev/null +++ b/beps/README.md @@ -0,0 +1,86 @@ +# Backstage Enhancement Proposals (BEPs) + +A Backstage Enhancement Proposal (BEP) is a way to propose, communicate and coordinate on new efforts for the Backstage project. + +## Quick start for the BEP process + +1. Discuss the idea with the community and maintainers. Either here on GitHub, Discord, or during community sessions or SIG meetings. + Make sure that others think the work is worth taking up and will help review the BEP and any code changes required. +1. Make a copy of the [BEP template](./NNNN-template/) directory as `beps/NNNN-short-descriptive-title`, where `NNNN` is the next available number padded with leading zeroes. +1. Fill out as much of the YAML metadata as you can. +1. Fill out the template as best you can. +1. If you want the BEP to be owned by a particular project area, add an entry for the BEP folder to [CODEOWNERS](../.github/CODEOWNERS). +1. Create a PR for the BEP. Title it "BEP: <title>". Aim to get the high level goals clarified and avoid getting hung up on specific details. The PR can be merged early and iterated on. +1. Once the BEP is ready to be merged, create a [feature issue](https://github.com/backstage/backstage/issues/new?template=feature.yaml) titled "BEP: <title>". Use the summary of the BEP as description and link to the BEP PR in the context section. Once the PR is merged, the issue should be updated to link to the BEP folder instead. This issue will serve as a general discussion issue for the BEP. +1. Once the initial BEP is merged you should keep iterating on it until it is ready to leave that `provisional` state. Leaving the `provisional` state is a decision made by the project area maintainers. + +Just because a BEP is merged does not mean it is complete or approved for implementation. Any BEP marked as `provisional` is a working document and subject to change. + +The authors of the BEP are also responsible for driving the BEP forward all the way to implementation. The approval of a BEP is not a commitment to implement it. + +## FAQs + +### Do I have to use the BEP process? + +No, but it is recommended for larger changes and contributions that affect the Backstage framework or core features where you want to make design decisions upfront and iterate on them across several PRs. + +### What is the difference between a BEP and an RFC issue? + +An RFC issue is a good way to receive feedback on an idea. The BEP process may involve getting feedback on an idea, but it takes things further by making it easier to iterate on the design of a new feature, getting it approved by the owning project area maintainers, and tracking its implementation. + +While anyone can open an RFC issue, the features added by a BEP need to be approved by the owners before it can be merged. The BEP will also contain the latest agreed upon design, whereas an RFC issue is more of a discussion forum. + +Often a BEP can start out as an RFC issue, which may then be converted into a BEP once the idea has received an owner and been approved. + +### Should I use the BEP process for new or existing Backstage plugins? + +No, except for plugins that implement core features of Backstage. The BEP process is only intended for changes to the Backstage framework and core features. + +### Can I update an existing BEP? + +Yes! As long as the BEP is still in the `provisional` state you should keep iterating on it. Please keep each PR focused on a single topic and avoid long-running and overly broad PRs. + +### Can I update a BEP that was submitted by someone else? + +Yes! BEPs are living documents and anyone can suggest changes to them. We encourage to challenge the design decisions in a BEP and suggest alternatives. You can also help fill out details in a BEP that has not yet been fully fleshed out. + +### What's the difference between a BEP and an [ADR](https://backstage.io/docs/architecture-decisions/)? + +Architecture Decision Records (ADRs) are used to document decisions made for development within the Backstage project. They are not intended to be used for proposing new features or changes to Backstage. + +### My FAQ isn't answered here! + +The BEP process is still evolving! + +If something is missing or not answered here feel free to reach out on our community [Discord](https://discord.gg/backstage-687207715902193673). +If you want to propose a change to the BEP process you can also open a PR directly with your proposal. + +### BEP Metadata + +At the start of each BEP is a YAML document that contains metadata about the BEP. These are the fields that should currently be provided: + +| Field | Description | +| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **title** | The title of the BEP in plain language. The title will also be used in the BEP filename. See the template for instructions and details. | +| **status** | The current state of the BEP, must be one of the values listed in the [BEP Status](#bep-status) section. | +| **authors** | A list of GitHub IDs for the authors of the BEP. Typically only the original authors are included, but additional authors can be added if significant contributions are made. | +| **owners** | A list of GitHub IDs for the owners of the BEP. The owners are responsible for the implementation of the BEP, and are required for the BEP to move to the `implementable` status. | +| **project-areas** | The Project Areas closely associated with this BEP that need to approve it. For a list of existing project areas, see [OWNERS.md](../OWNERS.md). If the BEP is not related to any existing project area, use `core-maintainers` instead. | +| **creation-date** | The `yyyy-mm-dd` date that the BEP was first submitted in a PR. | + +## BEP Status + +The BEP Status is critical to clearly communicate the status of each BEP. Each BEP must have its status field set to one of the following values: + +- `provisional`: The BEP has been proposed and is actively being defined. The BEP as been approved by the owning project area maintainers as work to be done. +- `implementable`: The approvers have approved this BEP for implementation. +- `implemented`: The BEP has been implemented and is no longer actively changed. +- `deferred`: The BEP is proposed but not actively being worked on. +- `rejected`: The approvers and authors have decided that this BEP is not moving forward. + The BEP is kept around as a historical document. +- `withdrawn`: The authors have withdrawn the BEP. +- `replaced`: The BEP has been replaced by a new BEP. + +### Prior Art + +The BEP process is heavily inspired by the [Kubernetes Enhancement Proposal (KEP) process](https://github.com/kubernetes/enhancements/blob/master/keps/README.md). diff --git a/contrib/.devcontainer/Dockerfile b/contrib/.devcontainer/Dockerfile index 35459b8d97..6407aa26dd 100644 --- a/contrib/.devcontainer/Dockerfile +++ b/contrib/.devcontainer/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/devcontainers/typescript-node:18 +FROM mcr.microsoft.com/devcontainers/typescript-node:20 RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ && apt-get -y install chromium \ diff --git a/contrib/chart/backstage/Chart.lock b/contrib/chart/backstage/Chart.lock index 6220a481dd..bd909c1071 100644 --- a/contrib/chart/backstage/Chart.lock +++ b/contrib/chart/backstage/Chart.lock @@ -1,6 +1,6 @@ dependencies: - name: postgresql repository: https://charts.bitnami.com/bitnami - version: 9.8.12 -digest: sha256:549b9a0cdf7b2e0ad949ebad853a467bf320928970a946fb0ef7e13e9bdb7a10 -generated: "2022-05-20T08:15:48.301491565Z" + version: 13.2.30 +digest: sha256:7b558cf1628b8cce366c980f20bd80a3cd7685fe419e43ee9d6df75bc577ec20 +generated: "2024-01-15T11:57:35.306830879Z" diff --git a/contrib/chart/backstage/Chart.yaml b/contrib/chart/backstage/Chart.yaml index 9770ef665c..f926c1b0d7 100644 --- a/contrib/chart/backstage/Chart.yaml +++ b/contrib/chart/backstage/Chart.yaml @@ -18,7 +18,7 @@ sources: dependencies: - name: postgresql condition: postgresql.enabled - version: 9.8.12 + version: 13.2.30 repository: https://charts.bitnami.com/bitnami maintainers: diff --git a/contrib/docs/tutorials/authenticate-api-requests.md b/contrib/docs/tutorials/authenticate-api-requests.md index c14eaebb54..4c44c8ae65 100644 --- a/contrib/docs/tutorials/authenticate-api-requests.md +++ b/contrib/docs/tutorials/authenticate-api-requests.md @@ -8,6 +8,8 @@ API requests from frontend plugins include an authorization header with a Backst As techdocs HTML pages load assets without an Authorization header the code below also sets a token cookie when the user logs in (and when the token is about to expire). +## Old Backend System Setup + Create `packages/backend/src/authMiddleware.ts`: ```typescript @@ -122,6 +124,151 @@ async function main() { } ``` +## New Backend System Setup + +Create `packages/backend/src/authMiddlewareFactory.ts`: + +```typescript +import { HostDiscovery } from '@backstage/backend-app-api'; +import { ServerTokenManager } from '@backstage/backend-common'; +import { + LoggerService, + RootConfigService, +} from '@backstage/backend-plugin-api'; +import { + DefaultIdentityClient, + getBearerTokenFromAuthorizationHeader, +} from '@backstage/plugin-auth-node'; +import { NextFunction, Request, RequestHandler, Response } from 'express'; +import { decodeJwt } from 'jose'; +import lzstring from 'lz-string'; +import { URL } from 'url'; + +type AuthMiddlewareFactoryOptions = { + config: RootConfigService; + logger: LoggerService; +}; + +export const authMiddlewareFactory = ({ + config, + logger, +}: AuthMiddlewareFactoryOptions): RequestHandler => { + const baseUrl = config.getString('backend.baseUrl'); + const discovery = HostDiscovery.fromConfig(config); + const identity = DefaultIdentityClient.create({ discovery }); + const tokenManager = ServerTokenManager.fromConfig(config, { logger }); + + return async (req: Request, res: Response, next: NextFunction) => { + const fullPath = `${req.baseUrl}${req.path}`; + + // Only apply auth to /api routes & skip auth for the following endpoints + // Add any additional plugin routes you want to whitelist eg. events + const nonAuthWhitelist = ['app', 'auth']; + const nonAuthRegex = new RegExp( + `^\/api\/(${nonAuthWhitelist.join('|')})(?=\/|$)\S*`, + ); + if (!fullPath.startsWith('/api/') || nonAuthRegex.test(fullPath)) { + next(); + return; + } + + try { + // Token cookies are compressed to reduce size + const cookieToken = lzstring.decompressFromEncodedURIComponent( + req.cookies.token, + ); + const token = + getBearerTokenFromAuthorizationHeader(req.headers.authorization) ?? + cookieToken; + + try { + // Attempt to authenticate as a frontend request token + await identity.authenticate(token); + } catch (err) { + // Attempt to authenticate as a backend request token + await tokenManager.authenticate(token); + } + + if (!req.headers.authorization) { + // Authorization header may be forwarded by plugin requests + req.headers.authorization = `Bearer ${token}`; + } + + if (token !== cookieToken) { + try { + const payload = decodeJwt(token); + res.cookie('token', token, { + // Compress token to reduce cookie size + encode: lzstring.compressToEncodedURIComponent, + expires: new Date((payload?.exp ?? 0) * 1000), + secure: baseUrl.startsWith('https://'), + sameSite: 'lax', + domain: new URL(baseUrl).hostname, + path: '/', + httpOnly: true, + }); + } catch { + // Ignore + } + } + next(); + } catch { + res.status(401).send(`Unauthorized`); + } + }; +}; +``` + +Install cookie-parser: + +```bash +# From your Backstage root directory +yarn add --cwd packages/backend cookie-parser @types/cookie-parser +``` + +Create a custom configured `rootHttpRouterService` in `packages/backend/src/customRootHttpRouterService.ts`: + +```typescript +import { rootHttpRouterServiceFactory } from '@backstage/backend-app-api'; +import cookieParser from 'cookie-parser'; +import { authMiddlewareFactory } from './authMiddlewareFactory'; + +export default rootHttpRouterServiceFactory({ + configure: ({ app, config, logger, middleware, routes }) => { + app.use(middleware.helmet()); + app.use(middleware.cors()); + app.use(middleware.compression()); + app.use(cookieParser()); + app.use(middleware.logging()); + + app.use(authMiddlewareFactory({ config, logger })); + + // Simple handler to set auth cookie for user + app.use('/api/cookie', (_, res) => { + res.status(200).send(); + }); + + app.use(routes); + + app.use(middleware.notFound()); + app.use(middleware.error()); + }, +}); +``` + +Update `packages/backend/src/index.ts` to add the custom `rootHttpRouterService` and override the default: + +```typescript +// ... +const backend = createBackend(); + +backend.add(import('./customRootHttpRouterService')); + +// ... +``` + +## Frontend Setup + Create `packages/app/src/cookieAuth.ts`: ```typescript diff --git a/docs/assets/backend-system/scaled-deployments.drawio.svg b/docs/assets/backend-system/scaled-deployments.drawio.svg new file mode 100644 index 0000000000..85060af236 --- /dev/null +++ b/docs/assets/backend-system/scaled-deployments.drawio.svg @@ -0,0 +1,429 @@ + + + + + + + + + + + + + + + + + + + +
+
+
+ Backend Deployment A +
+
+
+
+ + Backend Deployme... + +
+
+ + + + +
+
+
+ Frontend App +
+
+
+
+ + Frontend App + +
+
+ + + + + + + +
+
+
+ All other traffic +
+
+
+
+ + All other traffic + +
+
+ + + + + +
+
+
+ /api/{techdocs,scaffolder}/* +
+
+
+
+ + /api/{techdocs,scaffolder}/* + +
+
+ + + + +
+
+
+ (Authenticating) Reverse Proxy +
+
+
+
+ + (Authenticating)... + +
+
+ + + + + + + + +
+
+
+ Backend Deployment C +
+
+
+
+ + Backend Deployme... + +
+
+ + + + + + + + +
+
+
+ Backend Deployment B +
+
+
+
+ + Backend Deployme... + +
+
+ + + + + + +
+
+
+ app +
+
+
+
+ + app + +
+
+ + + + + + +
+
+
+ auth +
+
+
+
+ + auth + +
+
+ + + + + + +
+
+
+ catalog +
+
+
+
+ + catalog + +
+
+ + + + + + +
+
+
+ search +
+
+
+
+ + search + +
+
+ + + + + + +
+
+
+ techdocs +
+
+
+
+ + techdocs + +
+
+ + + + + + +
+
+
+ scaffolder +
+
+
+
+ + scaffolder + +
+
+ + + + + + +
+
+
+ proxy +
+
+
+
+ + proxy + +
+
+ + + + +
+
+
+ Plugins +
+
+
+
+ + Plugi... + +
+
+ + + + + + +
+
+
+ /api/{catalog,search}/* +
+
+
+
+ + /api/{catalog,search}/* + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + Horizontally Scaled + +
+ + Deployments + +
+
+
+
+ + Horizontally Scale... + +
+
+ + + + +
+
+
+ Logical Databases +
+
+
+
+ + Logical Databases + +
+
+ + + + + + + + + + + + + + + + + + + + + + +
+
+
+ DBMS Instances +
+
+
+
+ + DBMS Instances + +
+
+
+ + + + + Text is not SVG - cannot display + + + +
diff --git a/docs/assets/frontend-system/architecture-utility-apis.drawio.svg b/docs/assets/frontend-system/architecture-utility-apis.drawio.svg new file mode 100644 index 0000000000..a7008b1126 --- /dev/null +++ b/docs/assets/frontend-system/architecture-utility-apis.drawio.svg @@ -0,0 +1,314 @@ + + + + + + + +
+
+
+ App +
+
+
+
+ + App + +
+
+ + + + + +
+
+
+ provides +
+
+
+
+ + provides + +
+
+ + + + +
+
+
+ Catalog Plugin +
+ + plugin:catalog + +
+
+
+
+ + Catalog Plugin... + +
+
+ + + + + +
+
+
+ + replaces +
+ implementation +
+
+
+
+
+
+ + replaces... + +
+
+ + + + +
+
+
+ Extension Overrides +
+
+
+
+ + Extension Overr... + +
+
+ + + + + +
+
+
+ provides +
+
+
+
+ + provides + +
+
+ + + + +
+
+
+ Todo Plugin +
+ + plugin:todo + +
+
+
+
+ + Todo Plugin... + +
+
+ + + + +
+
+
+ Backstage Frontend Framework +
+
+
+
+ + Backstage Frontend Framework + +
+
+ + + + + + +
+
+
+ + Catalog Client Utility API +
+ + api:plugin.catalog.service + +
+
+
+
+
+ + Catalog Client Utility API... + +
+
+ + + + +
+
+
+ + Todo Utility API +
+ + api:plugin.todo.api + +
+
+
+
+
+ + Todo Utility API... + +
+
+ + + + + + + + + +
+
+
+ + installs + +
+
+
+
+ + installs + +
+
+ + + + +
+
+
+ + Fetch Utility API +
+ + api:core.fetch + +
+
+
+
+
+ + Fetch Utility API... + +
+
+ + + + + +
+
+
+ provides +
+
+
+
+ + provides + +
+
+ + + + + +
+
+
+ depends on +
+
+
+
+ + depends on + +
+
+ + + + + +
+
+
+ depends on +
+
+
+
+ + depends on + +
+
+
+ + + + + Text is not SVG - cannot display + + + +
diff --git a/docs/auth/identity-resolver.md b/docs/auth/identity-resolver.md index a65f3d7899..0a626ef175 100644 --- a/docs/auth/identity-resolver.md +++ b/docs/auth/identity-resolver.md @@ -236,6 +236,12 @@ export default async function createPlugin( // an entity you will need to replace this step as well. // // You might also replace it if you for example want to filter out certain groups. + // + // Note that `getDefaultOwnershipEntityRefs` only includes groups to which the + // user has a direct MEMBER_OF relationship. It's perfectly fine to include + // groups that the user is transitively part of in the claims array, but the + // catalog doesn't currently provide a direct way of accessing this list of + // groups. const ownershipRefs = getDefaultOwnershipEntityRefs(entity); // The last step is to issue the token, where we might provide more options in the future. diff --git a/docs/auth/index.md b/docs/auth/index.md index 091c8b01a0..806cda0ff7 100644 --- a/docs/auth/index.md +++ b/docs/auth/index.md @@ -371,6 +371,7 @@ createApiFactory({ configApi, discoveryApi, oauthRequestApi, + provider: { id: 'ghe', title: 'GitHub Enterprise', icon: () => null }, defaultScopes: ['read:user'], environment: configApi.getOptionalString('auth.environment'), }), diff --git a/docs/auth/okta/provider.md b/docs/auth/okta/provider.md index e4fc8bfb45..2242e4a0f0 100644 --- a/docs/auth/okta/provider.md +++ b/docs/auth/okta/provider.md @@ -27,6 +27,8 @@ To add Okta authentication, you must create an Application from Okta: - `Controlled access`: (select as appropriate) - Click Save +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 The provider configuration can then be added to your `app-config.yaml` under the @@ -43,6 +45,8 @@ auth: audience: ${AUTH_OKTA_DOMAIN} authServerId: ${AUTH_OKTA_AUTH_SERVER_ID} # Optional 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 ``` The values referenced are found on the Application page on your Okta site. @@ -55,6 +59,8 @@ The values referenced are found on the Application page on your Okta site. - `authServerId`: The authorization server ID for the Application - `idp`: The identity provider for the application, e.g. `0oaulob4BFVa4zQvt0g3` +`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. + ## Adding the provider to the Backstage frontend To add the provider to the frontend, add the `oktaAuthApi` reference and diff --git a/docs/backend-system/architecture/01-index.md b/docs/backend-system/architecture/01-index.md index 0e780039b6..9c37df7b66 100644 --- a/docs/backend-system/architecture/01-index.md +++ b/docs/backend-system/architecture/01-index.md @@ -6,8 +6,6 @@ sidebar_label: Overview description: The structure and architecture of the new Backend System and its component parts --- -> **NOTE: The new backend system is in alpha, and some plugins do not yet fully implement it.** - ## Building Blocks This section introduces the high-level building blocks upon which this new @@ -59,7 +57,7 @@ Just like plugins, modules also have access to services and can depend on their A detailed explanation of the package architecture can be found in the [Backstage Architecture -Overview](../../overview/architecture-overview/#package-architecture). The +Overview](../../overview/architecture-overview.md#package-architecture). The most important packages to consider for this system are the following: - `plugin--backend` houses the implementation of the backend plugins diff --git a/docs/backend-system/architecture/02-backends.md b/docs/backend-system/architecture/02-backends.md index c64024d653..3386cff3f7 100644 --- a/docs/backend-system/architecture/02-backends.md +++ b/docs/backend-system/architecture/02-backends.md @@ -6,8 +6,6 @@ sidebar_label: Backend description: Backend instances --- -> **NOTE: The new backend system is in alpha, and some plugins do not yet fully implement it.** - ## The Backend Instance This is the main entry point for creating a backend. It does not have any functionality in and of itself, but is simply responsible for wiring things together. diff --git a/docs/backend-system/architecture/03-services.md b/docs/backend-system/architecture/03-services.md index df610f45ab..573f6612c2 100644 --- a/docs/backend-system/architecture/03-services.md +++ b/docs/backend-system/architecture/03-services.md @@ -6,8 +6,6 @@ sidebar_label: Services description: Services for backend plugins --- -> **NOTE: The new backend system is in alpha, and some plugins do not yet fully implement it.** - Backend services provide shared functionality available to all backend plugins and modules. They are made available through service references that embed a type that represents the service interface, similar to how [Utility APIs](../../api/utility-apis.md) work in the Backstage frontend system. To use a service in your plugin or module you request an implementation of that service using the service reference. The system surrounding services exists to provide a level of indirection between the service interfaces and their implementation. It is an implementation of dependency injection, where each backend instance is the dependency injection container. The implementation for each service is provided by a service factory, which encapsulates the logic for how each service instance is created. diff --git a/docs/backend-system/architecture/04-plugins.md b/docs/backend-system/architecture/04-plugins.md index e93a6a39b2..195c32b049 100644 --- a/docs/backend-system/architecture/04-plugins.md +++ b/docs/backend-system/architecture/04-plugins.md @@ -6,8 +6,6 @@ sidebar_label: Plugins description: Backend plugins --- -> **NOTE: The new backend system is in alpha, and some plugins do not yet fully implement it.** - Plugins provide the actual base features of a Backstage backend. Each plugin operates completely independently of all other plugins and they only communicate with each other through network calls. This means that there is a strong degree of isolation between plugins, and that each plugin can be considered a separate microservice. While a default Backstage project has all plugins installed within a single backend, it is also possible to split this setup into multiple backends, with each backend housing one or more plugins. ## Defining a Plugin diff --git a/docs/backend-system/architecture/05-extension-points.md b/docs/backend-system/architecture/05-extension-points.md index d8d993b5bf..4b7f893f0b 100644 --- a/docs/backend-system/architecture/05-extension-points.md +++ b/docs/backend-system/architecture/05-extension-points.md @@ -6,8 +6,6 @@ sidebar_label: Extension Points description: Extension points of backend plugins --- -> **NOTE: The new backend system is in alpha, and some plugins do not yet fully implement it.** - While plugins are able to use static configuration for lightweight forms of customization, you can quickly hit a limit where you need something more powerful to allow users to extend your plugin. For this purpose, the backend system provides a mechanism for plugins to provide extension points, which can be used to expose deeper customizations for your plugin. Extension points are used by modules, which are installed in the backend adjacent to plugins. Modules are covered more in-depth in the [next section](./06-modules.md). Extension points are quite similar to services, in that they both encapsulate an interface in a reference object. The key difference is that extension points are registered and provided by plugins themselves, and do not have any factory associated with them. Extension points for a given plugin are also only accessible to modules that extend that same plugin. @@ -70,7 +68,7 @@ Note that we create a closure that adds to a shared `actions` structure when `ad ## Module Extension Points -Just like plugins, modules can also provide their own extension points. The API for registering and using extension points is the same as for plugins. However, modules should typically only use extension points to allow for complex internal customizations by users of the plugin module. It is therefore preferred to export the extension point directly from the module package, rather than creating a separate node library for that purpose. +Just like plugins, modules can also provide their own extension points. The API for registering and using extension points is the same as for plugins. However, modules should typically only use extension points to allow for complex internal customizations by users of the plugin module. It is therefore preferred to export the extension point directly from the module package, rather than creating a separate node library for that purpose. Extension points exported by a module are used the same way as extension points exported by a plugin, you create your own separate module and declare a dependency on the extension point that you want to interact with. ## Extension Point Design diff --git a/docs/backend-system/architecture/06-modules.md b/docs/backend-system/architecture/06-modules.md index e916e4fdf6..eb00e737e3 100644 --- a/docs/backend-system/architecture/06-modules.md +++ b/docs/backend-system/architecture/06-modules.md @@ -6,8 +6,6 @@ sidebar_label: Modules description: Modules for backend plugins --- -> **NOTE: The new backend system is in alpha, and some plugins do not yet fully implement it.** - Backend modules are used to extend [plugins](./04-plugins.md) or sometimes other modules with additional features or change existing behavior. They must always be installed in the same backend instance as the plugin that they extend, and may only extend a single plugin. Modules interact with their target plugin using the [extension points](./05-extension-points.md) registered by the plugin, while also being able to depend on the [services](./03-services.md) of that plugin. Both modules and plugins register an `init` method that is called during startup. In order to ensure that modules have registered all their extensions before the plugin starts up, all modules for each plugin are completely initialized before the plugin itself is initialized. In practice this means that all promises returned by each `init` method of the modules need to resolve before the plugin `init` method is called. This also means that it is not possible to further interact with the extension points once the `init` method has resolved. @@ -25,8 +23,8 @@ import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node' import { MyCustomProcessor } from './MyCustomProcessor'; export const catalogModuleExampleCustomProcessor = createBackendModule({ - moduleId: 'exampleCustomProcessor', pluginId: 'catalog', + moduleId: 'example-custom-processor', register(env) { env.registerInit({ deps: { diff --git a/docs/backend-system/architecture/07-naming-patterns.md b/docs/backend-system/architecture/07-naming-patterns.md index 3e57fa6863..f45355acf0 100644 --- a/docs/backend-system/architecture/07-naming-patterns.md +++ b/docs/backend-system/architecture/07-naming-patterns.md @@ -6,22 +6,22 @@ sidebar_label: Naming Patterns description: Naming patterns in the backend system --- -> **NOTE: The new backend system is in alpha, and some plugins do not yet fully implement it.** - These are the naming patterns to adhere to within the backend system. They help us keep exports consistent across packages and make it easier to understand the usage and intent of exports. +As a rule, all names should be camel case, with the exceptions of plugin and module IDs, which should be kebab case. + ### Plugins -| Description | Pattern | Examples | -| ----------- | ------------ | ----------------------------------- | -| export | `Plugin` | `catalogPlugin`, `scaffolderPlugin` | -| ID | `''` | `'catalog'`, `'scaffolder'` | +| Description | Pattern | Examples | +| ----------- | ----------------- | ------------------------------------- | +| export | `Plugin` | `catalogPlugin`, `userSettingsPlugin` | +| ID | `''` | `'catalog'`, `'user-settings'` | Example: ```ts -export const catalogPlugin = createBackendPlugin({ - pluginId: 'catalog', +export const userSettingsPlugin = createBackendPlugin({ + pluginId: 'user-settings', ... }) ``` @@ -31,14 +31,14 @@ export const catalogPlugin = createBackendPlugin({ | Description | Pattern | Examples | | ----------- | ---------------------------- | ----------------------------------- | | export | `Module` | `catalogModuleGithubEntityProvider` | -| ID | `''` | `'githubEntityProvider'` | +| ID | `''` | `'github-entity-provider'` | Example: ```ts export const catalogModuleGithubEntityProvider = createBackendModule({ pluginId: 'catalog', - moduleId: 'githubEntityProvider', + moduleId: 'github-entity-provider', ... }) ``` diff --git a/docs/backend-system/building-backends/01-index.md b/docs/backend-system/building-backends/01-index.md index 3c6c51be51..4caa6fd524 100644 --- a/docs/backend-system/building-backends/01-index.md +++ b/docs/backend-system/building-backends/01-index.md @@ -6,8 +6,6 @@ sidebar_label: Overview description: Building backends using the new backend system --- -> **NOTE: The new backend system is in alpha, and some plugins do not yet fully implement it.** - > NOTE: If you have an existing backend that is not yet using the new backend > system, see [migrating](./08-migrating.md). @@ -142,3 +140,13 @@ backend.start(); ``` We've now split the backend into two separate deployments, but we still need to make sure that they can communicate with each other. This is the hard and somewhat tedious part, as Backstage currently doesn't provide an out of the box solution that solves this. You'll need to manually configure the two backends with custom implementations of the `DiscoveryService` and have them return the correct URLs for each other. Likewise, you'll also need to provide a custom implementation of the `DiscoveryApi` in the frontend, unless you surface the two backends via a proxy that handles the routing instead. + +### Split backend deployments architecture example + +Below is an example of a more elaborate setup where we have three different backend deployments, each with their own set of plugins and modules. Between our frontend app and the backend instances we have a reverse proxy that routes the traffic to the appropriate instance. As an option for securing the Backstage deployment the proxy can be set up as an authenticating reverse proxy as well, denying unauthenticated users access to the backend instances. + +![diagram of a backstage deployment with three separate horizontally scaled backend systems](../../assets/backend-system/scaled-deployments.drawio.svg) + +In this example we have split out the Catalog and Search plugins into one backend deployment. The proxy routes all traffic for `/api/catalog/` and `/api/search/` to this instance. With this separation we're able to scale and deploy these two plugins independently, and they are also isolated from both a performance and security perspective. Likewise the TechDocs and Scaffolder plugins are split out as well, and then we route the rest of the traffic to our instance that contains the App, Auth, and Proxy plugins. + +We also see how each of the plugins have their own logical database, but are often set up to share the actual Database Management System (DBMS) instance. This is of course not a requirement, and you can choose to further divide or consolidate the databases as you see fit. diff --git a/docs/backend-system/building-backends/08-migrating.md b/docs/backend-system/building-backends/08-migrating.md index 1e30d0aa9e..45478d632e 100644 --- a/docs/backend-system/building-backends/08-migrating.md +++ b/docs/backend-system/building-backends/08-migrating.md @@ -6,8 +6,6 @@ sidebar_label: Migration Guide description: How to migrate existing backends to the new backend system --- -> **NOTE: The new backend system is in alpha, and some plugins do not yet fully implement it.** - ## Overview This section describes how to migrate an existing Backstage backend service @@ -21,8 +19,7 @@ internal plugins and support classes themselves to the backend system first - the migration here will mostly deal with wiring and using compatibility wrappers where possible in the backend package itself. We hope that you will find that you end up with a much smaller, easier to understand, and easier to maintain -package as a result of these steps, and then being able to [migrate -plugins](../building-plugins-and-modules/08-migrating.md) as a separate +package as a result of these steps, and then being able to [migrate plugins](../building-plugins-and-modules/08-migrating.md) as a separate endeavour later. ## Overall Structure @@ -262,6 +259,317 @@ If you have other customizations made to `plugins/catalog.ts`, such as adding custom processors or entity providers, read on. Otherwise, you should be able to just delete that file at this point. +#### Amazon Web Services + +`AwsEksClusterProcessor` and `AwsOrganizationCloudAccountProcessor` have not yet been migrated to the new backend system. +See [Other Catalog Extensions](#other-catalog-extensions) for how to use these in the new backend system. + +For `AwsS3DiscoveryProcessor`, first migrate to `AwsS3EntityProvider`. + +To migrate `AwsS3EntityProvider` to the new backend system, add a reference to the `@backstage/plugin-catalog-backend-module-aws` module. + +```ts title="packages/backend/src/index.ts" +backend.add(import('@backstage/plugin-catalog-backend/alpha')); +/* highlight-add-start */ +backend.add(import('@backstage/plugin-catalog-backend-module-aws/alpha')); +/* highlight-add-end */ +``` + +If you were providing a `schedule` in code, this now needs to be set via configuration. +All other AWS configuration in `app-config.yaml` remains the same. + +```yaml title="app-config.yaml" +catalog: + providers: + awsS3: + yourProviderId: + # ... + /* highlight-add-start */ + schedule: + frequency: PT1H + timeout: PT50M + /* highlight-add-end */ +``` + +#### Azure DevOps + +For `AzureDevOpsDiscoveryProcessor`, first migrate to `AzureDevOpsEntityProvider`. + +To migrate `AzureDevOpsEntityProvider` to the new backend system, add a reference to the `@backstage/plugin-catalog-backend-module-azure` module. + +```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-azure/alpha')); +/* highlight-add-end */ +``` + +If you were providing a `schedule` in code, this now needs to be set via configuration. +All other Azure DevOps configuration in `app-config.yaml` remains the same. + +```yaml title="app-config.yaml" +catalog: + providers: + azureDevOps: + yourProviderId: + # ... + /* highlight-add-start */ + schedule: + frequency: PT1H + timeout: PT50M + /* highlight-add-end */ +``` + +#### Open API + +`InternalOpenApiDocumentationProvider` has not yet been migrated to the new backend system. +See [Other Catalog Extensions](#other-catalog-extensions) for how to use this in the new backend system. + +#### Bitbucket + +For `BitbucketDiscoveryProcessor`, migrate to `BitbucketCloudEntityProvider` or `BitbucketServerEntityProvider` + +To migrate `BitbucketCloudEntityProvider` to the new backend system, add a reference to the `@backstage/plugin-catalog-backend-module-bitbucket-cloud` module. + +```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-bitbucket-cloud/alpha'), +); +/* highlight-add-end */ +``` + +If you were providing a `schedule` in code, this now needs to be set via configuration. +All other Bitbucket Cloud configuration in `app-config.yaml` remains the same. + +```yaml title="app-config.yaml" +catalog: + providers: + bitbucketCloud: + yourProviderId: + # ... + /* highlight-add-start */ + schedule: + frequency: PT30M + timeout: PT3M + /* highlight-add-end */ +``` + +To migrate `BitbucketServerEntityProvider` to the new backend system, add a reference to `@backstage/plugin-catalog-backend-module-bitbucket-server`. + +```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-bitbucket-server/alpha'), +); +/* highlight-add-end */ +``` + +If you were providing a `schedule` in code, this now needs to be set via configuration. +All other Bitbucket Server configuration in `app-config.yaml` remains the same. + +```yaml title="app-config.yaml" +catalog: + providers: + bitbucketServer: + yourProviderId: + # ... + /* highlight-add-start */ + schedule: + frequency: PT30M + timeout: PT3M + /* highlight-add-end */ +``` + +#### Google Cloud Platform + +To migrate `GkeEntityProvider` to the new backend system, add a reference to `@backstage/plugin-catalog-backend-module-gcp`. + +```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-gcp')); +/* highlight-add-end */ +``` + +Configuration in app-config.yaml remains the same. + +#### Gerrit + +To migrate `GerritEntityProvider` to the new backend system, add a reference to `@backstage/plugin-catalog-backend-module-gerrit`. + +```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-gerrit/alpha')); +/* highlight-add-end */ +``` + +If you were providing a `schedule` in code, this now needs to be set via configuration. +All other Gerrit configuration in `app-config.yaml` remains the same. + +```yaml title="app-config.yaml" +catalog: + providers: + gerrit: + yourProviderId: + # ... + /* highlight-add-start */ + schedule: + frequency: PT30M + timeout: PT3M + /* highlight-add-end */ +``` + +#### Github + +For `GithubDiscoveryProcessor`, `GithubMultiOrgReaderProcessor` and `GithubOrgReaderProcessor`, first migrate to the equivalent Entity Provider. + +To migrate `GithubEntityProvider` to the new backend system, add a reference to `@backstage/plugin-catalog-backend-module-github`. + +```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/alpha')); +/* 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. + +```yaml title="app-config.yaml" +catalog: + providers: + github: + yourProviderId: + # ... + /* highlight-add-start */ + schedule: + frequency: PT30M + timeout: PT3M + /* highlight-add-end */ +``` + +To migrate `GithubMultiOrgEntityProvider` and `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')); +/* highlight-add-start */ +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. + +```yaml title="app-config.yaml" +catalog: + providers: + githubOrg: + yourProviderId: + # ... + /* highlight-add-start */ + schedule: + frequency: PT30M + timeout: PT3M + /* highlight-add-end */ +``` + +If you were providing transformers, these can be configured by extending `githubOrgEntityProviderTransformsExtensionPoint` + +```ts title="packages/backend/src/index.ts" +import { createBackendModule } from '@backstage/backend-plugin-api'; +import { githubOrgEntityProviderTransformsExtensionPoint } from '@backstage/plugin-catalog-backend-module-github-org'; + +backend.add( + createBackendModule({ + pluginId: 'catalog', + moduleId: 'githubOrgTransformers', + register(env) { + env.registerInit({ + deps: { + /* highlight-add-start */ + githubOrgTransformers: + githubOrgEntityProviderTransformsExtensionPoint, + /* highlight-add-end */ + }, + async init({ githubOrgTransformers }) { + /* highlight-add-start */ + githubOrgTransformers.setUserTransformer(myUserTransformer); + githubOrgTransformers.setTeamTransformer(myTeamTransformer); + /* highlight-add-end */ + }, + }); + }, + }), +); +``` + +#### Microsoft Graph + +For `MicrosoftGraphOrgReaderProcessor`, first migrate to `MicrosoftGraphOrgEntityProvider` + +To migrate `MicrosoftGraphOrgEntityProvider` to the new backend system, add a reference to `@backstage/plugin-catalog-backend-module-msgraph`. + +```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 */ +``` + +If you were providing a `schedule` in code, this now needs to be set via configuration. +All other Microsoft Graph configuration in `app-config.yaml` remains the same. + +```yaml title="app-config.yaml" +catalog: + providers: + microsoftGraphOrg: + provider: + /* highlight-add-start */ + schedule: + frequency: PT4H + timeout: PT30M + /* highlight-add-end */ +``` + +If you were providing transformers, these can be configured by extending `microsoftGraphOrgEntityProviderTransformExtensionPoint` + +```ts title="packages/backend/src/index.ts" +import { createBackendModule } from '@backstage/backend-plugin-api'; +import { microsoftGraphOrgEntityProviderTransformExtensionPoint } from '@backstage/plugin-catalog-backend-module-msgraph/alpha'; + +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 */ + }, + }); + }, + }), +); +``` + +#### Other Catalog Extensions + You will use the [extension points](../architecture/05-extension-points.md) mechanism to extend or tweak the functionality of the plugin. To do that, you'll make your own bespoke [module](../architecture/06-modules.md) which @@ -269,21 +577,21 @@ depends on the appropriate extension point and interacts with it. ```ts title="packages/backend/src/index.ts" /* highlight-add-start */ -import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node'; +import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; import { createBackendModule } from '@backstage/backend-plugin-api'; /* highlight-add-end */ /* highlight-add-start */ const catalogModuleCustomExtensions = createBackendModule({ pluginId: 'catalog', // name of the plugin that the module is targeting - moduleId: 'customExtensions', + moduleId: 'custom-extensions', register(env) { env.registerInit({ deps: { catalog: catalogProcessingExtensionPoint, // ... and other dependencies as needed }, - init({ catalog /* ..., other dependencies */ }) { + async init({ catalog /* ..., other dependencies */ }) { // Here you have the opportunity to interact with the extension // point before the plugin itself gets instantiated catalog.addEntityProvider(new MyEntityProvider()); // just an example @@ -338,21 +646,21 @@ depends on the appropriate extension point and interacts with it. ```ts title="packages/backend/src/index.ts" /* highlight-add-start */ -import { eventsExtensionPoint } from '@backstage/plugin-events-node'; +import { eventsExtensionPoint } from '@backstage/plugin-events-node/alpha'; import { createBackendModule } from '@backstage/backend-plugin-api'; /* highlight-add-end */ /* highlight-add-start */ const eventsModuleCustomExtensions = createBackendModule({ pluginId: 'events', // name of the plugin that the module is targeting - moduleId: 'customExtensions', + moduleId: 'custom-extensions', register(env) { env.registerInit({ deps: { events: eventsExtensionPoint, // ... and other dependencies as needed }, - init({ events /* ..., other dependencies */ }) { + async init({ events /* ..., other dependencies */ }) { // Here you have the opportunity to interact with the extension // point before the plugin itself gets instantiated events.addSubscribers(new MySubscriber()); // just an example @@ -403,21 +711,21 @@ depends on the appropriate extension point and interacts with it. ```ts title="packages/backend/src/index.ts" /* highlight-add-start */ -import { scaffolderActionsExtensionPoint } from '@backstage/plugin-scaffolder-node'; +import { scaffolderActionsExtensionPoint } from '@backstage/plugin-scaffolder-node/alpha'; import { createBackendModule } from '@backstage/backend-plugin-api'; /* highlight-add-end */ /* highlight-add-start */ const scaffolderModuleCustomExtensions = createBackendModule({ pluginId: 'scaffolder', // name of the plugin that the module is targeting - moduleId: 'customExtensions', + moduleId: 'custom-extensions', register(env) { env.registerInit({ deps: { scaffolder: scaffolderActionsExtensionPoint, // ... and other dependencies as needed }, - init({ scaffolder /* ..., other dependencies */ }) { + async init({ scaffolder /* ..., other dependencies */ }) { // Here you have the opportunity to interact with the extension // point before the plugin itself gets instantiated scaffolder.addActions(new MyAction()); // just an example @@ -446,3 +754,255 @@ going easily, but feel free to move it out to where it fits best. As you migrate your entire plugin flora to the new backend system, you will probably make more and more of these modules as "first class" things, living right next to the implementations that they represent, and being exported from there. + +### The Auth Plugin + +A basic installation of the auth plugin with a Microsoft provider will look as follows. + +```ts title="packages/backend/src/index.ts" +const backend = createBackend(); +/* highlight-add-start */ +backend.add(import('@backstage/plugin-auth-backend')); +backend.add(import('@backstage/plugin-auth-backend-module-microsoft-provider')); +/* highlight-add-end */ +``` + +An additional step you'll need to take is to add the resolvers to your configuration, here's an example: + +```yaml title:"app-config.yaml" +auth: + environment: development + providers: + microsoft: + development: + clientId: ${AZURE_CLIENT_ID} + clientSecret: ${AZURE_CLIENT_SECRET} + tenantId: ${AZURE_TENANT_ID} + signIn: + resolvers: + - resolver: emailMatchingUserEntityAnnotation + - resolver: emailMatchingUserEntityProfileEmail + - resolver: emailLocalPartMatchingUserEntityName +``` + +> Note: the resolvers will be tried in order, but will only be skipped if they throw a `NotFoundError`. + +#### Auth Plugin Modules and Their Resolvers + +As you may have noticed in the above example you'll need to import the `auth-backend` and an `auth-backend-module`. The following sections outline each of them and their resolvers. + +All of the following modules include the following common resolvers: + +- [emailMatchingUserEntityProfileEmail](https://github.com/backstage/backstage/blob/5447cffd23cf00772988fb799ced0ec5e54efb2e/plugins/auth-node/src/sign-in/commonSignInResolvers.ts#L29) +- [emailLocalPartMatchingUserEntityName](https://github.com/backstage/backstage/blob/5447cffd23cf00772988fb799ced0ec5e54efb2e/plugins/auth-node/src/sign-in/commonSignInResolvers.ts#L54) + +##### Atlassian + +Setup: + +```ts title="packages/backend/src/index.ts" +const backend = createBackend(); +/* highlight-add-start */ +backend.add(import('@backstage/plugin-auth-backend')); +backend.add(import('@backstage/plugin-auth-backend-module-atlassian-provider')); +/* highlight-add-end */ +``` + +Additional resolvers: + +- [usernameMatchingUserEntityName](https://github.com/backstage/backstage/blob/5447cffd23cf00772988fb799ced0ec5e54efb2e/plugins/auth-backend-module-atlassian-provider/src/resolvers.ts#L33C16-L33C46) + +##### GCP IAM + +Setup: + +```ts title="packages/backend/src/index.ts" +const backend = createBackend(); +/* highlight-add-start */ +backend.add(import('@backstage/plugin-auth-backend')); +backend.add(import('@backstage/plugin-auth-backend-module-gcp-iap-provider')); +/* highlight-add-end */ +``` + +Additional resolvers: + +- [emailMatchingUserEntityAnnotation](https://github.com/backstage/backstage/blob/5447cffd23cf00772988fb799ced0ec5e54efb2e/plugins/auth-backend-module-gcp-iap-provider/src/resolvers.ts#L32C16-L32C49) + +##### GitHub + +Setup: + +```ts title="packages/backend/src/index.ts" +const backend = createBackend(); +/* highlight-add-start */ +backend.add(import('@backstage/plugin-auth-backend')); +backend.add(import('@backstage/plugin-auth-backend-module-github-provider')); +/* highlight-add-end */ +``` + +Additional resolvers: + +- [usernameMatchingUserEntityName](https://github.com/backstage/backstage/blob/5447cffd23cf00772988fb799ced0ec5e54efb2e/plugins/auth-backend-module-github-provider/src/resolvers.ts#L33C16-L33C46) + +##### GitLab + +Setup: + +```ts title="packages/backend/src/index.ts" +const backend = createBackend(); +/* highlight-add-start */ +backend.add(import('@backstage/plugin-auth-backend')); +backend.add(import('@backstage/plugin-auth-backend-module-gitlab-provider')); +/* highlight-add-end */ +``` + +Additional resolvers: + +- [usernameMatchingUserEntityName](https://github.com/backstage/backstage/blob/5447cffd23cf00772988fb799ced0ec5e54efb2e/plugins/auth-backend-module-gitlab-provider/src/resolvers.ts#L33C16-L33C46) + +##### Google + +Setup: + +```ts title="packages/backend/src/index.ts" +const backend = createBackend(); +/* highlight-add-start */ +backend.add(import('@backstage/plugin-auth-backend')); +backend.add(import('@backstage/plugin-auth-backend-module-google-provider')); +/* highlight-add-end */ +``` + +Additional resolvers: + +- [emailMatchingUserEntityAnnotation](https://github.com/backstage/backstage/blob/5447cffd23cf00772988fb799ced0ec5e54efb2e/plugins/auth-backend-module-google-provider/src/resolvers.ts#L33C16-L33C49) + +##### Microsoft + +Setup: + +```ts title="packages/backend/src/index.ts" +const backend = createBackend(); +/* highlight-add-start */ +backend.add(import('@backstage/plugin-auth-backend')); +backend.add(import('@backstage/plugin-auth-backend-module-microsoft-provider')); +/* highlight-add-end */ +``` + +Additional resolvers: + +- [emailMatchingUserEntityAnnotation](https://github.com/backstage/backstage/blob/5447cffd23cf00772988fb799ced0ec5e54efb2e/plugins/auth-backend-module-microsoft-provider/src/resolvers.ts#L33C16-L33C49) + +##### oauth2 + +Setup: + +```ts title="packages/backend/src/index.ts" +const backend = createBackend(); +/* highlight-add-start */ +backend.add(import('@backstage/plugin-auth-backend')); +backend.add(import('@backstage/plugin-auth-backend-module-oauth2-provider')); +/* highlight-add-end */ +``` + +Additional resolvers: + +- [usernameMatchingUserEntityName](https://github.com/backstage/backstage/blob/5447cffd23cf00772988fb799ced0ec5e54efb2e/plugins/auth-backend-module-oauth2-provider/src/resolvers.ts#L33C16-L33C46) + +##### oauth2 Proxy + +Setup: + +```ts title="packages/backend/src/index.ts" +const backend = createBackend(); +/* highlight-add-start */ +backend.add(import('@backstage/plugin-auth-backend')); +backend.add( + import('@backstage/plugin-auth-backend-module-oauth2-proxy-provider'), +); +/* highlight-add-end */ +``` + +Additional resolvers: + +- [forwardedUserMatchingUserEntityName](https://github.com/backstage/backstage/blob/5447cffd23cf00772988fb799ced0ec5e54efb2e/plugins/auth-backend-module-oauth2-proxy-provider/src/resolvers.ts#L27C16-L27C51) + +##### Okta + +Setup: + +```ts title="packages/backend/src/index.ts" +const backend = createBackend(); +/* highlight-add-start */ +backend.add(import('@backstage/plugin-auth-backend')); +backend.add(import('@backstage/plugin-auth-backend-module-okta-provider')); +/* highlight-add-end */ +``` + +Additional resolvers: + +- [emailMatchingUserEntityAnnotation](https://github.com/backstage/backstage/blob/5447cffd23cf00772988fb799ced0ec5e54efb2e/plugins/auth-backend-module-okta-provider/src/resolvers.ts#L34C16-L34C49) + +##### Pinniped + +Setup: + +```ts title="packages/backend/src/index.ts" +const backend = createBackend(); +/* highlight-add-start */ +backend.add(import('@backstage/plugin-auth-backend')); +backend.add(import('@backstage/plugin-auth-backend-module-pinniped-provider')); +/* highlight-add-end */ +``` + +##### VMware Cloud + +Setup: + +```ts title="packages/backend/src/index.ts" +const backend = createBackend(); +/* highlight-add-start */ +backend.add(import('@backstage/plugin-auth-backend')); +backend.add( + import('@backstage/plugin-auth-backend-module-vmware-cloud-provider'), +); +/* highlight-add-end */ +``` + +Additional resolvers: + +- [vmwareCloudSignInResolvers](https://github.com/backstage/backstage/blob/5447cffd23cf00772988fb799ced0ec5e54efb2e/plugins/auth-backend-module-vmware-cloud-provider/src/resolvers.ts#L29C18-L29C44) + +#### Custom Resolver + +You may have a case where the common resolvers or the ones that are included with the auth module you use won't work for your needs. In this case you will need to create a custom resolver. Instead of the 2nd import for your auth provider module you would provide your own: + +```ts title="packages/backend/src/index.ts" +/* highlight-add-start */ +export const authModuleGoogleProvider = createBackendModule({ + pluginId: 'auth', + moduleId: 'googleProvider', + register(reg) { + reg.registerInit({ + deps: { providers: authProvidersExtensionPoint }, + async init({ providers }) { + providers.registerProvider({ + providerId: 'google', + factory: createOAuthProviderFactory({ + authenticator: googleAuthenticator, + async signInResolver(info, ctx) { + // custom resolver ... + }, + }), + }); + }, + }); + }, +}); +/* highlight-add-end */ + +const backend = createBackend(); +/* highlight-add-start */ +backend.add(import('@backstage/plugin-auth-backend')); +backend.add(authModuleGoogleProvider); +/* highlight-add-end */ +``` 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 fed074b258..168646afab 100644 --- a/docs/backend-system/building-plugins-and-modules/01-index.md +++ b/docs/backend-system/building-plugins-and-modules/01-index.md @@ -6,8 +6,6 @@ sidebar_label: Overview description: Building backend plugins and modules using the new backend system --- -> **NOTE: The new backend system is in alpha, and some plugins do not yet fully implement it.** - > NOTE: If you have an existing backend and/or backend plugins that are not yet > using the new backend system, see [migrating](./08-migrating.md). @@ -72,12 +70,12 @@ items. ## Modules -Backend modules are used to extend [plugins](../architecture/04-plugins.md) with +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 that they extend, and may only extend -a single plugin. Modules interact with their target plugin using the [extension +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 -able to depend on the [services](../architecture/03-services.md) of that plugin. +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 same ones as the target plugin will receive later, i.e. they will be scoped @@ -88,6 +86,9 @@ package, for example `@backstage/plugin-catalog-node`, and does not directly declare a dependency on the plugin package itself. This is to avoid a direct dependency and potentially cause duplicate installations of the plugin package, while duplicate installations of library packages should always be supported. +Modules with extension points typically export their extension points from the same +package however, since the extension points are generally only intended for internal +customizations where package versions can be kept in sync. To create a Backend module, run `yarn new`, select `backend-module`, and fill out the rest of the prompts. This will create a new package at `plugins/-backend-module-`. @@ -101,8 +102,8 @@ import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node' import { MyCustomProcessor } from './MyCustomProcessor'; export const catalogModuleExampleCustomProcessor = createBackendModule({ - moduleId: 'exampleCustomProcessor', pluginId: 'catalog', + moduleId: 'example-custom-processor', register(env) { env.registerInit({ deps: { diff --git a/docs/backend-system/building-plugins-and-modules/02-testing.md b/docs/backend-system/building-plugins-and-modules/02-testing.md index d14f7de09c..f8af2bcabe 100644 --- a/docs/backend-system/building-plugins-and-modules/02-testing.md +++ b/docs/backend-system/building-plugins-and-modules/02-testing.md @@ -6,8 +6,6 @@ sidebar_label: Testing description: Learn how to test your backend plugins and modules --- -> **NOTE: The new backend system is in alpha, and some plugins do not yet fully implement it.** - Utilities for testing backend plugins and modules are available in `@backstage/backend-test-utils`. This section describes those facilities. @@ -120,7 +118,7 @@ describe('MyDatabaseClass', () => { // "physical" databases to test against is much costlier than creating the // "logical" databases within them that the individual tests use. const databases = TestDatabases.create({ - ids: ['POSTGRES_13', 'POSTGRES_9', 'SQLITE_3', 'MYSQL_8'], + ids: ['POSTGRES_16', 'POSTGRES_12', 'SQLITE_3', 'MYSQL_8'], }); // Just an example of how to conveniently bundle up the setup code 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 067ab02b4d..8a31251ee8 100644 --- a/docs/backend-system/building-plugins-and-modules/08-migrating.md +++ b/docs/backend-system/building-plugins-and-modules/08-migrating.md @@ -6,8 +6,6 @@ sidebar_label: Migration Guide description: How to migrate existing backend plugins to the new backend system --- -> **NOTE: The new backend system is in alpha, and some plugins do not yet fully implement it.** - Migrating an existing backend plugin to the new backend system is fairly straightforward. The process is similar across the majority of plugins which just return a `Router` that is then wired up in the `index.ts` file of your backend. The primary thing that we need to do is to make sure that the dependencies that are required by the plugin are available, and then registering the router with the HTTP router service. Let's look at an example of migrating the Kubernetes backend plugin. In the existing (old) system, the kubernetes backend is structured like this: @@ -73,30 +71,99 @@ export const kubernetesPlugin = createBackendPlugin({ }); ``` -Done! Users of this plugin are now able to import the `kubernetesPlugin` and register it in their backend using +Lastly, make sure you re-export the plugin instance as the default export of your package in `src/index.ts`: + +```ts +export { kubernetesPlugin as default } from './plugin.ts'; +``` + +Done! Users of this plugin are now able to import your plugin package and register it in their backend using ```ts // packages/backend/src/index.ts -import { kubernetesPlugin } from '@backstage/plugin-kubernetes-backend'; -backend.add(kubernetesPlugin); +backend.add(import('@backstage/plugin-kubernetes-backend')); ``` There's one thing missing that those sharp eyed readers might have noticed: the `clusterSupplier` option is missing from the original plugin. Let's add it and discuss the alternatives. -One alternative is to pass the `ClusterSupplier` in as options to the plugin, which is quick and easy but not very flexible, and also hard to evolve without introducing breaking changes as it changes the public API for the plugin. Having complex types passed in directly to the plugin also clutters the backend setup code and makes it harder to read. - -Options are primarily used for simple configuration values that are not complex types. In this case we want to allow users to register their own `ClusterSupplier` implementations to the plugin. This is where the new backend system's [extension points](../architecture/05-extension-points.md) come in handy, but let's look at doing this with options first. +One alternative is to make it possible to build the cluster supplier using static configuration. It could for example be that there is a selection of built-in implementations to choose from, or that the logic for how the `ClusterSupplier` is supposed to function is all determined by configuration, or a combination of the two. Using static configuration for customization is always the preferred option whenever it's possible. In this case, we could for example imagine that we would be able to configure our cluster supplier like this: ```ts /* omitted imports but they remain the same as above */ -export interface KubernetesOptions { - clusterSupplier?: KubernetesClustersSupplier; -} - -const kubernetesPlugin = createBackendPlugin((options: KubernetesOptions) => ({ +const kubernetesPlugin = createBackendPlugin({ pluginId: 'kubernetes', register(env) { + env.registerInit({ + deps: { + /* omitted dependencies but they remain the same as above */ + }, + async init({ config, logger, catalogApi, discovery, http }) { + // Note that in a real implementation this would be done by the `KubernetesBuilder` instead, + // but here we've extracted it into a separate call to highlight the example. + const configuredClusterSupplier = readClusterSupplierFromConfig(config); + + const { router } = await KubernetesBuilder.createBuilder({ + config, + logger, + catalogApi, + discovery, + }) + .setClusterSupplier(configuredClusterSupplier) + .build(); + http.use(router); + }, + }); + }, +}); +``` + +There are however many types of customizations that are not possible to do with static configuration. In this case we want integrators to be able to create arbitrary implementations of the `ClusterSupplier` interface, which in the end requires an implementation through code. This is where the new backend system's [extension points](../architecture/05-extension-points.md) come in handy. + +The new [extension points](../architecture/05-extension-points.md) API allows [modules](../architecture/06-modules.md) to add functionality into the backend plugin itself, in this case an additional `ClusterSupplier`. Let's look at how we could add support for installing custom suppliers using an extension point. This will allow integrators to build their own internal module with a custom `ClusterSupplier` implementation. + +First we'll go ahead and create a `@backstage/plugin-kubernetes-node` package where we can define our extension point. A separate package is used to avoid direct dependencies on the plugin package itself. With the new package created, we define the extension point like this: + +```ts +import { createExtensionPoint } from '@backstage/backend-plugin-api'; + +export interface KubernetesClusterSupplierExtensionPoint { + setClusterSupplier(supplier: KubernetesClustersSupplier): void; +} + +/** + * An extension point that allows other plugins to set the cluster supplier. + */ +export const kubernetesClustersSupplierExtensionPoint = + createExtensionPoint({ + id: 'kubernetes.cluster-supplier', + }); +``` + +For more information on how to design extension points, see the [extension points](../architecture/05-extension-points.md#extension-point-design) documentation. + +Next we'll need to add support for this extension point to the Kubernetes backend plugin itself: + +```ts +/* omitted other imports but they remain the same as above */ +import { kubernetesClustersSupplierExtensionPoint } from '@backstage/plugin-kubernetes-node'; + +export const kubernetesPlugin = createBackendPlugin({ + pluginId: 'kubernetes', + register(env) { + let clusterSupplier: KubernetesClustersSupplier | undefined = undefined; + + // We register the extension point with the backend, which allows modules to + // register their own ClusterSupplier. + env.registerExtensionPoint(kubernetesClustersSupplierExtensionPoint, { + setClusterSupplier(supplier) { + if (clusterSupplier) { + throw new Error('ClusterSupplier may only be set once'); + } + clusterSupplier = supplier; + }, + }); + env.registerInit({ deps: { /* omitted dependencies but they remain the same as above */ @@ -108,103 +175,7 @@ const kubernetesPlugin = createBackendPlugin((options: KubernetesOptions) => ({ catalogApi, discovery, }) - .setClusterSupplier(options.clusterSupplier) - .build(); - http.use(router); - }, - }); - }, -})); -``` - -The above would allow users to specify their own `ClusterSupplier` implementation to the plugin like this: - -```ts -backend.add( - kubernetesPlugin({ clusterSupplier: new MyCustomClusterSupplier() }), -); -``` - -Just to echo what was said above, this is not a very flexible solution and will for example be problematic to keep backwards compatible if we start evolving the options to for example accept multiple suppliers or tweak the `ClusterSupplier` interface. - -The new [extension points](../architecture/05-extension-points.md) API allows [modules](../architecture/06-modules.md) to add functionality into the backend plugin itself, in this case an additional `ClusterSupplier`. - -The kubernetes backend plugin only supports one `ClusterSupplier` at this time but let's look at how we could add support for multiple suppliers using extension points. This allows users to install several modules that add their own `ClusterSupplier` implementations to the plugin like this: - -```ts -backend.add(kubernetesPlugin()); -backend.add(kubernetesGoogleContainerEngineClusterSupplier()); -backend.add(kubernetesElasticContainerEngine()); -``` - -Now let's look at how to implement this with extension points. First we need to define the extension point itself. As the extension point will be used by other modules, it's common practice to export these from a shared package so that they can be imported by other modules and plugins. - -We'll go ahead and create a `@backstage/plugin-kubernetes-node` package for this and from there we'll export the extension point. - -```ts -import { createExtensionPoint } from '@backstage/backend-plugin-api'; - -export interface KubernetesClusterSupplierExtensionPoint { - addClusterSupplier(supplier: KubernetesClustersSupplier): void; -} - -/** - * An extension point that allows other plugins to add cluster suppliers. - * @public - */ -export const kubernetesClustersSupplierExtensionPoint = - createExtensionPoint({ - id: 'kubernetes.cluster-supplier', - }); -``` - -Now we can use this extension point in the kubernetes backend plugin to register the extension point for modules to use. - -```ts -import { kubernetesClustersSupplierExtensionPoint, KubernetesClusterSupplierExtensionPoint } from '@backstage/plugin-kubernetes-node'; - -// Our internal implementation of the extension point, should not be exported. -class ClusterSupplier implements KubernetesClusterSupplierExtensionPoint { - private clusterSuppliers: KubernetesClustersSupplier | undefined; - - // This method is private and only used internally to retrieve the registered supplier. - getClusterSupplier() { - return this.clusterSuppliers; - } - - addClusterSupplier(supplier: KubernetesClustersSupplier) { - // We can remove this check once the plugin support multiple suppliers. - if(this.clusterSuppliers) { - throw new Error('Multiple Kubernetes cluster suppliers is not supported at this time'); - } - this.clusterSuppliers = supplier; - } -} - -export const kubernetesPlugin = createBackendPlugin({ - pluginId: 'kubernetes', - register(env) { - const extensionPoint = new ClusterSupplier(); - // We register the extension point with the backend, which allows modules to - // register their own ClusterSupplier. - env.registerExtensionPoint( - kubernetesClustersSupplierExtensionPoint, - extensionPoint, - ); - - env.registerInit({ - deps: { - ... omitted ... - }, - async init({ config, logger, catalogApi, discovery, http }) { - const { router } = await KubernetesBuilder.createBuilder({ - config, - logger, - catalogApi, - discovery, - }) - // We pass in the registered supplier from the extension point. - .setClusterSupplier(extensionPoint.getClusterSupplier()) + .setClusterSupplier(clusterSupplier) .build(); http.use(router); }, @@ -213,24 +184,33 @@ export const kubernetesPlugin = createBackendPlugin({ }); ``` -And that's it! Modules can now be built that add clusters into to the kubernetes backend plugin, here's an example of a module that adds a `GoogleContainerEngineSupplier` to the kubernetes backend. +And that's it! Modules can now be built that add clusters into to the kubernetes backend plugin, here's an example of a module that adds a `GoogleContainerEngineSupplier` to the kubernetes backend: ```ts import { kubernetesClustersSupplierExtensionPoint } from '@backstage/plugin-kubernetes-node'; -export const kubernetesGoogleContainerEngineClusterSupplier = - createBackendModule({ - pluginId: 'kubernetes', - moduleId: 'gke.supplier', - register(env) { - env.registerInit({ - deps: { - supplier: kubernetesClustersSupplierExtensionPoint, - }, - async init({ supplier }) { - supplier.addClusterSupplier(new GoogleContainerEngineSupplier()); - }, - }); - }, - }); +// This is a custom implementation of the ClusterSupplier interface. +import { GoogleContainerEngineSupplier } from './GoogleContainerEngineSupplier'; + +export default createBackendModule({ + pluginId: 'kubernetes', + moduleId: 'gke-supplier', + register(env) { + env.registerInit({ + deps: { + supplier: kubernetesClustersSupplierExtensionPoint, + }, + async init({ supplier }) { + supplier.setClusterSupplier(new GoogleContainerEngineSupplier()); + }, + }); + }, +}); +``` + +The above module can then be installed by the integrator alongside the kubernetes backend plugin: + +```ts +backend.add(import('@backstage/plugin-kubernetes-backend')); +backend.add(import('@internal/gke-cluster-supplier')); ``` diff --git a/docs/backend-system/core-services/01-index.md b/docs/backend-system/core-services/01-index.md index 0163d45108..9074998719 100644 --- a/docs/backend-system/core-services/01-index.md +++ b/docs/backend-system/core-services/01-index.md @@ -6,8 +6,6 @@ sidebar_label: Overview description: Core backend service APIs --- -> **NOTE: The new backend system is in alpha, and some plugins do not yet fully implement it.** - The default backend provides several [core services](https://github.com/backstage/backstage/blob/master/packages/backend-plugin-api/src/services/definitions/coreServices.ts) out of the box which includes access to configuration, logging, URL Readers, databases and more. All core services are available through the `coreServices` namespace in the `@backstage/backend-plugin-api` package. diff --git a/docs/backend-system/index.md b/docs/backend-system/index.md index c74dd34102..22ea4c6c59 100644 --- a/docs/backend-system/index.md +++ b/docs/backend-system/index.md @@ -6,10 +6,8 @@ sidebar_label: Introduction description: The Backend System --- -> **NOTE: The new backend system is in alpha, and some plugins do not yet fully implement it.** - ## Status -The new backend system is in alpha, but many plugins have already been migrated. We recommend all plugins to migrate to the new system, and you can also try it out in your own production deployments. +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). diff --git a/docs/deployment/docker.md b/docs/deployment/docker.md index c9ace49d4d..675a8de947 100644 --- a/docs/deployment/docker.md +++ b/docs/deployment/docker.md @@ -53,7 +53,7 @@ yarn build:backend --config ../../app-config.yaml Once the host build is complete, we are ready to build our image. The following `Dockerfile` is included when creating a new app with `@backstage/create-app`: -```Dockerfile +```dockerfile FROM node:18-bookworm-slim # Install isolate-vm dependencies, these are needed by the @backstage/plugin-scaffolder-backend. @@ -74,8 +74,10 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ USER node # This should create the app dir as `node`. -# If it is instead created as `root` then the `tar` command below will fail: `can't create directory 'packages/': Permission denied`. -# If this occurs, then ensure BuildKit is enabled (`DOCKER_BUILDKIT=1`) so the app dir is correctly created as `node`. +# If it is instead created as `root` then the `tar` command below will +# fail: `can't create directory 'packages/': Permission denied`. +# If this occurs, then ensure BuildKit is enabled (`DOCKER_BUILDKIT=1`) +# so the app dir is correctly created as `node`. WORKDIR /app # This switches many Node.js dependencies to production mode. @@ -158,7 +160,7 @@ host build. The following `Dockerfile` executes the multi-stage build and should be added to the repo root: -```Dockerfile +```dockerfile # Stage 1 - Create yarn install skeleton layer FROM node:18-bookworm-slim AS packages @@ -229,8 +231,10 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ USER node # This should create the app dir as `node`. -# If it is instead created as `root` then the `tar` command below will fail: `can't create directory 'packages/': Permission denied`. -# If this occurs, then ensure BuildKit is enabled (`DOCKER_BUILDKIT=1`) so the app dir is correctly created as `node`. +# If it is instead created as `root` then the `tar` command below will +# fail: `can't create directory 'packages/': Permission denied`. +# If this occurs, then ensure BuildKit is enabled (`DOCKER_BUILDKIT=1`) +# so the app dir is correctly created as `node`. WORKDIR /app # Copy the install dependencies from the build stage and context @@ -309,7 +313,7 @@ package, which is done as follows: .addRouter('', await app(appEnv)); ``` 3. Remove the `@backstage/plugin-app-backend` and the app package dependency - (e.g. `app`) from `packages/backend/packages.json`. If you don't remove the + (e.g. `app`) from `packages/backend/package.json`. If you don't remove the app package dependency the app will still be built and bundled with the backend. @@ -321,3 +325,16 @@ an NGINX image is available in the Note that if you're building a separate docker build of the frontend you probably need to adjust `.dockerignore` appropriately. Most likely by making sure `packages/app/dist` is not ignored. + +## Troubleshooting Tips + +When building Docker images you may run into problems from time to time, there are two handy flags you can use to help: + +- `--progress=plain`: this will give you a more verbose output and not fold the logs into sections. This is very useful when have an error but it just shows you the last command and possibly an exit code. Using this flag you are more likely to see where the error actually is. +- `--no-cache`: this will rebuild all the layers every time. This is helpful when you want to be sure that it's building from scratch. + +Here's an example of these flags in use: + +```sh +docker image build . -f packages/backend/Dockerfile --tag backstage --progress=plain --no-cache +``` diff --git a/docs/features/kubernetes/configuration.md b/docs/features/kubernetes/configuration.md index 07e3a8a828..612d57334d 100644 --- a/docs/features/kubernetes/configuration.md +++ b/docs/features/kubernetes/configuration.md @@ -51,11 +51,13 @@ kubernetes: This configures how to determine which clusters a component is running in. -Currently, the only valid value is: +Valid values are: - `multiTenant` - This configuration assumes that all components run on all the provided clusters. +- `singleTenant` - This configuration assumes that current component run on one cluster in provided clusters. + ### `clusterLocatorMethods` This is an array used to determine where to retrieve cluster configuration from. @@ -63,20 +65,72 @@ This is an array used to determine where to retrieve cluster configuration from. Valid cluster locator methods are: - [`catalog`](#catalog) -- [`localKubectlProxy`](#localkubectlproxy) - [`config`](#config) - [`gke`](#gke) +- [`localKubectlProxy`](#localkubectlproxy) - [custom `KubernetesClustersSupplier`](#custom-kubernetesclusterssupplier) #### `catalog` -This cluster locator method will read cluster information from the catalog. +This cluster locator method will gather +[Resources](https://backstage.io/docs/features/software-catalog/system-model#resource) +of +[type](https://backstage.io/docs/features/software-catalog/descriptor-format#spectype-required-4) +`kubernetes-cluster` from the catalog and treat them as clusters for the +purposes of the Kubernetes plugin. In order for a resource to be detected by +this method, it must also have the following +[annotations](https://backstage.io/docs/features/software-catalog/descriptor-format#annotations-optional) +(as seen +[here](https://github.com/backstage/backstage/blob/86baccb2d7d378baed74eaebf017c60b410986e5/plugins/kubernetes-backend/src/cluster-locator/CatalogClusterLocator.ts#L51-L61) +in the code): -#### `localKubectlProxy` +- [`kubernetes.io/api-server`](https://backstage.io/docs/reference/plugin-kubernetes-common.annotation_kubernetes_api_server/), + denoting the base URL of the Kubernetes control plane +- [`kubernetes.io/api-server-certificate-authority`](https://backstage.io/docs/reference/plugin-kubernetes-common.annotation_kubernetes_api_server_ca/), + containing a base64-encoded certificate authority bundle in PEM format; + Backstage will check that the control plane presents a certificate signed by + this authority. +- [`kubernetes.io/auth-provider`](https://backstage.io/docs/reference/plugin-kubernetes-common.annotation_kubernetes_auth_provider/), + denoting the strategy to use to authenticate with the control plane. -This cluster locator method will assume a locally running [`kubectl proxy`](https://kubernetes.io/docs/tasks/extend-kubernetes/http-proxy-access-api/#using-kubectl-to-start-a-proxy-server) process using the default port (8001). +There are many other annotations that can be applied to a cluster resource to +configure the way Backstage communicates, documented +[here](https://backstage.io/docs/reference/plugin-kubernetes-common#variables) +in the API reference. Here is a YAML snippet illustrating an example of a +cluster in the catalog: -NOTE: This cluster locator method is for local development only and should not be used in production. +```yaml +apiVersion: backstage.io/v1alpha1 +kind: Resource +metadata: + name: my-cluster + annotations: + kubernetes.io/api-server: 'https://127.0.0.1:53725' + kubernetes.io/api-server-certificate-authority: # base64-encoded CA + kubernetes.io/auth-provider: 'oidc' + kubernetes.io/oidc-token-provider: 'microsoft' + kubernetes.io/skip-metrics-lookup: 'true' +spec: + type: kubernetes-cluster + owner: user:guest +``` + +Note that it is insecure to store a Kubernetes service account token in an +annotation on a catalog entity (where it could easily be accidentally revealed +by the catalog API) -- therefore there is no annotation corresponding to the +[`serviceAccountToken` field](#clustersserviceaccounttoken-optional) used by +the [`config`](#config) cluster locator. Accordingly, the catalog cluster +locator does not support the [`serviceAccount`](#clustersauthprovider) auth +strategy. + +This method can be quite helpful when used in combination with an ingestion +procedure like the +[`GkeEntityProvider`](https://backstage.io/docs/reference/plugin-catalog-backend-module-gcp.gkeentityprovider/) +(installation documented +[here](https://github.com/backstage/backstage/tree/master/plugins/catalog-backend-module-gcp#installation)) +or the +[`AwsEKSClusterProcessor`](https://backstage.io/docs/reference/plugin-catalog-backend-module-aws.awseksclusterprocessor/) +to automatically update the set of clusters tracked by Backstage. #### `config` @@ -386,6 +440,12 @@ Defaults to `false`. Array of key value labels used to filter out clusters which don't have the matching [resource labels](https://cloud.google.com/resource-manager/docs/creating-managing-labels). +#### `localKubectlProxy` + +This cluster locator method will assume a locally running [`kubectl proxy`](https://kubernetes.io/docs/tasks/extend-kubernetes/http-proxy-access-api/#using-kubectl-to-start-a-proxy-server) process using the default port (8001). + +NOTE: This cluster locator method is for local development only and should not be used in production. + #### Custom `KubernetesClustersSupplier` If the configuration-based cluster locators do not work for your use-case, @@ -577,6 +637,22 @@ for more info. 'backstage.io/kubernetes-label-selector': 'app=my-app,component=front-end' ``` +### Cluster Selection annotation + +This is applicable only for `singleTenant` serviceLocatorMethod. + +You can now select `single` kubernetes cluster that the entity is part-of from all your defined kubernetes clusters. To apply this use the following annotation. + +SingleTenant Cluster: + +```yaml +'backstage.io/kubernetes-cluster': dice-cluster +``` + +In the example above, we configured the "backstage.io/kubernetes-cluster" annotation on the entity `catalog-info.yaml` file to specify that the current component is running in a single cluster called "dice-cluster", so this cluster must have been specified in the `app-config.yaml`, under the Kubernetes clusters configuration (for more details, see [`Configuring Kubernetes clusters`](#configuring-kubernetes-clusters)). + +If you do not specify the annotation by `default Backstage fetches all` defined Kubernetes cluster. + [1]: https://cloud.google.com/kubernetes-engine [2]: https://cloud.google.com/docs/authentication/production#linux-or-macos [3]: https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/ diff --git a/docs/features/kubernetes/installation.md b/docs/features/kubernetes/installation.md index 216c4db3f4..5111b5ad2e 100644 --- a/docs/features/kubernetes/installation.md +++ b/docs/features/kubernetes/installation.md @@ -130,7 +130,7 @@ export class CustomClustersSupplier implements KubernetesClustersSupplier { static create(refreshInterval: Duration) { const clusterSupplier = new CustomClustersSupplier(); - // setup refresh, e.g. using a copy of https://github.com/backstage/backstage/blob/master/plugins/search-backend-node/src/runPeriodically.ts + // setup refresh, e.g. using a copy of https://github.com/backstage/backstage/blob/master/plugins/kubernetes-backend/src/service/runPeriodically.ts runPeriodically( () => clusterSupplier.refreshClusters(), refreshInterval.toMillis(), diff --git a/docs/features/search/declarative-integration.md b/docs/features/search/declarative-integration.md index f0083e4d4b..c331d810ef 100644 --- a/docs/features/search/declarative-integration.md +++ b/docs/features/search/declarative-integration.md @@ -51,18 +51,19 @@ _Example disabling the search page extension_ # app-config.yaml app: extensions: - - plugin.search.page: false # ✨ + - page:search: false # ✨ + - nav-item:search: false # ✨ ``` -_Example setting the search sidebar item label_ +_Example setting the search sidebar item title_ ```yaml # app-config.yaml app: extensions: - - plugin.search.nav.index: # ✨ + - nav-item:search: # ✨ config: - label: 'Search Page' + title: 'Search Page' ``` > **Known limitations:** diff --git a/docs/features/search/how-to-guides.md b/docs/features/search/how-to-guides.md index a5662999ae..e49bdb4fa5 100644 --- a/docs/features/search/how-to-guides.md +++ b/docs/features/search/how-to-guides.md @@ -391,8 +391,6 @@ There are other more specific search results layout components that also accept ## How to migrate your backend installation to use Search together with the new backend system -> DISCLAIMER: The new backend system is in alpha, and so are the search backend support for the new backend system. We don't recommend you to migrate your backend installations to the new system yet. But if you want to experiment, this is the guide for you! - 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]: diff --git a/docs/features/software-catalog/api.md b/docs/features/software-catalog/api.md index 3ccd89b286..3ab3c0df96 100644 --- a/docs/features/software-catalog/api.md +++ b/docs/features/software-catalog/api.md @@ -31,13 +31,190 @@ with a `Bearer` token, which should then be the Backstage token returned by the These are the endpoints that deal with reading of entities directly. What it exposes are final entities - i.e. the output of all processing and the stitching -process, not the raw originally ingested entity data. See [The Life of an -Entity](life-of-an-entity.md) for more details about this process and +process, not the raw originally ingested entity data. See +[The Life of an Entity](./life-of-an-entity.md) for more details about this process and distinction. +### `GET /entities/by-query` + +Query entities. Supports the following query parameters, described in the section below: + +- [`filter`](#filtering), for selecting only a subset of all entities +- [`fields`](#field-selection), for selecting only parts of the full data + structure of each entity +- `limit` for limiting the number of entities returned (20 is the default) +- [`orderField`](#ordering), for deciding the order of the entities +- [`fullTextFilter`](#full-text-filtering), for filtering the entities by text +- [`cursor`](#pagination), for retrieving the next or previous batch of entities + +The return type is JSON, on the following form + +```json +{ + "items": [{ "kind": "Component", "metadata": { "name": "foo" } }], + "totalItems": 4, + "pageInfo": { + "nextCursor": "a-cursor", + "prevCursor": "another-cursor" + } +} +``` + +#### Filtering + +You can pass in one or more filter sets that get matched against each entity. +Each filter set is a number of conditions that all have to match for the +condition to be true (conditions effectively have an AND between them). At least +one filter set has to be true for the entity to be part of the result set +(filter sets effectively have an OR between them). + +Example: + +```text +/entities/by-query?filter=kind=user,metadata.namespace=default&filter=kind=group,spec.type + + Return entities that match + + Filter set 1: + Condition 1: kind = user + AND + Condition 2: metadata.namespace = default + + OR + + Filter set 2: + Condition 1: kind = group + AND + Condition 2: spec.type exists +``` + +Each condition is either on the form ``, or on the form `=`. +The first form asserts on the existence of a certain key (with any value), and +the second asserts that the key exists and has a certain value. All checks are +always case _insensitive_. + +In all cases, the key is a simplified JSON path in a given piece of entity data. +Each part of the path is a key of an object, and the traversal also descends +through arrays. There are two special forms: + +- Array items that are simple value types (such as strings) match on a key-value + pair where the key is the item as a string, and the value is the string `true` +- Relations can be matched on a `relations.=` form + +Let's look at a simplified example to illustrate the concept: + +```json +{ + "a": { + "b": ["c", { "d": 1 }], + "e": 7 + } +} +``` + +This would match any one of the following conditions: + +- `a` +- `a.b` +- `a.b.c` +- `a.b.c=true` +- `a.b.d` +- `a.b.d=1` +- `a.e` +- `a.e=7` + +Some more real world usable examples: + +- Return all orphaned entities: + + `/entities/by-query?filter=metadata.annotations.backstage.io/orphan=true` + +- Return all users and groups: + + `/entities/by-query?filter=kind=user&filter=kind=group` + +- Return all service components: + + `/entities/by-query?filter=kind=component,spec.type=service` + +- Return all entities with the `java` tag: + + `/entities/by-query?filter=metadata.tags.java` + +- Return all users who are members of the `ops` group (note that the full + [reference](references.md) of the group is used): + + `/entities/by-query?filter=kind=user,relations.memberof=group:default/ops` + +#### Full text filtering + +TODO + +#### Field selection + +By default the full entities are returned, but you can pass in a `fields` query +parameter which selects what parts of the entity data to retain. This makes the +response smaller and faster to transfer, and may allow the catalog to perform +more efficient queries. + +The query parameter value is a comma separated list of simplified JSON paths +like above. Each path corresponds to the key of either a value, or of a subtree +root that you want to keep in the output. The rest is pruned away. For example, +specifying `?fields=metadata.name,metadata.annotations,spec` retains only the +`name` and `annotations` fields of the `metadata` of each entity (it'll be an +object with at most two keys), keeps the entire `spec` unchanged, and cuts out +all other roots such as `relations`. + +Some more real world usable examples: + +- Return only enough data to form the full ref of each entity: + + `/entities/by-query?fields=kind,metadata.namespace,metadata.name` + +#### Ordering + +By default the entities are returned ordered by their internal uid. You can +customize the `orderField` query parameters to affect that ordering. + +For example, to return entities by their name: + +`/entities/by-query?orderField=metadata.name,asc` + +Each parameter can be followed by `asc` for ascending lexicographical order or +`desc` for descending (reverse) lexicographical order. + +#### Pagination + +You may pass the `cursor` query parameters to perform cursor based pagination +through the set of entities. The value of `cursor` will be returned in the response, under the `pageInfo` property: + +```json + "pageInfo": { + "nextCursor": "a-cursor", + "prevCursor": "another-cursor" + } +``` + +If `nextCursor` exists, it can be used to retrieve the next batch of entities. Following the same approach, +if `prevCursor` exists, it can be used to retrieve the previous batch of entities. + +- [`filter`](#filtering), for selecting only a subset of all entities +- [`fields`](#field-selection), for selecting only parts of the full data + structure of each entity +- `limit` for limiting the number of entities returned (20 is the default) +- [`orderField`](#ordering), for deciding the order of the entities +- `fullTextFilter` + **NOTE**: [`filter`, `orderField`, `fullTextFilter`] and `cursor` are mutually exclusive. This means that, + it isn't possible to change any of [`filter`, `orderField`, `fullTextFilter`] when passing `cursor` as query parameters, + as changing any of these properties will affect pagination. If any of `filter`, `orderField`, `fullTextFilter` is specified together with `cursor`, only the latter is taken into consideration. + ### `GET /entities` -Lists entities. Supports the following query parameters, described in sections +Lists entities. + +**NOTE**: This endpoint is deprecated in favor of `GET /entities/by-query`, which provides a more efficient implementation and cursor based pagination. + +The endpoint supports the following query parameters, described in sections below: - [`filter`](#filtering), for selecting only a subset of all entities diff --git a/docs/features/software-catalog/configuration.md b/docs/features/software-catalog/configuration.md index 97c75a01ff..61366a91f7 100644 --- a/docs/features/software-catalog/configuration.md +++ b/docs/features/software-catalog/configuration.md @@ -46,7 +46,7 @@ action is logged for further investigation. ### Local File (`type: file`) Configurations -In addition to url locations, you can use the `file` location type to bring in content from the local file system. You should only use this for local development, test setups and example data, not for production data. +In addition to url locations, you can use the `file` location type to bring in content from the local file system. You should only use this for local development, test setups, and example data, not for production data. You are also not able to use placeholders in them like `$text`. You can however reference other files relative to the current file. See the full [catalog example data set here](https://github.com/backstage/backstage/tree/master/packages/catalog-model/examples) for an extensive example. Here is an example pulling in the `all.yaml` file from the examples folder. Note the use of `../../` to go up two levels from the current execution path of the backend. This is typically `packages/backend/`. @@ -61,7 +61,7 @@ catalog: ### Integration Processors Integrations may simply provide a mechanism to handle `url` location type for an -external provider, or they may also include additional processors out of the +external provider or they may also include additional processors out of the box, such as the GitHub [discovery](../../integrations/github/discovery.md) processor that scans a GitHub organization for [entity descriptor files](descriptor-format.md). @@ -78,10 +78,10 @@ Backstage's descriptor format. This is documented in ## Catalog Rules -By default the catalog will only allow ingestion of entities with the kind -`Component`, `API` and `Location`. In order to allow entities of other kinds to +By default, the catalog will only allow the ingestion of entities with the kind +`Component`, `API`, and `Location`. In order to allow entities of other kinds to be added, you need to add rules to the catalog. Rules are added either in a -separate `catalog.rules` key, or added to statically configured locations. +separate `catalog.rules` key or added to statically configured locations. For example, given the following configuration: @@ -99,7 +99,7 @@ catalog: We are able to add entities of kind `Component`, `API`, `Location`, or `Template` from any location, and `Group` entities from the `org-data.yaml`, -which will also be read as statically configured location. +which will also be read as a statically configured location. Note that if the `catalog.rules` key is present it will replace the default value, meaning that you need to add rules for the default kinds if you want @@ -115,10 +115,10 @@ catalog: ## Readonly mode -Processors provides a good way to automate ingestion of entities when combined +Processors provide a good way to automate the ingestion of entities when combined with [Static Location Configuration](#static-location-configuration) or a discovery processor like -[GitHub Discovery](../../integrations/github/discovery.md). To enforce usage of +[GitHub Discovery](../../integrations/github/discovery.md). To enforce the usage of processors to locate entities we can configure the catalog into `readonly` mode. This configuration disables registering and deleting locations with the catalog APIs. @@ -127,7 +127,7 @@ catalog: readonly: true ``` -> **Note that any plugin relying on the catalog API for creating, updating and +> **Note that any plugin relying on the catalog API for creating, updating, and > deleting entities will not work in this mode.** Deleting an entity by UUID, `DELETE /entities/by-uid/:uid`, is allowed when using this mode. It may be rediscovered as noted in [explicit deletion](life-of-an-entity.md#explicit-deletion). @@ -140,9 +140,9 @@ plugin. ## Clean up orphaned entities -In short entities can become orphaned through multiple means, such as when a catalog-info YAML file is moved from one place to another in the version control system without updating the registration in the catalog. For safety reasons the default behavior is to just tag the orphaned entities, and keep them around. You can read more about orphaned entities [here](life-of-an-entity.md#orphaning). +In short, entities can become orphaned through multiple means, such as when a catalog-info YAML file is moved from one place to another in the version control system without updating the registration in the catalog. For safety reasons, the default behavior is to just tag the orphaned entities, and keep them around. You can read more about orphaned entities [here](life-of-an-entity.md#orphaning). -However, if you do with to automatically remove the orphaned entities, you can use the following configuration, and everything with an orphaned entity tag will be eventually deleted. +However, if you do wish to automatically remove the orphaned entities, you can use the following configuration, and everything with an orphaned entity tag will be eventually deleted. ```yaml catalog: diff --git a/docs/features/software-catalog/descriptor-format.md b/docs/features/software-catalog/descriptor-format.md index 924c59a6fa..526ba15072 100644 --- a/docs/features/software-catalog/descriptor-format.md +++ b/docs/features/software-catalog/descriptor-format.md @@ -782,7 +782,7 @@ Describes the following entity kind: An API describes an interface that can be exposed by a component. The API can be defined in different formats, like [OpenAPI](https://swagger.io/specification/), -[AsyncAPI](https://www.asyncapi.com/docs/specifications/latest/), +[AsyncAPI](https://www.asyncapi.com/docs/reference/specification/latest), [GraphQL](https://graphql.org/learn/schema/), [gRPC](https://developers.google.com/protocol-buffers), or other formats. @@ -838,7 +838,7 @@ The current set of well-known and common values for this field is: - `openapi` - An API definition in YAML or JSON format based on the [OpenAPI](https://swagger.io/specification/) version 2 or version 3 spec. - `asyncapi` - An API definition based on the - [AsyncAPI](https://www.asyncapi.com/docs/specifications/latest/) spec. + [AsyncAPI](https://www.asyncapi.com/docs/reference/specification/latest) spec. - `graphql` - An API definition based on [GraphQL schemas](https://spec.graphql.org/) for consuming [GraphQL](https://graphql.org/) based APIs. diff --git a/docs/features/software-catalog/life-of-an-entity.md b/docs/features/software-catalog/life-of-an-entity.md index 583be7df20..d1c01141e4 100644 --- a/docs/features/software-catalog/life-of-an-entity.md +++ b/docs/features/software-catalog/life-of-an-entity.md @@ -341,7 +341,7 @@ the three-dots menu option of entity views does offer this option, and the orphaned status can be seen in an info box at the top of the entity's overview page. -However, if you were to try to do an explicit depletion on an entity that's +However, if you were to try to do an explicit deletion on an entity that's being kept actively updated by a parent entity, it would just reappear again shortly thereafter when the processing loops reconsider the parent entity that's still in there. diff --git a/docs/features/software-templates/adding-templates.md b/docs/features/software-templates/adding-templates.md index 7254a56d6c..6396d7530a 100644 --- a/docs/features/software-templates/adding-templates.md +++ b/docs/features/software-templates/adding-templates.md @@ -114,6 +114,6 @@ configured differently should be running on `/catalog-import`. For information about writing your own templates, you can check out the docs [here](./writing-templates.md) -If you are looking for a method to discover templates without the need for manual ingestion, there are several options available. One approach is to utilize Discovery providers, such as [GitHub Discovery](https://backstage.io/docs/integrations/github/discover). +If you are looking for a method to discover templates without the need for manual ingestion, there are several options available. One approach is to utilize Discovery providers, such as [GitHub Discovery](https://backstage.io/docs/integrations/github/discovery). Alternatively, you can choose to set up an external integration. This involves connecting your system to external sources or platforms that may host templates relevant to your needs, as mentioned in [External Integration](https://backstage.io/docs/features/software-catalog/external-integrations/). diff --git a/docs/features/software-templates/authorizing-parameters-steps-and-actions.md b/docs/features/software-templates/authorizing-parameters-steps-and-actions.md index 1351676c37..27e8d48023 100644 --- a/docs/features/software-templates/authorizing-parameters-steps-and-actions.md +++ b/docs/features/software-templates/authorizing-parameters-steps-and-actions.md @@ -128,10 +128,10 @@ class ExamplePermissionPolicy implements PermissionPolicy { } ``` -With this permission policy, the user `spiderman` won't be able to execute the debug:log action. +With this permission policy, the user `spiderman` won't be able to execute the `debug:log` action. You can also restrict the input provided to the action by combining multiple rules. -In the example below, `spiderman` won't be able to execute debug:log when passing `{ "message": "not-this!" }` as action input: +In the example below, `spiderman` won't be able to execute `debug:log` when passing `{ "message": "not-this!" }` as action input: ```ts title="packages/backend/src/plugins/permission.ts" /* highlight-add-start */ diff --git a/docs/features/software-templates/index.md b/docs/features/software-templates/index.md index c0f2e8a97e..aa650a9703 100644 --- a/docs/features/software-templates/index.md +++ b/docs/features/software-templates/index.md @@ -20,6 +20,11 @@ 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` + The Software Templates are available under `/create`. For local development you should be able to reach them at `http://localhost:3000/create`. diff --git a/docs/features/software-templates/migrating-to-rjsf-v5.md b/docs/features/software-templates/migrating-to-rjsf-v5.md new file mode 100644 index 0000000000..829aaf8410 --- /dev/null +++ b/docs/features/software-templates/migrating-to-rjsf-v5.md @@ -0,0 +1,135 @@ +--- +id: migrating-to-rjsf-v5 +title: 'Migrating to react-jsonschema-form@v5' +# prettier-ignore +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. + +## What's `react-jsonschema-form`? + +This library is core to the frontend part of the scaffolder plugin, and is responsible for rendering the form in which developers and end users fill out to meet the `jsonschema` requirement for the parameters section. + +Since the initial release of the `scaffolder` plugin, we we're on a pretty old version of `react-jsonschema-form` (v3), which has been pretty outdated as of late. The problem with us just bumping this library was that there are several breaking changes with the new v5 version, which we've tried pretty aggressively not to pass on to our end users for their templates and [Custom Field Extensions](https://backstage.io/docs/features/software-templates/writing-custom-field-extensions/). + +We're hoping that by duplicating the types from version 3 of `react-jsonschema-form` and making these the types that we will support even though the underlying library is v5, it should get us through all of the breaking changes without passing that down. + +## What's new? + +With that in mind, this release has `v5` of `react-jsonschema-form`, and with that comes all the new features and bugfixes in `v4` that we were waiting for - one of the main ones being the ability to use `if / then / else` syntax in the `template.yaml` definitions! 🎉 + +We've also rebuilt how validation works in the `scaffolder` components, which now means that we've opened the ability to have `async` validation functions in your `Field Extensions`. + +Some of the pages have gotten a little bit of an overhaul in terms of UI based on some research and feedback from the community and internally. + +- The `TemplateList` page has gotten some new `Card` components which show a little more information than the previous version with a little `material-ui` standards. +- The `WizardPage` has received some new updates with the stepper now running horizontally, and the `Review` step being a dedicated step in the stepper. +- The `OngoingTask` page now does not show the logs by default, and instead has a much cleaner interface for tracking the ongoing steps and the pipeline of actions that are currently showing. + - You can also now provide your own `OutputsComponent` which can be used to render the outputs from an ongoing / completed task in a way that suits your templates the best. For instance, if your template produces `Pull Requests`, it could be useful to render these in an interactive way where you can see the statuses of each of these `Pull Requests` in the `Ongoing Task` page. + +There's also a lot of bug fixes, and other things, but these are the main ones that we wanted to highlight. + +## How do I upgrade + +With the release of [`v1.20.0`](https://github.com/backstage/backstage/releases/tag/v1.20.0) these changes should have been made for you. We're hoping that it should be pretty transparent, and things just work as expected. Please reach out to us on [discord](https://discord.com/invite/MUpMjP2) or in a [issue](https://github.com/backstage/backstage/issues/new?assignees=&labels=bug&projects=&template=bug.yaml&title=%F0%9F%90%9B+Bug+Report%3A+%3Ctitle%3E) if you're having issues. + +It's possible that if you have a hard dependency on any of the `@rjsf/*` libraries in your app, you'll need to bump these manually to the version that we currently support: `5.13.6` at the time of writing. There could be breaking changes that you will have to fix here however, which we think should be pretty simple, but they're things like changing imports from `@rjsf/core` to `@rjsf/utils`. + +```ts +/* highlight-remove-next-line */ +import { FieldValidation } from '@rjsf/core'; +/* highlight-add-next-line */ +import { FieldValidation } from '@rjsf/utils; +``` + +## Escape hatch + +If for some reason the upgrade to [`v1.20.0`](https://github.com/backstage/backstage/releases/tag/v1.20.0) didn't go as planned, there's an escape hatch for use until the next mainline release in which we will try to get any issues fixed before removing the legacy code. + +We've moved some of the older exports to an `/alpha` export so you should be able switch to using the old library just in case. + +```tsx +/* highlight-remove-next-line */ +import { ScaffolderPage } from '@backstage/plugin-scaffolder'; +/* highlight-add-next-line */ +import { LegacyScaffolderPage } from '@backstage/plugin-scaffolder/alpha'; +``` + +And this API should be the exact same as the previous Router, so you should be able to make a change like the following further down in this file: + +```tsx + + entity?.metadata?.tags?.includes('recommended') ?? false, + }, + ]} + /> + } +> + + + {/* ... other extensions */} + + + + {/* ... other layouts */} + + +``` + +And you can also update any of your `CustomFieldExtensions` to use the old helper like so: + +```ts +/* highlight-remove-next-line */ +import { createScaffolderFieldExtension } from '@backstage/plugin-scaffolder'; +/* highlight-add-next-line */ +import { createLegacyScaffolderFieldExtension } from '@backstage/plugin-scaffolder-react/alpha'; + +export const EntityNamePickerFieldExtension = scaffolderPlugin.provide( + /* highlight-remove-next-line */ + createScaffolderFieldExtension({ + /* highlight-add-next-line */ + createLegacyScaffolderFieldExtension({ + component: EntityNamePicker, + name: 'EntityNamePicker', + validation: entityNamePickerValidation, + }), +); +``` + +And in the component themselves, you might have to do the following: + +```tsx +/* highlight-remove-next-line */ +import { FieldExtensionComponentProps } from '@backstage/plugin-scaffolder-react'; +/* highlight-add-next-line */ +import { LegacyFieldExtensionComponentProps } from '@backstage/plugin-scaffolder-react/alpha'; + +export const EntityNamePicker = ( + /* highlight-remove-next-line */ + props: FieldExtensionComponentProps, + /* highlight-add-next-line */ + props: LegacyFieldExtensionComponentProps, +) => { + const { + onChange, + required, + schema: { title = 'Name', description = 'Unique name of the component' }, + rawErrors, + formData, + idSchema, + placeholder, + } = props; + // .. +}; +``` diff --git a/docs/features/software-templates/testing-scaffolder-alpha.md b/docs/features/software-templates/testing-scaffolder-alpha.md deleted file mode 100644 index 02e579ef83..0000000000 --- a/docs/features/software-templates/testing-scaffolder-alpha.md +++ /dev/null @@ -1,276 +0,0 @@ ---- -id: testing-scaffolder-alpha -title: 'Experimental: Testing out the alpha Scaffolder plugin' -# prettier-ignore -description: Docs on the upcoming breaking release for the scaffolder plugin ---- - -## What's `scaffolder/next`? - -The `alpha` version, or as you might have seen referred to in other places the `scaffolder/next` release, is a new version of the `scaffolder` plugin that will be the first breaking change to the plugin, so you can also think of it as `@backstage/plugin-scaffolder@2.0.0`. -Its mostly a rewrite of a lot of the frontend components and pages that had very limited test coverage, which made adding new features to the `scaffolder` plugin quite hard, and we were lacking in confidence when making changes. - -There is of course some other things that have changed when re-writing this, which are essentially what has caused some breaking changes. -Now, this is not like previous scaffolder changes where you would have to change all of your templates as this is only the frontend plugin that is going to have breaking changes. You can read more about the [breaking changes](#breaking-changes) below. - -## What's new? - -First off, the main dependency that we have for the frontend which is responsible for rendering the `JSONSchema` into `material-ui` components is [react-jsonschema-form](https://github.com/rjsf-team/react-jsonschema-form). -This dependency in the current version of the plugin is 3.x.x, which is now 2 major versions out of date. Long story short, `v4` of this plugin contained some bug fixes, and new features but we we're unable to upgrade due to some issues with having support for `material-ui@v4`, so we had to wait for `v5` to be released, and because of the `FieldExtensions` and how they are very tightly coupled to the `react-jsonschema-form` library, we also wanted to make sure that this release was stable before getting people to migrate their `Field Extensions`. - -With that in mind, this release has `v5` of `react-jsonschema-form`, and with that comes all the new features and bugfixes in `v4` that we were waiting for - one of the main ones being the ability to use `if / then / else` syntax in the `template.yaml` definitions! 🎉 - -We've also rebuilt how validation works in the `scaffolder` components, which now means that we've opened the ability to have `async` validation functions in your `Field Extensions`. - -Some of the pages have gotten a little bit of an overhaul in terms of UI based on some research and feedback from the community and internally. - -- The `TemplateList` page has gotten some new `Card` components which show a little more information than the previous version with a little `material-ui` standards. -- The `WizardPage` has received some new updates with the stepper now running horizontally, and the `Review` step being a dedicated step in the stepper. -- The `OngoingTask` page now does not show the logs by default, and instead has a much cleaner interface for tracking the ongoing steps and the pipeline of actions that are currently showing. - - You can also now provide your own `OutputsComponent` which can be used to render the outputs from an ongoing / completed task in a way that suits your templates the best. For instance, if your template produces `Pull Requests`, it could be useful to render these in an interactive way where you can see the statuses of each of these `Pull Requests` in the `Ongoing Task` page. - -There's also a lot of bug fixes, and other things, but these are the main ones that we wanted to highlight. - -## How do I test out the `alpha` version? - -With the release of [`v1.11.0`](https://github.com/backstage/backstage/releases/tag/v1.11.0) it's now possible to run the `scaffolder/next` plugin and it be a drop in replacement for the current version that you use today. This means that you can start using the new code, and start testing it out. Once we have collected enough feedback, and squashed any bugs that might block us from releasing, it will be promoted from the `/alpha` exports and replace the existing code leading to breaking changes if you haven't already made these changes as part of this testing pilot. Those that have chosen to opt into this testing pilot means that once we promote it from the `/alpha` exports, you will need to update your code to point to the original exports from the `scaffolder` plugin, just like the code is today but with the [breaking changes](#breaking-changes) that you already made to your `Custom Field Extensions`. - -It's also worth calling out that if you do test this out, and find some issues or something not working out as expected, feel free to raise an issue in the [repo](https://github.com/backstage/backstage) or reach out to us on Discord! - -### Make the required changes to `App.tsx` - -The `ScaffolderPage` router has a completely different export for the `scaffolder/next` work, so you will want to change any import from the old `ScaffolderPage` to the new `NextScaffolderPage` - -```tsx -/* highlight-remove-next-line */ -import { ScaffolderPage } from '@backstage/plugin-scaffolder'; -/* highlight-add-next-line */ -import { NextScaffolderPage } from '@backstage/plugin-scaffolder/alpha'; -``` - -And this API should be the exact same as the previous Router, so you should be able to make a change like the following further down in this file: - -```tsx - - entity?.metadata?.tags?.includes('recommended') ?? false, - }, - ]} - /> - } -> - - - {/* ... other extensions */} - - - - {/* ... other layouts */} - - -``` - -Optionally, you can choose to run the two side by side by using `FeatureFlags` in your `App.tsx` if you wish, but, we would also recommend duplicating any `CustomFieldExtensions` too as the new `CustomFieldExtensions` might not be compatible with the old form. - -```tsx - - }> - - - - - - - }> - - - - - -``` - -You should then be able to enable the `scaffolder-next-preview` feature flag under `/settings/feature-flags` in Backstage. - -### Make the required changes to your `CustomFieldExtensions` - -There's differently named function for creating field extensions part of the `/alpha` exports as these are the ones that can contain breaking changes because of the breaking changes that have been applied in `react-jsonschema-form`. - -Let's take the following example: - -```ts -export const EntityNamePickerFieldExtension = scaffolderPlugin.provide( - createScaffolderFieldExtension({ - component: EntityNamePicker, - name: 'EntityNamePicker', - validation: entityNamePickerValidation, - schema: EntityNamePickerSchema, - }), -); -``` - -References for `createScaffolderFieldExtension` have an `/alpha` version of `createNextScaffolderFieldExtension`, which should be used instead. - -```ts -/* highlight-remove-next-line */ -import { createScaffolderFieldExtension } from '@backstage/plugin-scaffolder'; -/* highlight-add-next-line */ -import { createNextScaffolderFieldExtension } from '@backstage/plugin-scaffolder-react/alpha'; - -export const EntityNamePickerFieldExtension = scaffolderPlugin.provide( - /* highlight-remove-next-line */ - createScaffolderFieldExtension({ - /* highlight-add-next-line */ - createNextScaffolderFieldExtension({ - component: EntityNamePicker, - name: 'EntityNamePicker', - validation: entityNamePickerValidation, - }), -); -``` - -Once you've done this you will find that you will have two squiggly lines under the properties that are passed in. One for the component and one for the validation (if provided.) - -Let's take the following code for the `EntityNamePicker` component: - -```tsx -export const EntityNamePicker = ( - props: FieldExtensionComponentProps, -) => { - const { - onChange, - required, - schema: { title = 'Name', description = 'Unique name of the component' }, - rawErrors, - formData, - uiSchema: { 'ui:autofocus': autoFocus }, - idSchema, - placeholder, - } = props; - // .. -}; -``` - -There's another `/alpha` export that you need to replace `FieldExtensionComponentProps` with which is the `NextFieldExtensionComponentProps`. - -```tsx -/* highlight-remove-next-line */ -import { FieldExtensionComponentProps } from '@backstage/plugin-scaffolder-react'; -/* highlight-add-next-line */ -import { NextFieldExtensionComponentProps } from '@backstage/plugin-scaffolder-react/alpha'; - -export const EntityNamePicker = ( - /* highlight-remove-next-line */ - props: FieldExtensionComponentProps, - /* highlight-add-next-line */ - props: NextFieldExtensionComponentProps, -) => { - const { - onChange, - required, - schema: { title = 'Name', description = 'Unique name of the component' }, - rawErrors, - formData, - /* highlight-remove-next-line */ - uiSchema: { 'ui:autofocus': autoFocus }, - /* highlight-add-next-line */ - uiSchema: { 'ui:autofocus': autoFocus } = {}, - idSchema, - placeholder, - } = props; - // .. -}; -``` - -You'll notice that there's an additional change here, which is that we're now defaulting the `uiSchema` to an empty object. This is because the `uiSchema` is now optional, and if you don't provide it, it will be `undefined` instead of an empty object. There's more around this in the [breaking changes](#breaking-changes) section. - -To fix the previous validation error, you will need to change the import for the `FieldValidation` type that is used in the `validation` function. - -Let's take the following example of the validation function: - -```ts -import { FieldValidation } from '@rjsf/utils'; -import { KubernetesValidatorFunctions } from '@backstage/catalog-model'; - -export const entityNamePickerValidation = ( - value: string, - validation: FieldValidation, -) => { - if (!KubernetesValidatorFunctions.isValidObjectName(value)) { - validation.addError( - 'Must start and end with an alphanumeric character, and contain only alphanumeric characters, hyphens, underscores, and periods. Maximum length is 63 characters.', - ); - } -}; -``` - -You will need to change the import for `FieldValidation` to point at the new `react-jsonschema-form` dependency. - -> Note: you will probably need to install this dependency too, by using `yarn add @rjsf/utils` in the package where you define these validation functions, this could also be in the `packages/app` folder, so you can install it there if needed. - -```ts -/* highlight-remove-next-line */ -import { FieldValidation } from '@rjsf/core'; -/* highlight-add-next-line */ -import { FieldValidation } from '@rjsf/utils; -import { KubernetesValidatorFunctions } from '@backstage/catalog-model'; - -export const entityNamePickerValidation = ( - value: string, - validation: FieldValidation, -) => { -``` - -## Breaking Changes - -Once we fully release the code that is in the `/alpha` exports right now onto the current API and release v2.0.0 of `@backstage/plugin-scaffolder` the breaking changes will be as follows: - -### `uiSchema` is now optional - -Later releases of `react-jsonschema-form` have made the `uiSchema` optional, and if you don't provide it, it will be `undefined` instead of an empty object. This means that you will need to make sure that you're defaulting the `uiSchema` to an empty object if you're using it in your code. - -```tsx -const { - onChange, - required, - schema: { title = 'Name', description = 'Unique name of the component' }, - rawErrors, - formData, - /* highlight-remove-next-line */ - uiSchema: { 'ui:autofocus': autoFocus }, - /* highlight-add-next-line */ - uiSchema: { 'ui:autofocus': autoFocus } = {}, - idSchema, - placeholder, -} = props; -// .. -``` - -### `formData` can also be `undefined` - -If you were using the `formData` and assuming that it was set to an empty object when building `Field Extensions` that return objects, then this will be `undefined` now due to a change in the `react-jsonschema-form` library. - -```tsx -const { - onChange, - required, - schema: { title = 'Name', description = 'Unique name of the component' }, - rawErrors, - /* highlight-remove-next-line */ - formData, - /* highlight-add-next-line */ - formData = {}, // or maybe some other default value that you would prefer - uiSchema: { 'ui:autofocus': autoFocus } = {}, - idSchema, - placeholder, -} = props; -// .. -``` diff --git a/docs/features/software-templates/writing-templates.md b/docs/features/software-templates/writing-templates.md index 7019ecfb28..35458446c2 100644 --- a/docs/features/software-templates/writing-templates.md +++ b/docs/features/software-templates/writing-templates.md @@ -231,8 +231,53 @@ spec: inputType: tel ``` +### Using Secrets + +You may want to mark things as secret and make sure that these values are protected and not available through REST endpoints. You can do this by using the built in `ui:field: Secret`. + +You can define this property as any normal parameter, however the consumption of this parameter will not be available through `${{ parameters.myKey }}` you will instead need to use `${{ secrets.myKey }}` in your `template.yaml`. + +Parameters will be automatically masked in the review step. + +```yaml +apiVersion: scaffolder.backstage.io/v1beta3 +kind: Template +metadata: + name: v1beta3-demo + title: Test Action template + description: scaffolder v1beta3 template demo +spec: + owner: backstage/techdocs-core + type: service + + parameters: + - title: Authenticaion + description: Provide authentication for the resource + required: + - username + - password + properties: + username: + type: string + # use the built in Secret field extension + ui:field: Secret + password: + type: string + ui:field: Secret + + steps: + - id: setupAuthentication + action: auth:create + input: + # make sure to use ${{ secrets.parameterName }} to reference these values + username: ${{ secrets.username }} + password: ${{ secrets.password }} +``` + ### Hide or mask sensitive data on Review step +> Note: this approach is soon to be deprecated, please mark things as secret by using the `Secret` field extension instead as mentioned above. + Sometimes, specially in custom fields, you collect some data on Create form that must not be shown to the user on Review step. To hide or mask this data, you can use `ui:widget: password` or set some properties of `ui:backstage`: diff --git a/docs/features/techdocs/README.md b/docs/features/techdocs/README.md index 3251451cce..c6e1fd42ad 100644 --- a/docs/features/techdocs/README.md +++ b/docs/features/techdocs/README.md @@ -68,6 +68,7 @@ See [TechDocs Architecture](architecture.md) to get an overview of where the bel | Gerrit | Yes ✅ | | GitLab | Yes ✅ | | GitLab Enterprise | Yes ✅ | +| Gitea | Yes ✅ | ### File storage providers diff --git a/docs/features/techdocs/cli.md b/docs/features/techdocs/cli.md index 9704b9b21b..c824eb7d7d 100644 --- a/docs/features/techdocs/cli.md +++ b/docs/features/techdocs/cli.md @@ -91,6 +91,9 @@ Options: --docker-option Extra options to pass to the docker run command, e.g. "--add-host=internal.host:192.168.11.12" (can be added multiple times). --no-docker Do not use Docker, use MkDocs executable in current user environment. + --mkdocs-parameter-clean Pass "--clean" parameter to mkdocs server running in containerized environment. + --mkdocs-parameter-dirtyreload Pass "--dirtyreload" parameter to mkdocs server running in containerized environment. + --mkdocs-parameter-strict Pass "--strict" parameter to mkdocs server running in containerized environment. --mkdocs-port Port for MkDocs server to use (default: "8000") --preview-app-bundle-path Preview documentation using a web app other than the included one. --preview-app-port Port where the preview will be served. @@ -147,6 +150,7 @@ Options: Defaults to false, which means that the techdocs-core plugin is always added to the mkdocs file. --legacyCopyReadmeMdToIndexMd Attempt to ensure an index.md exists falling back to using /README.md or README.md in case a default /index.md is not provided. (default: false) + --runAsDefaultUser Bypass setting the container user as the same user and group id as host for Linux and MacOS (default: false) -v --verbose Enable verbose output. (default: false) -h, --help display help for command ``` diff --git a/docs/features/techdocs/creating-and-publishing.md b/docs/features/techdocs/creating-and-publishing.md index f63ff43b7f..1251f67276 100644 --- a/docs/features/techdocs/creating-and-publishing.md +++ b/docs/features/techdocs/creating-and-publishing.md @@ -9,8 +9,8 @@ This section will guide you through how to: - [Create a basic documentation setup](#create-a-basic-documentation-setup) - [Use any software template](#use-any-software-template) - - [Use the documentation template](#use-the-documentation-template) - [Enable documentation for an already existing entity](#enable-documentation-for-an-already-existing-entity) + - [Create a standalone documentation](#create-a-standalone-documentation) - [Writing and previewing your documentation](#writing-and-previewing-your-documentation) ## Prerequisites @@ -41,23 +41,6 @@ default, we highly recommend you to set that up. Follow our how-to guide [How to add documentation setup to your software templates](./how-to-guides.md#how-to-add-the-documentation-setup-to-your-software-templates) to get started. -### Use the documentation template - -There could be _some_ situations where you don't want to keep your docs close to -your code, but still want to publish documentation - for example, an onboarding -tutorial. For this use case, we have put together a documentation template. Your -Backstage instance should by default have a documentation template added. If -not, copy the catalog locations from the -[create-app template](https://github.com/backstage/backstage/blob/master/packages/create-app/templates/default-app/app-config.yaml.hbs) -to add the documentation template. The template creates a component with -**only** TechDocs configuration and default markdown files, and is otherwise -empty. - -![Documentation Template](../../assets/techdocs/documentation-template.png) - -Create an entity from the documentation template and you will get the needed -setup for free. - ### Enable documentation for an already existing entity Prerequisites: @@ -115,6 +98,56 @@ This is a basic example of documentation. Commit your changes, open a pull request and merge. You will now get your updated documentation next time you run Backstage! +### Create a standalone documentation + +There could be _some_ situations where you don't want to keep your docs close to +your code, but still want to publish documentation - for example, an onboarding +tutorial. For this case, you can create a documentation component, which will be +published as a standalone part of TechDocs. + +First, create an entity for your documentation. A minimal example could look like +this: + +```yaml title="catalog-info.yaml" +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: a-unique-name-for-your-docs + annotations: + # this could also be `url:` if the documentation isn't in the same location + backstage.io/techdocs-ref: dir:. +spec: + type: documentation + lifecycle: experimental + owner: user-or-team-name +``` + +Next, create the config file for [mkdocs](https://www.mkdocs.org/), which will be +used to parse your docs: + +```yaml title="mkdocs.yml" +site_name: a-unique-name-for-your-docs +site_description: An informative description +plugins: + - techdocs-core +nav: + - Getting Started: index.md +``` + +Finally, add your index.md Markdown file, in a folder named `docs/` with your desired +documentation in Markdown. Your file structure should now look like this: + +``` +your-great-documentation/ + docs/ + index.md + catalog-info.yaml + mkdocs.yml +``` + +Last but not least, register your component in the software catalog using +[one of several options](../software-catalog/index.md#adding-components-to-the-catalog). + ## Writing and previewing your documentation Using the [techdocs-cli](https://github.com/backstage/backstage/tree/master/packages/techdocs-cli) you can diff --git a/docs/features/techdocs/how-to-guides.md b/docs/features/techdocs/how-to-guides.md index 29f985904f..afc257f20b 100644 --- a/docs/features/techdocs/how-to-guides.md +++ b/docs/features/techdocs/how-to-guides.md @@ -504,6 +504,18 @@ folder (/docs) or replace the content in this file. Done! You now have support for TechDocs in your own software template! +### Prevent download of Google fonts + +If your Backstage instance does not have internet access, the generation will fail. TechDocs tries to download the Roboto font from Google. You can disable it by adding the following lines to mkdocs.yaml: + +```yaml +theme: + name: material + font: false +``` + +> Note: The addition `name: material` is necessary. Otherwise it will not work + ## How to enable iframes in TechDocs TechDocs uses the [DOMPurify](https://github.com/cure53/DOMPurify) library to diff --git a/docs/frontend-system/architecture/01-index.md b/docs/frontend-system/architecture/01-index.md index 380ebaa335..8585eb76fc 100644 --- a/docs/frontend-system/architecture/01-index.md +++ b/docs/frontend-system/architecture/01-index.md @@ -6,7 +6,7 @@ sidebar_label: Overview description: The structure and architecture of the new Frontend System --- -> **NOTE: The new frontend system is in a highly experimental phase** +> **NOTE: The new frontend system is in alpha and is only supported by a small number of plugins.** ## Building Blocks diff --git a/docs/frontend-system/architecture/02-app.md b/docs/frontend-system/architecture/02-app.md index 52fd20faee..1ffae71981 100644 --- a/docs/frontend-system/architecture/02-app.md +++ b/docs/frontend-system/architecture/02-app.md @@ -1,12 +1,12 @@ --- -id: apps +id: app title: App Instances sidebar_label: App # prettier-ignore description: App instances --- -> **NOTE: The new frontend system is in a highly experimental phase** +> **NOTE: The new frontend system is in alpha and is only supported by a small number of plugins.** ## The App Instance @@ -45,4 +45,35 @@ A common type of data that is shared between extensions is React elements and co ## Feature Discovery -TODO +App feature discovery lets you automatically discover and install features provided by dependencies in your app. In practice, it means that you don't need to manually `import` features in code, but they are instead installed as soon as you add them as a dependency in your `package.json`. + +Because feature discovery needs to interact with the compilation process, it is only available when using the `@backstage/cli` to build your app. It is hooked into the WebPack compilation process by scanning your app package for compatible dependencies, which are then made part of the app compilation bundle. + +Since the `@backstage/cli` is a more stable component than the new frontend system, feature discovery is currently marked as an experimental feature of the CLI and needs to be enabled manually. To enable it, add the following configuration to your `app-config.yaml`: + +```yaml +app: + experimental: + packages: all +``` + +This will cause all dependencies in your app package to be installed automatically. If this is not desired, you can use include or exclude filters to narrow down the set of packages: + +```yaml +app: + experimental: + packages: + # Only the following packages will be included + include: + - '@backstage/plugin-catalog' + - '@backstage/plugin-scaffolder' +--- +app: + experimental: + packages: + # All but the following package will be included + exclude: + - '@backstage/plugin-catalog' +``` + +Note that you do not need to manually exclude packages that you also import explicitly in code, since plugin instances are deduplicated by the app. You will never end up with duplicate plugin installations except if they are in fact two different plugin instances with different IDs. diff --git a/docs/frontend-system/architecture/03-extensions.md b/docs/frontend-system/architecture/03-extensions.md index 3d08bf1721..6d86415817 100644 --- a/docs/frontend-system/architecture/03-extensions.md +++ b/docs/frontend-system/architecture/03-extensions.md @@ -6,7 +6,7 @@ sidebar_label: Extensions description: Frontend extensions --- -> **NOTE: The new frontend system is in a highly experimental phase** +> **NOTE: The new frontend system is in alpha and is only supported by a small number of plugins.** As mentioned in the [previous section](./02-app.md), Backstage apps are built up from a tree of extensions. This section will go into more detail about what extensions are, how to create and use them, and how to create your own extensibility patterns. @@ -18,6 +18,10 @@ Each extensions has a number of different properties that define how it behaves ### ID + + The ID of an extension is used to uniquely identity it, and it should ideally by unique across the entire Backstage ecosystem. For each frontend app instance there can only be a single extension for any given ID. Installing multiple extensions with the same ID will either result in an error or one of the extensions will override the others. The ID is also used to reference the extensions from other extensions, in configuration, and in other places such as developer tools and analytics. ### Output @@ -56,7 +60,7 @@ Extensions are created using the `createExtension` function from `@backstage/fro ```tsx const extension = createExtension({ - id: 'my-extension', + name: 'my-extension', // This is the attachment point, `id` is the ID of the parent extension, // while `input` is the name of the input to attach to. attachTo: { id: 'my-parent', input: 'content' }, @@ -67,10 +71,10 @@ const extension = createExtension({ element: coreExtensionData.reactElement, }, // This factory is called to instantiate the extensions and produce its output. - factory({ bind }) { - bind({ + factory() { + return { element:
Hello World
, - }); + }; }, }); ``` @@ -81,24 +85,288 @@ Note that while the `createExtension` is public API and used in many places, it ## Extension Data -TODO +Communication between extensions happens in one direction, from one child extension through the attachment point to its parent. The child extension outputs data which is then passed as inputs to the parent extension. This data is called Extension Data, where the shape of each individual piece of data is described by an Extension Data Reference. These references are created separately from the extensions themselves, and can be shared across multiple different kinds of extensions. Each reference consists of an ID and a TypeScript type that the data needs to conform to, and represents one type of data that can be shared between extensions. + +### Extension Data References + +To create a new extension data reference to represent a type of shared extension data you use the `createExtensionDataRef` function. When defining a new reference you need to provide an ID and a TypeScript type, for example: + +```ts +export const reactElementExtensionDataRef = + createExtensionDataRef('my-plugin.reactElement'); +``` + +The `ExtensionDataRef` can then be used to describe an output property of the extension. This will enforce typing on the return value of the extension factory: + +```tsx +const extension = createExtension({ + // ... + output: { + element: reactElementExtensionDataRef, + }, + factory() { + return { + element:
Hello World
, + }; + }, +}); +``` + +### Extension Data Uniqueness + +Note that the key used in the output map, in this case `element`, is only used internally within the definition of the extension itself. That actual identifier for the data when consumed by other extensions is the ID of the reference, in this case `core.reactElement`. This means that you can not output multiple different values for the same extension data reference, as they would conflict with each other. That in turn makes overly generic extension data references a bad idea, for example a generic "string" type. Instead create separate references for each type of data that you want to share. + +```tsx +const extension = createExtension({ + // ... + output: { + // ❌ Bad example - outputting values of same type + element1: reactElementExtensionDataRef, + element2: reactElementExtensionDataRef, + }, + factory() { + return { + element1:
Hello World
, + element2:
Hello World
, + }; + }, +}); +``` + +### Core Extension Data + +We provide default `coreExtensionData`, which provides commonly used `ExtensionDataRef`s - e.g. for `React.JSX.Element` and `RouteRef`. They can be used when creating your own extension. For example, the React Element extension data that we defined above is already provided as `coreExtensionData.reactElement`. + + + +### Optional Extension Data + +By default all extension data is required, meaning that the extension factory must provide a value for each output. However, it is possible to make extension data optional by calling the `.optional()` method. This makes it optional for the factory function to return a value as part of its output. When calling the `.optional()` method you create a new copy of the extension data reference, it does not mutate the existing reference. + +```tsx +const extension = createExtension({ + // ... + output: { + element: coreExtensionData.reactElement.optional(), + }, + factory() { + return { + element: + Math.random() < 0.5 ? : undefined, + }; + }, +}); +``` ## Extension Inputs -TODO +The Extension Data can be passed up to other extensions through their extension inputs. Similar to the outputs seen before, let's create an example an extension with a extension input: -## Configuration +```tsx +const navigationExtension = createExtension({ + // ... + inputs: { + // [1]: Input + logo: createExtensionInput( + { + element: coreExtensionData.reactElement, + }, + { singleton: true, optional: true }, + ), + }, + factory({ inputs }) { + return { + element: ( + + ), + }; + }, + // ... +}); +``` -TODO +The input (see [1] above) is an object that we create using `createExtensionInput`. The first argument is the set of extension data that we accept via this input, and works just like the `output` option. The second argument is optional, and it allows us to put constraints on the extensions that are attached to our input. If the `singleton: true` option is set, only a single extension can attached at a time, and unless the `optional: true` option is set it will also be required that there is exactly on attached extension. -## Configuration Schema +So how can we now attach the output to the parent extension's input? If we think about a navigation component, like the Sidebar in Backstage, there might be plugins that want to attach a link to their plugin to this navigation component. In this case the plugin only needs to know the extension `id` and the name of the extension `input` to attach the extension `output` returned by the `factory` to the specified extension: -TODO +```tsx +const navigationItemExtension = createExtension({ + // ... + attachTo: { id: 'app/nav', input: 'items' }, + factory() { + return { + element: Home, + }; + }, +}); + +const navigationExtension = createExtension({ + // ... + // [2]: Extension `id` will be `app/nav` following the extension naming pattern + namespace: 'app', + name: 'nav', + output: { + element: coreExtensionData.reactElement, + }, + inputs: { + items: createExtensionInput({ + element: coreExtensionData.reactElement, + }), + }, + factory({ inputs }) { + return { + element: ( + + ), + }; + }, + // ... +}); +``` + +In this case the extension input `items` is an array, where each individual item is an extension that attached itself to the extension inputs of this `id`. + +With the `inputs` not only the `output` of an extensions item is passed to the extension, but also the `node`. However, it is discouraged to consume the `node` here unless needed. If we are looking at the `factory` function from the example above we could access the `node` like the following: + +```tsx + // ... + factory({ inputs }) { + return { + element: ( + + ), + }; + }, +``` + +## Extension Configuration + +With the `app-config.yaml` there is already the option to pass configuration to plugins or the app to e.g. define the `baseURL` of your app. For extensions this concept would be limiting as an extension can be independent of the plugin & initiated several times. Therefor we created a possibility to configure each extension individually through config. The extension config schema is created using the [`zod`](https://zod.dev/) library, which in addition to TypeScript type checking also provides runtime validation and coercion. If we continue with the example of the `navigationExtension` and now want it to contain a configurable title, we could make it available like the following: + +```tsx +const navigationExtension = createExtension({ + // ... + namespace: 'app', + name: 'nav', + // [3]: Extension `id` will be `app/nav` following the extension naming pattern + configSchema: createSchemaFromZod(z => + z.object({ + title: z.string().default('Sidebar Title'), + }), + ), + factory({ config }) { + return { + element: ( + + ), + }; + }, + // ... +}); +``` + +To now change the text of the title from "Sidebar Title" to "Backstage" we can look at the `id` of the extension & add the following to the `app-config.yaml`: + +```yaml +app: + # ... + extensions: + # ... + - app/nav: + config: + title: 'Backstage' +``` ## Extension Creators -TODO +With creating an extension by using `createExtension(...)` you have the advantage that the extension can be anything in your Backstage application. We realised that this comes with the trade-off of having to repeat boilerplate code for similar building blocks. Here extension creators come into play for covering common building blocks in Backstage like pages using `createPageExtension`, themes using the `createThemeExtension` or items for the navigation using `createNavItemExtension`. + +If we follow the example from above all items of the navigation have similarities, like they all want to be attached to the same extension with the same input as well as rendering the same navigation item component. Therefor `createExtension` can be abstracted for this use case to `createNavItemExtension` and if we add the extension to the app it will end up in the right place & looks like we expect a navigation item to look. + +```tsx +export const HomeNavIcon = createNavItemExtension({ + routeRef: routeRefForTheHomePage, + title: 'Home', + icon: HomeIcon, +}); +``` + +### Extension Kind + +With the example `HomeNavIcon` will end up on the extension input `items` of the extensions with the id `app/nav`. It raises the question what the `id` of the `HomeNavIcon` itself is. The extension creator for the navigation item has a defined `kind`, which by convention matches the own name. So in this example `createNavItemExtension` sets the kind to `nav-item`. + +The `id` of the extension is then build out of `namespace`, `name` & `kind` like the following - where `namespace` & `name` are optional properties that can be passed to the extension creator: + +``` +id: kind:namespace/name +``` + +For more information on naming of extension refer to the [naming patterns documentation](./08-naming-patterns.md). + +### Extension Creators in libraries + +Extension creators should be exported from frontend library packages (e.g. `*-react`) rather than plugin packages. + +If an extension is only for in-house tweaks, it's okay to put it in the plugin package. But if you want other open source plugins to use it, or you already have a `-react` package, always put extension creators in the `-react` package. ## Extension Boundary -TODO +The `ExtensionBoundary` wraps extensions with several React contexts for different purposes + +### Suspense + +All React elements rendered by extension creators should be wrapped in the extension boundary. With `Suspense` the extension can than load resources asynchronously with having a loading fallback. It also allows to lazy load the whole extension similar to how plugins are currently lazy loaded in Backstage. + +### Error Boundary + +Similar to plugins the `ErrorBoundary` for extension allows to pass in a fallback component in case there is an uncaught error inside of the component. With this the error can be isolated & it would prevent the rest of the plugin to crash. + +### Analytics + +Analytics information are provided through the `AnalyticsContext`, which will give `extensionId` & `pluginId` as context to analytics event fired inside of the extension. Additionally `RouteTracker` will capture an analytics event for routable extension to inform which extension metadata gets associated with a navigation event when the route navigated to is a gathered `mountPoint`. + +The `ExtensionBoundary` can be used like the following in an extension creator: + +```tsx +export function createSomeExtension< + TConfig extends {}, + TInputs extends AnyExtensionInputMap, +>(options): ExtensionDefinition { + return createExtension({ + // ... + factory({ config, inputs, node }) { + const ExtensionComponent = lazy(() => + options + .loader({ config, inputs }) + .then(element => ({ default: () => element })), + ); + + return { + path: config.path, + routeRef: options.routeRef, + element: ( + + + + ), + }; + }, + }); +} +``` diff --git a/docs/frontend-system/architecture/04-plugins.md b/docs/frontend-system/architecture/04-plugins.md index a1e85f8407..042d4fbc36 100644 --- a/docs/frontend-system/architecture/04-plugins.md +++ b/docs/frontend-system/architecture/04-plugins.md @@ -6,4 +6,88 @@ sidebar_label: Plugins description: Frontend plugins --- -> **NOTE: The new frontend system is in a highly experimental phase** +> **NOTE: The new frontend system is in alpha and is only supported by a small number of plugins.** + +## Introduction + + + +## Creating a Plugin + + + +```ts +export const myPlugin = createPlugin({ + id: 'my-plugin', +}); +``` + + + +### Plugin ID + + + +### Plugin Extensions + + + +### Plugin Routes + + + +### Plugin External Routes + + + +### Plugin Feature Flags + + + +## Installing a Plugin in an App + + diff --git a/docs/frontend-system/architecture/05-extension-overrides.md b/docs/frontend-system/architecture/05-extension-overrides.md index 743a5ea59e..e722145552 100644 --- a/docs/frontend-system/architecture/05-extension-overrides.md +++ b/docs/frontend-system/architecture/05-extension-overrides.md @@ -1,9 +1,47 @@ --- -id: extension overrides +id: extension-overrides title: Frontend Extension Overrides sidebar_label: Extension Overrides # prettier-ignore description: Frontend extension overrides --- -> **NOTE: The new frontend system is in a highly experimental phase** +> **NOTE: The new frontend system is in alpha and is only supported by a small number of plugins.** + +## Introduction + + + +## Creating a Extension Override + + + +## Overriding Existing Extensions + + diff --git a/docs/frontend-system/architecture/06-utility-apis.md b/docs/frontend-system/architecture/06-utility-apis.md index 135f60744a..fe714793d7 100644 --- a/docs/frontend-system/architecture/06-utility-apis.md +++ b/docs/frontend-system/architecture/06-utility-apis.md @@ -6,6 +6,25 @@ sidebar_label: Utility APIs description: Utility APIs --- -> **NOTE: The new frontend system is in a highly experimental phase** +> **NOTE: The new frontend system is in alpha and is only supported by a small number of plugins.** -See [Utility APIs docs](../../api/utility-apis.md). +## Overview + +Utility APIs are pieces of standalone functionality, interfaces that can be requested by plugins to use. They are defined by a TypeScript interface as well as a reference (an "API ref") used to access its implementation. They can be provided both by plugins and the core framework, and are themselves [extensions](../architecture/03-extensions.md) that can have inputs, be replaced, and be declaratively configured in your app-config. + +A common example of a utility API is a client interface to interact with the backend part of a plugin, such as the catalog client. Any frontend plugin can then request an implementation of that interface to make requests through. + +The following diagram shows a hypothetical application, which depends on two plugins and also provides some extra overrides. Note that both the plugins and the core framework provide utility APIs, and that they depended on each other. The app also chooses to use its overrides mechanism to supply a replacement implementation of one API, which takes precedence over the default one. Thus, all consumers of that API will be sure to get that new implementation provided to them. + +![frontend system utility apis diagram](../../assets/frontend-system/architecture-utility-apis.drawio.svg) + +## Extension structure + +All utility APIs implement the `createApiExtension.factoryDataRef` output data type, and must attach exclusively to the `core` extension's `apis` input no matter who provided them. These defaults are provided out of the box by the `createApiExtension` framework function. + +Since utility APIs are extensions, they can also have inputs in advanced use cases. This is occasionally useful for complex APIs that can themselves be extended with additional programmatic functionality by adopters. + +## Links + +- The [Utility APIs section](../utility-apis/01-index.md) of the plugin docs +- The legacy docs on [utility APIs](../../api/utility-apis.md) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index 354eaeda13..1402796077 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -6,6 +6,145 @@ sidebar_label: Routes description: Frontend routes --- -> **NOTE: The new frontend system is in a highly experimental phase** +> **NOTE: The new frontend system is in alpha and is only supported by a small number of plugins.** See [routing system docs](../../plugins/composability.md#routing-system) + +## Introduction + + + +## Route References + + + +### Creating a Route Reference + + + +### Using a Route Reference + + + +### Route Path Parameters + + + +### Providing Route References to Plugins + + + +## External Router References + + + +### Binding External Route References + + + +### Optional External Route References + + + +## Sub Route References + + + +```ts +/* + +Some examples + +export const indexPageRouteRef = createRouteRef() + +export const catalogPlugin = createPlugin({ + id: 'catalog, + routes: { + index: indexPageRouteRef, + }, +}) + +// in catalog plugin + +import {indexPageRouteRef} from '../../routes + +const link = useRouteRef(indexPageRouteRef) + +// scaffolder + +export const catalogIndexPageRouteRef = createExternalRouteRef({ + defaultTarget: 'catalog/index', +}) + +export const scaffolderPlugin = createPlugin({ + id: 'scaffolder, + externalRoutes: { + catalogIndex: catalogIndexPageRouteRef, + }, +}) + + +import {catalogIndexPageRouteRef} from '../../routes + +const link = useRouteRef(catalogIndexPageRouteRef) + +// app + +import {catalogPlugin} from '@backstage/plugin-catalog' + +const app = createApp({ + bindRoutes({bind}) { + bind(scaffolderPlugin, { + catalogIndex: catalogPlugin.routes.index, + }) + }, +}) +*/ +``` diff --git a/docs/frontend-system/architecture/08-naming-patterns.md b/docs/frontend-system/architecture/08-naming-patterns.md new file mode 100644 index 0000000000..0916d9fd51 --- /dev/null +++ b/docs/frontend-system/architecture/08-naming-patterns.md @@ -0,0 +1,142 @@ +--- +id: naming-patterns +title: Frontend System Naming Patterns +sidebar_label: Naming Patterns +# prettier-ignore +description: Naming patterns in the frontend system +--- + +> **NOTE: The new frontend system is in alpha and is only supported by a small number of plugins.** + +These are the naming patterns to adhere to within the frontend system. They help us keep exports and IDs consistent across packages and make it easier to understand the usage and intent of exports and IDs. + +As a rule, all names should be camel case, with the exceptions of plugin and extension IDs, which should use kebab case. + +## Plugins + +| Description | Pattern | Examples | +| ----------- | ------------ | ------------------------------------- | +| ID | `''` | `'catalog'`, `'user-settings'` | +| Symbol | `Plugin` | `catalogPlugin`, `userSettingsPlugin` | + +Example: + +```ts +// This declaration is only for internal usage in tests. This could also be a direct default export. +export const userSettingsPlugin = createPlugin({ + id: 'user-settings', + ... +}) + +// The plugin instance should be the default export of the package, typically this is placed in src/index.ts +export { userSettingsPlugin as default } from './plugin'; +``` + +Note that while we use this naming pattern for the plugin instance this is only for internal usage within the package. Plugins are always exported as the default export of the plugin package. + +## Extensions + +| Description | Pattern | Examples | +| ----------- | ------------------------------- | ------------------------------------------------------------------- | +| Creator | `createExtension` | `createPageExtension`, `createEntityCardExtension` | +| ID | `[:][/]` | `'core.nav'`, `'page:user-settings'`, `'entity-card:catalog/about'` | +| Symbol | `[][]` | `coreNav`, `userSettingsPage`, `catalogAboutEntityCard` | + +When you create a new extension you never provide the ID directly. Instead, you indirectly or directly provide the kind, namespace, and name parts that make up the ID. The kind is always provided by the extension creator function used to create the extension, the only exception is if you use `createExtension` directly. Any extension that is provided by a plugin will by default have its namespace set to the plugin ID, so you generally only need to provide an explicit namespace if you want to override an existing extension. The name is also optional, and primarily used to distinguish between multiple extensions of the same kind and namespace. If a plugin doesn't need to distinguish between different extensions of the same kind, the name can be omitted. + +Example: + +```ts +// This is an extension creator that is used to create an extension of the 'page' kind. +export function createPageExtension(options) { + return createExtension({ + kind: 'page', // Kinds are kebab-case + // ...options + }); +} + +// The namespace is inferred from the plugin ID, in this case 'catalog' +// The final ID for this extension will be 'page:catalog/entity' +const catalogEntityPage = createPageExtension({ + name: 'entity', + // ... +}); + +// The name is omitted, because the catalog plugin only provides a single extension of this kind +// The final ID for this extension will be 'search-result-list-item:catalog' +const catalogSearchResultListItem = createSearchResultListItemExtension({ + // ... +}); + +// Note that the extensions themselves are not exported, only the plugin instance +export const catalogPlugin = createPlugin({ + id: 'catalog', + extensions: [catalogEntityPage, catalogSearchResultListItem /* ... */], +}); +``` + +## Extension Data + +| Description | Pattern | Examples | +| -------------------- | ------------------------------------- | ----------------------------------------------------------------------------- | +| Interface | `ExtensionData` | `SearchResultItemExtensionData` | +| Standalone Reference | `ExtensionDataRef` | `searchResultItemExtensionDataRef` | +| Standalone ID | `.` | `'search.search-result-item'` | +| Grouped Reference | `ExtensionData.` | `coreExtensionData.reactElement`, `catalogFilterExtensionData.functionFilter` | +| Grouped ID | `.` | `'core.react-element'`, `'catalog-filter.function-filter'` | +| Creator Reference | `createExtension.DataRef` | `createGraphiQLEndpointExtension.endpointDataRef` | +| Creator ID | `..` | `'graphiql.graphiql-endpoint.endpoint'` | + +Extension data references can be defined in a couple of different ways, depending on the intended usage, all of which are covered below. + +#### Standalone Extension Data + +The most simple way of defining extension data is a standalone reference. This is useful when you want to export a single reference that isn't closely tied to a specific kind of extension. Because this creates an extra export for each reference, the two other ways of defining extension data are preferred when possible. + +```ts +// A separate named type declaration is only needed for bespoke complex extension data types +export interface SearchResultItemExtensionData { + /* ... */ +} + +export const searchResultItemExtensionDataRef = + createExtensionDataRef( + 'search.search-result-item', + ); +``` + +#### Grouped Extension Data + +This way of defining extension data is similar to the standalone way, but it used when you want to export multiple pieces of grouped extension data for general use. This avoids separate exports and helps make related extension data references easier to discover. The name of the group should generally by the same as the namespace of the exporting package, typically the plugin ID. If the group needs to be more specific it should be prefixed with the namespace. + +```ts +export const coreExtensionData = { + reactElement: createExtensionDataRef('core.react-element'), + routePath: createExtensionDataRef('core.route-path'), +}; +``` + +#### Extension Creator Extension Data + +This is a convenient way of defining extension data when that data is only meant to be produced by a specific extension creator. It avoids additional exports and clearly signals that this piece of data belongs to this particular kind of extension. + +```ts +export function createGraphiQLEndpointExtension(options) { + /* ... */ +} + +// Use a TypeScript namespace to merge the extension data references with the extension creator +export namespace createGraphiQLEndpointExtension { + export const endpointDataRef = createExtensionDataRef( + 'graphiql.graphiql-endpoint.endpoint', + ); +} +``` + +## Extension Inputs + +Extension inputs do not have naming patterns for all types of input, but there are some specific use-cases where we encourage using a recognizable input name. + +| Name | Description | +| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `children` | An extension input that accepts `coreExtensionData.reactElement` data and nothing else, used in a way that is equivalent of the `children` property in React. | diff --git a/docs/frontend-system/architecture/08-references.md b/docs/frontend-system/architecture/08-references.md new file mode 100644 index 0000000000..24a9e5df2a --- /dev/null +++ b/docs/frontend-system/architecture/08-references.md @@ -0,0 +1,17 @@ +--- +id: references +title: Value References +sidebar_label: Value References +# prettier-ignore +description: Value References +--- + +> **NOTE: The new frontend system is in alpha and is only supported by a small number of plugins.** + + diff --git a/docs/frontend-system/building-plugins/testing.md b/docs/frontend-system/building-plugins/testing.md new file mode 100644 index 0000000000..c6621d6584 --- /dev/null +++ b/docs/frontend-system/building-plugins/testing.md @@ -0,0 +1,235 @@ +--- +id: testing +title: Frontend System Testing Plugins +sidebar_label: Testing +# prettier-ignore +description: Testing plugins in the frontend system +--- + +> **NOTE: The new frontend system is in alpha and is only supported by a small number of plugins.** + +# Testing Frontend Plugins + +> NOTE: The new frontend system is in alpha, and some plugins do not yet fully implement it. + +Utilities for testing frontend features and components are available in `@backstage/frontend-test-utils`. + +## Testing React components + +A component can be used for more than one extension, and it should be tested independently of an extension environment. + +Use the `renderInTestApp` helper to render a given component inside a Backstage test app: + +```tsx +import React from 'react'; +import { screen } from '@testing-library/react'; +import { renderInTestApp } from '@backstage/frontend-test-utils'; +import { EntityDetails } from './plugin'; + +describe('Entity details component', () => { + it('should render the entity name and owner', async () => { + await renderInTestApp(); + + await expect( + screen.findByText('The entity "test" is owned by "tools"'), + ).resolves.toBeInTheDocument(); + }); +}); +``` + +To mock [Utility APIs](../architecture/06-utility-apis.md) that are used by your component you can use the `TestApiProvider` to override individual API implementations. In the snippet below, we wrap the component within a `TestApiProvider` in order to mock the catalog client API: + +```tsx +import React from 'react'; +import { screen } from '@testing-library/react'; +import { + renderInTestApp, + TestApiProvider, +} from '@backstage/frontend-test-utils'; +import { stringifyEntityRef } from '@backstage/catalog-model'; +import { CatalogApi, catalogApiRef } from '@backstage/plugin-catalog-react'; +import { EntityDetails } from './plugin'; + +describe('Entity details component', () => { + it('should render the entity name and owner', async () => { + const catalogApiMock = { + async getEntityFacets() { + return { + facets: { + 'relations.ownedBy': [{ count: 1, value: 'group:default/tools' }], + }, + }, + } + } satisfies Partial; + + const entityRef = stringifyEntityRef({ + kind: 'Component', + namespace: 'default', + name: 'test', + }); + + await renderInTestApp( + + + , + ); + + await expect( + screen.findByText('The entity "test" is owned by "tools"'), + ).resolves.toBeInTheDocument(); + }); +}); +``` + +## Testing extensions + +To facilitate testing of frontend extensions, the `@backstage/frontend-test-utils` package provides a tester class which starts up an entire frontend harness, complete with a number of default features. You can then provide overrides for extensions whose behavior you need to adjust for the test run. + +A number of features (frontend extensions and overrides) are also accepted by the tester. Here are some examples of how these facilities can be useful: + +### Single extension + +In order to test an extension in isolation, you simply need to pass it into the tester factory, then call the render method on the returned instance: + +```tsx +import { screen } from '@testing-library/react'; +import { createExtensionTester } from '@backstage/frontend-test-utils'; +import { indexPageExtension } from './plugin'; + +describe('Index page', () => { + it('should render a the index page', () => { + createExtensionTester(indexPageExtension).render(); + + expect(screen.getByText('Index Page')).toBeInTheDocument(); + }); +}); +``` + +### Extension preset + +There are some extensions that rely on other extensions existence, such as a page that links to another page. In that case, you can add more than one extension to the preset of features you want to render in the test, as shown below: + +```tsx +import { screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { createExtensionTester } from '@backstage/frontend-test-utils'; +import { indexPageExtension, detailsPageExtension } from './plugin'; + +describe('Index page', async () => { + it('should link to the details page', () => { + createExtensionTester(indexPageExtension) + // Adding more extensions to the preset being tested + .add(detailsPageExtension) + .render(); + + await expect(screen.findByText('Index Page')).toBeInTheDocument(); + + await userEvent.click(screen.getByRole('link', { name: 'See details' })); + + await expect( + screen.findByText('Details Page'), + ).resolves.toBeInTheDocument(); + }); +}); +``` + +### Mocking apis + +If your extensions requires implementation of APIs that aren't wired up by default, you'll have to add overrides to the preset of features being tested: + +```tsx +import { screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { createApiFactory } from '@backestage/core-plugin-api'; +import { + createExtensionOverrides, + configApiRef, + analyticsApiRef, +} from '@backstage/frontend-plugin-api'; +import { + createExtensionTester, + MockConfigApi, + MockAnalyticsApi, +} from '@backstage/frontend-test-utils'; +import { indexPageExtension } from './plugin'; + +describe('Index page', () => { + it('should capture click events in analytics', async () => { + // Mocking the analytics api implementation + const analyticsApiMock = new MockAnalyticsApi(); + + const analyticsApiOverride = createApiExtension({ + factory: createApiFactory({ + api: analyticsApiRef, + factory: () => analyticsApiMock, + }), + }); + + createExtensionTester(indexPageExtension) + // Overriding the analytics api extension + .add(analyticsApiOverride) + .render(); + + await userEvent.click( + await screen.findByRole('link', { name: 'See details' }), + ); + + expect(analyticsApiMock.getEvents()[0]).toMatchObject({ + action: 'click', + subject: 'See details', + }); + }); +}); +``` + +### Setting configuration + +In the case that your extension can be configured, you can test this capability by passing configuration values as follows: + +```tsx +import { screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { createExtensionTester } from '@backstage/frontend-test-utils'; +import { indexPageExtension, detailsPageExtension } from './plugin'; + +describe('Index page', () => { + it('should accepts a custom title via config', async () => { + createExtensionTester(indexPageExtension, { + // Configuration specific of index page + config: { title: 'Custom index' }, + }) + .add(detailsExtensionPage, { + // Configuration specific of details page + config: { title: 'Custom details' }, + }) + .render({ + // Configuration specific of the instance + config: { + app: { + title: 'Custom app', + }, + }, + }); + + await expect( + screen.findByRole('heading', { name: 'Custom app' }), + ).resolves.toBeInTheDocument(); + + await expect( + screen.findByRole('heading', { name: 'Custom index' }), + ).resolves.toBeInTheDocument(); + + await userEvent.click(screen.getByRole('link', { name: 'See details' })); + + await expect( + screen.findByText('Custom details'), + ).resolves.toBeInTheDocument(); + }); +}); +``` + +That's all for testing features! + +## Missing something? + +If there's anything else you think needs to be covered in the docs or that you think isn't covered by the test utilities, please create an issue in the Backstage repository. You are always welcome to contribute as well! diff --git a/docs/frontend-system/index.md b/docs/frontend-system/index.md index 3970c09f00..201718f6d3 100644 --- a/docs/frontend-system/index.md +++ b/docs/frontend-system/index.md @@ -6,10 +6,10 @@ sidebar_label: Introduction description: The Frontend System --- -> **NOTE: The new frontend system is in a highly experimental phase** +> **NOTE: The new frontend system is in alpha and is only supported by a small number of plugins.** ## Status -The new frontend system is in an experimental phase and we do not recommend any plugins or apps to migrate. +The new frontend system is in alpha, and only a few plugins support the system so far. We do not yet recommend migrating any apps to the new system. If you add support for the new system to your plugin, please do so under a `/alpha` sub-path export. -You can find an example app setup in [the `app-next` package](https://github.com/backstage/backstage/tree/master/packages/app-next). +You can find an example app setup in the [`app-next` package](https://github.com/backstage/backstage/tree/master/packages/app-next). diff --git a/docs/frontend-system/utility-apis/01-index.md b/docs/frontend-system/utility-apis/01-index.md new file mode 100644 index 0000000000..2d0f0a9698 --- /dev/null +++ b/docs/frontend-system/utility-apis/01-index.md @@ -0,0 +1,43 @@ +--- +id: index +title: Utility APIs +sidebar_label: Overview +# prettier-ignore +description: Working with Utility APIs in the New Frontend System +--- + +> **NOTE: The new frontend system is in alpha and is only supported by a small number of plugins.** + +As described [in the architecture section](../architecture/06-utility-apis.md), utility APIs are pieces of shared functionality - interfaces that can be requested by plugins to use. They are defined by a TypeScript interface as well as a reference (an "API ref") used to access its implementation. They can be provided both by plugins and the core framework, and are themselves [extensions](../architecture/03-extensions.md) that can accept inputs, be declaratively configured in your app-config, or transparently be replaced entirely with custom implementations that fulfill the same contract. + +## Creating utility APIs + +> For details, [see the main article](./02-creating.md). + +Backstage apps, plugins, and the core Backstage framework can all expose utility APIs for general use. + +Some are available out of the box, such as the API for reading app configuration. Some are provided by third party plugins, such as the catalog client API that both the catalog itself and your own code can leverage to talk to the catalog backend. Some, you may create yourself and make available inside your Backstage instance for use within your private ecosystem of plugins. + +[The main article](./02-creating.md) describes the process of creating and exposing utility APIs of your own, for sharing functionality or configurability across plugins and apps. + +## Consuming utility APIs + +> For details, [see the main article](./03-consuming.md). + +Once utility APIs are created, there are a few ways that they can be accessed to be consumed. + +Some utility APIs in turn depend on other utility APIs. This powerful composability lets you leverage already-written reusable pieces. In particular, you may want to rely on Backstage's framework-provided APIs e.g. for reading app configuration and many other use cases. Sometimes you request utility APIs inside your React components, e.g. for accessing i18n strings, or emitting analytics events. + +These are described in detail in [the main article](./03-consuming.md) + +## Configuring utility APIs + +> For details, [see the main article](./04-configuring.md). + +Most utility APIs are usable directly without any configuration. But they are proper extensions, and can therefore have their implementations entirely swapped out by your app for advanced use cases. They can also be built with the ability to configured in your app-config, or to have inputs that extend their functionality. + +These cases are all described in [the main article](./04-configuring.md). + +## Migrating from the old frontend system + +If you want to learn how to migrate your own utility APIs from the old frontend system to the new one, that's described in [a dedicated migration guide](./05-migrating.md). diff --git a/docs/frontend-system/utility-apis/02-creating.md b/docs/frontend-system/utility-apis/02-creating.md new file mode 100644 index 0000000000..8935b31b75 --- /dev/null +++ b/docs/frontend-system/utility-apis/02-creating.md @@ -0,0 +1,145 @@ +--- +id: creating +title: Creating Utility APIs +sidebar_label: Creating APIs +# prettier-ignore +description: Creating new utility APIs in your plugins and app +--- + +> **NOTE: The new frontend system is in alpha and is only supported by a small number of plugins.** + +This section describes how to make a Utility API from scratch, or to add configurability and inputs to an existing one. If you are instead interested in migrating an existing Utility API from the old frontend system, check out [the migrating section](./05-migrating.md). + +## Creating the Utility API contract + +The first step toward exposing a utility API is to define its TypeScript contract, as well as an API reference for consumers use to access the implementation. If you want your API to be accessible by other plugins this should be done in [your plugin's `-react` package](../../architecture-decisions/adr011-plugin-package-structure.md), so that it can be imported separately. If you just want to use the API within your own plugin it is fine to place the definition within the plugin itself. In this example, we have an Example plugin that wants to expose a utility API for performing some type of work. + +```tsx title="in @internal/plugin-example-react" +import { createApiRef } from '@backstage/frontend-plugin-api'; + +/** + * The work interface for the Example plugin. + * @public + */ +export interface WorkApi { + /** + * Performs some work. + */ + doWork(): Promise; +} + +/** + * API Reference for {@link WorkApi}. + * @public + */ +export const workApiRef = createApiRef({ + id: 'plugin.example.work', +}); +``` + +Both of these are properly exported publicly from the package, so that consumers can reach them. + +## Providing an extension through your plugin + +The plugin itself now wants to provide this API and its default implementation, in the form of an API extension. Doing so means that when users install the Example plugin, an instance of the Work utility API will also be automatically available in their apps - both to the Example plugin itself, and to others. We do this in the main plugin package, not the `-react` package. + +```tsx title="in @internal/plugin-example" +import { + createApiExtension, + createApiFactory, + createPlugin, + storageApiRef, + StorageApi, +} from '@backstage/frontend-plugin-api'; +import { WorkApi, workApiRef } from '@internal/plugin-example-react'; + +class WorkImpl implements WorkApi { + constructor(options: { storageApiRef: StorageApi }) { + /* TODO */ + } + async doWork() { + /* TODO */ + } +} + +const exampleWorkApi = createApiExtension({ + factory: createApiFactory({ + api: workApiRef, + deps: { storageApi: storageApiRef }, + factory: ({ storageApi }) => { + return new WorkImpl({ storageApi }); + }, + }), +}); + +/** + * The Example plugin. + * @public + */ +export default createPlugin({ + id: 'example', + extensions: [exampleWorkApi], +}); +``` + +For illustration we make a skeleton implementation class and the API extension and factory for it, in the same file. These are not exported to the public surface of the plugin package; only the plugin is, as the default export. Users who install the plugin will now get the utility API automatically as well. + +The code also illustrates how the API factory declares a dependency on another utility API - the core storage API in this case. An instance of that utility API is then provided to the factory function. + +The resulting extension ID of the work API will be the kind `api:` followed by the plugin ID as the namespace, in this case ending up as `api:plugin.example.work`. Check out [the naming patterns doc](../architecture/08-naming-patterns.md) for more information on how this works. You can now use this ID to refer to the API in app-config and elsewhere. + +## Adding configurability + +Here we will describe how to amend a utility API with the capability of having extension config, which is driven by [your app-config](../../conf/writing.md). You do this by giving an extension config schema to your API extension factory function. Let's make the required additions to our original work example API. + +```tsx title="in @internal/plugin-example" +/* highlight-add-next-line */ +import { createSchemaFromZod } from '@backstage/frontend-plugin-api'; + +const exampleWorkApi = createApiExtension({ + /* highlight-add-start */ + api: workApiRef, + configSchema: createSchemaFromZod(z => + z.object({ + goSlow: z.boolean().default(false), + }), + ), + /* highlight-add-end */ + /* highlight-remove-next-line */ + factory: createApiFactory({ + /* highlight-add-next-line */ + factory: ({ config }) => createApiFactory({ + api: workApiRef, + deps: { storageApi: storageApiRef }, + factory: ({ storageApi }) => { + /* highlight-add-start */ + if (config.goSlow) { + /* ... */ + } + /* highlight-add-end */ + }, + }), +}); +``` + +We wanted users to be able to set a `goSlow` extension config parameter for our API instances. So we passed in a `configSchema` to `createApiExtension` which matches that interface. This example builds it using [the zod library](https://zod.dev/). The actual extension config values will then be passed in a type safe manner in to the `factory` which is now a callback, wherein we can do what we wish with them. When changing to the callback form, we also had to add a top level `api: workApiRef` under `createApiExtension`. + +Note that the expression "extension config" as used here, is _not_ the same thing as the `configApi` which gives you access to the full app-config. The extension config discussed here is instead the particular configuration settings given to your utility API instance. This is discussed more [in the Configuring section](./04-configuring.md). + +Note also that the extension config schema contained a default value fo the `goSlow` field. This is an important consideration. You want users of your API to be able to get maximum value out of it, without having to dive deep into how to configure it. For that reason you generally want to provide as many sane defaults as possible, while letting users override them rarely but with purpose, only when called for. If you have an extension config schema without defaults, the framework will refuse to instantiate the utility API on startup unless the user had configured those values explicitly. Since it had a default value, the TypeScript code and interfaces also don't have to defensively allow `undefined` - we know that it'll have either the default value or an overridden value when we start consuming the extension config data. + +## Adding inputs + +Inputs are added to Utility APIs in the same way as other extension types: + +- Declaring a set of `inputs` on your extension +- If needed, create custom extension data types to be used in those inputs +- If needed, export an extension creator function for creating that particular attachment type + +This is a power use case and not very commonly used. + + + +## Next steps + +See [the Consuming section](./03-consuming.md) to see how to consume this new utility API in various ways. If you wish to configure and add inputs to it, check out [the Configuring section](./04-configuring.md). diff --git a/docs/frontend-system/utility-apis/03-consuming.md b/docs/frontend-system/utility-apis/03-consuming.md new file mode 100644 index 0000000000..5c53c8617e --- /dev/null +++ b/docs/frontend-system/utility-apis/03-consuming.md @@ -0,0 +1,69 @@ +--- +id: consuming +title: Consuming Utility APIs +sidebar_label: Consuming APIs +# prettier-ignore +description: Consuming utility APIs +--- + +> **NOTE: The new frontend system is in alpha and is only supported by a small number of plugins.** + +All of the utility API extensions that were passed into your app through installed plugins, get instantiated and configured in the right order by the framework, and are then made available for consumption. You can interact with these instances in the following ways. + +## Via React hooks + +The most common consumption pattern for utility APIs is to call the `useApi` hook inside React components to get an implementation via its API ref. This applies whether it was originally provided from the core framework or from a plugin. + +```tsx +import { useApi, configApiRef } from '@backstage/frontend-plugin-api'; + +const MyComponent = () => { + const configApi = useApi(configApiRef); + const title = configApi.getString('app.title'); + // ... +}; +``` + +The `useApi` hook always returns a value, or throws an exception if the API ref could not be resolved to a registered implementation. For advanced use cases, where you explicitly want to optionally request a utility API that may or may not have been provided at runtime, you can use the underlying `useApiHolder` hook instead. + +```tsx +import { useApiHolder, configApiRef } from '@backstage/frontend-plugin-api'; + +const MyComponent = () => { + const apis = useApiHolder(); + const configApi = apis.get(configApiRef); // may return undefined + if (configApi) { + const title = configApi.getString('app.title'); + // ... + } +}; +``` + +## Via dependencies + +Your utility APIs can depend on other utility APIs in their factories. You do this by declaring `deps` on your `createApiFactory`, and reading the outcome in your `factory`. + +```tsx +import { + configApiRef, + createApiExtension, + createApiFactory, + discoveryApiRef, +} from '@backstage/frontend-plugin-api'; +import { MyApiImpl } from './MyApiImpl'; + +const myApi = createApiExtension({ + factory: createApiFactory({ + api: myApiRef, + deps: { + configApi: configApiRef, + discoveryApi: discoveryApiRef, + }, + factory: ({ configApi, discoveryApi }) => { + return new MyApiImpl({ configApi, discoveryApi }); + }, + }), +}); +``` + +Note how the `deps` section essentially assigns free-form names that you choose, to API refs. Here we for example map `configApiRef` to the name `configApi`, but that's just a convention. The framework will ensure that all of those deps get instantiated and passed into your `factory` function with the same set of names as your `deps`. At that point, `configApi` refers to an actual functioning instance of that API ref. diff --git a/docs/frontend-system/utility-apis/04-configuring.md b/docs/frontend-system/utility-apis/04-configuring.md new file mode 100644 index 0000000000..7acf23decf --- /dev/null +++ b/docs/frontend-system/utility-apis/04-configuring.md @@ -0,0 +1,76 @@ +--- +id: configuring +title: Configuring Utility APIs +sidebar_label: Configuring +# prettier-ignore +description: Configuring, extending, and overriding utility APIs +--- + +> **NOTE: The new frontend system is in alpha and is only supported by a small number of plugins.** + +Utility APIs are extensions and can therefore optionally be amended with configurability, as well as inputs that other extensions attach themselves to. This section describes how to make use of that as a consumer of such utility APIs. + +## Configuring + +To configure your Utility API extension, first you'll need to know its ID. That ID is formed from the API ref ID; check [the naming patterns docs](../architecture/08-naming-patterns.md) for details. + +Our example work API from [the creating section](./02-creating.md) would have the ID `api:plugin.example.work`. You configure it and all other extensions under the `app.extensions` section of your app-config. + +```yaml title="in e.g. app-config.yaml or app-config.production.yaml" +app: + extensions: + - api:plugin.example.work: + config: + goSlow: false + - # ... other extensions +``` + +It's important to note that the `extensions` are a list (mind the initial `-`), and that the `api:plugin.example.work` entry is an object such that the `config` key needs to be indented below it. If you do not get those two pieces right, the application may not start up correctly. + +The extension config schema will tell you what parameters it supports. Here we override the `goSlow` extension config value, which replaces the default. + +## Attaching extensions to inputs + +Like with other extension types, you add input attachments to a Utility API by declaring the `attachTo` section of that attachment to point to the Utility APIs ID and input name. + +Well written input-enabled extension often have extension creator functions that help you make such attachments. Those functions typically set the `attachTo` section correctly on your behalf so that you don't have to figure them out. + +## Replacing a Utility API implementation + +Like with other extension types, you replace Utility APIs with your own custom implementation using [extension overrides](../architecture/05-extension-overrides.md). + +```tsx title="in your app" +/* highlight-add-start */ +import { createExtensionOverrides } from '@backstage/frontend-plugin-api'; + +class CustomWorkImpl implements WorkApi { + /* ... */ +} + +const myOverrides = createExtensionOverrides({ + extensions: [ + createApiExtension({ + api: workApiRef, + factory: () => + createApiFactory({ + api: workApiRef, + factory: () => new CustomWorkImpl(), + }), + }), + ], +}); +/* highlight-add-end */ + +// Remember to pass the overrides to your createApp +export default createApp({ + features: [ + // ... other features + /* highlight-add-next-line */ + myOverrides, + ], +}); +``` + +In this example the overriding extension is kept minimal, but just like any other extension it can also have `deps`, configurability, and inputs. Check out [the Creating section](./02-creating.md) for more details about that. + +When you create a replacement extension, in general you may want to mimic its extension config schema or input shapes where applicable. This makes it an easier thing to slot in to an app, since it'll be responding to extensibility the same way as the original one did. diff --git a/docs/frontend-system/utility-apis/05-migrating.md b/docs/frontend-system/utility-apis/05-migrating.md new file mode 100644 index 0000000000..a81dc796ac --- /dev/null +++ b/docs/frontend-system/utility-apis/05-migrating.md @@ -0,0 +1,126 @@ +--- +id: migrating +title: Migrating Utility APIs from the old frontend system +sidebar_label: Migrating +# prettier-ignore +description: Migrating Utility APIs from the old frontend system +--- + +> **NOTE: The new frontend system is in alpha and is only supported by a small number of plugins.** + +If you are migrating your plugins or app over from the old frontend system, there are a few things to keep in mind in regards to utility APIs. + +## Overview + +- Migrate your repo overall to the latest release of Backstage +- Follow the plugin migration guide +- Optionally change your package dependencies and code from `core-*-api` to `frontend-*-api` +- Keep the TypeScript interface and API ref exported as they were, except possibly reconsidering the choice of ID of the latter +- Wrap the old API factory call in an extension using `createApiExtension` +- Make sure that this extension is referenced by your migrated plugin + +## Prerequisites + +This guide assumes that you first [upgrade your repo](../../getting-started/keeping-backstage-updated.md) to the latest release of Backstage. This ensures that you do not have to fight several types of incompatibilities and updates at the same time. + +## Dependency changes + +In this article we will discuss some old interfaces that you used to import from the `@backstage/core-plugin-api` package. Those are now generally lifted over to `@backstage/frontend-plugin-api`, next to the new interfaces that are specific to the new frontend system. If you want to, you can already update your `package.json` and code imports to only use the new plugin API, but for the time being you don't have to. The old core exports will continue to work for the foreseeable future. + +To at least get access to the new interfaces, you'll need to run the following command. Note that it's just an example! It refers to `plugins/example`, which you'll have to change to the actual folder name that your package to migrate is in. + +```bash title="from your repo root" +yarn --cwd plugins/example add @backstage/frontend-plugin-api +``` + +## React package interface and ref changes + +Let's begin with [your `-react` package](../../architecture-decisions/adr011-plugin-package-structure.md). The act of exporting TypeScript interfaces and API refs have not changed from the old system. You can typically keep those as-is. For illustrative purposes, this is an example of an interface and its API ref: + +```tsx title="in @internal/plugin-example-react" +import { createApiRef } from '@backstage/frontend-plugin-api'; + +/** + * Performs some work. + * @public + */ +export interface WorkApi { + doWork(): Promise; +} + +/** + * The work interface for the Example plugin. + * @public + */ +export const workApiRef = createApiRef({ + id: 'plugin.example.work', +}); +``` + +In this example, the plugin ID already follows the common naming convention. If it doesn't, you may want to consider renaming that ID at this point. Don't worry, this won't hurt consumers in the old frontend system since the ID is mostly used for debugging purposes there. In the new system, it's much more important and appears in app-config files and similar. + +Note at the top of the file that it uses the updated import from `@backstage/frontend-plugin-api` that we migrated in the previous section, instead of the old `@backstage/core-plugin-api`. + +## Plugin package changes + +Now let's turn to the main plugin package where the plugin itself is exported. You will probably already have a `createPlugin` call in here. Before we changed the `core-plugin-api` imports it'll have looked somewhat similar to the following: + +```tsx title="in @internal/plugin-example, NOTE THIS IS LEGACY CODE" +import { + storageApiRef, + createPlugin, + createApiFactory, +} from '@backstage/core-plugin-api'; +import { workApiRef } from '@internal/plugin-example-react'; +import { WorkImpl } from './WorkImpl'; + +const exampleWorkApi = createApiFactory({ + api: workApiRef, + deps: { storageApi: storageApiRef }, + factory: ({ storageApi }) => new WorkImpl({ storageApi }), +}); + +/** @public */ +export const catalogPlugin = createPlugin({ + id: 'example', + apis: [exampleWorkApi], +}); +``` + +The major changes we'll make are + +- Optionally change the old imports to the new package as per the top section of this guide +- Wrap the existing API factory in a `createApiExtension` +- Change to the new version of `createPlugin` which exports this extension +- Change the plugin export to be the default instead + +The end result, after simplifying imports and cleaning up a bit, might look like this: + +```tsx title="in @internal/plugin-example" +import { + storageApiRef, + createPlugin, + createApiFactory, + createApiExtension, +} from '@backstage/frontend-plugin-api'; +import { workApiRef } from '@internal/plugin-example-react'; +import { WorkImpl } from './WorkImpl'; + +const exampleWorkApi = createApiExtension({ + factory: createApiFactory({ + api: workApiRef, + deps: { storageApi: storageApiRef }, + factory: ({ storageApi }) => new WorkImpl({ storageApi }), + }), +}); + +/** @public */ +export default createPlugin({ + id: 'example', + extensions: [exampleWorkApi], +}); +``` + +## Further work + +Since utility APIs are now complete extensions, you may want to take a bigger look at how they used to be used, and what the new frontend system offers. You may for example consider [adding configurability or inputs](./02-creating.md) to your API, if that makes sense for your current application. diff --git a/docs/getting-started/app-custom-theme.md b/docs/getting-started/app-custom-theme.md index 3b042d5eb4..d6a13ca6e3 100644 --- a/docs/getting-started/app-custom-theme.md +++ b/docs/getting-started/app-custom-theme.md @@ -484,3 +484,7 @@ You can see more ways to use this in the [Storybook Sidebar examples](https://ba In addition to a custom theme, a custom logo, you can also customize the homepage of your app. Read the full guide on the [next page](homepage.md). + +## Migrating to Material UI v5 + +We now support Material UI v5 in Backstage. Check out our [migration guide](../tutorials/migrate-to-mui5.md) to get started. diff --git a/docs/getting-started/configuration.md b/docs/getting-started/configuration.md index 17f07811c0..5d797ecb4b 100644 --- a/docs/getting-started/configuration.md +++ b/docs/getting-started/configuration.md @@ -134,7 +134,7 @@ links: There are multiple authentication providers available for you to use with Backstage, feel free to follow -[the instructions for adding authentication](../auth/). +[the instructions for adding authentication](../auth/index.md). For this tutorial we choose to use GitHub, a free service most of you might be familiar with. For other options, see @@ -205,7 +205,7 @@ Restart Backstage from the terminal, by stopping it with `Control-C`, and starti To learn more about Authentication in Backstage, here are some docs you could read: -- [Authentication in Backstage](../auth/) +- [Authentication in Backstage](../auth/index.md) - [Using organizational data from GitHub](../integrations/github/org.md) ### Setting up a GitHub Integration @@ -254,7 +254,7 @@ integrations: Some helpful links, for if you want to learn more about: -- [Other available integrations](../integrations/) +- [Other available integrations](../integrations/index.md) - [Using GitHub Apps instead of a Personal Access Token](../integrations/github/github-apps.md#docsNav) ### Explore what we've done so far @@ -275,8 +275,8 @@ otherwise something went terribly wrong. ![Software template main screen, with a blue button to add an existing component](../assets/getting-started/b-existing-1.png) -- As URL use `https://github.com/backstage/demo/blob/master/catalog-info.yaml`. - This is used by our [demo site](https://demo.backstage.io). +- As URL use `https://github.com/backstage/backstage/blob/master/catalog-info.yaml`. + This is used in our [demo site](https://demo.backstage.io) catalog. ![Register a new component wizard, asking for an URL to the existing component YAML file](../assets/getting-started/b-existing-2.png) @@ -285,11 +285,16 @@ otherwise something went terribly wrong. ![Register a new component wizard, showing the metadata for the component YAML we use in this tutorial](../assets/getting-started/b-existing-3.png) - You should receive a message that your entities have been added. -- If you go back to `Home`, you should be able to find `demo`. You should be +- If you go back to `Home`, you should be able to find `backstage`. You should be able to click it and see the details ## Create a new component using a software template +> Note: if you're running Backstage with Node 20 or later, you'll need to pass the flag `--no-node-snapshot` to Node in order to +> use the templates feature. +> One way to do this is to specify the `NODE_OPTIONS` environment variable before starting Backstage: +> `export NODE_OPTIONS=--no-node-snapshot` + - Go to `create` and choose to create a website with the `Example Node.js Template` - Type in a name, let's use `tutorial` and click `Next Step` diff --git a/docs/getting-started/configure-app-with-plugins.md b/docs/getting-started/configure-app-with-plugins.md index b44f7877a7..5611117636 100644 --- a/docs/getting-started/configure-app-with-plugins.md +++ b/docs/getting-started/configure-app-with-plugins.md @@ -15,7 +15,7 @@ The following steps assume that you have to it. We are using the -[CircleCI](https://github.com/backstage/backstage/blob/master/plugins/circleci/README.md) +[CircleCI](https://github.com/CircleCI-Public/backstage-plugin/tree/main/plugins/circleci) plugin in this example, which is designed to show CI/CD pipeline information attached to an entity in the software catalog. @@ -23,7 +23,7 @@ to an entity in the software catalog. ```bash # From your Backstage root directory - yarn add --cwd packages/app @backstage/plugin-circleci + yarn add --cwd packages/app @circleci/backstage-plugin ``` Note the plugin is added to the `app` package, rather than the root @@ -38,7 +38,7 @@ to an entity in the software catalog. import { EntityCircleCIContent, isCircleCIAvailable, - } from '@backstage/plugin-circleci'; + } from '@circleci/backstage-plugin'; /* highlight-add-end */ const cicdContent = ( diff --git a/docs/getting-started/index.md b/docs/getting-started/index.md index cd5a1725c9..11de12feb9 100644 --- a/docs/getting-started/index.md +++ b/docs/getting-started/index.md @@ -26,7 +26,7 @@ you to use the [Contributors](https://github.com/backstage/backstage/blob/master On MacOS, you will want to have run `xcode-select --install` to get the XCode command line build tooling in place. - An account with elevated rights to install the dependencies - `curl` or `wget` installed -- Node.js [Active LTS Release](https://nodejs.org/en/blog/release/) installed using one of these +- Node.js [Active LTS Release](https://nodejs.org/en/about/previous-releases) installed using one of these methods: - Using `nvm` (recommended) - [Installing nvm](https://github.com/nvm-sh/nvm#install--update-script) diff --git a/docs/integrations/aws-s3/discovery.md b/docs/integrations/aws-s3/discovery.md index 4a2b953bc9..ceb780141f 100644 --- a/docs/integrations/aws-s3/discovery.md +++ b/docs/integrations/aws-s3/discovery.md @@ -32,7 +32,7 @@ catalog: bucketName: sample-bucket prefix: prefix/ # optional region: us-east-2 # optional, uses the default region otherwise - schedule: # optional; same options as in TaskScheduleDefinition + 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 @@ -52,7 +52,7 @@ catalog: bucketName: sample-bucket prefix: prefix/ # optional region: us-east-2 # optional, uses the default region otherwise - schedule: # optional; same options as in TaskScheduleDefinition + 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 @@ -79,12 +79,6 @@ const builder = await CatalogBuilder.create(env); builder.addEntityProvider( AwsS3EntityProvider.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, }), ); diff --git a/docs/integrations/azure/discovery.md b/docs/integrations/azure/discovery.md index 7b91308b56..3b25a9ac75 100644 --- a/docs/integrations/azure/discovery.md +++ b/docs/integrations/azure/discovery.md @@ -71,7 +71,7 @@ The parameters available are: - **`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`** _(optional)_: +- **`schedule`**: - **`frequency`**: How often you want the task to run. The system does its best to avoid overlapping invocations. - **`timeout`**: diff --git a/docs/integrations/azure/org.md b/docs/integrations/azure/org.md index c4968b0399..061baf7301 100644 --- a/docs/integrations/azure/org.md +++ b/docs/integrations/azure/org.md @@ -34,6 +34,9 @@ catalog: 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`. @@ -52,11 +55,7 @@ export default async function createPlugin( builder.addEntityProvider( MicrosoftGraphOrgEntityProvider.fromConfig(env.config, { logger: env.logger, - schedule: env.scheduler.createScheduledTaskRunner({ - frequency: { hours: 1 }, - timeout: { minutes: 50 }, - initialDelay: { seconds: 15 }, - }), + scheduler: env.scheduler, }), ); /* highlight-add-end */ diff --git a/docs/integrations/bitbucketCloud/discovery.md b/docs/integrations/bitbucketCloud/discovery.md index 6e1533dea0..53315a4c48 100644 --- a/docs/integrations/bitbucketCloud/discovery.md +++ b/docs/integrations/bitbucketCloud/discovery.md @@ -49,19 +49,6 @@ export default async function createPlugin( } ``` -Alternatively to the config-based schedule, you can use - -```ts -/* highlight-remove-next-line */ -scheduler: env.scheduler, -/* highlight-add-start */ -schedule: env.scheduler.createScheduledTaskRunner({ - frequency: { minutes: 30 }, - timeout: { minutes: 3 }, -}), -/* highlight-add-end */ -``` - ### Installation with Events Support Please follow the installation instructions at @@ -131,7 +118,7 @@ catalog: filters: # optional projectKey: '^apis-.*$' # optional; RegExp repoSlug: '^service-.*$' # optional; RegExp - schedule: # optional; same options as in TaskScheduleDefinition + 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 @@ -153,7 +140,7 @@ catalog: Regular expression used to filter results based on the project key. - **`repoSlug`** _(optional)_: Regular expression used to filter results based on the repo slug. -- **`schedule`** _(optional)_: +- **`schedule`**: - **`frequency`**: How often you want the task to run. The system does its best to avoid overlapping invocations. - **`timeout`**: diff --git a/docs/integrations/bitbucketServer/discovery.md b/docs/integrations/bitbucketServer/discovery.md index 05d0510553..ad59006ff1 100644 --- a/docs/integrations/bitbucketServer/discovery.md +++ b/docs/integrations/bitbucketServer/discovery.md @@ -38,12 +38,6 @@ export default async function createPlugin( builder.addEntityProvider( BitbucketServerEntityProvider.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, }), ); @@ -69,7 +63,7 @@ catalog: filters: # optional projectKey: '^apis-.*$' # optional; RegExp repoSlug: '^service-.*$' # optional; RegExp - schedule: # optional; same options as in TaskScheduleDefinition + 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 @@ -87,7 +81,7 @@ catalog: Regular expression used to filter results based on the project key. - **`repoSlug`** _(optional)_: Regular expression used to filter results based on the repo slug. -- **`schedule`** _(optional)_: +- **`schedule`**: - **`frequency`**: How often you want the task to run. The system does its best to avoid overlapping invocations. - **`timeout`**: diff --git a/docs/integrations/gerrit/discovery.md b/docs/integrations/gerrit/discovery.md index 5d822effb5..ee843d2454 100644 --- a/docs/integrations/gerrit/discovery.md +++ b/docs/integrations/gerrit/discovery.md @@ -26,18 +26,11 @@ Then add the plugin to the plugin catalog `packages/backend/src/plugins/catalog. ```ts /* packages/backend/src/plugins/catalog.ts */ import { GerritEntityProvider } from '@backstage/plugin-catalog-backend-module-gerrit'; -import { Duration } from 'luxon'; const builder = await CatalogBuilder.create(env); /** ... other processors and/or providers ... */ builder.addEntityProvider( GerritEntityProvider.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, }), ); @@ -57,7 +50,7 @@ catalog: host: gerrit-your-company.com branch: master # Optional query: 'state=ACTIVE&prefix=webapps' - schedule: # optional; same options as in TaskScheduleDefinition + schedule: # supports cron, ISO duration, "human duration" as used in code frequency: { minutes: 30 } # supports ISO duration, "human duration" as used in code diff --git a/docs/integrations/github/discovery.md b/docs/integrations/github/discovery.md index 46d59cbf1b..3c3d90d6e9 100644 --- a/docs/integrations/github/discovery.md +++ b/docs/integrations/github/discovery.md @@ -40,12 +40,6 @@ export default async function createPlugin( builder.addEntityProvider( GithubEntityProvider.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, }), ); @@ -85,12 +79,6 @@ export default async function createPlugin( /* highlight-add-start */ const githubProvider = GithubEntityProvider.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, }); env.eventBroker.subscribe(githubProvider); @@ -122,7 +110,7 @@ catalog: filters: branch: 'main' # string repository: '.*' # Regex - schedule: # optional; same options as in TaskScheduleDefinition + 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 @@ -213,7 +201,7 @@ This provider supports multiple organizations via unique provider IDs. 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`** _(optional)_: +- **`schedule`**: - **`frequency`**: How often you want the task to run. The system does its best to avoid overlapping invocations. - **`timeout`**: @@ -229,13 +217,12 @@ GitHub [rate limits](https://docs.github.com/en/rest/overview/resources-in-the-r 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 `packages/backend/src/plugins/catalog.ts` file: +rate limiting. You can change the refresh frequency of the catalog in your `app-config.yaml` file by controlling the `schedule`. -```typescript -schedule: env.scheduler.createScheduledTaskRunner({ - frequency: { minutes: 35 }, - timeout: { minutes: 30 }, -}), +```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. diff --git a/docs/local-dev/cli-build-system.md b/docs/local-dev/cli-build-system.md index 7bb4918d47..51c328c871 100644 --- a/docs/local-dev/cli-build-system.md +++ b/docs/local-dev/cli-build-system.md @@ -295,7 +295,8 @@ Webpack configuration itself varies very little between the frontend development and production bundling, so we'll dive more into the configuration in the production section below. The main differences are that `process.env.NODE_ENV` is set to `'development'`, minification is disabled, cheap source maps are used, -and [React Hot Loader](https://github.com/gaearon/react-hot-loader) is enabled. +and [React Refresh](https://github.com/pmmmwh/react-refresh-webpack-plugin#readme) +is enabled. If you prefer to run type checking and linting as part of the Webpack process, you can enable usage of the @@ -589,22 +590,25 @@ For your productivity working with unit tests it's quite essential to have your A complete launch configuration for VS Code debugging may look like this: -```json +```jsonc { "type": "node", - "name": "vscode-jest-tests", + "name": "vscode-jest-tests.v2", "request": "launch", + "args": [ + "repo", + "test", + "--runInBand", + "--watchAll=false", + "--testNamePattern", + "${jest.testNamePattern}", + "--runTestsByPath", + "${jest.testFile}" + ], "console": "integratedTerminal", "internalConsoleOptions": "neverOpen", "disableOptimisticBPs": true, - "program": "${workspaceFolder}/node_modules/.bin/jest", - "cwd": "${workspaceFolder}", - "args": [ - "--config", - "node_modules/@backstage/cli/config/jest.js", - "--runInBand", - "--watchAll=false" - ] + "program": "${workspaceFolder}/node_modules/.bin/backstage-cli" } ``` diff --git a/docs/local-dev/debugging.md b/docs/local-dev/debugging.md index d2a4d02db0..39981f2e54 100644 --- a/docs/local-dev/debugging.md +++ b/docs/local-dev/debugging.md @@ -47,3 +47,44 @@ The resulting log should now have more information available for debugging: [1] 2023-04-12T00:51:44.118Z search info Collating documents for tools succeeded type=plugin documentType=tools [1] 2023-04-12T00:51:44.119Z backstage debug task: search_index_tools will next occur around 2023-04-11T21:01:44.118-04:00 type=taskManager task=search_index_tools ``` + +## Debugger + +### VSCode + +In your `launch.json`, add a new entry with the following, + +```jsonc +{ + "name": "Start Backend", + "type": "node", + "request": "launch", + "args": [ + "package", + "start" + ], + "cwd": "${workspaceFolder}/packages/backend", + "program": "${workspaceFolder}/node_modules/.bin/backstage-cli", + "skipFiles": [ + "/**" + ], + "console": "integratedTerminal" +}, +``` + +### WebStorm + +This section describes the process for enabling run configurations for Backstage in WebStorm. +Run configurations enable the use of debugging functionality such as steppers and breakpoints. + +1. Select `Edit Configurations` in the `Run` dropdown menu. Click the plus sign to add a new + configuration, then select `Node.js`. +2. In `Working directory`, input `{PROJECT_DIR}/packages/backend`. + Replace `{PROJECT_DIR}` with the path to your Backstage repo. +3. In `JavaScript file`, input `{PROJECT_DIR}/node_modules/@backstage/cli/bin/backstage-cli`. + Replace `{PROJECT_DIR}` with the path to your Backstage repo. +4. In `Application parameters`, input `package start`. +5. Optionally, for `Environment Variables`, input `LOG_LEVEL=debug`. +6. Click `Apply` to save the changes. +7. With the newly-created configuration selected, use the `Run` or `Debug` icons on the + toolbar to execute the newly created configuration. diff --git a/docs/openapi/01-getting-started.md b/docs/openapi/01-getting-started.md new file mode 100644 index 0000000000..eb3b1c1209 --- /dev/null +++ b/docs/openapi/01-getting-started.md @@ -0,0 +1,115 @@ +--- +id: 01-getting-started +title: Schema-first plugins with OpenAPI (Experimental) +description: Tutorial on how to start using OpenAPI schema-first development in your plugins. +--- + +# Getting started with OpenAPI in your Backstage plugins + +Target Audience: Plugin developers + +Difficulty: Medium + +## Goal + +The goal of this tutorial is to give you exposure to tools that more tightly couple your OpenAPI specification and plugin lifecycle. The tools we'll be presenting were created by the OpenAPI tooling project area and allow you to create, + +1. A typed `express` router that provides strong guardrails during development for input and output values. Support for query, path parameters and request body, as well as experimental support for headers and cookies. +2. An auto-generated client to interact with your plugin's backend. Support for all request types, parameters and body, as well as return types. Provides a low-level interface to allow more customization by higher level libraries. +3. Validation and verification tooling to ensure your API and specification stay in sync. Includes testing against your unit tests. + +## Prerequisites + +### Technical Knowledge + +This tutorial assumes that you're already familiar with the following, + +1. How to build a Backstage plugin. +2. `Express.js` and `Typescript` +3. OpenAPI 3.0 schemas + +### Setting up + +There are two required npm packages before we start, + +1. `@backstage/repo-tools`, this package contains all OpenAPI related commands for your plugins. We will be using this throughout the tutorial. +2. `@opticdev/optic`, this package is a dependency of `@backstage/repo-tools` but is only required for OpenAPI related commands. + +You should install both of the above packages in the _root_ of your workspace. + +## Storing your OpenAPI specification + +You should create a new folder, `src/schema` in your backend plugin to store your OpenAPI (and any other) specifications. For example, if you're adding a specification to the catalog plugin, you would add a `src/schema` folder to `plugins/catalog-backend`, making a `plugins/catalog-backend/src/schema` directory. This directory should have an `openapi.yaml` file inside. + +> Currently, only the `.yaml` extension is supported, not `.yml`. + +## Generating a typed express router from a spec + +Run `yarn backstage-repo-tools schema openapi generate `. This will create an `openapi.generated.ts` file in the `src/schema` directory that contains the OpenAPI schema as well as a generated express router with types. + +Use it like so, update your `router.ts` or `createRouter.ts` file with the following content, + +```diff ++ import { createOpenApiRouter } from '../schema/openapi.generated'; +- import Router from 'express-promise-router'; + +... +export async function createRouter( + options: RouterOptions, +): Promise { ++ const router = await createOpenApiRouter(); +- const router = Router(); +``` + +## Generating a typed client from a spec + +Run `yarn backstage-repo-tools schema openapi generate-client --input-spec /src/schema/openapi.yaml --output-directory `. `` should match the same backend plugin we've been using so far. `` is a new directory and npm package that you should create. The general pattern is `plugins/-client`. + +The generated client will have a directory `src/generated` that exports a `DefaultApiClient` class and all generated types. You can use the client like so, + +```diff ++ import { DefaultApiClient } from './generated'; + +export class CatalogClient implements CatalogApi { ++ private readonly apiClient: DefaultApiClient; + + constructor(options: { + discoveryApi: { getBaseUrl(pluginId: string): Promise }; + fetchApi?: { fetch: typeof fetch }; + }) { ++ this.apiClient = new DefaultApiClient(options); + } + ... +``` + +usage of the types will depend on your type names. + +You should be able to use the generated `DefaultApi.client.ts` file out of the box for your API needs. For full customization, you can use a wrapper around the generated client to adjust the flavor of your clients. + +For more information, see [the docs](./generate-client.md). + +## Validating your spec with test traffic + +Add the following lines to your `createRouter.test.ts` or `router.test.ts` file, + +```diff ++ import { wrapInOpenApiTestServer } from '@backstage/backend-openapi-utils'; ++ import { Server } from 'http'; + +... + +describe('createRouter', () => { +- let app: express.Express; ++ let app: express.Express | Server; + +... + +- app = express().use(router); ++ app = wrapInOpenApiTestServer(express().use(router)); +``` + +This adds a wrapper around the express server that allows it to reroute traffic for `supertest`. Run `yarn backstage-repo-tools schema openapi init` to create some required config files. Now, when you run `yarn backstage-repo-tools schema openapi test` your schema will now be tested against your test data. Any errors will be reported. + +Our command is a small wrapper over [`Optic`](https://github.com/opticdev/optic) which does all of the heavy lifting. + +For more information, see [the docs](./test-case-validation.md). diff --git a/docs/openapi/generate-client.md b/docs/openapi/generate-client.md new file mode 100644 index 0000000000..4afa7d64d7 --- /dev/null +++ b/docs/openapi/generate-client.md @@ -0,0 +1,31 @@ +--- +id: generate-client +title: Generate a client from your OpenAPI spec +description: Documentation on how to create a client for a given OpenAPI spec +--- + +## How to generate a client with `repo-tools schema openapi generate-client`? + +### Prerequisites + +1. Add your plugin ID as the last `servers` item, like this, + +```yaml +servers: + # first value, used for OpenAPI router validation. + - url: / + + # final value, pluginId. + - url: catalog +``` + +2. Find or create a new plugin to house your new generated client. Currently, we do not support generating an entirely new plugin and instead just generate client files. + +### Generating your client + +1. Run `yarn backstage-repo-tools schema openapi generate-client --input-spec --output-directory `. This will create a new folder in `/src/generated` to house the generated content. +2. You should use the generated files as follows, + +- `apis/DefaultApi.client.ts` - this is the client that you should use. It has types for all of the various operations on your API. +- `models/*` - These are the types generated from your OpenAPI file, ideally you should not need to use these directly and can instead use the inferred types from `apis/DefaultApi.client.ts`. +- everything else is directory specific and shouldn't be touched. diff --git a/docs/openapi/test-case-validation.md b/docs/openapi/test-case-validation.md index 50686b5ba0..0d93b6d5b5 100644 --- a/docs/openapi/test-case-validation.md +++ b/docs/openapi/test-case-validation.md @@ -1,3 +1,9 @@ +--- +id: test-case-validation +title: Validate your OpenAPI spec against test data +description: Documentation on how to use the `schema openapi test` command. +--- + ## OpenAPI Validation using Test Cases This is primarily performed by `backstage-repo-tools schema openapi test`. Any errors found in the generated specs can be either diff --git a/docs/overview/versioning-policy.md b/docs/overview/versioning-policy.md index c38ba404b5..2ff3588af1 100644 --- a/docs/overview/versioning-policy.md +++ b/docs/overview/versioning-policy.md @@ -158,7 +158,7 @@ package export. The Backstage project uses [Node.js](https://nodejs.org/) for both its development tooling and backend runtime. In order for expectations to be clear we use the -following schedule for determining the [Node.js releases](https://nodejs.org/en/about/releases/) that we support: +following schedule for determining the [Node.js releases](https://nodejs.org/en/about/previous-releases) that we support: - At any given point in time we support exactly two adjacent even-numbered releases of Node.js, for example v12 and v14. @@ -182,3 +182,11 @@ The TypeScript release cadence is roughly every three months. An important aspec Our policy is to support the last 3 TypeScript versions, for example 4.8, 4.9, and 5.0. Converted to time, this means that we typically support the TypeScript version from the last six to nine months, depending on where in the TypeScript release window we are. This policy applies as a snapshot at the time of any given Backstage release, new TypeScript releases only apply to the following Backstage main-line release, not to the current one. For anyone maintaining their own Backstage project, this means that you should strive to bump to the latest TypeScript version at least every 6 months, or you may encounter breakages as you upgrade Backstage packages. If you encounter any issues in doing so, please [file an issue in the main Backstage repository](https://github.com/backstage/backstage/issues/new/choose), as per this policy we should always support the latest version. In order to ensure that we do not start using new TypeScript features too early, the Backstage project itself uses the version at the beginning of the currently supported window, in the above example that would be version 4.8. + +## PostgreSQL Releases + +The Backstage project recommends and supports using PostgreSQL for persistent storage. + +The PostgreSQL [versioning policy](https://www.postgresql.org/support/versioning/) is to release a new major version every year with new features which is then supported for 5 years after its initial release. + +Our policy mirrors the PostgreSQL versioning policy - we will support the last 5 major versions. We will also test the newest and oldest versions in that range. For example, if the range we support is currently 12 to 16, then we would only test 12 and 16 explicitly. diff --git a/docs/permissions/custom-rules.md b/docs/permissions/custom-rules.md index cab138ed9e..c0f4e3e156 100644 --- a/docs/permissions/custom-rules.md +++ b/docs/permissions/custom-rules.md @@ -8,9 +8,17 @@ For some use cases, you may want to define custom [rules](./concepts.md#resource ## Define a custom rule -Plugins should export a rule factory that provides type-safety that ensures compatibility with the plugin's backend. The catalog plugin exports `createCatalogPermissionRule` from `@backstage/plugin-catalog-backend/alpha` for this purpose. Note: the `/alpha` path segment is temporary until this API is marked as stable. For this example, we'll define the rule in `packages/backend/src/plugins/permission.ts`, but you can put it anywhere that's accessible by your `backend` package. +Plugins should export a rule factory that provides type-safety that ensures compatibility with the plugin's backend. The catalog plugin exports `createCatalogPermissionRule` from `@backstage/plugin-catalog-backend/alpha` for this purpose. Note: the `/alpha` path segment is temporary until this API is marked as stable. For this example, we'll define the rule and create a condition in `packages/backend/src/plugins/permission.ts`. + +We use Zod in our example below. To install, run: + +```bash +yarn workspace backend add zod +``` ```typescript title="packages/backend/src/plugins/permission.ts" +... + import type { Entity } from '@backstage/catalog-model'; import { createCatalogPermissionRule } from '@backstage/plugin-catalog-backend/alpha'; import { createConditionFactory } from '@backstage/plugin-permission-node'; @@ -41,42 +49,55 @@ export const isInSystemRule = createCatalogPermissionRule({ }); const isInSystem = createConditionFactory(isInSystemRule); + +... ``` For a more detailed explanation on defining rules, refer to the [documentation for plugin authors](./plugin-authors/03-adding-a-resource-permission-check.md#adding-support-for-conditional-decisions). -## Provide the rule during plugin setup - -Now that we have a custom rule defined, we need provide it to the catalog plugin. This step is important because the catalog plugin will use the rule's `toQuery` and `apply` methods while evaluating conditional authorize results. There's no guarantee that the catalog and permission backends are running on the same server, so we must explicitly link the rule to ensure that it's available at runtime. - -The api for providing custom rules may differ between plugins, but there should typically be some integration point during the creation of the backend router. For the catalog, this integration point is exposed via `CatalogBuilder.addPermissionRules`. - -```typescript title="packages/backend/src/plugins/catalog.ts" -import { isInSystemRule } from './permission'; -// The CatalogBuilder with the addPermissionRules function is in the alpha path -import { CatalogBuilder } from '@backstage/plugin-catalog-backend/alpha'; - -... - -export default async function createPlugin( - env: PluginEnvironment, -): Promise { - const builder = await CatalogBuilder.create(env); - builder.addPermissionRules(isInSystemRule); - ... - return router; -} -``` - -The new rule is now ready for use in a permission policy! - -## Use the rule in a policy - -Let's bring this all together by extending the example policy from the previous section. +Still in the `packages/backend/src/plugins/permission.ts` file, let's use the condition we just created in our `TestPermissionPolicy`. ```ts title="packages/backend/src/plugins/permission.ts" +... +/* highlight-remove-next-line */ +import { createCatalogPermissionRule } from '@backstage/plugin-catalog-backend/alpha'; /* highlight-add-next-line */ -import { isInSystem } from './catalog'; +import { catalogConditions, createCatalogConditionalDecision, createCatalogPermissionRule } from '@backstage/plugin-catalog-backend/alpha'; +/* highlight-remove-next-line */ +import { createConditionFactory } from '@backstage/plugin-permission-node'; +/* highlight-add-next-line */ +import { PermissionPolicy, PolicyQuery, createConditionFactory } from '@backstage/plugin-permission-node'; +/* highlight-add-start */ +import { BackstageIdentityResponse } from '@backstage/plugin-auth-node'; +import { AuthorizeResult, PolicyDecision, isResourcePermission } from '@backstage/plugin-permission-common'; +/* highlight-add-end */ +... + +export const isInSystemRule = createCatalogPermissionRule({ + name: 'IS_IN_SYSTEM', + description: 'Checks if an entity is part of the system provided', + resourceType: 'catalog-entity', + paramsSchema: z.object({ + systemRef: z + .string() + .describe('SystemRef to check the resource is part of'), + }), + apply: (resource: Entity, { systemRef }) => { + if (!resource.relations) { + return false; + } + + return resource.relations + .filter(relation => relation.type === 'partOf') + .some(relation => relation.targetRef === systemRef); + }, + toQuery: ({ systemRef }) => ({ + key: 'relations.partOf', + values: [systemRef], + }), +}); + +const isInSystem = createConditionFactory(isInSystemRule); class TestPermissionPolicy implements PermissionPolicy { async handle( @@ -95,20 +116,47 @@ class TestPermissionPolicy implements PermissionPolicy { { anyOf: [ catalogConditions.isEntityOwner({ - claims: user?.identity.ownershipEntityRefs ?? [] + claims: user?.identity.ownershipEntityRefs ?? [], }), - isInSystem('interviewing') - ] - } + isInSystem({ systemRef: 'interviewing' }), + ], + }, /* highlight-add-end */ ); } return { result: AuthorizeResult.ALLOW }; } +} + +... +``` + +## Provide the rule during plugin setup + +Now that we have a custom rule defined and added to our policy, we need provide it to the catalog plugin. This step is important because the catalog plugin will use the rule's `toQuery` and `apply` methods while evaluating conditional authorize results. There's no guarantee that the catalog and permission backends are running on the same server, so we must explicitly link the rule to ensure that it's available at runtime. + +The api for providing custom rules may differ between plugins, but there should typically be some integration point during the creation of the backend router. For the catalog, this integration point is exposed via `CatalogBuilder.addPermissionRules`. + +```typescript title="packages/backend/src/plugins/catalog.ts" +import { CatalogBuilder } from '@backstage/plugin-catalog-backend'; +/* highlight-add-next-line */ +import { isInSystemRule } from './permission'; + +... + +export default async function createPlugin( + env: PluginEnvironment, +): Promise { + const builder = await CatalogBuilder.create(env); + /* highlight-add-next-line */ + builder.addPermissionRules(isInSystemRule); + ... + return router; +} ``` The updated policy will allow catalog entity resource permissions if any of the following are true: - User owns the target entity -- Target entity is part of the `'interviewing'` system +- Target entity is part of the 'interviewing' system diff --git a/docs/plugins/add-to-directory.md b/docs/plugins/add-to-directory.md index dfa43c2ed7..8be0d764dd 100644 --- a/docs/plugins/add-to-directory.md +++ b/docs/plugins/add-to-directory.md @@ -21,7 +21,18 @@ description: A brief description of the plugin. # Max 170 characters documentation: # A link to your documentation E.g. Your github README iconUrl: # Used as the src attribute for your logo. # You can provide an external url or add your logo under static/img and provide a path -# relative to static/ e.g. img/my-logo.png +# relative to static/ e.g. /img/my-logo.png npmPackageName: # Your npm package name E.g. '@backstage/plugin-' quotes are required addedDate: # The date plugin added to directory E.g. '2022-10-01' quotes are required ``` + +## Submission Tips + +Here are a few tips to help speed up the review process when you submit your plugin: + +- For any icon that you use make sure you have the proper rights to use it. +- Make sure that your package had been published on the NPM registry and that it's public. +- Make sure your package on NPM has a link back to your code repo, this helps provide confidence that it's the right package. +- Where possible, please use an [NPM scope](https://docs.npmjs.com/about-scopes) that matches either your Organization name or user name, this provides trust in the plugin +- If your plugin has both a frontend and backend link the documentation to the frontend package but make sure it mentioned needing to install the backend package. +- Where possible include a screenshot of the features in you plugin documentation, it really does help when deciding to use a plugin. diff --git a/docs/plugins/backend-plugin.md b/docs/plugins/backend-plugin.md index 73b8f9027a..d2e93bb08c 100644 --- a/docs/plugins/backend-plugin.md +++ b/docs/plugins/backend-plugin.md @@ -41,9 +41,11 @@ standalone mode. You can do a first-light test of your service: ```sh cd plugins/carmen-backend -yarn start +LEGACY_BACKEND_START=true yarn start ``` +> Note: `LEGACY_BACKEND_START=true` is needed while we transition fully to the [New Backend System](../backend-system/index.md). The templates have not been migrated yet; you can track this in [issue 21288](https://github.com/backstage/backstage/issues/21288) + This will think for a bit, and then say `Listening on :7007`. In a different terminal window, now run diff --git a/docs/plugins/internationalization.md b/docs/plugins/internationalization.md index 78b7de6342..fd12452cff 100644 --- a/docs/plugins/internationalization.md +++ b/docs/plugins/internationalization.md @@ -6,11 +6,11 @@ description: Documentation on adding internationalization to the plugin ## Overview -The Backstage core function provides internationalization for plugins +The Backstage core function provides internationalization for plugins. The underlying library is [`i18next`](https://www.i18next.com/) with some additional Backstage typescript magic for type safety with keys. ## For a plugin developer -When you are creating your plugin, you have the possibility to use `createTranslationRef` to define all messages for your plugin. For example +When you are creating your plugin, you have the possibility to use `createTranslationRef` to define all messages for your plugin. For example: ```ts import { createTranslationRef } from '@backstage/core-plugin-api/alpha'; @@ -19,8 +19,13 @@ import { createTranslationRef } from '@backstage/core-plugin-api/alpha'; export const myPluginTranslationRef = createTranslationRef({ id: 'plugin.my-plugin', messages: { - index_page_title: 'All your components', - create_component_button_label: 'Create new component', + indexPage: { + title: 'All your components', + createButtonTitle: 'Create new component', + }, + entityPage: { + notFound: 'Entity not found', + }, }, }); ``` @@ -33,14 +38,115 @@ import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; const { t } = useTranslationRef(myPluginTranslationRef); return ( - + ); ``` +You will see how the initial dictionary structure and nesting gets converted into dot notation, so we encourage `camelCase` in key names and lean on the nesting structure to separate keys. + +### Guidelines for `i18n` messages and keys + +The API for `i18n` messages and keys can be pretty tricky to get right, as it's a pretty flexible API. We've put together some guidelines to help you get started that encourage good practices when thinking about translating plugins: + +#### Key names + +When defining messages it is recommended to use a nested structure that represents the semantic hierarchy in your translations. This allows for better organization and understanding of the structure. For example: + +```ts +export const myPluginTranslationRef = createTranslationRef({ + id: 'plugin.my-plugin', + messages: { + dashboardPage: { + title: 'All your components', + subtitle: 'Create new component', + widgets: { + weather: { + title: 'Weather', + description: 'Shows the weather', + }, + calendar: { + title: 'Calendar', + description: 'Shows the calendar', + }, + }, + }, + entityPage: { + notFound: 'Entity not found', + }, + }, +}); +``` + +Think about the semantic placement of content rather than the text content itself. Group related translations under a common prefix, and use nesting to represent relationships between different parts of your application. It's good to start grouping under extensions, page sections, or visual scopes and experiences. + +Translations should avoid using their own text content as key where possible, as this can lead to confusion if the translation changes. Instead prefer to use keys that describe the location or usage of the text. + +#### Common Key names + +This list is intended to grow over time, but below are some examples of common key names and patterns that we encourage you to use where possible: + +- `${page}.title` +- `${page}.subtitle` +- `${page}.description` + +- `${page}.header.title` + +#### Key reuse + +Reusing the same key in multiple places is discouraged. This helps prevent ambiguity, and instead keeps the usage of each key as clear as possible. Consider creating duplicate keys that are grouped under a semantic section instead. + +#### Flat keys + +Avoid a flat key structure at the root level, as it can lead to naming conflicts and make the translation file harder to manage and change evolve over time. Instead, group translations under a common prefix. + +```ts +export const myPluginTranslationRef = createTranslationRef({ + id: 'plugin.my-plugin', + messages: { + // this is BAD + title: 'My page', + subtitle: 'My subtitle', + // this is GOOD + dashboardPage: { + header: { + title: 'All your components', + subtitle: 'Create new component', + }, + }, + }, +}); +``` + +#### Plurals + +The `i18next` library, which is used as the underlying implementation, has built-in support for pluralization. You can use this feature as is described in [the documentation](https://www.i18next.com/translation-function/plurals). + +We encourage you to use this feature and avoid creating different key prefixes for pluralized content. For example: + +```ts +export const myPluginTranslationRef = createTranslationRef({ + id: 'plugin.my-plugin', + messages: { + dashboardPage: { + title: 'All your components', + subtitle: 'Create new component', + cards: { + title_one: 'You have one card', + title_two: 'You have two cards', + title_other: 'You have many cards ({{count}})', + }, + }, + entityPage: { + notFound: 'Entity not found', + }, + }, +}); +``` + ## For an application developer overwrite plugin messages In an app you can both override the default messages, as well as register translations for additional languages: @@ -53,7 +159,7 @@ In an app you can both override the default messages, as well as register transl + createTranslationMessages({ + ref: myPluginTranslationRef, + messages: { -+ create_component_button_label: 'Create new entity', ++ 'indexPage.createButtonTitle': 'Create new entity', + }, + }), + createTranslationResource({ diff --git a/docs/plugins/new-backend-system.md b/docs/plugins/new-backend-system.md index be27e9427d..0fc44f283f 100644 --- a/docs/plugins/new-backend-system.md +++ b/docs/plugins/new-backend-system.md @@ -6,25 +6,24 @@ description: Details of the new backend system ## Status -The new backend system is in alpha, and some plugins do not yet fully implement it. But do feel free to try it out! We would love to hear back about your impressions. +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). ## Overview -The new Backstage backend system is being built to help make it simpler to install backend plugins and to keep projects up to date. It also changes the foundation to one that makes it a lot easier to evolve plugins and the system itself with minimal disruption or cause for breaking changes. You can read more about the reasoning in the [original RFC](https://github.com/backstage/backstage/issues/11611). +The new Backstage backend system was built to help make it simpler to install backend plugins and to keep projects up to date. It also changed the foundation to one that makes it a lot easier to evolve plugins and the system itself with minimal disruption or cause for breaking changes. You can read more about the reasoning in the [original RFC](https://github.com/backstage/backstage/issues/11611). One of the goals of the new system was to reduce the code needed for setting up a Backstage backend and installing plugins. This is an example of how you create, add features, and start up your backend in the new system: ```ts import { createBackend } from '@backstage/backend-defaults'; -import { catalogPlugin } from '@backstage/plugin-catalog-backend'; // Create your backend instance const backend = createBackend(); // Install all desired features -backend.add(catalogPlugin()); +backend.add(import('@backstage/plugin-catalog-backend')); // Start up the backend await backend.start(); @@ -147,8 +146,8 @@ import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node' import { MyCustomProcessor } from './processor'; export const exampleCustomProcessorCatalogModule = createBackendModule({ - moduleId: 'exampleCustomProcessor', pluginId: 'catalog', + moduleId: 'example-custom-processor', register(env) { env.registerInit({ deps: { diff --git a/docs/publishing.md b/docs/publishing.md index f8964278b5..15813275de 100644 --- a/docs/publishing.md +++ b/docs/publishing.md @@ -53,6 +53,7 @@ Additional steps for the main line release - 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 + - 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. @@ -134,3 +135,9 @@ process is used to release an emergency fix as version `6.5.1` in the patch rele - [ ] The fix, which you can likely cherry-pick from your patch branch: `git cherry-pick origin/patch/v1.18.0^` - [ ] An updated `CHANGELOG.md` of all patched packages from the tip of the patch branch, `git checkout origin/patch/v1.18.0 -- {packages,plugins}/*/CHANGELOG.md`. Note that if the patch happens after any next-line releases you'll need to restore those entries in the changelog, placing the patch release entry beneath any next-line release entries. - [ ] A changeset with the message "Applied the fix from version `6.5.1` of this package, which is part of the `v1.18.1` release of Backstage." + +## Troubleshooting + +### When the release workflow is not triggered for some reason, such as a GitHub incident + +Ask one of the maintainers to force push master back to a previous commit and then push the release merge commit again. diff --git a/docs/releases/v1.20.0-changelog.md b/docs/releases/v1.20.0-changelog.md new file mode 100644 index 0000000000..6df613ac77 --- /dev/null +++ b/docs/releases/v1.20.0-changelog.md @@ -0,0 +1,3723 @@ +# Release v1.20.0 + +## @backstage/backend-openapi-utils@0.1.0 + +### Minor Changes + +- 785fb1ea75: Adds a new route, `/openapi.json` to validated routers for displaying their full OpenAPI spec in a standard endpoint. + +### Patch Changes + +- 6694b369a3: Adds a new function `wrapInOpenApiTestServer` that allows for proxied requests at runtime. This will support the new `yarn backstage-repo-tools schema openapi test` command. +- Updated dependencies + - @backstage/backend-plugin-api@0.6.7 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/cli@0.24.0 + +### Minor Changes + +- 8db5c3cd7a: Removed support for the `publishConfig.alphaTypes` and `.betaTypes` fields that were used together with `--experimental-type-build` to generate `/alpha` and `/beta` entry points. Use the `exports` field to achieve this instead. +- 4e36abef14: Remove support for the deprecated `--experimental-type-build` option for `package build`. + +### Patch Changes + +- 4ba4ac351f: Switch from using deprecated `@esbuild-kit/*` packages to using `tsx`. This also switches to using the new module loader `register` API when available, avoiding the experimental warning when starting backends. +- cd80ebb062: Updated dependency `vite-plugin-node-polyfills` to `^0.16.0`. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- 971dcba764: Updated dependency `@typescript-eslint/eslint-plugin` to `6.10.0`. +- 6bf7561d3c: The experimental package detection will now ignore packages that don't make `package.json` available. +- e14cbf563d: Added `EXPERIMENTAL_VITE` flag for using [vite](https://vitejs.dev) as dev server instead of Webpack +- 7cd34392f5: Ignore `stdin` when spawning backend child process for the `start` command. Fixing an issue where backend startup would hang. +- Updated dependencies + - @backstage/config-loader@1.5.3 + - @backstage/cli-node@0.2.0 + - @backstage/integration@1.7.2 + - @backstage/release-manifests@0.0.11 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/eslint-plugin@0.1.3 + - @backstage/types@1.1.1 + +## @backstage/cli-node@0.2.0 + +### Minor Changes + +- 8db5c3cd7a: Removed support for the `publishConfig.alphaTypes` and `.betaTypes` fields that were used together with `--experimental-type-build` to generate `/alpha` and `/beta` entry points. Use the `exports` field to achieve this instead. + +### Patch Changes + +- Updated dependencies + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/core-plugin-api@1.8.0 + +### Minor Changes + +- 1e5b7d993a: `IconComponent` can now have a `fontSize` of `inherit`, which is useful for in-line icons. +- cb6db75bc2: Introduced `AnyRouteRefParams` as a replacement for `AnyParams`, which is now deprecated. + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- cb6db75bc2: Deprecated several types related to the routing system that are scheduled to be removed, as well as several fields on the route ref types themselves. +- 68fc9dc60e: Added a new `/alpha` export `convertLegacyRouteRef`, which is a temporary utility to allow existing route refs to be used with the new experimental packages. +- Updated dependencies + - @backstage/version-bridge@1.0.7 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## @backstage/frontend-app-api@0.3.0 + +### Minor Changes + +- 68fc9dc60e: Added the ability to configure bound routes through `app.routes.bindings`. The routing system used by `createApp` has been replaced by one that only supports route refs of the new format from `@backstage/frontend-plugin-api`. The requirement for route refs to have the same ID as their associated extension has been removed. + +### Patch Changes + +- e28d379e32: Refactor internal extension instance system into an app graph. +- fdc348d5d3: The options parameter of `createApp` is now optional. +- 6c2b872153: Add official support for React 18. +- dc613f9bcf: Updated `app.extensions` configuration schema. +- 733bd95746: Implement new `AppTreeApi` +- 685a4c8901: Installed features are now deduplicated both by reference and ID when available. Features passed to `createApp` now override both discovered and loaded features. +- fa28d4e6df: No longer throw error on invalid input if the child is disabled. +- bb98953cb9: Register default implementation for the `Translation API` on the new `createApp`. +- fe6d09953d: Fix for app node output IDs not being serialized correctly. +- 77f009b35d: Internal updates to match changes in the experimental `@backstage/frontend-plugin-api`. +- 4d6fa921db: Internal refactor to rename the app graph to app tree +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/frontend-plugin-api@0.3.0 + - @backstage/plugin-graphiql@0.3.0 + - @backstage/core-plugin-api@1.8.0 + - @backstage/version-bridge@1.0.7 + - @backstage/core-app-api@1.11.1 + - @backstage/theme@0.4.4 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## @backstage/frontend-plugin-api@0.3.0 + +### Minor Changes + +- 68fc9dc60e: Added `RouteRef`, `SubRouteRef`, `ExternalRouteRef`, and related types. All exports from this package that previously relied on the types with the same name from `@backstage/core-plugin-api` now use the new types instead. To convert and existing legacy route ref to be compatible with the APIs from this package, use the `convertLegacyRouteRef` utility from `@backstage/core-plugin-api/alpha`. +- 77f009b35d: Extensions now return their output from the factory function rather than calling `bind(...)`. + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 733bd95746: Add new `AppTreeApi`. +- 6af88a05ff: Improve the extension boundary component and create a default extension suspense component. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/version-bridge@1.0.7 + - @backstage/types@1.1.1 + +## @backstage/repo-tools@0.4.0 + +### Minor Changes + +- 4e36abef14: Remove support for the deprecated `--experimental-type-build` option for `package build`. +- 6694b369a3: Adds a new command `schema openapi test` that performs runtime validation of your OpenAPI specs using your test data. Under the hood, we're using Optic to perform this check, really cool work by them! + + To use this new command, you will have to run `yarn add @useoptic/optic` in the root of your repo. + +### Patch Changes + +- Updated dependencies + - @backstage/cli-node@0.2.0 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + +## @techdocs/cli@1.7.0 + +### Minor Changes + +- 8600b86820: validate Docker status before running mkdocs server + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs-node@1.10.0 + - @backstage/backend-common@0.19.9 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + +## @backstage/plugin-api-docs@0.10.0 + +### Minor Changes + +- 0ac0e10822: Replace GraphiQL playground with DocExplorer +- 62310404b7: Define a default for oauth2RedirectUrl option of swagger-ui-react to match documentation + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- 613a55911f: Updated dependency `graphiql` to `3.0.9`. +- 4ad15278e6: Updated dependency `@graphiql/react` to `^0.20.0`. +- 62b5922916: Internal theme type updates +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/plugin-catalog@1.15.0 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-auth-backend@0.20.0 + +### Minor Changes + +- bdf08ad04a: Adds the StaticTokenIssuer and StaticKeyStore, an alternative token issuer that can be used to sign the Authorization header using a predefined public/private key pair. + +### Patch Changes + +- 243c655a68: JSDoc and Error message updates to handle `Azure Active Directory` re-brand to `Entra ID` +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. +- f2fc5acca6: Added an optional `additionalScopes` configuration parameter to `okta` providers, that lets you add additional scopes on top of the default ones. +- 96c4f54bf6: Reverted the Microsoft auth provider to the previous implementation. +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.4 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.1 + - @backstage/plugin-auth-backend-module-github-provider@0.1.4 + - @backstage/plugin-auth-backend-module-google-provider@0.1.4 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.1.4 + - @backstage/plugin-auth-node@0.4.1 + +## @backstage/plugin-catalog@1.15.0 + +### Minor Changes + +- 1e5b7d993a: Added the `DefaultEntityPresentationApi`, which is an implementation of the + `EntityPresentationApi` that `@backstage/plugin-catalog-react` exposes through + its `entityPresentationApiRef`. This implementation is also by default made + available automatically by the catalog plugin, unless you replace it with a + custom one. It batch fetches and caches data from the catalog as needed for + display, and is customizable by adopters to add their own rendering functions. + +### Patch Changes + +- eb817ee6d4: Fix spacing inconsistency with links and labels in headers + +- 8a8445663b: Migrate catalog entity cards to new frontend system extension format. + +- e964c17db9: Use default extensions boundary and suspense on the alpha declarative `createCatalogFilterExtension` extension factory. + +- 71c97e7d73: The \`spec.lifecycle' field in entities will now always be rendered as a string. + +- 6c2b872153: Add official support for React 18. + +- 0bf6ebda88: Initial entity page implementation for new frontend system at `/alpha`, with an overview page enabled by default and the about card available as an optional card. + +- bb98953cb9: Create declarative extensions for the `Catalog` plugin; this initial plugin preset contains sidebar item, index page and filter extensions, all distributed via `/alpha` subpath. + + The `EntityPage` will be migrated in a follow-up patch. + +- 7c265b9758: Fix type error on `CatalogTable` when using Material UI v5 + +- 69c14904b6: Use `EntityRefLinks` with `hideIcons` property to avoid double icons + +- 62b5922916: Internal theme type updates + +- 77f009b35d: Internal updates to match changes in the experimental `@backstage/frontend-plugin-api`. + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/frontend-plugin-api@0.3.0 + - @backstage/plugin-scaffolder-common@1.4.3 + - @backstage/integration-react@1.1.21 + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-search-react@1.7.2 + - @backstage/theme@0.4.4 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-catalog-backend@1.15.0 + +### Minor Changes + +- e5bf3749ad: Support adding location analyzers in new catalog analysis extension point and move `AnalyzeOptions` and `ScmLocationAnalyzer` types to `@backstage/plugin-catalog-node` +- 8d756968f9: Introduce a new optional config parameter `catalog.stitchingStrategy.mode`, + which can have the values `'immediate'` (default) and `'deferred'`. The default + is for stitching to work as it did before this change, which means that it + happens "in-band" (blocking) immediately when each processing task finishes. + When set to `'deferred'`, stitching is instead deferred to happen on a separate + asynchronous worker queue just like processing. + + Deferred stitching should make performance smoother when ingesting large amounts + of entities, and reduce p99 processing times and repeated over-stitching of + hot spot entities when fan-out/fan-in in terms of relations is very large. It + does however also come with some performance cost due to the queuing with how + much wall-clock time some types of task take. + +### Patch Changes + +- 6694b369a3: Update the OpenAPI spec with more complete error responses and request bodies using Optic. Also, updates the test cases to use the new `supertest` pass through from `@backstage/backend-openapi-utils`. +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/integration@1.7.2 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/catalog-client@1.4.6 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/backend-openapi-utils@0.1.0 + - @backstage/plugin-search-backend-module-catalog@0.1.11 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-events-node@0.2.16 + - @backstage/plugin-permission-node@0.7.18 + +## @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.0 + +### Minor Changes + +- 785fb1ea75: Adds a new catalog module for ingesting Backstage plugin OpenAPI specs into the catalog for display as an API entity. + +### Patch Changes + +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/backend-openapi-utils@0.1.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-catalog-graph@0.3.0 + +### Minor Changes + +- a604623324: Add the entire `Entity` to `EntityNodeData` and deprecate `name`, `kind`, `title`, `namespace` and `spec`. + + To get the deprecated properties in your custom component you can use: + + ```typescript + import { DEFAULT_NAMESPACE } from '@backstage/catalog-model'; + + const { + kind, + metadata: { name, namespace = DEFAULT_NAMESPACE, title }, + } = entity; + ``` + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 62b5922916: Internal theme type updates +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-node@1.5.0 + +### Minor Changes + +- e5bf3749ad: Support adding location analyzers in new catalog analysis extension point and move `AnalyzeOptions` and `ScmLocationAnalyzer` types to `@backstage/plugin-catalog-node` + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.7 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + +## @backstage/plugin-catalog-react@1.9.0 + +### Minor Changes + +- 1e5b7d993a: Added an `EntityPresentationApi` and associated `entityPresentationApiRef`. This + API lets you control how references to entities (e.g. in links, headings, + iconography etc) are represented in the user interface. + + Usage of this API is initially added to the `EntityRefLink` and `EntityRefLinks` + components, so that they can render richer, more correct representation of + entity refs. There's also a new `EntityDisplayName` component, which works just like + the `EntityRefLink` but without the link. + + Along with that change, the `fetchEntities` and `getTitle` props of + `EntityRefLinksProps` are deprecated and no longer used, since the same need + instead is fulfilled (and by default always enabled) by the + `entityPresentationApiRef`. + +- 1fd53fa0c6: The `UserListPicker` component has undergone improvements to enhance its performance. + + The previous implementation inferred the number of owned and starred entities based on the entities available in the `EntityListContext`. The updated version no longer relies on the `EntityListContext` for inference, allowing for better decoupling. + + The component now loads the entities' count asynchronously, resulting in improved performance and responsiveness. For this purpose, some of the exported filters such as `EntityTagFilter`, `EntityOwnerFilter`, `EntityLifecycleFilter` and `EntityNamespaceFilter` have now the `getCatalogFilters` method implemented. + +### Patch Changes + +- 2ad1bacef7: Add EntityRef to Entity Inspector UI +- 6c2b872153: Add official support for React 18. +- 69ee8d75f4: Remove `button` prop from used MaterialUI `MenuItem` component fixing incompatibility with MaterialUI v5. +- 0bf6ebda88: Added new APIs at the `/alpha` subpath for creating entity page cards and content for the new frontend system. +- 77f009b35d: Internal updates to match changes in the experimental `@backstage/frontend-plugin-api`. +- 71c97e7d73: The `spec.type` field in entities will now always be rendered as a string. +- 69c14904b6: Move the `EntityRefLink` icon to the left hand side as per Material-UI guidelines +- 000dcd01af: Removed unnecessary `@backstage/integration` dependency, replaced by `@backstage/integration-react`. +- 6c357184e2: Export `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/frontend-plugin-api@0.3.0 + - @backstage/integration-react@1.1.21 + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-permission-react@0.4.17 + - @backstage/version-bridge@1.0.7 + - @backstage/theme@0.4.4 + - @backstage/catalog-client@1.4.6 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + +## @backstage/plugin-graphiql@0.3.0 + +### Minor Changes + +- 57fda44b90: Upgrade to GraphiQL to 3.0.6 + +### Patch Changes + +- 68fc9dc60e: Updated alpha exports according to routing changes in `@backstage/frontend-plugin-api`. +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- 77f009b35d: Internal updates to match changes in the experimental `@backstage/frontend-plugin-api`. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/frontend-plugin-api@0.3.0 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + +## @backstage/plugin-playlist@0.2.0 + +### Minor Changes + +- f0e2ef3b81: Support being able to define custom composable Playlist index pages + + **BREAKING** The individual `PlaylistPage` route must now be manually hooked up by making the following change to your setup: + + ```diff + -import { PlaylistIndexPage } from '@backstage/plugin-playlist'; + +import { PlaylistIndexPage, PlaylistPage } from '@backstage/plugin-playlist'; + + // ... + + } /> + +} /> + ``` + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 69ee8d75f4: Remove `button` prop from used MaterialUI `MenuItem` component fixing incompatibility with MaterialUI v5. +- 62b5922916: Internal theme type updates +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-permission-react@0.4.17 + - @backstage/plugin-search-react@1.7.2 + - @backstage/theme@0.4.4 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-playlist-common@0.1.12 + +## @backstage/plugin-scaffolder@1.16.0 + +### Minor Changes + +- f28c11743a: Add a possibility to use a formatter on a warning panel. Applied it for a scaffolder template +- 3fdffbb699: Release design improvements for the `Scaffolder` plugin and support v5 of `@rjsf/*` libraries. + + This change should be non-breaking. If you're seeing typescript issues after migrating please [open an issue](https://github.com/backstage/backstage/issues/new/choose) + + The `next` versions like `createNextFieldExtension` and `NextScaffolderPage` have been promoted to the public interface under `createScaffolderFieldExtension` and `ScaffolderPage`, so any older imports which are no longer found will need updating from `@backstage/plugin-scaffolder/alpha` or `@backstage/plugin-scaffolder-react/alpha` will need to be imported from `@backstage/plugin-scaffolder` and `@backstage/plugin-scaffolder-react` respectively. + + The legacy versions are now available in `/alpha` under `createLegacyFieldExtension` and `LegacyScaffolderPage` if you're running into issues, but be aware that these will be removed in a next mainline release. + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 69ee8d75f4: Remove `button` prop from used MaterialUI `MenuItem` component fixing incompatibility with MaterialUI v5. +- c838da0edd: Updated dependency `@rjsf/utils` to `5.13.6`. + Updated dependency `@rjsf/core` to `5.13.6`. + Updated dependency `@rjsf/material-ui` to `5.13.6`. + Updated dependency `@rjsf/validator-ajv8` to `5.13.6`. +- 26e4d916d5: Title and description in RepoUrlPicker are now correctly displayed. +- 69c14904b6: Use `EntityRefLinks` with `hideIcons` property to avoid double icons +- 62b5922916: Internal theme type updates +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/plugin-scaffolder-common@1.4.3 + - @backstage/integration@1.7.2 + - @backstage/integration-react@1.1.21 + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-permission-react@0.4.17 + - @backstage/plugin-scaffolder-react@1.6.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + +## @backstage/plugin-scaffolder-backend@1.19.0 + +### Minor Changes + +- f3ab9cfcb7: Made shut down stale tasks configurable. + + There are two properties exposed: + + - `scaffolder.processingInterval` - sets the processing interval for staled tasks. + - `scaffolder.taskTimeoutJanitorFrequency` - sets the task's heartbeat timeout, when to consider a task to be staled. + +- 7d5a921114: Allow using `globby`'s negative matching with `copyWithoutTemplating`/`copyWithoutRender`. This allows including an entire subdirectory while excluding a single file so that it will still be templated instead of needing to list every other file and ensure the list is updated when new files are added. + +- 5e4127c18e: Allow setting `update: true` in `publish:github:pull-request` scaffolder action + +### Patch Changes + +- 0920fd02ac: Add examples for `github:environment:create` scaffolder action & improve related tests +- ae30a9ae8c: Added description for publish:gerrit scaffolder actions +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. +- 23f72b2cba: Refactoring the runner to generate minimally informative task log per iteration and properly validate iterated actions. +- 8613ba3928: Switched to using `"exports"` field for `/alpha` subpath export. +- 99d4936f6c: Add examples for `github:webhook` scaffolder action & improve related tests +- 2be3922eb8: Add examples for `github:deployKey:create` scaffolder action & improve related tests +- 76d07da66a: Make it possible to define control buttons text (Back, Create, Review) per template +- f8727ad228: Add examples for `publish:github:pull-request` scaffolder action & improve related tests +- Updated dependencies + - @backstage/plugin-catalog-backend@1.15.0 + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/plugin-scaffolder-common@1.4.3 + - @backstage/integration@1.7.2 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/catalog-client@1.4.6 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-scaffolder-node@0.2.8 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.4 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-node@0.7.18 + +## @backstage/plugin-scaffolder-react@1.6.0 + +### Minor Changes + +- 3fdffbb699: Release design improvements for the `Scaffolder` plugin and support v5 of `@rjsf/*` libraries. + + This change should be non-breaking. If you're seeing typescript issues after migrating please [open an issue](https://github.com/backstage/backstage/issues/new/choose) + + The `next` versions like `createNextFieldExtension` and `NextScaffolderPage` have been promoted to the public interface under `createScaffolderFieldExtension` and `ScaffolderPage`, so any older imports which are no longer found will need updating from `@backstage/plugin-scaffolder/alpha` or `@backstage/plugin-scaffolder-react/alpha` will need to be imported from `@backstage/plugin-scaffolder` and `@backstage/plugin-scaffolder-react` respectively. + + The legacy versions are now available in `/alpha` under `createLegacyFieldExtension` and `LegacyScaffolderPage` if you're running into issues, but be aware that these will be removed in a next mainline release. + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 171a99816b: Fixed `backstage:featureFlag` in `scaffolder/next` by sorting out `manifest.steps`. +- c838da0edd: Updated dependency `@rjsf/utils` to `5.13.6`. + Updated dependency `@rjsf/core` to `5.13.6`. + Updated dependency `@rjsf/material-ui` to `5.13.6`. + Updated dependency `@rjsf/validator-ajv8` to `5.13.6`. +- 69c14904b6: Use `EntityRefLinks` with `hideIcons` property to avoid double icons +- 62b5922916: Internal theme type updates +- dda56ae265: Preserve step's time execution for a non-running task. +- 76d07da66a: Make it possible to define control buttons text (Back, Create, Review) per template +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/plugin-scaffolder-common@1.4.3 + - @backstage/core-plugin-api@1.8.0 + - @backstage/version-bridge@1.0.7 + - @backstage/theme@0.4.4 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-search-backend-module-stack-overflow-collator@0.1.0 + +### Minor Changes + +- 46f0f1700e: Extract a package for the Stack Overflow new backend system plugin. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-node@1.2.11 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/config@1.1.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-techdocs@1.9.0 + +### Minor Changes + +- 17f93d5589: A new analytics event `not-found` will be published when a user visits a documentation site that does not exist + +### Patch Changes + +- 4728b3960d: Fixed navigation bug that caused users to not be scrolled to the top of a new page. Fixed navigation bug where using backwards and forwards browser navigation did not scroll users to the correct place on the TechDoc page. +- a3add7a682: Export alpha routes and nav item extension, only available for applications that uses the new Frontend system. +- 71c97e7d73: The \`spec.lifecycle' field in entities will now always be rendered as a string. +- 68fc9dc60e: Updated alpha exports according to routing changes in `@backstage/frontend-plugin-api`. +- 6c2b872153: Add official support for React 18. +- 0bf6ebda88: Added entity page content for the new plugin exported via `/alpha`. +- 67cc85bb14: Switched the conditional `react-dom/client` import to use `import(...)` rather than `require(...)`. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- 38cda52746: Added support for React 18. The new `createRoot` API from `react-dom/client` will now be used if present. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/frontend-plugin-api@0.3.0 + - @backstage/integration@1.7.2 + - @backstage/integration-react@1.1.21 + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-techdocs-react@1.1.13 + - @backstage/plugin-search-react@1.7.2 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-techdocs-backend@1.9.0 + +### Minor Changes + +- 67cff7b06f: Expose an extension point to set a custom build strategy. Also move `DocsBuildStrategy` type to `@backstage/plugin-techdocs-node` and deprecate `ShouldBuildParameters` type. + +### Patch Changes + +- c3c5c7e514: Add info about the entity when tech docs fail to build +- 48a61bfdca: Fix potential memory leak by not creating a build log transport if not given via `RouterOptions`. +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. +- Updated dependencies + - @backstage/plugin-techdocs-node@1.10.0 + - @backstage/integration@1.7.2 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/plugin-search-backend-module-techdocs@0.1.11 + - @backstage/catalog-client@1.4.6 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-techdocs-node@1.10.0 + +### Minor Changes + +- 67cff7b06f: Expose an extension point to set a custom build strategy. Also move `DocsBuildStrategy` type to `@backstage/plugin-techdocs-node` and deprecate `ShouldBuildParameters` type. + +### Patch Changes + +- e61a975f61: Switch to `@smithy/node-http-handler` instead of the `@aws-sdk/node-http-handler` +- 3d043526f4: Updated dependency `aws-sdk-client-mock` to `^3.0.0`. +- Updated dependencies + - @backstage/integration@1.7.2 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/integration-aws-node@0.1.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-vault-backend@0.4.0 + +### Minor Changes + +- a873a32a1f: Added support for the [new backend system](https://backstage.io/docs/backend-system/). + + In your `packages/backend/src/index.ts` make the following changes: + + ```diff + import { createBackend } from '@backstage/backend-defaults'; + const backend = createBackend(); + // ... other feature additions + + backend.add(import('@backstage/plugin-vault-backend'); + backend.start(); + ``` + + If you use the new backend system, the token renewal task can be defined via configuration file: + + ```diff + vault: + baseUrl: + token: + schedule: + + frequency: ... + + timeout: ... + + # Other schedule options, such as scope or initialDelay + ``` + + If the `schedule` is omitted or set to `false` no token renewal task will be scheduled. + If the value of `schedule` is set to `true` the renew will be scheduled hourly (the default). + In other cases (like in the diff above), the defined schedule will be used. + + **DEPRECATIONS**: The interface `VaultApi` and the type `VaultSecret` are now deprecated. Import them from `@backstage/plugin-vault-node`. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-vault-node@0.1.0 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-vault-node@0.1.0 + +### Minor Changes + +- 7a41bcf2af: Initial version of the \`plugin-vault-node\`\` package. It contains the extension point definitions + for the vault backend, as well as some types that will be deprecated in the backend plugin. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.7 + +## @backstage/app-defaults@1.4.5 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-permission-react@0.4.17 + - @backstage/core-app-api@1.11.1 + - @backstage/theme@0.4.4 + +## @backstage/backend-app-api@0.5.8 + +### Patch Changes + +- bc9a18d5ec: Added a workaround for double `default` wrapping when dynamically importing CommonJS modules with default exports. +- Updated dependencies + - @backstage/config-loader@1.5.3 + - @backstage/cli-node@0.2.0 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.1 + - @backstage/plugin-permission-node@0.7.18 + +## @backstage/backend-common@0.19.9 + +### Patch Changes + +- aa13482090: Limit the database creation concurrency to one, defensively +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. +- 3d043526f4: Updated dependency `aws-sdk-client-mock` to `^3.0.0`. +- Updated dependencies + - @backstage/config-loader@1.5.3 + - @backstage/integration@1.7.2 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/integration-aws-node@0.1.8 + - @backstage/backend-app-api@0.5.8 + - @backstage/backend-dev-utils@0.1.2 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/backend-defaults@0.2.7 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-app-api@0.5.8 + +## @backstage/backend-plugin-api@0.6.7 + +### Patch Changes + +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. +- Updated dependencies + - @backstage/backend-tasks@0.5.12 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.1 + +## @backstage/backend-tasks@0.5.12 + +### Patch Changes + +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/backend-test-utils@0.2.8 + +### Patch Changes + +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. +- bb688f7b3b: Ensure recursive deletion of temporary directories in tests +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-app-api@0.5.8 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.1 + +## @backstage/catalog-client@1.4.6 + +### Patch Changes + +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/config-loader@1.5.3 + +### Patch Changes + +- 22ca64f117: Correctly resolve config targets into absolute paths +- 087bab5b42: Updated dependency `typescript-json-schema` to `^0.62.0`. +- Updated dependencies + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/core-app-api@1.11.1 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 89d13e5618: Add current and default scopes when refreshing session +- 9ab0572217: Add component data `core.type` marker for `AppRouter` and `FlatRoutes`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.0 + - @backstage/version-bridge@1.0.7 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## @backstage/core-components@0.13.8 + +### Patch Changes + +- 81c8db2088: Fix `RoutedTabs` so that it does not explode without tabs. + +- eb817ee6d4: Fix spacing inconsistency with links and labels in headers + +- f28c11743a: Add a possibility to use a formatter on a warning panel. Applied it for a scaffolder template + +- 6c2b872153: Add official support for React 18. + +- e07570a740: Fixed an issue causing the `Select` component to show empty chips when some of the selected values did not match any item + +- 7bdc1b0a12: Fixed compatibility with Safari <16.3 by eliminating RegEx lookbehind in `extractInitials`. + + This PR also changed how initials are generated resulting in _John Jonathan Doe_ => _JD_ instead of _JJ_. + +- 66071b42c0: Make the `options.titleFormat` prop of `` apply to all keys including nested ones. Previously, this option would only apply to the root keys of the `metadata` prop. + + Document and improve the props of ``. Previously, the `options` prop was `any`. + +- 71c97e7d73: Fixed the type declaration of `DependencyGraphProps`, the `defs` prop now expects `JSX.Element`s. + +- 0c5b78650c: Reverting the `MissingAnnotationEmptyState` component due to cyclical dependency. This component is now deprecated, please use the import from `@backstage/plugin-catalog-react` instead to use the new functionality + +- 4b7d341746: Updated dependency `linkify-react` to `4.1.2`. + +- 0ef24425c1: Updated dependency `linkifyjs` to `4.1.2`. + +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. + +- Updated dependencies + - @backstage/core-plugin-api@1.8.0 + - @backstage/version-bridge@1.0.7 + - @backstage/theme@0.4.4 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/create-app@0.5.7 + +### Patch Changes + +- 770763487a: Cleaned up cases where deprecated code was being used but had a new location they should be imported from + +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. + + You can do the same in your own Backstage repository to ensure that you get future node 18+ relevant updates, by having the following lines in your `packages/backend/package.json`: + + "dependencies": { + // ... + "knex": "^3.0.0" + }, + "devDependencies": { + // ... + "better-sqlite3": "^9.0.0", + +- f577e1176f: Bumped create-app version. + +- 6c2b872153: Add official support for React 18. + +- ae1602e54d: If create app installs dependencies, don't suggest to user that they also need to do it. + +- e6b7ab8d2b: Added missing node-gyp dependency to fix Docker image build + +- Updated dependencies + - @backstage/cli-common@0.1.13 + +## @backstage/dev-utils@1.0.23 + +### Patch Changes + +- 67cc85bb14: Switched the conditional `react-dom/client` import to use `import(...)` rather than `require(...)`. +- 38cda52746: Added support for React 18. The new `createRoot` API from `react-dom/client` will now be used if present. +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/integration-react@1.1.21 + - @backstage/core-plugin-api@1.8.0 + - @backstage/app-defaults@1.4.5 + - @backstage/core-app-api@1.11.1 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + +## @backstage/integration@1.7.2 + +### Patch Changes + +- 243c655a68: JSDoc and Error message updates to handle `Azure Active Directory` re-brand to `Entra ID` +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- Updated dependencies + - @backstage/config@1.1.1 + +## @backstage/integration-aws-node@0.1.8 + +### Patch Changes + +- 20d97d28a3: Updated dependency `aws-sdk-client-mock-jest` to `^3.0.0`. +- 3d043526f4: Updated dependency `aws-sdk-client-mock` to `^3.0.0`. +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/integration-react@1.1.21 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/integration@1.7.2 + - @backstage/core-plugin-api@1.8.0 + - @backstage/config@1.1.1 + +## @backstage/release-manifests@0.0.11 + +### Patch Changes + +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. + +## @backstage/test-utils@1.4.5 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-permission-react@0.4.17 + - @backstage/core-app-api@1.11.1 + - @backstage/theme@0.4.4 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## @backstage/theme@0.4.4 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. + +## @backstage/version-bridge@1.0.7 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. + +## @backstage/plugin-adr@0.6.9 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/frontend-plugin-api@0.3.0 + - @backstage/integration-react@1.1.21 + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-search-react@1.7.2 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-adr-common@0.2.17 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-adr-backend@0.4.4 + +### Patch Changes + +- 68f8a55622: Updated dependency `@types/marked` to `^5.0.0`. +- Updated dependencies + - @backstage/integration@1.7.2 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-adr-common@0.2.17 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-adr-common@0.2.17 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.2 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-airbrake@0.3.26 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/test-utils@1.4.5 + - @backstage/theme@0.4.4 + - @backstage/dev-utils@1.0.23 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-airbrake-backend@0.3.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/config@1.1.1 + +## @backstage/plugin-allure@0.1.42 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-analytics-module-ga@0.1.35 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/config@1.1.1 + +## @backstage/plugin-analytics-module-ga4@0.1.6 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 504614d313: Updated dependency `@types/jest` to `^29.0.0`. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/config@1.1.1 + +## @backstage/plugin-analytics-module-newrelic-browser@0.0.4 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/config@1.1.1 + +## @backstage/plugin-apache-airflow@0.2.17 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + +## @backstage/plugin-api-docs-module-protoc-gen-doc@0.1.5 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. + +## @backstage/plugin-apollo-explorer@0.1.17 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + +## @backstage/plugin-app-backend@0.3.55 + +### Patch Changes + +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. +- Updated dependencies + - @backstage/config-loader@1.5.3 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.7 + +## @backstage/plugin-app-node@0.1.7 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.7 + +## @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.7 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.1 + +## @backstage/plugin-auth-backend-module-github-provider@0.1.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/plugin-auth-node@0.4.1 + +## @backstage/plugin-auth-backend-module-gitlab-provider@0.1.4 + +### Patch Changes + +- a3236ad0ca: Fix link to the repository in `README.md`. +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/plugin-auth-node@0.4.1 + +## @backstage/plugin-auth-backend-module-google-provider@0.1.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.7 + - @backstage/plugin-auth-node@0.4.1 + +## @backstage/plugin-auth-backend-module-microsoft-provider@0.1.2 + +### Patch Changes + +- a3236ad0ca: Fix link to the repository in `README.md`. + +- 3979524c74: Added support for specifying a domain hint on the Microsoft authentication provider configuration. + +- fde212dd10: Re-add the missing profile photo + as well as access token retrieval for foreign scopes. + + Additionally, we switch from previously 48x48 to 96x96 + which is the size used at the profile card. + +- 5aeb14f035: Correctly mark the client secret in configuration as secret + +- 2817115d09: Removed `prompt=consent` from start method to fix #20641 + +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/plugin-auth-node@0.4.1 + +## @backstage/plugin-auth-backend-module-oauth2-provider@0.1.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/plugin-auth-node@0.4.1 + +## @backstage/plugin-auth-backend-module-pinniped-provider@0.1.1 + +### Patch Changes + +- a8f6afda4a: Introduced metadata cache for the `pinniped` provider. +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.1 + +## @backstage/plugin-auth-node@0.4.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-azure-devops@0.3.8 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- ce9e59cbb3: Refactored the error handling for some of the hooks +- 361bb34d8e: Consolidated getting the annotation values into a single function to help with future changes +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-azure-devops-common@0.3.1 + +## @backstage/plugin-azure-devops-backend@0.4.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/config@1.1.1 + - @backstage/plugin-azure-devops-common@0.3.1 + +## @backstage/plugin-azure-sites@0.1.15 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-azure-sites-common@0.1.1 + +## @backstage/plugin-azure-sites-backend@0.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/config@1.1.1 + - @backstage/plugin-azure-sites-common@0.1.1 + +## @backstage/plugin-badges@0.2.50 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-badges-backend@0.3.4 + +### Patch Changes + +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.1 + +## @backstage/plugin-bazaar@0.2.18 + +### Patch Changes + +- c6e7940ccf: Updated Readme document in bazaar plugin +- 4e66e37bd1: Added alert popup for link and unlink entity in bazaar project +- c5aad900e3: Adding descending sort in a bazaar plugin +- 6c2b872153: Add official support for React 18. +- 69ee8d75f4: Remove `button` prop from used MaterialUI `MenuItem` component fixing incompatibility with MaterialUI v5. +- b3acba9091: Added alert popup in the bazaar plugin +- 1a40159acb: Removed unnecessary dependency on `@backstage/cli`. +- 62b5922916: Internal theme type updates +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/plugin-catalog@1.15.0 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-bazaar-backend@0.3.5 + +### Patch Changes + +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. +- 8613ba3928: Switched to using `"exports"` field for `/alpha` subpath export. +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.1 + +## @backstage/plugin-bitbucket-cloud-common@0.2.14 + +### Patch Changes + +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- Updated dependencies + - @backstage/integration@1.7.2 + +## @backstage/plugin-bitrise@0.1.53 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-catalog-backend-module-aws@0.3.1 + +### Patch Changes + +- 20d97d28a3: Updated dependency `aws-sdk-client-mock-jest` to `^3.0.0`. +- 3d043526f4: Updated dependency `aws-sdk-client-mock` to `^3.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/plugin-kubernetes-common@0.7.1 + - @backstage/integration@1.7.2 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/integration-aws-node@0.1.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + +## @backstage/plugin-catalog-backend-module-azure@0.1.26 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/integration@1.7.2 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + +## @backstage/plugin-catalog-backend-module-bitbucket@0.2.22 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/integration@1.7.2 + - @backstage/backend-common@0.19.9 + - @backstage/plugin-bitbucket-cloud-common@0.2.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.1.22 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/integration@1.7.2 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/catalog-client@1.4.6 + - @backstage/plugin-bitbucket-cloud-common@0.2.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-events-node@0.2.16 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.1.20 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/integration@1.7.2 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-catalog-backend-module-gcp@0.1.7 + +### Patch Changes + +- 62180df4ee: Allow integration with kubernetes dashboard +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/plugin-kubernetes-common@0.7.1 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + +## @backstage/plugin-catalog-backend-module-gerrit@0.1.23 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/integration@1.7.2 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-catalog-backend-module-github@0.4.5 + +### Patch Changes + +- 88b673aa76: Import `AnalyzeOptions` and `ScmLocationAnalyzer` types from `@backstage/plugin-catalog-node` +- Updated dependencies + - @backstage/plugin-catalog-backend@1.15.0 + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/integration@1.7.2 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-events-node@0.2.16 + +## @backstage/plugin-catalog-backend-module-github-org@0.1.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/plugin-catalog-backend-module-github@0.4.5 + - @backstage/config@1.1.1 + +## @backstage/plugin-catalog-backend-module-gitlab@0.3.4 + +### Patch Changes + +- d732f17610: Added try catch around fetching gitlab group users to prevent refresh from failing completely while only a select number of groups might not be able to load correctly. +- 0873a43ac1: Resolved a bug affecting the retrieval of users from group members. By appending '/all' to the API call, we now include members from all inherited groups, as per Gitlab's API specifications. This change is reflected in the listSaaSUsers function. +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/integration@1.7.2 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + +## @backstage/plugin-catalog-backend-module-incremental-ingestion@0.4.11 + +### Patch Changes + +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. +- Updated dependencies + - @backstage/plugin-catalog-backend@1.15.0 + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-events-node@0.2.16 + +## @backstage/plugin-catalog-backend-module-ldap@0.5.22 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/backend-tasks@0.5.12 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + +## @backstage/plugin-catalog-backend-module-msgraph@0.5.14 + +### Patch Changes + +- 224aa6f64c: export the function to read ms graph provider config +- 243c655a68: JSDoc and Error message updates to handle `Azure Active Directory` re-brand to `Entra ID` +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + +## @backstage/plugin-catalog-backend-module-openapi@0.1.24 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.15.0 + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/integration@1.7.2 + - @backstage/backend-common@0.19.9 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + +## @backstage/plugin-catalog-backend-module-puppetdb@0.1.12 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/plugin-scaffolder-common@1.4.3 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.18 + +## @backstage/plugin-catalog-backend-module-unprocessed@0.3.4 + +### Patch Changes + +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. +- Updated dependencies + - @backstage/backend-plugin-api@0.6.7 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-auth-node@0.4.1 + +## @backstage/plugin-catalog-common@1.0.18 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.10 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-catalog-graphql@0.4.1 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-import@0.10.2 + +### Patch Changes + +- 6db75b900a: Create an experimental plugin that is compatible with the declarative integration system, it is exported from the `/alpha` subpath. +- 6c2b872153: Add official support for React 18. +- dee1f39fcc: Fix missing children key warning on the default catalog import page. +- 71c97e7d73: The `app.title` configuration is now properly required to be a string. +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/frontend-plugin-api@0.3.0 + - @backstage/integration@1.7.2 + - @backstage/integration-react@1.1.21 + - @backstage/core-plugin-api@1.8.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.18 + +## @backstage/plugin-catalog-unprocessed-entities@0.1.5 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- a11cdb9200: Added filtering and sorting to unprocessed entities tables. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-cicd-statistics@0.1.28 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-plugin-api@1.8.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-cicd-statistics-module-gitlab@0.1.22 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-cicd-statistics@0.1.28 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-circleci@0.3.26 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-cloudbuild@0.3.26 + +### Patch Changes + +- 8ae07cab4c: Added Installation Steps so that it is clear what is needed to install and use the Google Cloud Plugin. +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-code-climate@0.1.26 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 62b5922916: Internal theme type updates +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-code-coverage@0.2.19 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 71c97e7d73: The warning for missing code coverage will now render the entity as a reference. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-code-coverage-backend@0.2.21 + +### Patch Changes + +- 11f671eaa9: Added support for new backend system +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. +- Updated dependencies + - @backstage/integration@1.7.2 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.1 + +## @backstage/plugin-codescene@0.1.19 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-config-schema@0.1.47 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-cost-insights@0.12.15 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 69ee8d75f4: Remove `button` prop from used MaterialUI `MenuItem` component fixing incompatibility with MaterialUI v5. +- d49cffaf6a: Updated dependency `@types/pluralize` to `^0.0.33`. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- 7da799d5b7: Updated dependency `@types/pluralize` to `^0.0.32`. +- 62b5922916: Internal theme type updates +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-cost-insights-common@0.1.2 + +## @backstage/plugin-devtools@0.1.6 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-permission-react@0.4.17 + - @backstage/theme@0.4.4 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.6 + +## @backstage/plugin-devtools-backend@0.2.4 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.5.3 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.1 + - @backstage/plugin-devtools-common@0.1.6 + - @backstage/plugin-permission-node@0.7.18 + +## @backstage/plugin-devtools-common@0.1.6 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.10 + - @backstage/types@1.1.1 + +## @backstage/plugin-dynatrace@8.0.0 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-entity-feedback@0.2.9 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## @backstage/plugin-entity-feedback-backend@0.2.4 + +### Patch Changes + +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.1 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## @backstage/plugin-entity-validation@0.1.11 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.18 + +## @backstage/plugin-events-backend@0.2.16 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.16 + +## @backstage/plugin-events-backend-module-aws-sqs@0.2.10 + +### Patch Changes + +- 3d043526f4: Updated dependency `aws-sdk-client-mock` to `^3.0.0`. +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.16 + +## @backstage/plugin-events-backend-module-azure@0.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.7 + - @backstage/plugin-events-node@0.2.16 + +## @backstage/plugin-events-backend-module-bitbucket-cloud@0.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.7 + - @backstage/plugin-events-node@0.2.16 + +## @backstage/plugin-events-backend-module-gerrit@0.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.7 + - @backstage/plugin-events-node@0.2.16 + +## @backstage/plugin-events-backend-module-github@0.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.7 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.16 + +## @backstage/plugin-events-backend-module-gitlab@0.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.7 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.16 + +## @backstage/plugin-events-backend-test-utils@0.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.2.16 + +## @backstage/plugin-events-node@0.2.16 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.7 + +## @backstage/plugin-explore@0.4.12 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- 62b5922916: Internal theme type updates +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/frontend-plugin-api@0.3.0 + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-explore-react@0.0.33 + - @backstage/plugin-search-react@1.7.2 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-explore-backend@0.0.17 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-backend-module-explore@0.1.11 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-explore-react@0.0.33 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-explore-common@0.0.2 + +## @backstage/plugin-firehydrant@0.2.10 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-fossa@0.2.58 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-gcalendar@0.3.20 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- 62b5922916: Internal theme type updates +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/errors@1.2.3 + +## @backstage/plugin-gcp-projects@0.3.43 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + +## @backstage/plugin-git-release-manager@0.3.39 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/integration@1.7.2 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + +## @backstage/plugin-github-actions@0.6.7 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- ee0c44ce62: Fixed an issue that was preventing the sorting of workflow runs by their status. +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/integration@1.7.2 + - @backstage/integration-react@1.1.21 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-github-deployments@0.1.57 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/integration@1.7.2 + - @backstage/integration-react@1.1.21 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-github-issues@0.2.15 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/integration@1.7.2 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-github-pull-requests-board@0.1.20 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/integration@1.7.2 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-gitops-profiles@0.3.42 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/config@1.1.1 + +## @backstage/plugin-gocd@0.1.32 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-graphql-backend@0.2.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/plugin-catalog-graphql@0.4.1 + - @backstage/config@1.1.1 + +## @backstage/plugin-graphql-voyager@0.1.9 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + +## @backstage/plugin-home@0.5.10 + +### Patch Changes + +- d86b2acec4: Fix bug where `retrieveAll` method wasn't fetching visits + +- 3fdffbb699: Remove the duplicate versions of `@rjsf/*` as they're no longer needed + +- 6c2b872153: Add official support for React 18. + +- 5b364984bf: Added experimental support for declarative integration via the `/alpha` subpath. + +- c838da0edd: Updated dependency `@rjsf/utils` to `5.13.6`. + Updated dependency `@rjsf/core` to `5.13.6`. + Updated dependency `@rjsf/material-ui` to `5.13.6`. + Updated dependency `@rjsf/validator-ajv8` to `5.13.6`. + +- cc0e8d0b51: Temporarily pin the `react-grid-layout` sub-dependency to version `1.3.4` while the horizontal resizing of the latest version is not fixed. For more details, see [#20712](https://github.com/backstage/backstage/issues/20712). + +- 302316d231: Added a new Featured Docs component to `plugin-home`, which can display any entity given a filter. + + import { FeaturedDocsCard } from '@backstage/plugin-home'; + + + + See the [storybook examples](https://backstage.io/storybook/?path=/story/plugins-home-components-featureddocs--default) + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/frontend-plugin-api@0.3.0 + - @backstage/core-plugin-api@1.8.0 + - @backstage/core-app-api@1.11.1 + - @backstage/plugin-home-react@0.1.5 + - @backstage/theme@0.4.4 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## @backstage/plugin-home-react@0.1.5 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- c838da0edd: Updated dependency `@rjsf/utils` to `5.13.6`. + Updated dependency `@rjsf/core` to `5.13.6`. + Updated dependency `@rjsf/material-ui` to `5.13.6`. + Updated dependency `@rjsf/validator-ajv8` to `5.13.6`. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + +## @backstage/plugin-ilert@0.2.15 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-jenkins@0.9.1 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-jenkins-common@0.1.21 + +## @backstage/plugin-jenkins-backend@0.3.1 + +### Patch Changes + +- 4bfb878807: Updated dependency `@types/jenkins` to `^1.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/catalog-client@1.4.6 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.1 + - @backstage/plugin-jenkins-common@0.1.21 + - @backstage/plugin-permission-node@0.7.18 + +## @backstage/plugin-jenkins-common@0.1.21 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-catalog-common@1.0.18 + +## @backstage/plugin-kafka@0.3.26 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + +## @backstage/plugin-kafka-backend@0.3.5 + +### Patch Changes + +- 8613ba3928: Switched to using `"exports"` field for `/alpha` subpath export. +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-kubernetes@0.11.1 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/plugin-kubernetes-common@0.7.1 + - @backstage/plugin-kubernetes-react@0.1.1 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-kubernetes-backend@0.13.1 + +### Patch Changes + +- 62180df4ee: Allow storing dashboard parameters for kubernetes in catalog +- df40b067e1: Fixed the lack of `resourcequotas` as part of the Default Objects to fetch from the kubernetes api +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/plugin-kubernetes-common@0.7.1 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/integration-aws-node@0.1.8 + - @backstage/catalog-client@1.4.6 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.1 + - @backstage/plugin-kubernetes-node@0.1.1 + - @backstage/plugin-permission-node@0.7.18 + +## @backstage/plugin-kubernetes-cluster@0.0.2 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/plugin-kubernetes-common@0.7.1 + - @backstage/plugin-kubernetes-react@0.1.1 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-kubernetes-common@0.7.1 + +### Patch Changes + +- 62180df4ee: Allow storing dashboard parameters for kubernetes in catalog +- df40b067e1: Fixed the lack of `resourcequotas` as part of the Default Objects to fetch from the kubernetes api +- Updated dependencies + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-kubernetes-node@0.1.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes-common@0.7.1 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-kubernetes-react@0.1.1 + +### Patch Changes + +- 0f4cad6da0: Internal refactor to avoid a null pointer problem + +- 6c2b872153: Add official support for React 18. + +- b52f576f48: Make sure types exported by other `kubernetes` plugins in the past are exported again after the creation + of the react package. + + Some types have been moved to this new package but the export was missing, so they were not available anymore for developers. + +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/plugin-kubernetes-common@0.7.1 + - @backstage/core-plugin-api@1.8.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-lighthouse@0.4.11 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-lighthouse-common@0.1.4 + +## @backstage/plugin-lighthouse-backend@0.3.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-lighthouse-common@0.1.4 + +## @backstage/plugin-linguist@0.1.11 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-linguist-common@0.1.2 + +## @backstage/plugin-linguist-backend@0.5.4 + +### Patch Changes + +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.1 + - @backstage/plugin-linguist-common@0.1.2 + +## @backstage/plugin-microsoft-calendar@0.1.9 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 62b5922916: Internal theme type updates +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/errors@1.2.3 + +## @backstage/plugin-newrelic@0.3.42 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + +## @backstage/plugin-newrelic-dashboard@0.3.1 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-nomad@0.1.7 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + +## @backstage/plugin-nomad-backend@0.1.9 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-octopus-deploy@0.2.8 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4d2f72c572: Added Deep link into Octopus Deploy project from the Release Table. +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-opencost@0.2.2 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + +## @backstage/plugin-org@0.6.16 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 62b5922916: Internal theme type updates +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-org-react@0.1.15 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 62b5922916: Internal theme type updates +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-pagerduty@0.6.7 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-home-react@0.1.5 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-periskop@0.1.24 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-periskop-backend@0.2.5 + +### Patch Changes + +- 8613ba3928: Switched to using `"exports"` field for `/alpha` subpath export. +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/config@1.1.1 + +## @backstage/plugin-permission-backend@0.5.30 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.1 + - @backstage/plugin-permission-node@0.7.18 + +## @backstage/plugin-permission-backend-module-allow-all-policy@0.1.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-auth-node@0.4.1 + - @backstage/plugin-permission-node@0.7.18 + +## @backstage/plugin-permission-common@0.7.10 + +### Patch Changes + +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-permission-node@0.7.18 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.1 + +## @backstage/plugin-permission-react@0.4.17 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/config@1.1.1 + +## @backstage/plugin-playlist-backend@0.3.11 + +### Patch Changes + +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/catalog-client@1.4.6 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.1 + - @backstage/plugin-permission-node@0.7.18 + - @backstage/plugin-playlist-common@0.1.12 + +## @backstage/plugin-playlist-common@0.1.12 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.10 + +## @backstage/plugin-proxy-backend@0.4.5 + +### Patch Changes + +- 8613ba3928: Switched to using `"exports"` field for `/alpha` subpath export. +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/config@1.1.1 + +## @backstage/plugin-puppetdb@0.1.9 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-rollbar@0.4.26 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-rollbar-backend@0.1.52 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/config@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.8 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.2 + - @backstage/backend-common@0.19.9 + - @backstage/plugin-scaffolder-node@0.2.8 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.2.31 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.2 + - @backstage/backend-common@0.19.9 + - @backstage/plugin-scaffolder-node@0.2.8 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-gitlab@0.2.10 + +### Patch Changes + +- 26ca97ebaa: Add examples for `gitlab:projectAccessToken:create` scaffolder action & improve related tests +- Updated dependencies + - @backstage/integration@1.7.2 + - @backstage/plugin-scaffolder-node@0.2.8 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-scaffolder-backend-module-rails@0.4.24 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.2 + - @backstage/backend-common@0.19.9 + - @backstage/plugin-scaffolder-node@0.2.8 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-sentry@0.1.15 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.8 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.2.28 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.8 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-common@1.4.3 + +### Patch Changes + +- 2e0cef42ab: Add missing required property `type` in `Template.v1beta3.schema.json` schema +- 76d07da66a: Make it possible to define control buttons text (Back, Create, Review) per template +- Updated dependencies + - @backstage/plugin-permission-common@0.7.10 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-node@0.2.8 + +### Patch Changes + +- 8613ba3928: Switched to using `"exports"` field for `/alpha` subpath export. +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.4.3 + - @backstage/integration@1.7.2 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-search@1.4.2 + +### Patch Changes + +- 68fc9dc60e: Updated alpha exports according to routing changes in `@backstage/frontend-plugin-api`. +- 6c2b872153: Add official support for React 18. +- 62b5922916: Internal theme type updates +- fa11120050: Fixed incorrect plugin ID in `/alpha` export. +- 71c97e7d73: Minor internal code cleanup. +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/frontend-plugin-api@0.3.0 + - @backstage/core-plugin-api@1.8.0 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-search-react@1.7.2 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend@1.4.7 + +### Patch Changes + +- 6694b369a3: Update the OpenAPI spec with more complete error responses and request bodies using Optic. Also, updates the test cases to use the new `supertest` pass through from `@backstage/backend-openapi-utils`. +- Updated dependencies + - @backstage/plugin-search-backend-node@1.2.11 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/backend-openapi-utils@0.1.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.1 + - @backstage/plugin-permission-node@0.7.18 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-module-catalog@0.1.11 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/plugin-search-backend-node@1.2.11 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/catalog-client@1.4.6 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-module-elasticsearch@1.3.10 + +### Patch Changes + +- 006df4a581: Support AWS OpenSearch Serverless search backend. Does not support `_refresh` endpoint. +- Updated dependencies + - @backstage/plugin-search-backend-node@1.2.11 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/integration-aws-node@0.1.8 + - @backstage/config@1.1.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-module-explore@0.1.11 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-node@1.2.11 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/config@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-module-pg@0.5.16 + +### Patch Changes + +- 2b4cd1ccae: Optimize outdated documents deletion logic in PgSearchEngine DatabaseDocumentStore which significantly reduces cost on large tables +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. +- Updated dependencies + - @backstage/plugin-search-backend-node@1.2.11 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/config@1.1.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-module-techdocs@0.1.11 + +### Patch Changes + +- c437253b7a: The process of adding or modifying fields in the techdocs search index has been simplified. For more details, see [How to customize fields in the Software Catalog or TechDocs index](https://backstage.io/docs/features/search/how-to-guides.md#how-to-customize-fields-in-the-software-catalog-or-techdocs-index). +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/plugin-techdocs-node@1.10.0 + - @backstage/plugin-search-backend-node@1.2.11 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/catalog-client@1.4.6 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-node@1.2.11 + +### Patch Changes + +- b168d7e7ea: Fix highlighting for non-string fields on the `Lunr` search engine implementation. +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-common@1.2.8 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.10 + - @backstage/types@1.1.1 + +## @backstage/plugin-search-react@1.7.2 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- f48cde800a: Emit search analytics in the search hook instead of in a dedicated component +- f75caf9f3d: Fixed a rare occurrence where a race in the search bar could throw away user input or cause the clear button not to work. +- 77f009b35d: Internal updates to match changes in the experimental `@backstage/frontend-plugin-api`. +- a539643cba: Minor refactor of search bar analytics capture +- 71c97e7d73: The filter options passed to `SearchResultGroupLayout` are now always explicitly rendered as strings by default. +- e7c09c4f4b: Use default extensions boundary and suspense on the alpha declarative `createSearchResultListItem` extension factory. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/frontend-plugin-api@0.3.0 + - @backstage/frontend-app-api@0.3.0 + - @backstage/core-plugin-api@1.8.0 + - @backstage/version-bridge@1.0.7 + - @backstage/theme@0.4.4 + - @backstage/types@1.1.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-sentry@0.5.11 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-shortcuts@0.3.16 + +### Patch Changes + +- 55725922a5: Ensure that shortcuts aren't duplicate-checked against themselves +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/types@1.1.1 + +## @backstage/plugin-sonarqube@0.7.8 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- 62b5922916: Internal theme type updates +- 8613ba3928: Switched to using `"exports"` field for `/alpha` subpath export. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-sonarqube-react@0.1.10 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-sonarqube-backend@0.2.9 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-sonarqube-react@0.1.10 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/core-plugin-api@1.8.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-splunk-on-call@0.4.15 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-stack-overflow@0.1.22 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- b168d7e7ea: Migrate package to the new Frontend system, the new module is distributed with a `/alpha` subpath. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/frontend-plugin-api@0.3.0 + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-search-react@1.7.2 + - @backstage/plugin-home-react@0.1.5 + - @backstage/theme@0.4.4 + - @backstage/config@1.1.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-stack-overflow-backend@0.2.11 + +### Patch Changes + +- b168d7e7ea: Deprecate package in favor of the new `@backstage/plugin-search-backend-module-stack-overflow-collator` module. + + The search collator `requestParams` option is optional now, so its default value is `{ order: 'desc', sort: 'activity', site: 'stackoverflow' }` as defined in the `Try It` section on the [official Stack Overflow API documentation](https://api.stackexchange.com/docs/questions). + +- Updated dependencies + - @backstage/plugin-search-backend-module-stack-overflow-collator@0.1.0 + - @backstage/backend-common@0.19.9 + - @backstage/config@1.1.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-stackstorm@0.1.8 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/errors@1.2.3 + +## @backstage/plugin-tech-insights@0.3.18 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 62b5922916: Internal theme type updates +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-insights-backend@0.5.21 + +### Patch Changes + +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. +- 193ad022bb: Add `factRetrieverId` to the fact retriever's logger metadata. +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-tasks@0.5.12 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + - @backstage/plugin-tech-insights-node@0.4.13 + +## @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.39 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-tech-insights-common@0.2.12 + - @backstage/plugin-tech-insights-node@0.4.13 + +## @backstage/plugin-tech-insights-node@0.4.13 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-tasks@0.5.12 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-radar@0.6.10 + +### Patch Changes + +- 68fc9dc60e: Updated alpha exports according to routing changes in `@backstage/frontend-plugin-api`. +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/frontend-plugin-api@0.3.0 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.23 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/plugin-catalog@1.15.0 + - @backstage/plugin-techdocs@1.9.0 + - @backstage/integration-react@1.1.21 + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-techdocs-react@1.1.13 + - @backstage/core-app-api@1.11.1 + - @backstage/plugin-search-react@1.7.2 + - @backstage/test-utils@1.4.5 + - @backstage/theme@0.4.4 + +## @backstage/plugin-techdocs-module-addons-contrib@1.1.2 + +### Patch Changes + +- 4728b3960d: Fixed navigation bug that caused users to not be scrolled to the top of a new page. Fixed navigation bug where using backwards and forwards browser navigation did not scroll users to the correct place on the TechDoc page. +- 6c2b872153: Add official support for React 18. +- 62b5922916: Internal theme type updates +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/integration@1.7.2 + - @backstage/integration-react@1.1.21 + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-techdocs-react@1.1.13 + - @backstage/theme@0.4.4 + +## @backstage/plugin-techdocs-react@1.1.13 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/version-bridge@1.0.7 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + +## @backstage/plugin-todo@0.2.30 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 8613ba3928: Switched to using `"exports"` field for `/alpha` subpath export. +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-todo-backend@0.3.5 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/integration@1.7.2 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/catalog-client@1.4.6 + - @backstage/backend-openapi-utils@0.1.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-user-settings@0.7.12 + +### Patch Changes + +- 68fc9dc60e: Updated alpha exports according to routing changes in `@backstage/frontend-plugin-api`. +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/frontend-plugin-api@0.3.0 + - @backstage/core-plugin-api@1.8.0 + - @backstage/core-app-api@1.11.1 + - @backstage/theme@0.4.4 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-user-settings-backend@0.2.6 + +### Patch Changes + +- dd0350379b: Added dependency on `@backstage/config` +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. +- 8613ba3928: Switched to using `"exports"` field for `/alpha` subpath export. +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.1 + +## @backstage/plugin-vault@0.1.21 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-xcmetrics@0.2.45 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 62b5922916: Internal theme type updates +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/errors@1.2.3 + +## example-app@0.2.89 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-api-docs@0.10.0 + - @backstage/plugin-catalog-import@0.10.2 + - @backstage/cli@0.24.0 + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/plugin-shortcuts@0.3.16 + - @backstage/plugin-home@0.5.10 + - @backstage/core-components@0.13.8 + - @backstage/plugin-catalog@1.15.0 + - @backstage/plugin-graphiql@0.3.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.2 + - @backstage/plugin-techdocs@1.9.0 + - @backstage/plugin-cloudbuild@0.3.26 + - @backstage/plugin-scaffolder@1.16.0 + - @backstage/frontend-app-api@0.3.0 + - @backstage/plugin-user-settings@0.7.12 + - @backstage/plugin-tech-radar@0.6.10 + - @backstage/plugin-search@1.4.2 + - @backstage/plugin-catalog-unprocessed-entities@0.1.5 + - @backstage/integration-react@1.1.21 + - @backstage/plugin-kubernetes-cluster@0.0.2 + - @backstage/plugin-microsoft-calendar@0.1.9 + - @backstage/plugin-newrelic-dashboard@0.3.1 + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-permission-react@0.4.17 + - @backstage/plugin-scaffolder-react@1.6.0 + - @backstage/plugin-entity-feedback@0.2.9 + - @backstage/plugin-apache-airflow@0.2.17 + - @backstage/plugin-github-actions@0.6.7 + - @backstage/plugin-octopus-deploy@0.2.8 + - @backstage/plugin-stack-overflow@0.1.22 + - @backstage/plugin-techdocs-react@1.1.13 + - @backstage/app-defaults@1.4.5 + - @backstage/core-app-api@1.11.1 + - @backstage/plugin-catalog-graph@0.3.0 + - @backstage/plugin-code-coverage@0.2.19 + - @backstage/plugin-cost-insights@0.12.15 + - @backstage/plugin-tech-insights@0.3.18 + - @backstage/plugin-azure-devops@0.3.8 + - @backstage/plugin-gcp-projects@0.3.43 + - @backstage/plugin-search-react@1.7.2 + - @backstage/plugin-azure-sites@0.1.15 + - @backstage/plugin-kubernetes@0.11.1 + - @backstage/plugin-lighthouse@0.4.11 + - @backstage/plugin-stackstorm@0.1.8 + - @backstage/plugin-dynatrace@8.0.0 + - @backstage/plugin-gcalendar@0.3.20 + - @backstage/plugin-pagerduty@0.6.7 + - @backstage/plugin-airbrake@0.3.26 + - @backstage/plugin-circleci@0.3.26 + - @backstage/plugin-devtools@0.1.6 + - @backstage/plugin-linguist@0.1.11 + - @backstage/plugin-newrelic@0.3.42 + - @backstage/plugin-playlist@0.2.0 + - @backstage/plugin-puppetdb@0.1.9 + - @backstage/plugin-explore@0.4.12 + - @backstage/plugin-jenkins@0.9.1 + - @backstage/plugin-rollbar@0.4.26 + - @backstage/theme@0.4.4 + - @backstage/plugin-badges@0.2.50 + - @backstage/plugin-sentry@0.5.11 + - @backstage/plugin-kafka@0.3.26 + - @backstage/plugin-nomad@0.1.7 + - @backstage/plugin-gocd@0.1.32 + - @backstage/plugin-todo@0.2.30 + - @backstage/plugin-adr@0.6.9 + - @backstage/plugin-org@0.6.16 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.8 + +## example-app-next@0.0.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-api-docs@0.10.0 + - @backstage/plugin-catalog-import@0.10.2 + - @backstage/cli@0.24.0 + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/plugin-shortcuts@0.3.16 + - @backstage/plugin-home@0.5.10 + - @backstage/core-components@0.13.8 + - @backstage/frontend-plugin-api@0.3.0 + - @backstage/plugin-catalog@1.15.0 + - @backstage/plugin-graphiql@0.3.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.2 + - @backstage/plugin-techdocs@1.9.0 + - @backstage/plugin-cloudbuild@0.3.26 + - @backstage/plugin-scaffolder@1.16.0 + - @backstage/frontend-app-api@0.3.0 + - @backstage/plugin-user-settings@0.7.12 + - @backstage/plugin-tech-radar@0.6.10 + - @backstage/plugin-search@1.4.2 + - @backstage/plugin-catalog-unprocessed-entities@0.1.5 + - @backstage/integration-react@1.1.21 + - @backstage/plugin-microsoft-calendar@0.1.9 + - @backstage/plugin-newrelic-dashboard@0.3.1 + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-permission-react@0.4.17 + - @backstage/plugin-scaffolder-react@1.6.0 + - @backstage/plugin-entity-feedback@0.2.9 + - @backstage/plugin-apache-airflow@0.2.17 + - @backstage/plugin-github-actions@0.6.7 + - @backstage/plugin-octopus-deploy@0.2.8 + - @backstage/plugin-techdocs-react@1.1.13 + - @backstage/app-defaults@1.4.5 + - @backstage/core-app-api@1.11.1 + - @backstage/plugin-catalog-graph@0.3.0 + - @backstage/plugin-code-coverage@0.2.19 + - @backstage/plugin-cost-insights@0.12.15 + - @backstage/plugin-tech-insights@0.3.18 + - @backstage/plugin-azure-devops@0.3.8 + - @backstage/plugin-gcp-projects@0.3.43 + - @backstage/plugin-search-react@1.7.2 + - @backstage/plugin-azure-sites@0.1.15 + - @backstage/plugin-kubernetes@0.11.1 + - @backstage/plugin-lighthouse@0.4.11 + - @backstage/plugin-stackstorm@0.1.8 + - @backstage/plugin-dynatrace@8.0.0 + - @backstage/plugin-gcalendar@0.3.20 + - @backstage/plugin-pagerduty@0.6.7 + - @backstage/plugin-airbrake@0.3.26 + - @backstage/plugin-circleci@0.3.26 + - @backstage/plugin-devtools@0.1.6 + - @backstage/plugin-linguist@0.1.11 + - @backstage/plugin-newrelic@0.3.42 + - @backstage/plugin-playlist@0.2.0 + - @backstage/plugin-puppetdb@0.1.9 + - @backstage/plugin-explore@0.4.12 + - @backstage/plugin-jenkins@0.9.1 + - @backstage/plugin-rollbar@0.4.26 + - @backstage/theme@0.4.4 + - @backstage/plugin-badges@0.2.50 + - @backstage/plugin-sentry@0.5.11 + - @backstage/plugin-kafka@0.3.26 + - @backstage/plugin-gocd@0.1.32 + - @backstage/plugin-todo@0.2.30 + - @backstage/plugin-adr@0.6.9 + - @backstage/plugin-org@0.6.16 + - app-next-example-plugin@0.0.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-compat-api@0.0.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.8 + +## app-next-example-plugin@0.0.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/frontend-plugin-api@0.3.0 + +## example-backend@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 + +## example-backend-next@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 + +## @backstage/backend-plugin-manager@0.0.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.15.0 + - @backstage/cli-node@0.2.0 + - @backstage/plugin-search-backend-node@1.2.11 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-scaffolder-node@0.2.8 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.1 + - @backstage/plugin-events-backend@0.2.16 + - @backstage/plugin-events-node@0.2.16 + - @backstage/plugin-permission-node@0.7.18 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/core-compat-api@0.0.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.3.0 + - @backstage/core-plugin-api@1.8.0 + +## e2e-test@0.2.9 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.7 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + +## techdocs-cli-embedded-app@0.2.88 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.24.0 + - @backstage/core-components@0.13.8 + - @backstage/plugin-catalog@1.15.0 + - @backstage/plugin-techdocs@1.9.0 + - @backstage/integration-react@1.1.21 + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-techdocs-react@1.1.13 + - @backstage/app-defaults@1.4.5 + - @backstage/core-app-api@1.11.1 + - @backstage/test-utils@1.4.5 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + +## @internal/plugin-todo-list@1.0.19 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + +## @internal/plugin-todo-list-backend@1.0.19 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.1 + +## @internal/plugin-todo-list-common@1.0.15 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.10 diff --git a/docs/releases/v1.20.0.md b/docs/releases/v1.20.0.md new file mode 100644 index 0000000000..921b8219fb --- /dev/null +++ b/docs/releases/v1.20.0.md @@ -0,0 +1,50 @@ +--- +id: v1.20.0 +title: v1.20.0 +description: Backstage Release v1.20.0 +--- + +These are the release notes for the v1.20.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 + +### 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. + +### Experimental support for Vite ⚡ + +Due to some concerns about performance in larger monorepo setups and hot-reloading times, we’re looking to replace [Webpack](https://webpack.js.org/) with [Vite](https://vitejs.dev/) longer term, and in this release we’re shipping experimental support for Vite behind an `EXPERIMENTAL_VITE` environment variable flag when running `yarn start` in the frontend. + +Please reach out by [creating a GitHub issue](https://github.com/backstage/backstage/issues/new/choose) with any problems that you might be running into when using this experimental feature. + +### Scaffolder: `react-jsonschema-form@v5` + Design tweaks 💅 + +It’s finally here. We’ve shipped support for `react-jsonschema-form@v5` which **should** be a completely non-breaking change for end users. We’ve also tweaked some of the designs for some of the new Scaffolder Pages. You can read more in the [relevant migration docs](https://backstage.io/docs/features/software-templates/migrating-to-rjsf-v5) + +### Catalog Presentation API + +The Catalog plugin now uses the `EntityPresentationApi` to decide how entities are rendered in the UI. This includes fetching catalog data in the background in order to show entities using their `metadata.title`. For more information, including how to customize the presentation, see [the PR](https://github.com/backstage/backstage/pull/17474), (documentation is in the works!). + +## 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.20.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.21.0-changelog.md b/docs/releases/v1.21.0-changelog.md new file mode 100644 index 0000000000..2a93c55305 --- /dev/null +++ b/docs/releases/v1.21.0-changelog.md @@ -0,0 +1,3731 @@ +# Release v1.21.0 + +## @backstage/backend-common@0.20.0 + +### Minor Changes + +- 870db76: Implemented `readTree` for Gitea provider to support TechDocs functionality + +### Patch Changes + +- 7f04128: Allow a default cache TTL to be set through the app config +- 1ad8906: Use `Readable.from` to fix some of the stream issues +- d86a007: Fixed the AwsS3UrlReader host regex and host to allow the S3 reading for CN AWS domain +- bc67498: Updated dependency `archiver` to `^6.0.0`. + Updated dependency `@types/archiver` to `^6.0.0`. +- 706fc3a: Updated dependency `@kubernetes/client-node` to `0.20.0`. +- 2666675: Updated dependency `@google-cloud/storage` to `^7.0.0`. +- d15d483: Add command `--runAsDefaultUser` for `@techdocs/cli generate` to bypass running the docker builds as host user for macOS and Linux. +- d1e00aa: Expose an `onAuth` handler for `git` actions to provide custom credentials +- Updated dependencies + - @backstage/config-loader@1.6.0 + - @backstage/backend-app-api@0.5.9 + - @backstage/integration@1.8.0 + - @backstage/backend-dev-utils@0.1.2 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + +## @backstage/catalog-client@1.5.0 + +### Minor Changes + +- 3834067: The internals of `CatalogClient` are now auto-generated using the `backstage-repo-tools schema openapi generate-client` command. + +### Patch Changes + +- 82fa88b: Fixes a bug where some query parameters were double URL encoded. +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/cli@0.25.0 + +### Minor Changes + +- 3834067: Updates the ESLint config to ignore issues created by generated files in `**/src/generated/**`. + +### Patch Changes + +- 32018ff: Enable the `tsx` loader to work on Node 18.19 and up +- 0ffee55: Toned down the warning message when git is not found +- c6f3743: Added a warning when starting a standalone backend plugin that hasn't been updated to the new backend system. +- 3e358b0: Added deprecation warning for React Router v6 beta, please make sure you have migrated your apps to use React Router v6 stable as support for the beta version will be removed. See the [migration tutorial](https://backstage.io/docs/tutorials/react-router-stable-migration) for more information. +- 219d7f0: Updating template generation for scaffolder module +- 8cda3c7: Tweaked Node.js version check for when to use the new module register API with the new backend `package start` command. +- a3edc18: Updated dependency `vite-plugin-node-polyfills` to `^0.17.0`. +- 627554e: Updated dependency `@rollup/plugin-node-resolve` to `^15.0.0`. +- c07cee5: Updated dependency `@rollup/plugin-json` to `^6.0.0`. +- bd586a5: Updated dependency `bfj` to `^8.0.0`. +- 8056425: Updated dependency `@typescript-eslint/eslint-plugin` to `6.12.0`. +- 017c425: Updated dependency `@typescript-eslint/eslint-plugin` to `6.11.0`. +- 2565cc8: Updated dependency `@rollup/plugin-commonjs` to `^25.0.0`. +- 33e96e5: Switched the `@typescript-eslint/eslint-plugin` dependency back to using a `^` version range. +- 0cbb03b: Fixing regular expression ReDoS with zod packages. Upgrading to latest. ref: +- Updated dependencies + - @backstage/eslint-plugin@0.1.4 + - @backstage/config-loader@1.6.0 + - @backstage/integration@1.8.0 + - @backstage/cli-node@0.2.1 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/release-manifests@0.0.11 + - @backstage/types@1.1.1 + +## @backstage/config-loader@1.6.0 + +### Minor Changes + +- 24f5a85: Add "path" to `TransformFunc` context + +### Patch Changes + +- Updated dependencies + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/core-compat-api@0.1.0 + +### Minor Changes + +- cf5cc4c: Discover plugins and routes recursively beneath the root routes in `collectLecacyRoutes` +- af7bc3e: Switched all core extensions to instead use the namespace `'app'`. +- f63dd72: The `collectLegacyRoutes` has been removed and is replaced by `convertLegacyApp` now being able to convert a `FlatRoutes` element directly. + +### Patch Changes + +- 03d0b6d: Added `convertLegacyRouteRef` utility to convert existing route refs to be used with the new experimental packages. +- a379243: Leverage the new `FrontendFeature` type to simplify interfaces +- 8226442: Added `compatWrapper`, which can be used to wrap any React element to provide bi-directional interoperability between the `@backstage/core-*-api` and `@backstage/frontend-*-api` APIs. +- 8f5d6c1: Updates to match the new extension input wrapping. +- c219b16: Made package public so it can be published +- b7adf24: Delete alpha DI compatibility helper for components, migrating components should be simple without a helper. +- 046e443: Updates for compatibility with the new extension IDs. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/frontend-plugin-api@0.4.0 + - @backstage/core-app-api@1.11.2 + - @backstage/version-bridge@1.0.7 + +## @backstage/frontend-app-api@0.4.0 + +### Minor Changes + +- e539735: Updated core extension structure to make space for the sign-in page by adding `core.router`. +- 44735df: Removed `featureLoader` from `createApp`, `features` instead accepts both `FrontendFeature` and `CreateAppFeatureLoader` +- af7bc3e: Switched all core extensions to instead use the namespace `'app'`. +- ea06590: The app no longer provides the `AppContext` from `@backstage/core-plugin-api`. Components that require this context to be available should use the `compatWrapper` helper from `@backstage/core-compat-api`. + +### Patch Changes + +- 5eb6b8a: Added the nav logo extension for customization of sidebar logo +- aeb8008: Add support for translation extensions. +- 1f12fb7: Create a core components extension that allows adopters to override core app components such as `Progress`, `BootErrorPage`, `NotFoundErrorPage` and `ErrorBoundaryFallback`. +- a379243: Leverage the new `FrontendFeature` type to simplify interfaces +- 60d6eb5: Removed `@backstage/plugin-graphiql` dependency. +- b7adf24: Use the new plugin type for error boundary components. +- 5970928: Collect and register feature flags from plugins and extension overrides. +- 9ad4039: Bringing over apis from core-plugin-api +- 8f5d6c1: Updates to match the new extension input wrapping. +- c35036b: A `configLoader` passed to `createApp` now returns an object, to make room for future expansion +- f27ee7d: Migrate analytics route tracker component. +- b8cb780: Added `createSpecializedApp`, which is a synchronous version of `createApp` where config and features already need to be loaded. +- c36e0b9: Renamed `AppRouteBinder` to `CreateAppRouteBinder` +- cb4197a: Forward ` node`` instead of `extensionId\` to resolved extension inputs. +- 8837a96: Updates to match the introduction of `ExtensionDefinition` and new extension ID naming patterns. +- a5a0473: Updates to provide `node` to extension factories instead of `id` and `source`. +- 5cdf2b3: Updated usage of `Extension` and `ExtensionDefinition` as they are now opaque. +- f9ef632: Updates to match the new `coreExtensionData` structure. +- f1183b7: Renamed the `component` option of `createComponentExtension` to `loader`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/frontend-plugin-api@0.4.0 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/core-app-api@1.11.2 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/frontend-plugin-api@0.4.0 + +### Minor Changes + +- af7bc3e: Switched all core extensions to instead use the namespace `'app'`. + +- 5cdf2b3: Changed `Extension` and `ExtensionDefinition` to use opaque types. + +- 8f5d6c1: Extension inputs are now wrapped into an additional object when passed to the extension factory, with the previous values being available at the `output` property. The `ExtensionInputValues` type has also been replaced by `ResolvedExtensionInputs`. + +- 8837a96: **BREAKING**: This version changes how extensions are created and how their IDs are determined. The `createExtension` function now accepts `kind`, `namespace` and `name` instead of `id`. All of the new options are optional, and are used to construct the final extension ID. By convention extension creators should set the `kind` to match their own name, for example `createNavItemExtension` sets the kind `nav-item`. + + The `createExtension` function as well as all extension creators now also return an `ExtensionDefinition` rather than an `Extension`, which in turn needs to be passed to `createPlugin` or `createExtensionOverrides` to be used. + +- f9ef632: Moved several extension data references from `coreExtensionData` to their respective extension creators. + +- a5a0473: The extension `factory` function now longer receives `id` or `source`, but instead now provides the extension's `AppNode` as `node`. The `ExtensionBoundary` component has also been updated to receive a `node` prop rather than `id` and `source`. + +### Patch Changes + +- a379243: Add the `FrontendFeature` type, which is the union of `BackstagePlugin` and `ExtensionOverrides` +- b7adf24: Update alpha component ref type to be more specific than any, delete boot page component and use new plugin type for error boundary component extensions. +- 5eb6b8a: Added the nav logo extension for customization of sidebar logo +- 1f12fb7: Create factories for overriding default core components extensions. +- 5970928: Add feature flags to plugins and extension overrides. +- e539735: Added `createSignInPageExtension`. +- 73246ec: Added translation APIs as well as `createTranslationExtension`. +- cb4197a: Forward ` node`` instead of `extensionId\` to resolved extension inputs. +- f27ee7d: Migrate analytics api and context files. +- 0cbb03b: Fixing regular expression ReDoS with zod packages. Upgrading to latest. ref: +- f1183b7: Renamed the `component` option of `createComponentExtension` to `loader`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/frontend-test-utils@0.1.0 + +### Minor Changes + +- 59fabd5: New testing utility library for `@backstage/frontend-app-api` and `@backstage/frontend-plugin-api`. +- af7bc3e: Switched all core extensions to instead use the namespace `'app'`. + +### Patch Changes + +- 59fabd5: Added `createExtensionTester` for rendering extensions in tests. +- 7e4b0db: The `createExtensionTester` helper is now able to render more than one route in the test app. +- 818eea4: Updates for compatibility with the new extension IDs. +- b9aa6e4: Migrate `renderInTestApp` to `@backstage/frontend-test-utils` for testing individual React components in an app. +- e539735: Updates for `core.router` addition. +- c21c9cf: Re-export mock API implementations as well as `TestApiProvider`, `TestApiRegistry`, `withLogCollector`, and `setupRequestMockHandlers` from `@backstage/test-utils`. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0 + - @backstage/frontend-app-api@0.4.0 + - @backstage/test-utils@1.4.6 + - @backstage/types@1.1.1 + +## @backstage/integration@1.8.0 + +### Minor Changes + +- 870db76: Implemented `readTree` for Gitea provider to support TechDocs functionality + +### Patch Changes + +- 99fb541: Updated dependency `@azure/identity` to `^4.0.0`. +- Updated dependencies + - @backstage/config@1.1.1 + +## @backstage/repo-tools@0.5.0 + +### Minor Changes + +- aea8f8d: **BREAKING**: API Reports generated for sub-path exports now place the name as a suffix rather than prefix, for example `api-report-alpha.md` instead of `alpha-api-report.md`. When upgrading to this version you'll need to re-create any such API reports and delete the old ones. +- 3834067: Adds a new command `schema openapi generate-client` that creates a Typescript client with Backstage flavor, including the discovery API and fetch API. This command doesn't currently generate a complete client and needs to be wrapped or exported manually by a separate Backstage plugin. See `@backstage/catalog-client/src/generated` for example output. + +### Patch Changes + +- f909e9d: Includes templates in @backstage/repo-tools package and use them in the CLI + +- da3c4db: Updates the `schema openapi generate-client` command to export all generated types from the generated directory. + +- 7959f23: The `api-reports` command now checks for api report files that no longer apply. + If it finds such files, it's treated basically the same as report errors do, and + the check fails. + + For example, if you had an `api-report-alpha.md` but then removed the alpha + export, the reports generator would now report that this file needs to be + deleted. + +- f49e237: Fixed a bug where `schema openapi init` created an invalid test command. + +- f91be2c: Updated dependency `@stoplight/types` to `^14.0.0`. + +- 45bfb20: Execute `openapi-generator-cli` from `@backstage/repo-tools` directory to force it to use our openapitools.json config file. + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/cli-node@0.2.1 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + +## @techdocs/cli@1.8.0 + +### Minor Changes + +- d15d483: Add command `--runAsDefaultUser` for `@techdocs/cli generate` to bypass running the docker builds as host user for macOS and Linux. +- b2dccad: Support passing additional `mkdocs-server` CLI parameters (`--dirtyreload`, `--strict` and `--clean`) when run in containerized mode. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-techdocs-node@1.11.0 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + +## @backstage/theme@0.5.0 + +### Minor Changes + +- 4d9e3b3: Added a global `OverrideComponentNameToClassKeys` for other plugins and packages to populate using module augmentation. This will in turn will provide component style override types for `createUnifiedTheme`. + +### Patch Changes + +- cd0dd4c: Align Material UI v5 `Paper` component background color in dark mode to v4. + +## @backstage/plugin-auth-backend-module-atlassian-provider@0.1.0 + +### Minor Changes + +- 2a5891e: New module for `@backstage/plugin-auth-backend` that adds an atlassian auth provider + +### Patch Changes + +- a62764b: Updated dependency `passport` to `^0.7.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + +## @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.0 + +### Minor Changes + +- 271aa12: Release of `oauth2-proxy-provider` plugin + +### Patch Changes + +- a6be465: Exported the provider as default so it gets discovered when using `featureDiscoveryServiceFactory()` +- 510dab4: Change provider id from `oauth2ProxyProvider` to `oauth2Proxy` +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/errors@1.2.3 + +## @backstage/plugin-auth-backend-module-vmware-cloud-provider@0.1.0 + +### Minor Changes + +- ed02c69: Add VMware Cloud auth backend module provider + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-azure-devops-backend@0.5.0 + +### Minor Changes + +- 844969c: **BREAKING** New `fromConfig` static method must be used now when creating an instance of the `AzureDevOpsApi` + + Added support for using the `AzureDevOpsCredentialsProvider` + +### Patch Changes + +- c70e4f5: Added multi-org support +- 646db72: Updated encoding of Org to use `encodeURIComponent` when building URL used to get credentials from credential provider +- 043b724: Introduced new `AzureDevOpsAnnotatorProcessor` that adds the needed annotations automatically. Also, moved constants to common package so they can be shared more easily +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/plugin-azure-devops-common@0.3.2 + - @backstage/integration@1.8.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + +## @backstage/plugin-catalog@1.16.0 + +### Minor Changes + +- e223f22: Properly support both function- and string-form visibility filter expressions in the new extensions exported via `/alpha`. +- b8e1eb2: The `columns` prop can be an array or a function that returns an array in order to override the default columns of the `CatalogIndexPage`. + +### Patch Changes + +- bc7e6d3: Fix copy entity url function in http contexts. + +- 5360097: Ensure that passed-in icons are taken advantage of in the presentation API + +- 4785d05: Add permission check to catalog create and refresh button + +- cd910c4: - Fixes bug where after unregistering an entity you are redirected to `/`. + + - Adds an optional external route `unregisterRedirect` to override this behaviour to another route. + +- 03d0b6d: The `convertLegacyRouteRef` utility used by the alpha exports is now imported from `@backstage/core-compat-api`. + +- 2d708d8: Internal naming updates for `/alpha` exports. + +- a5a0473: Internal refactor of alpha exports due to a change in how extension factories are defined. + +- 4d9e3b3: Register component overrides in the global `OverrideComponentNameToClassKeys` provided by `@backstage/theme`. This will in turn will provide component style override types for `createUnifiedTheme`. + +- a1227cc: Wrap `/alpha` export extension elements in backwards compatibility wrapper. + +- 78a10bb: Adding in spec.type chip to search results for clarity + +- 8f5d6c1: Updates to the `/alpha` exports to match the extension input wrapping change. + +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. + +- 8587f06: Added pagination support to `CatalogIndexPage` + + `CatalogIndexPage` now offers an optional pagination feature, designed to accommodate adopters managing extensive catalogs. This new capability allows for better handling of large amounts of data. + + To activate the pagination mode, simply update your `App.tsx` as follows: + + ```diff + const routes = ( + + ... + - } /> + + } /> + ... + ``` + + In case you have a custom catalog page and you want to enable pagination, you need to pass the `pagination` prop to `EntityListProvider` instead. + +- fb8f3bd: Updated alpha translation message keys to use nested format and camel case. + +- 531e1a2: Updated alpha plugin to include the `unregisterRedirect` external route. + +- Updated dependencies + - @backstage/core-compat-api@0.1.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/frontend-plugin-api@0.4.0 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-client@1.5.0 + - @backstage/plugin-search-react@1.7.4 + - @backstage/integration-react@1.1.22 + - @backstage/plugin-permission-react@0.4.18 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-scaffolder-common@1.4.4 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-catalog-backend@1.16.0 + +### Minor Changes + +- 7804597: Permission rules can now be added for the Catalog plugin through the `CatalogPermissionExtensionPoint` interface. + +### Patch Changes + +- 3834067: Update the OpenAPI spec to support the use of `openapi-generator`. +- 50ee804: Wrap single `pipelineLoop` of TaskPipeline in a span for better traces +- 7123c58: Updated dependency `@types/glob` to `^8.0.0`. +- 0cbb03b: Fixing regular expression ReDoS with zod packages. Upgrading to latest. ref: +- a168507: Deprecated `EntitiesSearchFilter` and `EntityFilter`, which can now be imported from `@backstage/plugin-catalog-node` instead +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/catalog-client@1.5.0 + - @backstage/backend-openapi-utils@0.1.1 + - @backstage/backend-tasks@0.5.13 + - @backstage/integration@1.8.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.19 + - @backstage/plugin-search-backend-module-catalog@0.1.12 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-events-node@0.2.17 + +## @backstage/plugin-catalog-node@1.6.0 + +### Minor Changes + +- a168507: Added `EntitiesSearchFilter` and `EntityFilter` from `@backstage/plugin-catalog-backend`, for reuse +- 7804597: Permission rules can now be added for the Catalog plugin through the `CatalogPermissionExtensionPoint` interface. + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.19 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + +## @backstage/plugin-home@0.6.0 + +### Minor Changes + +- 5a317f5: Added view of entities grouped by kind to make it easier to distinguish entities with different kind but same name + +### Patch Changes + +- 2633d64: Change user settings backend plugin id and fix when using user setting backend home page first will cause edit page loop render +- a1227cc: Wrap `/alpha` export extension elements in backwards compatibility wrapper. +- 5814122: Updated `/alpha` exports to fit new naming patterns. +- 8f5d6c1: Updates to the `/alpha` exports to match the extension input wrapping change. +- 2b72591: Updated dependency `@rjsf/utils` to `5.14.3`. + Updated dependency `@rjsf/core` to `5.14.3`. + Updated dependency `@rjsf/material-ui` to `5.14.3`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.3`. +- 6cd12f2: Updated dependency `@rjsf/utils` to `5.14.1`. + Updated dependency `@rjsf/core` to `5.14.1`. + Updated dependency `@rjsf/material-ui` to `5.14.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.1`. +- 64301d3: Updated dependency `@rjsf/utils` to `5.15.0`. + Updated dependency `@rjsf/core` to `5.15.0`. + Updated dependency `@rjsf/material-ui` to `5.15.0`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.0`. +- 63c494e: Updated dependency `@rjsf/utils` to `5.14.2`. + Updated dependency `@rjsf/core` to `5.14.2`. + Updated dependency `@rjsf/material-ui` to `5.14.2`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.2`. +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- 54cef27: StarredEntities component calls `getEntitiesByRefs` instead of `getEntities` to improve performance since we have the `entityRefs` +- c8908d4: Use new option from RJSF 5.15 +- 0cbb03b: Fixing regular expression ReDoS with zod packages. Upgrading to latest. ref: +- Updated dependencies + - @backstage/core-compat-api@0.1.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/frontend-plugin-api@0.4.0 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-client@1.5.0 + - @backstage/core-app-api@1.11.2 + - @backstage/plugin-home-react@0.1.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## @backstage/plugin-kubernetes-backend@0.14.0 + +### Minor Changes + +- 52050ad: You can now select `single` kubernetes cluster that the entity is part-of from all your defined kubernetes clusters, by passing `backstage.io/kubernetes-cluster` annotation with the defined cluster name. + + If you do not specify the annotation by `default it fetches all` defined kubernetes cluster. + + To apply + + catalog-info.yaml + + ```diff + annotations: + 'backstage.io/kubernetes-id': dice-roller + 'backstage.io/kubernetes-namespace': dice-space + + 'backstage.io/kubernetes-cluster': dice-cluster + 'backstage.io/kubernetes-label-selector': 'app=my-app,component=front-end' + ``` + +### Patch Changes + +- 6010564: The `kubernetes-node` plugin has been modified to house a new extension points for Kubernetes backend plugin; + `KubernetesClusterSupplierExtensionPoint` is introduced . + `kubernetesAuthStrategyExtensionPoint` is introduced . + `kubernetesFetcherExtensionPoint` is introduced . + `kubernetesServiceLocatorExtensionPoint` is introduced . + + The `kubernetes-backend` plugin was modified to use this new extension point. + +- 706fc3a: Updated dependency `@kubernetes/client-node` to `0.20.0`. + +- ae94d3c: Updated dependency `@aws-crypto/sha256-js` to `^5.0.0`. + +- 99fb541: Updated dependency `@azure/identity` to `^4.0.0`. + +- 42c1aee: Updated dependency `@google-cloud/container` to `^5.0.0`. + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/catalog-client@1.5.0 + - @backstage/plugin-kubernetes-node@0.1.2 + - @backstage/plugin-kubernetes-common@0.7.2 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.19 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + +## @backstage/plugin-kubernetes-react@0.2.0 + +### Minor Changes + +- 899d71a: Change `formatClusterLink` to be an API and make it async for further customization possibilities. + + **BREAKING** + If you have a custom k8s page and used `formatClusterLink` directly, you need to migrate to new `kubernetesClusterLinkFormatterApiRef` + +### Patch Changes + +- b5ae2e5: Add ID property to the table displaying kubernetes pods to avoid closing the info sidebar when the data reloads and needs to rerender. +- 706fc3a: Updated dependency `@kubernetes/client-node` to `0.20.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/plugin-kubernetes-common@0.7.2 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-lighthouse-backend@0.4.0 + +### Minor Changes + +- 7f0dbfd: Fixed crashes faced with custom schedule configuration. The configuration schema has been update to leverage the TaskScheduleDefinition interface. It is highly recommended to move the `lighthouse.shedule` and `lighthouse.timeout` respectively to `lighthouse.schedule.frequency` and `lighthouse.schedule.timeout`. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/catalog-client@1.5.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-lighthouse-common@0.1.4 + +## @backstage/plugin-pagerduty@0.7.0 + +### Minor Changes + +- 5fca16f: This package has been deprecated, consider using [@pagerduty/backstage-plugin](https://github.com/pagerduty/backstage-plugin) instead. + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/plugin-home-react@0.1.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-scaffolder@1.17.0 + +### Minor Changes + +- df88d09: Add a new git repository url picker for `gitea`. This `GiteaRepoPicker` can be used in a template to scaffold a project to be cloned using gitea. +- 33edf50: Added support for dealing with user provided secrets using a new field extension `ui:field: Secret` + +### Patch Changes + +- 6806d10: Added `headerOptions` to `TemplateListPage` to optionally override default values. + Changed `themeId` of TemplateListPage from `website` to `home`. +- aaa6fb3: Minor updates for TypeScript 5.2.2+ compatibility +- 2b72591: Updated dependency `@rjsf/utils` to `5.14.3`. + Updated dependency `@rjsf/core` to `5.14.3`. + Updated dependency `@rjsf/material-ui` to `5.14.3`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.3`. +- 6cd12f2: Updated dependency `@rjsf/utils` to `5.14.1`. + Updated dependency `@rjsf/core` to `5.14.1`. + Updated dependency `@rjsf/material-ui` to `5.14.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.1`. +- a518c5a: Updated dependency `@react-hookz/web` to `^23.0.0`. +- 64301d3: Updated dependency `@rjsf/utils` to `5.15.0`. + Updated dependency `@rjsf/core` to `5.15.0`. + Updated dependency `@rjsf/material-ui` to `5.15.0`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.0`. +- 63c494e: Updated dependency `@rjsf/utils` to `5.14.2`. + Updated dependency `@rjsf/core` to `5.14.2`. + Updated dependency `@rjsf/material-ui` to `5.14.2`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.2`. +- b5fa691: Fixing `headerOptions` not being passed through the `TemplatePage` component +- c8908d4: Use new option from RJSF 5.15 +- 0cbb03b: Fixing regular expression ReDoS with zod packages. Upgrading to latest. ref: +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/plugin-scaffolder-react@1.7.0 + - @backstage/catalog-client@1.5.0 + - @backstage/integration@1.8.0 + - @backstage/integration-react@1.1.22 + - @backstage/plugin-permission-react@0.4.18 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-scaffolder-common@1.4.4 + +## @backstage/plugin-scaffolder-backend-module-azure@0.1.0 + +### Minor Changes + +- 219d7f0: Create new scaffolder module for external integrations + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-scaffolder-node@0.2.9 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-scaffolder-backend-module-bitbucket@0.1.0 + +### Minor Changes + +- 219d7f0: Create new scaffolder module for external integrations + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-scaffolder-node@0.2.9 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-scaffolder-backend-module-gerrit@0.1.0 + +### Minor Changes + +- 219d7f0: Create new scaffolder module for external integrations + +### Patch Changes + +- d86cd98: Add dry run support for the `publish:gerrit` action. +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.9 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-scaffolder-backend-module-github@0.1.0 + +### Minor Changes + +- 219d7f0: Create new scaffolder module for external integrations + +### Patch Changes + +- cb6a65e: The `scaffolder.defaultCommitMessage` config value is now being used if provided and uses "initial commit" when it is not provided. +- 28949ea: Add a new action for creating github-autolink references for a repository: `github:autolinks:create` +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-scaffolder-node@0.2.9 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-scaffolder-react@1.7.0 + +### Minor Changes + +- 33edf50: Added support for dealing with user provided secrets using a new field extension `ui:field: Secret` + +### Patch Changes + +- 670c7cc: Fix bug where `properties` is set to empty object when it should be empty for schema dependencies +- fa66d1b: Fixed bug in `ReviewState` where `enum` value was displayed in step review instead of the corresponding label when using `enumNames` +- e516bf4: Step titles in the Stepper are now clickable and redirect the user to the corresponding step, as an alternative to using the back buttons. +- aaa6fb3: Minor updates for TypeScript 5.2.2+ compatibility +- 2aee53b: Add horizontal slider if stepper overflows +- 2b72591: Updated dependency `@rjsf/utils` to `5.14.3`. + Updated dependency `@rjsf/core` to `5.14.3`. + Updated dependency `@rjsf/material-ui` to `5.14.3`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.3`. +- 6cd12f2: Updated dependency `@rjsf/utils` to `5.14.1`. + Updated dependency `@rjsf/core` to `5.14.1`. + Updated dependency `@rjsf/material-ui` to `5.14.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.1`. +- a518c5a: Updated dependency `@react-hookz/web` to `^23.0.0`. +- 64301d3: Updated dependency `@rjsf/utils` to `5.15.0`. + Updated dependency `@rjsf/core` to `5.15.0`. + Updated dependency `@rjsf/material-ui` to `5.15.0`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.0`. +- 63c494e: Updated dependency `@rjsf/utils` to `5.14.2`. + Updated dependency `@rjsf/core` to `5.14.2`. + Updated dependency `@rjsf/material-ui` to `5.14.2`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.2`. +- c8908d4: Use new option from RJSF 5.15 +- 0cbb03b: Fixing regular expression ReDoS with zod packages. Upgrading to latest. ref: +- 5bb5240: Fixed issue for showing undefined for hidden form items +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-client@1.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-scaffolder-common@1.4.4 + +## @backstage/plugin-techdocs-node@1.11.0 + +### Minor Changes + +- d15d483: Add command `--runAsDefaultUser` for `@techdocs/cli generate` to bypass running the docker builds as host user for macOS and Linux. + +### Patch Changes + +- 99fb541: Updated dependency `@azure/identity` to `^4.0.0`. +- 2666675: Updated dependency `@google-cloud/storage` to `^7.0.0`. +- 4f773c1: Bumped the default TechDocs docker image version to the latest which was released several month ago +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/integration@1.8.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/app-defaults@1.4.6 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/core-app-api@1.11.2 + - @backstage/plugin-permission-react@0.4.18 + +## @backstage/backend-app-api@0.5.9 + +### Patch Changes + +- 1da5f43: Ensure redaction of secrets that have accidental extra whitespace around them +- 9f8f266: Add redacting for secrets in stack traces of logs +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/config-loader@1.6.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/plugin-permission-node@0.7.19 + - @backstage/cli-node@0.2.1 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/backend-defaults@0.2.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/backend-app-api@0.5.9 + - @backstage/backend-plugin-api@0.6.8 + +## @backstage/backend-openapi-utils@0.1.1 + +### Patch Changes + +- aaa6fb3: Minor updates for TypeScript 5.2.2+ compatibility +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/backend-plugin-api@0.6.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.13 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## @backstage/backend-tasks@0.5.13 + +### Patch Changes + +- d8f488a: Allow tasks to run more often that the default work check interval, which is 5 seconds. +- 0cbb03b: Fixing regular expression ReDoS with zod packages. Upgrading to latest. ref: +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/backend-test-utils@0.2.9 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. + +- b7de76a: Added support for PostgreSQL versions 15 and 16 + + Also introduced a new `setDefaults(options: { ids?: TestDatabaseId[] })` static method that can be added to the `setupTests.ts` file to define the default database ids you want to use throughout your package. Usage would look like this: `TestDatabases.setDefaults({ ids: ['POSTGRES_12','POSTGRES_16'] })` and would result in PostgreSQL versions 12 and 16 being used for your tests. + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/backend-app-api@0.5.9 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/cli-node@0.2.1 + +### Patch Changes + +- 0cbb03b: Fixing regular expression ReDoS with zod packages. Upgrading to latest. ref: +- Updated dependencies + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/core-app-api@1.11.2 + +### Patch Changes + +- 3e358b0: Added deprecation warning for React Router v6 beta, please make sure you have migrated your apps to use React Router v6 stable as support for the beta version will be removed. See the [migration tutorial](https://backstage.io/docs/tutorials/react-router-stable-migration) for more information. +- 0cbb03b: Fixing regular expression ReDoS with zod packages. Upgrading to latest. ref: +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/core-components@0.13.9 + +### Patch Changes + +- e8f2ace: Added a new `/testUtils` sub-path that initially exports a `mockBreakpoint` helper. +- 381ed86: Add missing export for IconLinkVertical +- 5c8a3e3: Minor improvements to `Table` component. +- 752df93: Fixes a problem where the `LogViewer` was not able to handle very large logs +- 4d9e3b3: Register component overrides in the global `OverrideComponentNameToClassKeys` provided by `@backstage/theme`. This will in turn will provide component style override types for `createUnifiedTheme`. +- 07dfdf3: Updated dependency `linkifyjs` to `4.1.3`. +- a518c5a: Updated dependency `@react-hookz/web` to `^23.0.0`. +- f291757: Update `linkify-react` to version `4.1.3` +- 175d86b: Fixed an issue where the `onChange` prop within `HeaderTabs` was triggering twice upon tab-switching. +- 0cbb03b: Fixing regular expression ReDoS with zod packages. Upgrading to latest. ref: +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/theme@0.5.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/version-bridge@1.0.7 + +## @backstage/core-plugin-api@1.8.1 + +### Patch Changes + +- 03d0b6d: Removed the alpha `convertLegacyRouteRef` utility, which as been moved to `@backstage/core-compat-api` +- 0c93dc3: The `createTranslationRef` function from the `/alpha` subpath can now also accept a nested object structure of default translation messages, which will be flatted using `.` separators. +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/create-app@0.5.8 + +### Patch Changes + +- 8ece804: Bumped create-app version. +- 0351e09: Bumped create-app version. +- 3f1192f: Bumped create-app version. +- a96c2d4: Include the `` for group entities by default +- 375b6f7: CircelCI plugin moved permanently +- Updated dependencies + - @backstage/cli-common@0.1.13 + +## @backstage/dev-utils@1.0.25 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/core-app-api@1.11.2 + - @backstage/app-defaults@1.4.6 + - @backstage/integration-react@1.1.22 + - @backstage/catalog-model@1.4.3 + +## @backstage/eslint-plugin@0.1.4 + +### Patch Changes + +- 107dc46: The `no-undeclared-imports` rule will now prefer using version queries that already exist en the repo for the same dependency type when installing new packages. + +## @backstage/integration-react@1.1.22 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + +## @backstage/test-utils@1.4.6 + +### Patch Changes + +- e8f2ace: Deprecated `mockBreakpoint`, as it is now available from `@backstage/core-components/testUtils` instead. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/theme@0.5.0 + - @backstage/core-app-api@1.11.2 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-react@0.4.18 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## @backstage/plugin-adr@0.6.11 + +### Patch Changes + +- 5814122: Updated `/alpha` exports to fit new naming patterns. +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- fb8f3bd: Updated alpha translation message keys to use nested format and camel case. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/frontend-plugin-api@0.4.0 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/plugin-search-react@1.7.4 + - @backstage/integration-react@1.1.22 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-adr-common@0.2.18 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-adr-backend@0.4.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/catalog-client@1.5.0 + - @backstage/integration@1.8.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-adr-common@0.2.18 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-adr-common@0.2.18 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-airbrake@0.3.28 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/test-utils@1.4.6 + - @backstage/dev-utils@1.0.25 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-airbrake-backend@0.3.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + +## @backstage/plugin-allure@0.1.44 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-analytics-module-ga@0.1.36 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/config@1.1.1 + +## @backstage/plugin-analytics-module-ga4@0.1.7 + +### Patch Changes + +- af6f227: Disabled `send_page_view` to get rid of events duplication +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/config@1.1.1 + +## @backstage/plugin-analytics-module-newrelic-browser@0.0.5 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/config@1.1.1 + +## @backstage/plugin-apache-airflow@0.2.18 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + +## @backstage/plugin-api-docs@0.10.2 + +### Patch Changes + +- 816d331: Add dependency on `graphql-config` to compensate for `graphql-language-service` needing it but not shipping the dep properly +- 615159e: Updated dependency `graphiql` to `3.0.10`. +- e16e7ce: Updated dependency `@asyncapi/react-component` to `1.2.2`. +- 82fb18b: Updated dependency `@asyncapi/react-component` to `1.2.6`. +- 53e2c06: Updated dependency `@asyncapi/react-component` to `1.1.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/plugin-catalog@1.16.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-apollo-explorer@0.1.18 + +### Patch Changes + +- e296b94: Updated dependency `@apollo/explorer` to `^3.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + +## @backstage/plugin-app-backend@0.3.56 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/config-loader@1.6.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.8 + +## @backstage/plugin-app-node@0.1.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8 + +## @backstage/plugin-auth-backend@0.20.1 + +### Patch Changes + +- 7ac2575: `oauth2-proxy` auth implementation has been moved to `@backstage/plugin-auth-backend-module-oauth2-proxy-provider` +- 2a5891e: Migrate the atlassian auth provider to be implemented using the new `@backstage/plugin-auth-backend-module-atlassian-provider` module +- 783797a: fix static token issuer not being able to initialize +- e1c189b: The Okta provider implementation is moved to the new module +- a62764b: Updated dependency `passport` to `^0.7.0`. +- bcbbf8e: Updated dependency `@google-cloud/firestore` to `^7.0.0`. +- Updated dependencies + - @backstage/plugin-auth-backend-module-atlassian-provider@0.1.0 + - @backstage/backend-common@0.20.0 + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/catalog-client@1.5.0 + - @backstage/plugin-auth-backend-module-okta-provider@0.0.1 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.5 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.1.5 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.2 + - @backstage/plugin-auth-backend-module-google-provider@0.1.5 + - @backstage/plugin-auth-backend-module-github-provider@0.1.5 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-auth-backend-module-github-provider@0.1.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + +## @backstage/plugin-auth-backend-module-gitlab-provider@0.1.5 + +### Patch Changes + +- a62764b: Updated dependency `passport` to `^0.7.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + +## @backstage/plugin-auth-backend-module-google-provider@0.1.5 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + +## @backstage/plugin-auth-backend-module-microsoft-provider@0.1.3 + +### Patch Changes + +- a62764b: Updated dependency `passport` to `^0.7.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + +## @backstage/plugin-auth-backend-module-oauth2-provider@0.1.5 + +### Patch Changes + +- a62764b: Updated dependency `passport` to `^0.7.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + +## @backstage/plugin-auth-backend-module-okta-provider@0.0.1 + +### Patch Changes + +- e1c189b: Adds okta-provider backend module for the auth plugin +- a62764b: Updated dependency `passport` to `^0.7.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + +## @backstage/plugin-auth-backend-module-pinniped-provider@0.1.2 + +### Patch Changes + +- a62764b: Updated dependency `passport` to `^0.7.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + +## @backstage/plugin-auth-node@0.4.2 + +### Patch Changes + +- a62764b: Updated dependency `passport` to `^0.7.0`. +- 0cbb03b: Fixing regular expression ReDoS with zod packages. Upgrading to latest. ref: +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/catalog-client@1.5.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-azure-devops@0.3.10 + +### Patch Changes + +- c70e4f5: Added multi-org support +- 7c9af0b: Added support for annotations that use a subpath for the host. Also validated that the annotations have the correct number of slashes. +- 043b724: Introduced new `AzureDevOpsAnnotatorProcessor` that adds the needed annotations automatically. Also, moved constants to common package so they can be shared more easily +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/plugin-azure-devops-common@0.3.2 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-azure-devops-common@0.3.2 + +### Patch Changes + +- c70e4f5: Added multi-org support +- 043b724: Introduced new `AzureDevOpsAnnotatorProcessor` that adds the needed annotations automatically. Also, moved constants to common package so they can be shared more easily + +## @backstage/plugin-azure-sites@0.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-azure-sites-common@0.1.1 + +## @backstage/plugin-azure-sites-backend@0.1.18 + +### Patch Changes + +- 99fb541: Updated dependency `@azure/identity` to `^4.0.0`. +- b7a13ed: Updated dependency `@azure/arm-appservice` to `^14.0.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/config@1.1.1 + - @backstage/plugin-azure-sites-common@0.1.1 + +## @backstage/plugin-badges@0.2.52 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-badges-backend@0.3.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/catalog-client@1.5.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-bazaar@0.2.20 + +### Patch Changes + +- 5d79682: Internalize 'AboutField' to break catalog dependency +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-client@1.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-bazaar-backend@0.3.6 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-bitbucket-cloud-common@0.2.15 + +### Patch Changes + +- acf9390: Updated dependency `ts-morph` to `^20.0.0`. +- Updated dependencies + - @backstage/integration@1.8.0 + +## @backstage/plugin-bitrise@0.1.55 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-catalog-backend-module-aws@0.3.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/plugin-kubernetes-common@0.7.2 + - @backstage/integration@1.8.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + +## @backstage/plugin-catalog-backend-module-azure@0.1.27 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/integration@1.8.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + +## @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.1 + +### Patch Changes + +- eb44e92: Support authenticated backends +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/backend-openapi-utils@0.1.1 + - @backstage/backend-tasks@0.5.13 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-catalog-backend-module-bitbucket@0.2.23 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.15 + - @backstage/integration@1.8.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.1.23 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/catalog-client@1.5.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/plugin-bitbucket-cloud-common@0.2.15 + - @backstage/integration@1.8.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-events-node@0.2.17 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.1.21 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/integration@1.8.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-catalog-backend-module-gcp@0.1.8 + +### Patch Changes + +- 42c1aee: Updated dependency `@google-cloud/container` to `^5.0.0`. +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/plugin-kubernetes-common@0.7.2 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + +## @backstage/plugin-catalog-backend-module-gerrit@0.1.24 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/integration@1.8.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-catalog-backend-module-github@0.4.6 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/plugin-catalog-backend@1.16.0 + - @backstage/catalog-client@1.5.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/integration@1.8.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-events-node@0.2.17 + +## @backstage/plugin-catalog-backend-module-github-org@0.1.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/plugin-catalog-backend-module-github@0.4.6 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + +## @backstage/plugin-catalog-backend-module-gitlab@0.3.5 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/integration@1.8.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + +## @backstage/plugin-catalog-backend-module-incremental-ingestion@0.4.12 + +### Patch Changes + +- 43b2eb8: Ensure that cursors always come back as JSON on sqlite too +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/plugin-catalog-backend@1.16.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-events-node@0.2.17 + +## @backstage/plugin-catalog-backend-module-ldap@0.5.23 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + +## @backstage/plugin-catalog-backend-module-msgraph@0.5.15 + +### Patch Changes + +- 99fb541: Updated dependency `@azure/identity` to `^4.0.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + +## @backstage/plugin-catalog-backend-module-openapi@0.1.25 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/plugin-catalog-backend@1.16.0 + - @backstage/integration@1.8.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + +## @backstage/plugin-catalog-backend-module-puppetdb@0.1.13 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.5 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-scaffolder-common@1.4.4 + +## @backstage/plugin-catalog-backend-module-unprocessed@0.3.5 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-catalog-common@1.0.19 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.11 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-catalog-graph@0.3.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-client@1.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-import@0.10.4 + +### Patch Changes + +- 03d0b6d: The `convertLegacyRouteRef` utility used by the alpha exports is now imported from `@backstage/core-compat-api`. +- a1227cc: Wrap `/alpha` export extension elements in backwards compatibility wrapper. +- 5814122: Updated `/alpha` exports to fit new naming patterns. +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- Updated dependencies + - @backstage/core-compat-api@0.1.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/frontend-plugin-api@0.4.0 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/catalog-client@1.5.0 + - @backstage/integration@1.8.0 + - @backstage/integration-react@1.1.22 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.19 + +## @backstage/plugin-catalog-react@1.9.2 + +### Patch Changes + +- 8587f06: Added pagination support to `EntityListProvider`. + +- 5360097: Ensure that passed-in icons are taken advantage of in the presentation API + +- fd9863c: Grouped all `/alpha` extension data reference exports under `catalogExtensionData`. + +- 08d9e67: Add default icon for kind resource. + +- aaa6fb3: Minor updates for TypeScript 5.2.2+ compatibility + +- a5a0473: Internal refactor of alpha exports due to a change in how extension factories are defined. + +- 4d9e3b3: Register component overrides in the global `OverrideComponentNameToClassKeys` provided by `@backstage/theme`. This will in turn will provide component style override types for `createUnifiedTheme`. + +- 8f5d6c1: Updates to the `/alpha` exports to match the extension input wrapping change. + +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. + +- e223f22: Breaking alpha-API change to entity visibility filter functions to accept a bare entity as their first argument, instead of an object with an entity property. + + Functions that accept such filters now also support the string expression form of filters. + +- eee0ff2: Fixed a issue where `CatalogPage` wasn't using the chosen `initiallySelectedFilter` as intended. + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/frontend-plugin-api@0.4.0 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-client@1.5.0 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/integration-react@1.1.22 + - @backstage/plugin-permission-react@0.4.18 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-catalog-common@1.0.19 + +## @backstage/plugin-catalog-unprocessed-entities@0.1.6 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-cicd-statistics@0.1.30 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-cicd-statistics-module-gitlab@0.1.24 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-cicd-statistics@0.1.30 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-circleci@0.3.28 + +### Patch Changes + +- 375b6f7: CircelCI plugin moved permanently +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-cloudbuild@0.3.28 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-code-climate@0.1.28 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-code-coverage@0.2.21 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-code-coverage-backend@0.2.22 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/catalog-client@1.5.0 + - @backstage/integration@1.8.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-codescene@0.1.20 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-config-schema@0.1.48 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-cost-insights@0.12.17 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-cost-insights-common@0.1.2 + +## @backstage/plugin-devtools@0.1.7 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/plugin-permission-react@0.4.18 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.7 + +## @backstage/plugin-devtools-backend@0.2.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/config-loader@1.6.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.19 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.7 + +## @backstage/plugin-devtools-common@0.1.7 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.11 + - @backstage/types@1.1.1 + +## @backstage/plugin-dynatrace@8.0.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-entity-feedback@0.2.11 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## @backstage/plugin-entity-feedback-backend@0.2.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/catalog-client@1.5.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## @backstage/plugin-entity-validation@0.1.13 + +### Patch Changes + +- a518c5a: Updated dependency `@react-hookz/web` to `^23.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-client@1.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.19 + +## @backstage/plugin-events-backend@0.2.17 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.17 + +## @backstage/plugin-events-backend-module-aws-sqs@0.2.11 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.17 + +## @backstage/plugin-events-backend-module-azure@0.1.18 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8 + - @backstage/plugin-events-node@0.2.17 + +## @backstage/plugin-events-backend-module-bitbucket-cloud@0.1.18 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8 + - @backstage/plugin-events-node@0.2.17 + +## @backstage/plugin-events-backend-module-gerrit@0.1.18 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8 + - @backstage/plugin-events-node@0.2.17 + +## @backstage/plugin-events-backend-module-github@0.1.18 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.17 + +## @backstage/plugin-events-backend-module-gitlab@0.1.18 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.17 + +## @backstage/plugin-events-backend-test-utils@0.1.18 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.2.17 + +## @backstage/plugin-events-node@0.2.17 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8 + +## @backstage/plugin-explore@0.4.14 + +### Patch Changes + +- aac659e: Added option to set `Direction` for the graph in the `GroupsDiagram` +- 5814122: Updated `/alpha` exports to fit new naming patterns. +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/frontend-plugin-api@0.4.0 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/plugin-search-react@1.7.4 + - @backstage/plugin-explore-react@0.0.34 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-explore-backend@0.0.18 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-search-backend-module-explore@0.1.12 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-explore-react@0.0.34 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-explore-common@0.0.2 + +## @backstage/plugin-firehydrant@0.2.12 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-fossa@0.2.60 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-gcalendar@0.3.21 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/errors@1.2.3 + +## @backstage/plugin-gcp-projects@0.3.44 + +### Patch Changes + +- a518c5a: Updated dependency `@react-hookz/web` to `^23.0.0`. +- d2f5662: Fix query parameter for project details page which should point to projectId rather than project name +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + +## @backstage/plugin-git-release-manager@0.3.40 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/integration@1.8.0 + +## @backstage/plugin-github-actions@0.6.9 + +### Patch Changes + +- 08d7e46: Github Workflow Runs UI is modified to show in optional Card view instead of table, with branch selection option +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/integration@1.8.0 + - @backstage/integration-react@1.1.22 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-github-deployments@0.1.59 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/integration@1.8.0 + - @backstage/integration-react@1.1.22 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-github-issues@0.2.17 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/integration@1.8.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-github-pull-requests-board@0.1.22 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/integration@1.8.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-gitops-profiles@0.3.43 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/config@1.1.1 + +## @backstage/plugin-gocd@0.1.34 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-graphiql@0.3.1 + +### Patch Changes + +- 03d0b6d: The `convertLegacyRouteRef` utility used by the alpha exports is now imported from `@backstage/core-compat-api`. +- a1227cc: Wrap `/alpha` export extension elements in backwards compatibility wrapper. +- 5814122: Updated `/alpha` exports to fit new naming patterns. +- 8f5d6c1: Updates to the `/alpha` exports to match the extension input wrapping change. +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- Updated dependencies + - @backstage/core-compat-api@0.1.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/frontend-plugin-api@0.4.0 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + +## @backstage/plugin-graphql-voyager@0.1.10 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + +## @backstage/plugin-home-react@0.1.6 + +### Patch Changes + +- 2b72591: Updated dependency `@rjsf/utils` to `5.14.3`. + Updated dependency `@rjsf/core` to `5.14.3`. + Updated dependency `@rjsf/material-ui` to `5.14.3`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.3`. +- 6cd12f2: Updated dependency `@rjsf/utils` to `5.14.1`. + Updated dependency `@rjsf/core` to `5.14.1`. + Updated dependency `@rjsf/material-ui` to `5.14.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.1`. +- 64301d3: Updated dependency `@rjsf/utils` to `5.15.0`. + Updated dependency `@rjsf/core` to `5.15.0`. + Updated dependency `@rjsf/material-ui` to `5.15.0`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.0`. +- 63c494e: Updated dependency `@rjsf/utils` to `5.14.2`. + Updated dependency `@rjsf/core` to `5.14.2`. + Updated dependency `@rjsf/material-ui` to `5.14.2`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.2`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + +## @backstage/plugin-ilert@0.2.17 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-jenkins@0.9.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-jenkins-common@0.1.22 + +## @backstage/plugin-jenkins-backend@0.3.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/catalog-client@1.5.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.19 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-jenkins-common@0.1.22 + +## @backstage/plugin-jenkins-common@0.1.22 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-catalog-common@1.0.19 + +## @backstage/plugin-kafka@0.3.28 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + +## @backstage/plugin-kafka-backend@0.3.6 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-kubernetes@0.11.3 + +### Patch Changes + +- 899d71a: Change `formatClusterLink` to be an API and make it async for further customization possibilities. + + **BREAKING** + If you have a custom k8s page and used `formatClusterLink` directly, you need to migrate to new `kubernetesClusterLinkFormatterApiRef` + +- 706fc3a: Updated dependency `@kubernetes/client-node` to `0.20.0`. + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/plugin-kubernetes-react@0.2.0 + - @backstage/plugin-kubernetes-common@0.7.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-kubernetes-cluster@0.0.4 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/plugin-kubernetes-react@0.2.0 + - @backstage/plugin-kubernetes-common@0.7.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-kubernetes-common@0.7.2 + +### Patch Changes + +- 706fc3a: Updated dependency `@kubernetes/client-node` to `0.20.0`. +- 5d79682: Remove unused dependency +- Updated dependencies + - @backstage/plugin-permission-common@0.7.11 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-kubernetes-node@0.1.2 + +### Patch Changes + +- 6010564: The `kubernetes-node` plugin has been modified to house a new extension points for Kubernetes backend plugin; + `KubernetesClusterSupplierExtensionPoint` is introduced . + `kubernetesAuthStrategyExtensionPoint` is introduced . + `kubernetesFetcherExtensionPoint` is introduced . + `kubernetesServiceLocatorExtensionPoint` is introduced . + + The `kubernetes-backend` plugin was modified to use this new extension point. + +- Updated dependencies + - @backstage/plugin-kubernetes-common@0.7.2 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-lighthouse@0.4.13 + +### Patch Changes + +- ffbf656: Updated README +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-lighthouse-common@0.1.4 + +## @backstage/plugin-linguist@0.1.13 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-linguist-common@0.1.2 + +## @backstage/plugin-linguist-backend@0.5.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/catalog-client@1.5.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-linguist-common@0.1.2 + +## @backstage/plugin-microsoft-calendar@0.1.10 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/errors@1.2.3 + +## @backstage/plugin-newrelic@0.3.43 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + +## @backstage/plugin-newrelic-dashboard@0.3.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-nomad@0.1.9 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + +## @backstage/plugin-nomad-backend@0.1.10 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-octopus-deploy@0.2.10 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-opencost@0.2.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + +## @backstage/plugin-org@0.6.18 + +### Patch Changes + +- 59c24b9: Fix issue where members inside of `` would be rendered as squished when the card itself was shrunk down. +- 3a65d9c: Support member list scrollable when parent has specified height +- 4785d05: Add permission check to catalog create and refresh button +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.19 + +## @backstage/plugin-org-react@0.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-client@1.5.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-periskop@0.1.26 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-periskop-backend@0.2.6 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + +## @backstage/plugin-permission-backend@0.5.31 + +### Patch Changes + +- 0cbb03b: Fixing regular expression ReDoS with zod packages. Upgrading to latest. ref: +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.19 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-permission-backend-module-allow-all-policy@0.1.5 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.19 + - @backstage/backend-plugin-api@0.6.8 + +## @backstage/plugin-permission-common@0.7.11 + +### Patch Changes + +- 0cbb03b: Fixing regular expression ReDoS with zod packages. Upgrading to latest. ref: +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-permission-node@0.7.19 + +### Patch Changes + +- 0cbb03b: Fixing regular expression ReDoS with zod packages. Upgrading to latest. ref: +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-permission-react@0.4.18 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/config@1.1.1 + +## @backstage/plugin-playlist@0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/plugin-search-react@1.7.4 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-react@0.4.18 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-playlist-common@0.1.13 + +## @backstage/plugin-playlist-backend@0.3.12 + +### Patch Changes + +- 0cbb03b: Fixing regular expression ReDoS with zod packages. Upgrading to latest. ref: +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/catalog-client@1.5.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.19 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-playlist-common@0.1.13 + +## @backstage/plugin-playlist-common@0.1.13 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.11 + +## @backstage/plugin-proxy-backend@0.4.6 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + +## @backstage/plugin-puppetdb@0.1.11 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-rollbar@0.4.28 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-rollbar-backend@0.1.53 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/config@1.1.1 + +## @backstage/plugin-scaffolder-backend@1.19.2 + +### Patch Changes + +- 219d7f0: Refactor some methods to `-node` instead and use the new external modules +- aff34fc: Fix issue with Circular JSON dependencies in templating +- 48667b4: Fix creating env secret in github:environment:create action +- 0cbb03b: Fixing regular expression ReDoS with zod packages. Upgrading to latest. ref: +- 28949ea: Add a new action for creating github-autolink references for a repository: `github:autolinks:create` +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-scaffolder-backend-module-github@0.1.0 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.2.11 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.1.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/catalog-client@1.5.0 + - @backstage/plugin-scaffolder-node@0.2.9 + - @backstage/backend-tasks@0.5.13 + - @backstage/integration@1.8.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.1.0 + - @backstage/plugin-scaffolder-backend-module-azure@0.1.0 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.19 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.5 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-common@1.4.4 + +## @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.9 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-scaffolder-node@0.2.9 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.2.32 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-scaffolder-node@0.2.9 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-gitlab@0.2.11 + +### Patch Changes + +- 219d7f0: Extract some more actions to this library +- 0cbb03b: Fixing regular expression ReDoS with zod packages. Upgrading to latest. ref: +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-scaffolder-node@0.2.9 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-scaffolder-backend-module-rails@0.4.25 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-scaffolder-node@0.2.9 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-sentry@0.1.16 + +### Patch Changes + +- 7f8a801: Added examples for `sentry:project:create` scaffolder action and unit tests. +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.9 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.2.29 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.9 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-common@1.4.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.11 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-node@0.2.9 + +### Patch Changes + +- 219d7f0: Refactor some methods to `-node` instead and use the new external modules +- 0cbb03b: Fixing regular expression ReDoS with zod packages. Upgrading to latest. ref: +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/integration@1.8.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-common@1.4.4 + +## @backstage/plugin-search@1.4.4 + +### Patch Changes + +- 03d0b6d: The `convertLegacyRouteRef` utility used by the alpha exports is now imported from `@backstage/core-compat-api`. +- a1227cc: Wrap `/alpha` export extension elements in backwards compatibility wrapper. +- 5814122: Updated `/alpha` exports to fit new naming patterns. +- 8f5d6c1: Updates to the `/alpha` exports to match the extension input wrapping change. +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- Updated dependencies + - @backstage/core-compat-api@0.1.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/frontend-plugin-api@0.4.0 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/plugin-search-react@1.7.4 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-search-backend@1.4.8 + +### Patch Changes + +- 0cbb03b: Fixing regular expression ReDoS with zod packages. Upgrading to latest. ref: +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/backend-openapi-utils@0.1.1 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.19 + - @backstage/plugin-search-backend-node@1.2.12 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-search-backend-module-catalog@0.1.12 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/catalog-client@1.5.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-search-backend-node@1.2.12 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-search-backend-module-elasticsearch@1.3.11 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-search-backend-node@1.2.12 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + - @backstage/integration-aws-node@0.1.8 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-search-backend-module-explore@0.1.12 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/plugin-search-backend-node@1.2.12 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-search-backend-module-pg@0.5.17 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-search-backend-node@1.2.12 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-search-backend-module-stack-overflow-collator@0.1.1 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/plugin-search-backend-node@1.2.12 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-search-backend-module-techdocs@0.1.12 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/catalog-client@1.5.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/plugin-techdocs-node@1.11.0 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-search-backend-node@1.2.12 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-search-backend-node@1.2.12 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-search-common@1.2.9 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.11 + - @backstage/types@1.1.1 + +## @backstage/plugin-search-react@1.7.4 + +### Patch Changes + +- a5a0473: Internal refactor of alpha exports due to a change in how extension factories are defined. +- 84dabc5: Removed `@backstage/frontend-app-api` dependency. +- 5814122: Updated `/alpha` exports to fit new naming patterns. +- 6f280fa: Capture analytics even when number of results is not available, since the total result count is not something that is always available for all search engines and configurations. +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/frontend-plugin-api@0.4.0 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-sentry@0.5.13 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-shortcuts@0.3.17 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-sonarqube@0.7.10 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/plugin-sonarqube-react@0.1.11 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-sonarqube-backend@0.2.10 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-sonarqube-react@0.1.11 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-splunk-on-call@0.4.17 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-stack-overflow@0.1.23 + +### Patch Changes + +- 5814122: Updated `/alpha` exports to fit new naming patterns. +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/frontend-plugin-api@0.4.0 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/plugin-search-react@1.7.4 + - @backstage/plugin-home-react@0.1.6 + - @backstage/config@1.1.1 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-stack-overflow-backend@0.2.12 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-search-backend-module-stack-overflow-collator@0.1.1 + - @backstage/config@1.1.1 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-stackstorm@0.1.9 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/errors@1.2.3 + +## @backstage/plugin-tech-insights@0.3.20 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-insights-backend@0.5.22 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/catalog-client@1.5.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/plugin-tech-insights-node@0.4.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.40 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-tech-insights-node@0.4.14 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-insights-node@0.4.14 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-radar@0.6.11 + +### Patch Changes + +- 03d0b6d: The `convertLegacyRouteRef` utility used by the alpha exports is now imported from `@backstage/core-compat-api`. +- a1227cc: Wrap `/alpha` export extension elements in backwards compatibility wrapper. +- 5814122: Updated `/alpha` exports to fit new naming patterns. +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- Updated dependencies + - @backstage/core-compat-api@0.1.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/frontend-plugin-api@0.4.0 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + +## @backstage/plugin-techdocs@1.9.2 + +### Patch Changes + +- 03d0b6d: The `convertLegacyRouteRef` utility used by the alpha exports is now imported from `@backstage/core-compat-api`. +- a1227cc: Wrap `/alpha` export extension elements in backwards compatibility wrapper. +- 5814122: Updated `/alpha` exports to fit new naming patterns. +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- Updated dependencies + - @backstage/core-compat-api@0.1.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/frontend-plugin-api@0.4.0 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/plugin-search-react@1.7.4 + - @backstage/integration@1.8.0 + - @backstage/integration-react@1.1.22 + - @backstage/plugin-techdocs-react@1.1.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.25 + +### Patch Changes + +- 3f354e6: Move `@testing-library/react` to be a `peerDependency` +- 5d79682: Remove unnecessary catalog dependency +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/plugin-catalog@1.16.0 + - @backstage/core-app-api@1.11.2 + - @backstage/test-utils@1.4.6 + - @backstage/plugin-techdocs@1.9.2 + - @backstage/plugin-search-react@1.7.4 + - @backstage/integration-react@1.1.22 + - @backstage/plugin-techdocs-react@1.1.14 + +## @backstage/plugin-techdocs-backend@1.9.1 + +### Patch Changes + +- a402644: Regenerates a fresh token for each call to the search index when collating techdocs. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/catalog-client@1.5.0 + - @backstage/integration@1.8.0 + - @backstage/plugin-techdocs-node@1.11.0 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-search-backend-module-techdocs@0.1.12 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-techdocs-module-addons-contrib@1.1.3 + +### Patch Changes + +- a518c5a: Updated dependency `@react-hookz/web` to `^23.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/integration@1.8.0 + - @backstage/integration-react@1.1.22 + - @backstage/plugin-techdocs-react@1.1.14 + +## @backstage/plugin-techdocs-react@1.1.14 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/plugin-todo@0.2.32 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-todo-backend@0.3.6 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/catalog-client@1.5.0 + - @backstage/backend-openapi-utils@0.1.1 + - @backstage/integration@1.8.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-user-settings@0.7.14 + +### Patch Changes + +- 03d0b6d: The `convertLegacyRouteRef` utility used by the alpha exports is now imported from `@backstage/core-compat-api`. +- a1227cc: Wrap `/alpha` export extension elements in backwards compatibility wrapper. +- 5814122: Updated `/alpha` exports to fit new naming patterns. +- 8f5d6c1: Updates to the `/alpha` exports to match the extension input wrapping change. +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- fb8f3bd: Updated alpha translation message keys to use nested format and camel case. +- Updated dependencies + - @backstage/core-compat-api@0.1.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/frontend-plugin-api@0.4.0 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/core-app-api@1.11.2 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-user-settings-backend@0.2.7 + +### Patch Changes + +- 2633d64: Change user settings backend plugin id and fix when using user setting backend home page first will cause edit page loop render +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-vault@0.1.23 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-vault-backend@0.4.1 + +### Patch Changes + +- b7de76a: Updated to test using PostgreSQL 12 and 16 +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-vault-node@0.1.1 + +## @backstage/plugin-vault-node@0.1.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8 + +## @backstage/plugin-xcmetrics@0.2.46 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/errors@1.2.3 + +## example-app@0.2.90 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/frontend-app-api@0.4.0 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/plugin-api-docs@0.10.2 + - @backstage/core-components@0.13.9 + - @backstage/cli@0.25.0 + - @backstage/theme@0.5.0 + - @backstage/plugin-scaffolder@1.17.0 + - @backstage/plugin-home@0.6.0 + - @backstage/plugin-catalog@1.16.0 + - @backstage/plugin-scaffolder-react@1.7.0 + - @backstage/plugin-kubernetes@0.11.3 + - @backstage/plugin-org@0.6.18 + - @backstage/plugin-github-actions@0.6.9 + - @backstage/plugin-azure-devops@0.3.10 + - @backstage/core-app-api@1.11.2 + - @backstage/plugin-lighthouse@0.4.13 + - @backstage/plugin-explore@0.4.14 + - @backstage/plugin-catalog-import@0.10.4 + - @backstage/plugin-user-settings@0.7.14 + - @backstage/plugin-tech-radar@0.6.11 + - @backstage/plugin-graphiql@0.3.1 + - @backstage/plugin-techdocs@1.9.2 + - @backstage/plugin-search@1.4.4 + - @backstage/plugin-search-react@1.7.4 + - @backstage/plugin-stack-overflow@0.1.23 + - @backstage/plugin-adr@0.6.11 + - @backstage/plugin-gcp-projects@0.3.44 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.3 + - @backstage/plugin-pagerduty@0.7.0 + - @backstage/app-defaults@1.4.6 + - @backstage/integration-react@1.1.22 + - @backstage/plugin-airbrake@0.3.28 + - @backstage/plugin-apache-airflow@0.2.18 + - @backstage/plugin-azure-sites@0.1.17 + - @backstage/plugin-badges@0.2.52 + - @backstage/plugin-catalog-graph@0.3.2 + - @backstage/plugin-catalog-unprocessed-entities@0.1.6 + - @backstage/plugin-cloudbuild@0.3.28 + - @backstage/plugin-code-coverage@0.2.21 + - @backstage/plugin-cost-insights@0.12.17 + - @backstage/plugin-devtools@0.1.7 + - @backstage/plugin-dynatrace@8.0.2 + - @backstage/plugin-entity-feedback@0.2.11 + - @backstage/plugin-gcalendar@0.3.21 + - @backstage/plugin-gocd@0.1.34 + - @backstage/plugin-jenkins@0.9.3 + - @backstage/plugin-kafka@0.3.28 + - @backstage/plugin-kubernetes-cluster@0.0.4 + - @backstage/plugin-linguist@0.1.13 + - @backstage/plugin-microsoft-calendar@0.1.10 + - @backstage/plugin-newrelic@0.3.43 + - @backstage/plugin-newrelic-dashboard@0.3.3 + - @backstage/plugin-nomad@0.1.9 + - @backstage/plugin-octopus-deploy@0.2.10 + - @backstage/plugin-permission-react@0.4.18 + - @backstage/plugin-playlist@0.2.2 + - @backstage/plugin-puppetdb@0.1.11 + - @backstage/plugin-rollbar@0.4.28 + - @backstage/plugin-sentry@0.5.13 + - @backstage/plugin-shortcuts@0.3.17 + - @backstage/plugin-stackstorm@0.1.9 + - @backstage/plugin-tech-insights@0.3.20 + - @backstage/plugin-techdocs-react@1.1.14 + - @backstage/plugin-todo@0.2.32 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.9 + +## example-app-next@0.0.4 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.1.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/frontend-plugin-api@0.4.0 + - @backstage/frontend-app-api@0.4.0 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/plugin-api-docs@0.10.2 + - @backstage/core-components@0.13.9 + - @backstage/cli@0.25.0 + - @backstage/theme@0.5.0 + - @backstage/plugin-scaffolder@1.17.0 + - @backstage/plugin-home@0.6.0 + - @backstage/plugin-catalog@1.16.0 + - @backstage/plugin-scaffolder-react@1.7.0 + - @backstage/plugin-kubernetes@0.11.3 + - @backstage/plugin-org@0.6.18 + - @backstage/plugin-github-actions@0.6.9 + - @backstage/plugin-azure-devops@0.3.10 + - @backstage/core-app-api@1.11.2 + - @backstage/plugin-lighthouse@0.4.13 + - @backstage/plugin-explore@0.4.14 + - @backstage/plugin-catalog-import@0.10.4 + - @backstage/plugin-user-settings@0.7.14 + - @backstage/plugin-tech-radar@0.6.11 + - @backstage/plugin-graphiql@0.3.1 + - @backstage/plugin-techdocs@1.9.2 + - @backstage/plugin-search@1.4.4 + - @backstage/plugin-search-react@1.7.4 + - @backstage/plugin-adr@0.6.11 + - @backstage/plugin-gcp-projects@0.3.44 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.3 + - @backstage/plugin-pagerduty@0.7.0 + - @backstage/app-defaults@1.4.6 + - @backstage/integration-react@1.1.22 + - @backstage/plugin-airbrake@0.3.28 + - @backstage/plugin-apache-airflow@0.2.18 + - @backstage/plugin-azure-sites@0.1.17 + - @backstage/plugin-badges@0.2.52 + - @backstage/plugin-catalog-graph@0.3.2 + - @backstage/plugin-catalog-unprocessed-entities@0.1.6 + - @backstage/plugin-cloudbuild@0.3.28 + - @backstage/plugin-code-coverage@0.2.21 + - @backstage/plugin-cost-insights@0.12.17 + - @backstage/plugin-devtools@0.1.7 + - @backstage/plugin-dynatrace@8.0.2 + - @backstage/plugin-entity-feedback@0.2.11 + - @backstage/plugin-gcalendar@0.3.21 + - @backstage/plugin-gocd@0.1.34 + - @backstage/plugin-jenkins@0.9.3 + - @backstage/plugin-kafka@0.3.28 + - @backstage/plugin-linguist@0.1.13 + - @backstage/plugin-microsoft-calendar@0.1.10 + - @backstage/plugin-newrelic@0.3.43 + - @backstage/plugin-newrelic-dashboard@0.3.3 + - @backstage/plugin-octopus-deploy@0.2.10 + - @backstage/plugin-permission-react@0.4.18 + - @backstage/plugin-playlist@0.2.2 + - @backstage/plugin-puppetdb@0.1.11 + - @backstage/plugin-rollbar@0.4.28 + - @backstage/plugin-sentry@0.5.13 + - @backstage/plugin-shortcuts@0.3.17 + - @backstage/plugin-stackstorm@0.1.9 + - @backstage/plugin-tech-insights@0.3.20 + - @backstage/plugin-techdocs-react@1.1.14 + - @backstage/plugin-todo@0.2.32 + - @backstage/plugin-visualizer@0.0.1 + - app-next-example-plugin@0.0.4 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.9 + +## app-next-example-plugin@0.0.4 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0 + - @backstage/core-components@0.13.9 + +## example-backend@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 + +## example-backend-next@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 + +## @backstage/backend-plugin-manager@0.0.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-backend@1.16.0 + - @backstage/plugin-scaffolder-node@0.2.9 + - @backstage/backend-tasks@0.5.13 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.19 + - @backstage/cli-node@0.2.1 + - @backstage/plugin-events-backend@0.2.17 + - @backstage/plugin-search-backend-node@1.2.12 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.17 + - @backstage/plugin-search-common@1.2.9 + +## e2e-test@0.2.10 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.8 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + +## techdocs-cli-embedded-app@0.2.89 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/cli@0.25.0 + - @backstage/theme@0.5.0 + - @backstage/plugin-catalog@1.16.0 + - @backstage/core-app-api@1.11.2 + - @backstage/test-utils@1.4.6 + - @backstage/plugin-techdocs@1.9.2 + - @backstage/app-defaults@1.4.6 + - @backstage/integration-react@1.1.22 + - @backstage/plugin-techdocs-react@1.1.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + +## @internal/plugin-todo-list@1.0.20 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + +## @internal/plugin-todo-list-backend@1.0.20 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @internal/plugin-todo-list-common@1.0.16 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.11 + +## @backstage/plugin-visualizer@0.0.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/frontend-plugin-api@0.4.0 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 diff --git a/docs/releases/v1.21.0-next.0-changelog.md b/docs/releases/v1.21.0-next.0-changelog.md new file mode 100644 index 0000000000..a306e4158b --- /dev/null +++ b/docs/releases/v1.21.0-next.0-changelog.md @@ -0,0 +1,3058 @@ +# Release v1.21.0-next.0 + +## @backstage/backend-common@0.20.0-next.0 + +### Minor Changes + +- 870db76a45: Implemented `readTree` for Gitea provider to support TechDocs functionality + +### Patch Changes + +- 7f04128bbc: Allow a default cache TTL to be set through the app config +- 1ad8906a9e: Use `Readable.from` to fix some of the stream issues +- 706fc3a7e1: Updated dependency `@kubernetes/client-node` to `0.20.0`. +- d15d483a49: Add command `--runAsDefaultUser` for `@techdocs/cli generate` to bypass running the docker builds as host user for macOS and Linux. +- d1e00aa17a: Expose an `onAuth` handler for `git` actions to provide custom credentials +- Updated dependencies + - @backstage/integration@1.8.0-next.0 + - @backstage/backend-app-api@0.5.9-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/backend-dev-utils@0.1.2 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.5.3 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + +## @backstage/frontend-test-utils@0.1.0-next.0 + +### Minor Changes + +- 59fabd5106: New testing utility library for `@backstage/frontend-app-api` and `@backstage/frontend-plugin-api`. + +### Patch Changes + +- 59fabd5106: Added `createExtensionTester` for rendering extensions in tests. +- Updated dependencies + - @backstage/frontend-app-api@0.3.1-next.0 + - @backstage/frontend-plugin-api@0.3.1-next.0 + - @backstage/test-utils@1.4.6-next.0 + - @backstage/types@1.1.1 + +## @backstage/integration@1.8.0-next.0 + +### Minor Changes + +- 870db76a45: Implemented `readTree` for Gitea provider to support TechDocs functionality + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.1 + +## @techdocs/cli@1.8.0-next.0 + +### Minor Changes + +- d15d483a49: Add command `--runAsDefaultUser` for `@techdocs/cli generate` to bypass running the docker builds as host user for macOS and Linux. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-techdocs-node@1.11.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + +## @backstage/theme@0.5.0-next.0 + +### Minor Changes + +- 4d9e3b39e4: Added a global `OverrideComponentNameToClassKeys` for other plugins and packages to populate using module augmentation. This will in turn will provide component style override types for `createUnifiedTheme`. + +## @backstage/plugin-auth-backend-module-atlassian-provider@0.1.0-next.0 + +### Minor Changes + +- 2a5891e816: New module for `@backstage/plugin-auth-backend` that adds an atlassian auth provider + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + +## @backstage/plugin-catalog@1.16.0-next.0 + +### Minor Changes + +- b8e1eb2c0f: The `columns` prop can be an array or a function that returns an array in order to override the default columns of the `CatalogIndexPage`. + +### Patch Changes + +- bc7e6d3eb9: Fix copy entity url function in http contexts. + +- cd910c4fa5: - Fixes bug where after unregistering an entity you are redirected to `/`. + + - Adds an optional external route `unregisterRedirect` to override this behaviour to another route. + +- 03d0b6dcdc: The `convertLegacyRouteRef` utility used by the alpha exports is now imported from `@backstage/core-compat-api`. + +- 4d9e3b39e4: Register component overrides in the global `OverrideComponentNameToClassKeys` provided by `@backstage/theme`. This will in turn will provide component style override types for `createUnifiedTheme`. + +- 8587f067d2: Added pagination support to `CatalogIndexPage` + + `CatalogIndexPage` now offers an optional pagination feature, designed to accommodate adopters managing extensive catalogs. This new capability allows for better handling of large amounts of data. + + To activate the pagination mode, simply update your `App.tsx` as follows: + + ```diff + const routes = ( + + ... + - } /> + + } /> + ... + ``` + + In case you have a custom catalog page and you want to enable pagination, you need to pass the `pagination` prop to `EntityListProvider` instead. + +- Updated dependencies + - @backstage/core-compat-api@0.0.2-next.0 + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/plugin-search-react@1.7.4-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/frontend-plugin-api@0.3.1-next.0 + - @backstage/integration-react@1.1.22-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-scaffolder-common@1.4.3 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-kubernetes-backend@0.14.0-next.0 + +### Minor Changes + +- 52050ada6e: You can now select `single` kubernetes cluster that the entity is part-of from all your defined kubernetes clusters, by passing `backstage.io/kubernetes-cluster` annotation with the defined cluster name. + + If you do not specify the annotation by `default it fetches all` defined kubernetes cluster. + + To apply + + catalog-info.yaml + + ```diff + annotations: + 'backstage.io/kubernetes-id': dice-roller + 'backstage.io/kubernetes-namespace': dice-space + + 'backstage.io/kubernetes-cluster': dice-cluster + 'backstage.io/kubernetes-label-selector': 'app=my-app,component=front-end' + ``` + +### Patch Changes + +- 706fc3a7e1: Updated dependency `@kubernetes/client-node` to `0.20.0`. +- 42c1aee741: Updated dependency `@google-cloud/container` to `^5.0.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-kubernetes-common@0.7.2-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/plugin-permission-node@0.7.19-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + - @backstage/plugin-kubernetes-node@0.1.2-next.0 + - @backstage/plugin-permission-common@0.7.10 + +## @backstage/plugin-techdocs-node@1.11.0-next.0 + +### Minor Changes + +- d15d483a49: Add command `--runAsDefaultUser` for `@techdocs/cli generate` to bypass running the docker builds as host user for macOS and Linux. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/app-defaults@1.4.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/core-app-api@1.11.2-next.0 + - @backstage/plugin-permission-react@0.4.18-next.0 + +## @backstage/backend-app-api@0.5.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/plugin-permission-node@0.7.19-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.5.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/backend-defaults@0.2.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-app-api@0.5.9-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + +## @backstage/backend-openapi-utils@0.1.1-next.0 + +### Patch Changes + +- aaa6fb3bc9: Minor updates for TypeScript 5.2.2+ compatibility +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/backend-plugin-api@0.6.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.10 + +## @backstage/backend-tasks@0.5.13-next.0 + +### Patch Changes + +- d8f488aaa8: Allow tasks to run more often that the default work check interval, which is 5 seconds. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/backend-test-utils@0.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-app-api@0.5.9-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/cli@0.24.1-next.0 + +### Patch Changes + +- 8cda3c72f2: Tweaked Node.js version check for when to use the new module register API with the new backend `package start` command. +- 017c425f93: Updated dependency `@typescript-eslint/eslint-plugin` to `6.11.0`. +- Updated dependencies + - @backstage/integration@1.8.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.5.3 + - @backstage/errors@1.2.3 + - @backstage/eslint-plugin@0.1.3 + - @backstage/release-manifests@0.0.11 + - @backstage/types@1.1.1 + +## @backstage/core-app-api@1.11.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/core-components@0.13.9-next.0 + +### Patch Changes + +- 381ed86d5e: Add missing export for IconLinkVertical +- 5c8a3e3960: Minor improvements to `Table` component. +- 4d9e3b39e4: Register component overrides in the global `OverrideComponentNameToClassKeys` provided by `@backstage/theme`. This will in turn will provide component style override types for `createUnifiedTheme`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/version-bridge@1.0.7 + +## @backstage/core-plugin-api@1.8.1-next.0 + +### Patch Changes + +- 03d0b6dcdc: Removed the alpha `convertLegacyRouteRef` utility, which as been moved to `@backstage/core-compat-api` +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/create-app@0.5.8-next.0 + +### Patch Changes + +- Bumped create-app version. +- Updated dependencies + - @backstage/cli-common@0.1.13 + +## @backstage/dev-utils@1.0.25-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/app-defaults@1.4.6-next.0 + - @backstage/core-app-api@1.11.2-next.0 + - @backstage/integration-react@1.1.22-next.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/frontend-app-api@0.3.1-next.0 + +### Patch Changes + +- 60d6eb544e: Removed `@backstage/plugin-graphiql` dependency. +- 9ad4039efa: Bringing over apis from core-plugin-api +- b8cb7804c8: Added `createSpecializedApp`, which is a synchronous version of `createApp` where config and features already need to be loaded. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/frontend-plugin-api@0.3.1-next.0 + - @backstage/core-app-api@1.11.2-next.0 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/frontend-plugin-api@0.3.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/integration-react@1.1.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/config@1.1.1 + +## @backstage/test-utils@1.4.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/core-app-api@1.11.2-next.0 + - @backstage/plugin-permission-react@0.4.18-next.0 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.10 + +## @backstage/plugin-adr@0.6.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/plugin-search-react@1.7.4-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/frontend-plugin-api@0.3.1-next.0 + - @backstage/integration-react@1.1.22-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-adr-common@0.2.18-next.0 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-adr-backend@0.4.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-adr-common@0.2.18-next.0 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-adr-common@0.2.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-airbrake@0.3.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/dev-utils@1.0.25-next.0 + - @backstage/test-utils@1.4.6-next.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-airbrake-backend@0.3.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + +## @backstage/plugin-allure@0.1.44-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-analytics-module-ga@0.1.36-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/config@1.1.1 + +## @backstage/plugin-analytics-module-ga4@0.1.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/config@1.1.1 + +## @backstage/plugin-analytics-module-newrelic-browser@0.0.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/config@1.1.1 + +## @backstage/plugin-apache-airflow@0.2.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + +## @backstage/plugin-api-docs@0.10.2-next.0 + +### Patch Changes + +- 816d331d16: Add dependency on `graphql-config` to compensate for `graphql-language-service` needing it but not shipping the dep properly +- 615159e536: Updated dependency `graphiql` to `3.0.10`. +- 53e2c06f41: Updated dependency `@asyncapi/react-component` to `1.1.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/plugin-catalog@1.16.0-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-apollo-explorer@0.1.18-next.0 + +### Patch Changes + +- e296b94128: Updated dependency `@apollo/explorer` to `^3.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-app-backend@0.3.56-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.5.3 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.8-next.0 + +## @backstage/plugin-app-node@0.1.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.0 + +## @backstage/plugin-auth-backend@0.20.1-next.0 + +### Patch Changes + +- 2a5891e816: Migrate the atlassian auth provider to be implemented using the new `@backstage/plugin-auth-backend-module-atlassian-provider` module +- e1c189b524: The Okta provider implementation is moved to the new module +- Updated dependencies + - @backstage/plugin-auth-backend-module-atlassian-provider@0.1.0-next.0 + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-backend-module-okta-provider@0.0.1-next.0 + - @backstage/plugin-auth-backend-module-github-provider@0.1.5-next.0 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.5-next.0 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.1.5-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/plugin-auth-backend-module-google-provider@0.1.5-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.2-next.0 + +## @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-auth-backend-module-github-provider@0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + +## @backstage/plugin-auth-backend-module-gitlab-provider@0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + +## @backstage/plugin-auth-backend-module-google-provider@0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + +## @backstage/plugin-auth-backend-module-microsoft-provider@0.1.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + +## @backstage/plugin-auth-backend-module-oauth2-provider@0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + +## @backstage/plugin-auth-backend-module-okta-provider@0.0.1-next.0 + +### Patch Changes + +- e1c189b524: Adds okta-provider backend module for the auth plugin +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + +## @backstage/plugin-auth-backend-module-pinniped-provider@0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + +## @backstage/plugin-auth-node@0.4.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-azure-devops@0.3.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-azure-devops-common@0.3.1 + +## @backstage/plugin-azure-devops-backend@0.4.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + - @backstage/plugin-azure-devops-common@0.3.1 + +## @backstage/plugin-azure-sites@0.1.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-azure-sites-common@0.1.1 + +## @backstage/plugin-azure-sites-backend@0.1.18-next.0 + +### Patch Changes + +- b7a13edf6d: Updated dependency `@azure/arm-appservice` to `^14.0.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/config@1.1.1 + - @backstage/plugin-azure-sites-common@0.1.1 + +## @backstage/plugin-badges@0.2.52-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-badges-backend@0.3.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-bazaar@0.2.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/plugin-catalog@1.16.0-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-bazaar-backend@0.3.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-bitbucket-cloud-common@0.2.15-next.0 + +### Patch Changes + +- acf93904e7: Updated dependency `ts-morph` to `^20.0.0`. +- Updated dependencies + - @backstage/integration@1.8.0-next.0 + +## @backstage/plugin-bitrise@0.1.55-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-catalog-backend@1.15.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-openapi-utils@0.1.1-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/plugin-permission-node@0.7.19-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.12-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-events-node@0.2.17-next.0 + - @backstage/plugin-permission-common@0.7.10 + +## @backstage/plugin-catalog-backend-module-aws@0.3.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/plugin-kubernetes-common@0.7.2-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + +## @backstage/plugin-catalog-backend-module-azure@0.1.27-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + +## @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-openapi-utils@0.1.1-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-catalog-backend-module-bitbucket@0.2.23-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.15-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.1.23-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.15-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-events-node@0.2.17-next.0 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.1.21-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-catalog-backend-module-gcp@0.1.8-next.0 + +### Patch Changes + +- 42c1aee741: Updated dependency `@google-cloud/container` to `^5.0.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/plugin-kubernetes-common@0.7.2-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + +## @backstage/plugin-catalog-backend-module-gerrit@0.1.24-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-catalog-backend-module-github@0.4.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/plugin-catalog-backend@1.15.1-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-events-node@0.2.17-next.0 + +## @backstage/plugin-catalog-backend-module-github-org@0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/plugin-catalog-backend-module-github@0.4.6-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + +## @backstage/plugin-catalog-backend-module-gitlab@0.3.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + +## @backstage/plugin-catalog-backend-module-incremental-ingestion@0.4.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/plugin-catalog-backend@1.15.1-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-events-node@0.2.17-next.0 + - @backstage/plugin-permission-common@0.7.10 + +## @backstage/plugin-catalog-backend-module-ldap@0.5.23-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + +## @backstage/plugin-catalog-backend-module-msgraph@0.5.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + +## @backstage/plugin-catalog-backend-module-openapi@0.1.25-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/plugin-catalog-backend@1.15.1-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + +## @backstage/plugin-catalog-backend-module-puppetdb@0.1.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-scaffolder-common@1.4.3 + +## @backstage/plugin-catalog-backend-module-unprocessed@0.3.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-catalog-graph@0.3.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-import@0.10.4-next.0 + +### Patch Changes + +- 03d0b6dcdc: The `convertLegacyRouteRef` utility used by the alpha exports is now imported from `@backstage/core-compat-api`. +- Updated dependencies + - @backstage/core-compat-api@0.0.2-next.0 + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/frontend-plugin-api@0.3.1-next.0 + - @backstage/integration-react@1.1.22-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.18 + +## @backstage/plugin-catalog-node@1.5.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + +## @backstage/plugin-catalog-react@1.9.2-next.0 + +### Patch Changes + +- 8587f067d2: Added pagination support to `EntityListProvider`. +- aaa6fb3bc9: Minor updates for TypeScript 5.2.2+ compatibility +- 4d9e3b39e4: Register component overrides in the global `OverrideComponentNameToClassKeys` provided by `@backstage/theme`. This will in turn will provide component style override types for `createUnifiedTheme`. +- eee0ff2946: Fixed a issue where `CatalogPage` wasn't using the chosen `initiallySelectedFilter` as intended. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/frontend-plugin-api@0.3.1-next.0 + - @backstage/integration-react@1.1.22-next.0 + - @backstage/plugin-permission-react@0.4.18-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-common@0.7.10 + +## @backstage/plugin-catalog-unprocessed-entities@0.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-cicd-statistics@0.1.30-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-cicd-statistics-module-gitlab@0.1.24-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-cicd-statistics@0.1.30-next.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-circleci@0.3.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-cloudbuild@0.3.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-code-climate@0.1.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-code-coverage@0.2.21-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-code-coverage-backend@0.2.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-codescene@0.1.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-config-schema@0.1.48-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-cost-insights@0.12.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-cost-insights-common@0.1.2 + +## @backstage/plugin-devtools@0.1.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-permission-react@0.4.18-next.0 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.6 + +## @backstage/plugin-devtools-backend@0.2.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/plugin-permission-node@0.7.19-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.5.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.6 + - @backstage/plugin-permission-common@0.7.10 + +## @backstage/plugin-dynatrace@8.0.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-entity-feedback@0.2.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## @backstage/plugin-entity-feedback-backend@0.2.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## @backstage/plugin-entity-validation@0.1.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.18 + +## @backstage/plugin-events-backend@0.2.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.0 + +## @backstage/plugin-events-backend-module-aws-sqs@0.2.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.0 + +## @backstage/plugin-events-backend-module-azure@0.1.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/plugin-events-node@0.2.17-next.0 + +## @backstage/plugin-events-backend-module-bitbucket-cloud@0.1.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/plugin-events-node@0.2.17-next.0 + +## @backstage/plugin-events-backend-module-gerrit@0.1.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/plugin-events-node@0.2.17-next.0 + +## @backstage/plugin-events-backend-module-github@0.1.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.0 + +## @backstage/plugin-events-backend-module-gitlab@0.1.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.0 + +## @backstage/plugin-events-backend-test-utils@0.1.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.2.17-next.0 + +## @backstage/plugin-events-node@0.2.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.0 + +## @backstage/plugin-explore@0.4.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/plugin-search-react@1.7.4-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/frontend-plugin-api@0.3.1-next.0 + - @backstage/plugin-explore-react@0.0.34-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-explore-backend@0.0.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-search-backend-module-explore@0.1.12-next.0 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-explore-react@0.0.34-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-explore-common@0.0.2 + +## @backstage/plugin-firehydrant@0.2.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-fossa@0.2.60-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-gcalendar@0.3.21-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/errors@1.2.3 + +## @backstage/plugin-gcp-projects@0.3.44-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-git-release-manager@0.3.40-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-github-actions@0.6.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/integration-react@1.1.22-next.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-github-deployments@0.1.59-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/integration-react@1.1.22-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-github-issues@0.2.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-github-pull-requests-board@0.1.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-gitops-profiles@0.3.43-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/config@1.1.1 + +## @backstage/plugin-gocd@0.1.34-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-graphiql@0.3.1-next.0 + +### Patch Changes + +- 03d0b6dcdc: The `convertLegacyRouteRef` utility used by the alpha exports is now imported from `@backstage/core-compat-api`. +- Updated dependencies + - @backstage/core-compat-api@0.0.2-next.0 + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/frontend-plugin-api@0.3.1-next.0 + +## @backstage/plugin-graphql-voyager@0.1.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-home@0.5.12-next.0 + +### Patch Changes + +- 6cd12f277b: Updated dependency `@rjsf/utils` to `5.14.1`. + Updated dependency `@rjsf/core` to `5.14.1`. + Updated dependency `@rjsf/material-ui` to `5.14.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.1`. +- 63c494ef22: Updated dependency `@rjsf/utils` to `5.14.2`. + Updated dependency `@rjsf/core` to `5.14.2`. + Updated dependency `@rjsf/material-ui` to `5.14.2`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.2`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/plugin-home-react@0.1.6-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/frontend-plugin-api@0.3.1-next.0 + - @backstage/core-app-api@1.11.2-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## @backstage/plugin-home-react@0.1.6-next.0 + +### Patch Changes + +- 6cd12f277b: Updated dependency `@rjsf/utils` to `5.14.1`. + Updated dependency `@rjsf/core` to `5.14.1`. + Updated dependency `@rjsf/material-ui` to `5.14.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.1`. +- 63c494ef22: Updated dependency `@rjsf/utils` to `5.14.2`. + Updated dependency `@rjsf/core` to `5.14.2`. + Updated dependency `@rjsf/material-ui` to `5.14.2`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.2`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + +## @backstage/plugin-ilert@0.2.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-jenkins@0.9.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-jenkins-common@0.1.21 + +## @backstage/plugin-jenkins-backend@0.3.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/plugin-permission-node@0.7.19-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-jenkins-common@0.1.21 + - @backstage/plugin-permission-common@0.7.10 + +## @backstage/plugin-kafka@0.3.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + +## @backstage/plugin-kafka-backend@0.3.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-kubernetes@0.11.3-next.0 + +### Patch Changes + +- 706fc3a7e1: Updated dependency `@kubernetes/client-node` to `0.20.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/plugin-kubernetes-react@0.1.2-next.0 + - @backstage/plugin-kubernetes-common@0.7.2-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-kubernetes-cluster@0.0.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/plugin-kubernetes-react@0.1.2-next.0 + - @backstage/plugin-kubernetes-common@0.7.2-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-kubernetes-common@0.7.2-next.0 + +### Patch Changes + +- 706fc3a7e1: Updated dependency `@kubernetes/client-node` to `0.20.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.10 + +## @backstage/plugin-kubernetes-node@0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes-common@0.7.2-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-kubernetes-react@0.1.2-next.0 + +### Patch Changes + +- b5ae2e5a62: Add ID property to the table displaying kubernetes pods to avoid closing the info sidebar when the data reloads and needs to rerender. +- 706fc3a7e1: Updated dependency `@kubernetes/client-node` to `0.20.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/plugin-kubernetes-common@0.7.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-lighthouse@0.4.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-lighthouse-common@0.1.4 + +## @backstage/plugin-lighthouse-backend@0.3.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-lighthouse-common@0.1.4 + +## @backstage/plugin-linguist@0.1.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-linguist-common@0.1.2 + +## @backstage/plugin-linguist-backend@0.5.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-linguist-common@0.1.2 + +## @backstage/plugin-microsoft-calendar@0.1.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/errors@1.2.3 + +## @backstage/plugin-newrelic@0.3.43-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-newrelic-dashboard@0.3.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-nomad@0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + +## @backstage/plugin-nomad-backend@0.1.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-octopus-deploy@0.2.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-opencost@0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-org@0.6.18-next.0 + +### Patch Changes + +- 3a65d9c4d7: Support member list scrollable when parent has specified height +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-org-react@0.1.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-pagerduty@0.6.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/plugin-home-react@0.1.6-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-periskop@0.1.26-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-periskop-backend@0.2.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + +## @backstage/plugin-permission-backend@0.5.31-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/plugin-permission-node@0.7.19-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-permission-common@0.7.10 + +## @backstage/plugin-permission-backend-module-allow-all-policy@0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/plugin-permission-node@0.7.19-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/plugin-permission-common@0.7.10 + +## @backstage/plugin-permission-node@0.7.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-permission-common@0.7.10 + +## @backstage/plugin-permission-react@0.4.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/config@1.1.1 + - @backstage/plugin-permission-common@0.7.10 + +## @backstage/plugin-playlist@0.2.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/plugin-search-react@1.7.4-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-permission-react@0.4.18-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-playlist-common@0.1.12 + +## @backstage/plugin-playlist-backend@0.3.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/plugin-permission-node@0.7.19-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-playlist-common@0.1.12 + +## @backstage/plugin-proxy-backend@0.4.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + +## @backstage/plugin-puppetdb@0.1.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-rollbar@0.4.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-rollbar-backend@0.1.53-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/config@1.1.1 + +## @backstage/plugin-scaffolder@1.16.2-next.0 + +### Patch Changes + +- 6806d10be3: Added `headerOptions` to `TemplateListPage` to optionally override default values. + Changed `themeId` of TemplateListPage from `website` to `home`. +- aaa6fb3bc9: Minor updates for TypeScript 5.2.2+ compatibility +- 6cd12f277b: Updated dependency `@rjsf/utils` to `5.14.1`. + Updated dependency `@rjsf/core` to `5.14.1`. + Updated dependency `@rjsf/material-ui` to `5.14.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.1`. +- 63c494ef22: Updated dependency `@rjsf/utils` to `5.14.2`. + Updated dependency `@rjsf/core` to `5.14.2`. + Updated dependency `@rjsf/material-ui` to `5.14.2`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.2`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/plugin-scaffolder-react@1.6.2-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/integration-react@1.1.22-next.0 + - @backstage/plugin-permission-react@0.4.18-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-scaffolder-common@1.4.3 + +## @backstage/plugin-scaffolder-backend@1.19.2-next.0 + +### Patch Changes + +- aff34fcf23: Fix issue with Circular JSON dependencies in templating +- 48667b4d3a: Fix creating env secret in github:environment:create action +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/plugin-auth-node@0.4.2-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-permission-node@0.7.19-next.0 + - @backstage/plugin-scaffolder-node@0.2.9-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-scaffolder-common@1.4.3 + +## @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/plugin-scaffolder-node@0.2.9-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.2.32-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/plugin-scaffolder-node@0.2.9-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-gitlab@0.2.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.0 + - @backstage/plugin-scaffolder-node@0.2.9-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-scaffolder-backend-module-rails@0.4.25-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/plugin-scaffolder-node@0.2.9-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-sentry@0.1.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.9-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.2.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.9-next.0 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-node@0.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-common@1.4.3 + +## @backstage/plugin-scaffolder-react@1.6.2-next.0 + +### Patch Changes + +- e516bf4da8: Step titles in the Stepper are now clickable and redirect the user to the corresponding step, as an alternative to using the back buttons. +- aaa6fb3bc9: Minor updates for TypeScript 5.2.2+ compatibility +- 6cd12f277b: Updated dependency `@rjsf/utils` to `5.14.1`. + Updated dependency `@rjsf/core` to `5.14.1`. + Updated dependency `@rjsf/material-ui` to `5.14.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.1`. +- 63c494ef22: Updated dependency `@rjsf/utils` to `5.14.2`. + Updated dependency `@rjsf/core` to `5.14.2`. + Updated dependency `@rjsf/material-ui` to `5.14.2`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.2`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-scaffolder-common@1.4.3 + +## @backstage/plugin-search@1.4.4-next.0 + +### Patch Changes + +- 03d0b6dcdc: The `convertLegacyRouteRef` utility used by the alpha exports is now imported from `@backstage/core-compat-api`. +- Updated dependencies + - @backstage/core-compat-api@0.0.2-next.0 + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/plugin-search-react@1.7.4-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/frontend-plugin-api@0.3.1-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend@1.4.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-openapi-utils@0.1.1-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/plugin-permission-node@0.7.19-next.0 + - @backstage/plugin-search-backend-node@1.2.12-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-module-catalog@0.1.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/plugin-search-backend-node@1.2.12-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-module-elasticsearch@1.3.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-search-backend-node@1.2.12-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + - @backstage/integration-aws-node@0.1.8 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-module-explore@0.1.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/plugin-search-backend-node@1.2.12-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-module-pg@0.5.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-search-backend-node@1.2.12-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-module-stack-overflow-collator@0.1.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/plugin-search-backend-node@1.2.12-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-module-techdocs@0.1.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/plugin-techdocs-node@1.11.0-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/plugin-search-backend-node@1.2.12-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-node@1.2.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-react@1.7.4-next.0 + +### Patch Changes + +- 84dabc5363: Removed `@backstage/frontend-app-api` dependency. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/frontend-plugin-api@0.3.1-next.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-sentry@0.5.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-shortcuts@0.3.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-sonarqube@0.7.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-sonarqube-react@0.1.11-next.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-sonarqube-backend@0.2.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-sonarqube-react@0.1.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-splunk-on-call@0.4.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-stack-overflow@0.1.23-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/plugin-search-react@1.7.4-next.0 + - @backstage/plugin-home-react@0.1.6-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/frontend-plugin-api@0.3.1-next.0 + - @backstage/config@1.1.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-stack-overflow-backend@0.2.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-search-backend-module-stack-overflow-collator@0.1.1-next.0 + - @backstage/config@1.1.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-stackstorm@0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/errors@1.2.3 + +## @backstage/plugin-tech-insights@0.3.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-insights-backend@0.5.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/plugin-tech-insights-node@0.4.14-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.40-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-tech-insights-node@0.4.14-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-insights-node@0.4.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-radar@0.6.11-next.0 + +### Patch Changes + +- 03d0b6dcdc: The `convertLegacyRouteRef` utility used by the alpha exports is now imported from `@backstage/core-compat-api`. +- Updated dependencies + - @backstage/core-compat-api@0.0.2-next.0 + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/frontend-plugin-api@0.3.1-next.0 + +## @backstage/plugin-techdocs@1.9.2-next.0 + +### Patch Changes + +- 03d0b6dcdc: The `convertLegacyRouteRef` utility used by the alpha exports is now imported from `@backstage/core-compat-api`. +- Updated dependencies + - @backstage/core-compat-api@0.0.2-next.0 + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/plugin-search-react@1.7.4-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/frontend-plugin-api@0.3.1-next.0 + - @backstage/integration-react@1.1.22-next.0 + - @backstage/plugin-techdocs-react@1.1.14-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.25-next.0 + +### Patch Changes + +- 3f354e68f4: Move `@testing-library/react` to be a `peerDependency` +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/plugin-catalog@1.16.0-next.0 + - @backstage/plugin-techdocs@1.9.2-next.0 + - @backstage/plugin-search-react@1.7.4-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/core-app-api@1.11.2-next.0 + - @backstage/integration-react@1.1.22-next.0 + - @backstage/test-utils@1.4.6-next.0 + - @backstage/plugin-techdocs-react@1.1.14-next.0 + +## @backstage/plugin-techdocs-backend@1.9.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/plugin-techdocs-node@1.11.0-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.12-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-techdocs-module-addons-contrib@1.1.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/integration-react@1.1.22-next.0 + - @backstage/plugin-techdocs-react@1.1.14-next.0 + +## @backstage/plugin-techdocs-react@1.1.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/plugin-todo@0.2.32-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-todo-backend@0.3.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-openapi-utils@0.1.1-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-user-settings@0.7.14-next.0 + +### Patch Changes + +- 03d0b6dcdc: The `convertLegacyRouteRef` utility used by the alpha exports is now imported from `@backstage/core-compat-api`. +- Updated dependencies + - @backstage/core-compat-api@0.0.2-next.0 + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/frontend-plugin-api@0.3.1-next.0 + - @backstage/core-app-api@1.11.2-next.0 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-user-settings-backend@0.2.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-vault@0.1.23-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-vault-backend@0.4.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-vault-node@0.1.1-next.0 + +## @backstage/plugin-vault-node@0.1.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.0 + +## @backstage/plugin-xcmetrics@0.2.46-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/errors@1.2.3 + +## example-app@0.2.90-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/plugin-api-docs@0.10.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/plugin-scaffolder@1.16.2-next.0 + - @backstage/plugin-catalog@1.16.0-next.0 + - @backstage/frontend-app-api@0.3.1-next.0 + - @backstage/plugin-org@0.6.18-next.0 + - @backstage/plugin-scaffolder-react@1.6.2-next.0 + - @backstage/plugin-catalog-import@0.10.4-next.0 + - @backstage/plugin-user-settings@0.7.14-next.0 + - @backstage/plugin-tech-radar@0.6.11-next.0 + - @backstage/plugin-graphiql@0.3.1-next.0 + - @backstage/plugin-techdocs@1.9.2-next.0 + - @backstage/plugin-search@1.4.4-next.0 + - @backstage/plugin-search-react@1.7.4-next.0 + - @backstage/cli@0.24.1-next.0 + - @backstage/plugin-home@0.5.12-next.0 + - @backstage/plugin-kubernetes@0.11.3-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/app-defaults@1.4.6-next.0 + - @backstage/core-app-api@1.11.2-next.0 + - @backstage/integration-react@1.1.22-next.0 + - @backstage/plugin-adr@0.6.11-next.0 + - @backstage/plugin-airbrake@0.3.28-next.0 + - @backstage/plugin-apache-airflow@0.2.18-next.0 + - @backstage/plugin-azure-devops@0.3.10-next.0 + - @backstage/plugin-azure-sites@0.1.17-next.0 + - @backstage/plugin-badges@0.2.52-next.0 + - @backstage/plugin-catalog-graph@0.3.2-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.1.6-next.0 + - @backstage/plugin-circleci@0.3.28-next.0 + - @backstage/plugin-cloudbuild@0.3.28-next.0 + - @backstage/plugin-code-coverage@0.2.21-next.0 + - @backstage/plugin-cost-insights@0.12.17-next.0 + - @backstage/plugin-devtools@0.1.7-next.0 + - @backstage/plugin-dynatrace@8.0.2-next.0 + - @backstage/plugin-entity-feedback@0.2.11-next.0 + - @backstage/plugin-explore@0.4.14-next.0 + - @backstage/plugin-gcalendar@0.3.21-next.0 + - @backstage/plugin-gcp-projects@0.3.44-next.0 + - @backstage/plugin-github-actions@0.6.9-next.0 + - @backstage/plugin-gocd@0.1.34-next.0 + - @backstage/plugin-jenkins@0.9.3-next.0 + - @backstage/plugin-kafka@0.3.28-next.0 + - @backstage/plugin-kubernetes-cluster@0.0.4-next.0 + - @backstage/plugin-lighthouse@0.4.13-next.0 + - @backstage/plugin-linguist@0.1.13-next.0 + - @backstage/plugin-microsoft-calendar@0.1.10-next.0 + - @backstage/plugin-newrelic@0.3.43-next.0 + - @backstage/plugin-newrelic-dashboard@0.3.3-next.0 + - @backstage/plugin-nomad@0.1.9-next.0 + - @backstage/plugin-octopus-deploy@0.2.10-next.0 + - @backstage/plugin-pagerduty@0.6.9-next.0 + - @backstage/plugin-permission-react@0.4.18-next.0 + - @backstage/plugin-playlist@0.2.2-next.0 + - @backstage/plugin-puppetdb@0.1.11-next.0 + - @backstage/plugin-rollbar@0.4.28-next.0 + - @backstage/plugin-sentry@0.5.13-next.0 + - @backstage/plugin-shortcuts@0.3.17-next.0 + - @backstage/plugin-stack-overflow@0.1.23-next.0 + - @backstage/plugin-stackstorm@0.1.9-next.0 + - @backstage/plugin-tech-insights@0.3.20-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.3-next.0 + - @backstage/plugin-techdocs-react@1.1.14-next.0 + - @backstage/plugin-todo@0.2.32-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.8 + +## example-app-next@0.0.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.0.2-next.0 + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/plugin-api-docs@0.10.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/plugin-scaffolder@1.16.2-next.0 + - @backstage/plugin-catalog@1.16.0-next.0 + - @backstage/frontend-app-api@0.3.1-next.0 + - @backstage/plugin-org@0.6.18-next.0 + - @backstage/plugin-scaffolder-react@1.6.2-next.0 + - @backstage/plugin-catalog-import@0.10.4-next.0 + - @backstage/plugin-user-settings@0.7.14-next.0 + - @backstage/plugin-tech-radar@0.6.11-next.0 + - @backstage/plugin-graphiql@0.3.1-next.0 + - @backstage/plugin-techdocs@1.9.2-next.0 + - @backstage/plugin-search@1.4.4-next.0 + - @backstage/plugin-search-react@1.7.4-next.0 + - @backstage/cli@0.24.1-next.0 + - @backstage/plugin-home@0.5.12-next.0 + - @backstage/plugin-kubernetes@0.11.3-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/frontend-plugin-api@0.3.1-next.0 + - @backstage/app-defaults@1.4.6-next.0 + - @backstage/core-app-api@1.11.2-next.0 + - @backstage/integration-react@1.1.22-next.0 + - @backstage/plugin-adr@0.6.11-next.0 + - @backstage/plugin-airbrake@0.3.28-next.0 + - @backstage/plugin-apache-airflow@0.2.18-next.0 + - @backstage/plugin-azure-devops@0.3.10-next.0 + - @backstage/plugin-azure-sites@0.1.17-next.0 + - @backstage/plugin-badges@0.2.52-next.0 + - @backstage/plugin-catalog-graph@0.3.2-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.1.6-next.0 + - @backstage/plugin-circleci@0.3.28-next.0 + - @backstage/plugin-cloudbuild@0.3.28-next.0 + - @backstage/plugin-code-coverage@0.2.21-next.0 + - @backstage/plugin-cost-insights@0.12.17-next.0 + - @backstage/plugin-devtools@0.1.7-next.0 + - @backstage/plugin-dynatrace@8.0.2-next.0 + - @backstage/plugin-entity-feedback@0.2.11-next.0 + - @backstage/plugin-explore@0.4.14-next.0 + - @backstage/plugin-gcalendar@0.3.21-next.0 + - @backstage/plugin-gcp-projects@0.3.44-next.0 + - @backstage/plugin-github-actions@0.6.9-next.0 + - @backstage/plugin-gocd@0.1.34-next.0 + - @backstage/plugin-jenkins@0.9.3-next.0 + - @backstage/plugin-kafka@0.3.28-next.0 + - @backstage/plugin-lighthouse@0.4.13-next.0 + - @backstage/plugin-linguist@0.1.13-next.0 + - @backstage/plugin-microsoft-calendar@0.1.10-next.0 + - @backstage/plugin-newrelic@0.3.43-next.0 + - @backstage/plugin-newrelic-dashboard@0.3.3-next.0 + - @backstage/plugin-octopus-deploy@0.2.10-next.0 + - @backstage/plugin-pagerduty@0.6.9-next.0 + - @backstage/plugin-permission-react@0.4.18-next.0 + - @backstage/plugin-playlist@0.2.2-next.0 + - @backstage/plugin-puppetdb@0.1.11-next.0 + - @backstage/plugin-rollbar@0.4.28-next.0 + - @backstage/plugin-sentry@0.5.13-next.0 + - @backstage/plugin-shortcuts@0.3.17-next.0 + - @backstage/plugin-stackstorm@0.1.9-next.0 + - @backstage/plugin-tech-insights@0.3.20-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.3-next.0 + - @backstage/plugin-techdocs-react@1.1.14-next.0 + - @backstage/plugin-todo@0.2.32-next.0 + - app-next-example-plugin@0.0.4-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.8 + +## app-next-example-plugin@0.0.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.0 + - @backstage/frontend-plugin-api@0.3.1-next.0 + +## example-backend@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 + +## example-backend-next@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 + +## @backstage/backend-plugin-manager@0.0.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/plugin-catalog-backend@1.15.1-next.0 + - @backstage/plugin-events-backend@0.2.17-next.0 + - @backstage/plugin-permission-node@0.7.19-next.0 + - @backstage/plugin-scaffolder-node@0.2.9-next.0 + - @backstage/plugin-search-backend-node@1.2.12-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.0 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/core-compat-api@0.0.2-next.0 + +### Patch Changes + +- 03d0b6dcdc: Added `convertLegacyRouteRef` utility to convert existing route refs to be used with the new experimental packages. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/frontend-plugin-api@0.3.1-next.0 + - @backstage/core-app-api@1.11.2-next.0 + +## e2e-test@0.2.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.8-next.0 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + +## techdocs-cli-embedded-app@0.2.89-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/plugin-catalog@1.16.0-next.0 + - @backstage/plugin-techdocs@1.9.2-next.0 + - @backstage/cli@0.24.1-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/app-defaults@1.4.6-next.0 + - @backstage/core-app-api@1.11.2-next.0 + - @backstage/integration-react@1.1.22-next.0 + - @backstage/test-utils@1.4.6-next.0 + - @backstage/plugin-techdocs-react@1.1.14-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + +## @internal/plugin-todo-list@1.0.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + +## @internal/plugin-todo-list-backend@1.0.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 diff --git a/docs/releases/v1.21.0-next.1-changelog.md b/docs/releases/v1.21.0-next.1-changelog.md new file mode 100644 index 0000000000..aa5f14b1b4 --- /dev/null +++ b/docs/releases/v1.21.0-next.1-changelog.md @@ -0,0 +1,140 @@ +# Release v1.21.0-next.1 + +## @backstage/core-compat-api@0.0.1-next.0 + +### Patch Changes + +- c219b168aa: Made package public so it can be published + +## @backstage/create-app@0.5.8-next.1 + +### Patch Changes + +- Bumped create-app version. + +## @backstage/plugin-api-docs@0.10.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.16.0-next.1 + +## @backstage/plugin-bazaar@0.2.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.16.0-next.1 + +## @backstage/plugin-catalog@1.16.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.0.1-next.0 + +## @backstage/plugin-catalog-import@0.10.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.0.1-next.0 + +## @backstage/plugin-graphiql@0.3.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.0.1-next.0 + +## @backstage/plugin-search@1.4.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.0.1-next.0 + +## @backstage/plugin-tech-radar@0.6.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.0.1-next.0 + +## @backstage/plugin-techdocs@1.9.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.0.1-next.0 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.16.0-next.1 + - @backstage/plugin-techdocs@1.9.2-next.1 + +## @backstage/plugin-user-settings@0.7.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.0.1-next.0 + +## example-app@0.2.90-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.16.0-next.1 + - @backstage/plugin-catalog-import@0.10.4-next.1 + - @backstage/plugin-graphiql@0.3.1-next.1 + - @backstage/plugin-search@1.4.4-next.1 + - @backstage/plugin-tech-radar@0.6.11-next.1 + - @backstage/plugin-techdocs@1.9.2-next.1 + - @backstage/plugin-user-settings@0.7.14-next.1 + - @backstage/plugin-api-docs@0.10.2-next.1 + - @backstage/plugin-catalog-graph@0.3.2-next.0 + - @backstage/plugin-explore@0.4.14-next.0 + - @backstage/plugin-org@0.6.18-next.0 + - @backstage/plugin-scaffolder@1.16.2-next.0 + - @backstage/plugin-scaffolder-react@1.6.2-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.3-next.0 + +## example-app-next@0.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.0.1-next.0 + - @backstage/plugin-catalog@1.16.0-next.1 + - @backstage/plugin-catalog-import@0.10.4-next.1 + - @backstage/plugin-graphiql@0.3.1-next.1 + - @backstage/plugin-search@1.4.4-next.1 + - @backstage/plugin-tech-radar@0.6.11-next.1 + - @backstage/plugin-techdocs@1.9.2-next.1 + - @backstage/plugin-user-settings@0.7.14-next.1 + - @backstage/plugin-api-docs@0.10.2-next.1 + - @backstage/plugin-catalog-graph@0.3.2-next.0 + - @backstage/plugin-explore@0.4.14-next.0 + - @backstage/plugin-org@0.6.18-next.0 + - @backstage/plugin-scaffolder@1.16.2-next.0 + - @backstage/plugin-scaffolder-react@1.6.2-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.3-next.0 + +## e2e-test@0.2.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.8-next.1 + +## techdocs-cli-embedded-app@0.2.89-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.16.0-next.1 + - @backstage/plugin-techdocs@1.9.2-next.1 diff --git a/docs/releases/v1.21.0-next.2-changelog.md b/docs/releases/v1.21.0-next.2-changelog.md new file mode 100644 index 0000000000..ba5c3c007d --- /dev/null +++ b/docs/releases/v1.21.0-next.2-changelog.md @@ -0,0 +1,3088 @@ +# Release v1.21.0-next.2 + +## @backstage/catalog-client@1.5.0-next.0 + +### Minor Changes + +- 38340678c3: The internals of `CatalogClient` are now auto-generated using the `backstage-repo-tools schema openapi generate-client` command. + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/cli@0.25.0-next.1 + +### Minor Changes + +- 38340678c3: Updates the ESLint config to ignore issues created by generated files in `**/src/generated/**`. + +### Patch Changes + +- 0ffee55010: Toned down the warning message when git is not found +- c6f3743172: Added a warning when starting a standalone backend plugin that hasn't been updated to the new backend system. +- 3e358b0dff: Added deprecation warning for React Router v6 beta, please make sure you have migrated your apps to use React Router v6 stable as support for the beta version will be removed. See the [migration tutorial](https://backstage.io/docs/tutorials/react-router-stable-migration) for more information. +- 8056425e09: Updated dependency `@typescript-eslint/eslint-plugin` to `6.12.0`. +- 33e96e59e7: Switched the `@typescript-eslint/eslint-plugin` dependency back to using a `^` version range. +- Updated dependencies + - @backstage/eslint-plugin@0.1.4-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.5.3 + - @backstage/errors@1.2.3 + - @backstage/release-manifests@0.0.11 + - @backstage/types@1.1.1 + +## @backstage/frontend-app-api@0.4.0-next.1 + +### Minor Changes + +- e539735435: Updated core extension structure to make space for the sign-in page by adding `core.router`. + +### Patch Changes + +- 5eb6b8a7bc: Added the nav logo extension for customization of sidebar logo +- 1f12fb762c: Create a core components extension that allows adopters to override core app components such as `Progress`, `BootErrorPage`, `NotFoundErrorPage` and `ErrorBoundaryFallback`. +- 59709286b3: Collect and register feature flags from plugins and extension overrides. +- f27ee7d937: Migrate analytics route tracker component. +- a5a04739e1: Updates to provide `node` to extension factories instead of `id` and `source`. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/frontend-plugin-api@0.4.0-next.1 + +### Minor Changes + +- a5a04739e1: The extension `factory` function now longer receives `id` or `source`, but instead now provides the extension's `AppNode` as `node`. The `ExtensionBoundary` component has also been updated to receive a `node` prop rather than `id` and `source`. + +### Patch Changes + +- 5eb6b8a7bc: Added the nav logo extension for customization of sidebar logo +- 1f12fb762c: Create factories for overriding default core components extensions. +- 59709286b3: Add feature flags to plugins and extension overrides. +- e539735435: Added `createSignInPageExtension`. +- f27ee7d937: Migrate analytics api and context files. +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/repo-tools@0.5.0-next.0 + +### Minor Changes + +- aea8f8d329: **BREAKING**: API Reports generated for sub-path exports now place the name as a suffix rather than prefix, for example `api-report-alpha.md` instead of `alpha-api-report.md`. When upgrading to this version you'll need to re-create any such API reports and delete the old ones. +- 38340678c3: Adds a new command `schema openapi generate-client` that creates a Typescript client with Backstage flavor, including the discovery API and fetch API. This command doesn't currently generate a complete client and needs to be wrapped or exported manually by a separate Backstage plugin. See `@backstage/catalog-client/src/generated` for example output. + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/errors@1.2.3 + +## @techdocs/cli@1.8.0-next.1 + +### Minor Changes + +- b2dccad7b3: Support passing additional `mkdocs-server` CLI parameters (`--dirtyreload`, `--strict` and `--clean`) when run in containerized mode. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs-node@1.11.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + +## @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.0-next.0 + +### Minor Changes + +- 271aa12c7c: Release of `oauth2-proxy-provider` plugin + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## @backstage/plugin-auth-backend-module-vmware-cloud-provider@0.1.0-next.0 + +### Minor Changes + +- ed02c69a3c: Add VMware Cloud auth backend module provider + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## @backstage/plugin-azure-devops-backend@0.5.0-next.1 + +### Minor Changes + +- 844969cd97: **BREAKING** New `fromConfig` static method must be used now when creating an instance of the `AzureDevOpsApi` + + Added support for using the `AzureDevOpsCredentialsProvider` + +### Patch Changes + +- 043b724c56: Introduced new `AzureDevOpsAnnotatorProcessor` that adds the needed annotations automatically. Also, moved constants to common package so they can be shared more easily +- Updated dependencies + - @backstage/plugin-azure-devops-common@0.3.2-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## @backstage/plugin-catalog@1.16.0-next.2 + +### Minor Changes + +- e223f2264d: Properly support both function- and string-form visibility filter expressions in the new extensions exported via `/alpha`. + +### Patch Changes + +- 53600976bb: Ensure that passed-in icons are taken advantage of in the presentation API +- a5a04739e1: Internal refactor of alpha exports due to a change in how extension factories are defined. +- 78a10bb085: Adding in spec.type chip to search results for clarity +- fb8f3bdbc2: Updated alpha translation message keys to use nested format and camel case. +- 531e1a2a79: Updated alpha plugin to include the `unregisterRedirect` external route. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/plugin-search-react@1.7.4-next.1 + - @backstage/core-compat-api@0.0.1-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-scaffolder-common@1.4.3 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-home@0.6.0-next.1 + +### Minor Changes + +- 5a317f59c0: Added view of entities grouped by kind to make it easier to distinguish entities with different kind but same name + +### Patch Changes + +- 2b725913c1: Updated dependency `@rjsf/utils` to `5.14.3`. + Updated dependency `@rjsf/core` to `5.14.3`. + Updated dependency `@rjsf/material-ui` to `5.14.3`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.3`. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/plugin-home-react@0.1.6-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-pagerduty@0.7.0-next.1 + +### Minor Changes + +- 5fca16fdf6: This package has been deprecated, consider using [@pagerduty/backstage-plugin](https://github.com/pagerduty/backstage-plugin) instead. + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-home-react@0.1.6-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/app-defaults@1.4.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/theme@0.5.0-next.0 + +## @backstage/backend-app-api@0.5.9-next.1 + +### Patch Changes + +- 1da5f434f3: Ensure redaction of secrets that have accidental extra whitespace around them +- 9f8f266ff4: Add redacting for secrets in stack traces of logs +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.5.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-permission-node@0.7.19-next.1 + +## @backstage/backend-common@0.20.0-next.1 + +### Patch Changes + +- 2666675457: Updated dependency `@google-cloud/storage` to `^7.0.0`. +- Updated dependencies + - @backstage/backend-app-api@0.5.9-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-dev-utils@0.1.2 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.5.3 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + +## @backstage/backend-defaults@0.2.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@0.5.9-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + +## @backstage/backend-openapi-utils@0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/backend-plugin-api@0.6.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-permission-common@0.7.10 + +## @backstage/backend-tasks@0.5.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/backend-test-utils@0.2.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@0.5.9-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## @backstage/core-app-api@1.11.2-next.1 + +### Patch Changes + +- 3e358b0dff: Added deprecation warning for React Router v6 beta, please make sure you have migrated your apps to use React Router v6 stable as support for the beta version will be removed. See the [migration tutorial](https://backstage.io/docs/tutorials/react-router-stable-migration) for more information. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/core-compat-api@0.0.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/core-app-api@1.11.2-next.1 + +## @backstage/core-components@0.13.9-next.1 + +### Patch Changes + +- e8f2acef80: Added a new `/testUtils` sub-path that initially exports a `mockBreakpoint` helper. +- 07dfdf3702: Updated dependency `linkifyjs` to `4.1.3`. +- a518c5a25b: Updated dependency `@react-hookz/web` to `^23.0.0`. +- f291757e70: Update `linkify-react` to version `4.1.3` +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/version-bridge@1.0.7 + +## @backstage/core-plugin-api@1.8.1-next.1 + +### Patch Changes + +- 0c93dc37b2: The `createTranslationRef` function from the `/alpha` subpath can now also accept a nested object structure of default translation messages, which will be flatted using `.` separators. +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/create-app@0.5.8-next.2 + +### Patch Changes + +- 375b6f7d68: CircelCI plugin moved permanently +- Updated dependencies + - @backstage/cli-common@0.1.13 + +## @backstage/dev-utils@1.0.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/app-defaults@1.4.6-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/eslint-plugin@0.1.4-next.0 + +### Patch Changes + +- 107dc46ab1: The `no-undeclared-imports` rule will now prefer using version queries that already exist en the repo for the same dependency type when installing new packages. + +## @backstage/frontend-test-utils@0.1.0-next.1 + +### Patch Changes + +- e539735435: Updates for `core.router` addition. +- c21c9cf07b: Re-export mock API implementations as well as `TestApiProvider`, `TestApiRegistry`, `withLogCollector`, and `setupRequestMockHandlers` from `@backstage/test-utils`. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/frontend-app-api@0.4.0-next.1 + - @backstage/test-utils@1.4.6-next.1 + - @backstage/types@1.1.1 + +## @backstage/integration@1.8.0-next.1 + +### Patch Changes + +- 99fb54183b: Updated dependency `@azure/identity` to `^4.0.0`. +- Updated dependencies + - @backstage/config@1.1.1 + +## @backstage/integration-react@1.1.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/config@1.1.1 + +## @backstage/test-utils@1.4.6-next.1 + +### Patch Changes + +- e8f2acef80: Deprecated `mockBreakpoint`, as it is now available from `@backstage/core-components/testUtils` instead. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.10 + +## @backstage/plugin-adr@0.6.11-next.1 + +### Patch Changes + +- fb8f3bdbc2: Updated alpha translation message keys to use nested format and camel case. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-search-react@1.7.4-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-adr-common@0.2.18-next.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-adr-backend@0.4.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-adr-common@0.2.18-next.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-adr-common@0.2.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-airbrake@0.3.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/test-utils@1.4.6-next.1 + - @backstage/dev-utils@1.0.25-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-airbrake-backend@0.3.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + +## @backstage/plugin-allure@0.1.44-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-analytics-module-ga@0.1.36-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-analytics-module-ga4@0.1.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-analytics-module-newrelic-browser@0.0.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + +## @backstage/plugin-apache-airflow@0.2.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @backstage/plugin-api-docs@0.10.2-next.2 + +### Patch Changes + +- e16e7ce6a5: Updated dependency `@asyncapi/react-component` to `1.2.2`. +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-catalog@1.16.0-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-apollo-explorer@0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-app-backend@0.3.56-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.5.3 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.8-next.1 + +## @backstage/plugin-app-node@0.1.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + +## @backstage/plugin-auth-backend@0.20.1-next.1 + +### Patch Changes + +- 7ac25759a5: `oauth2-proxy` auth implementation has been moved to `@backstage/plugin-auth-backend-module-oauth2-proxy-provider` +- bcbbf8e042: Updated dependency `@google-cloud/firestore` to `^7.0.0`. +- Updated dependencies + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.0-next.0 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.1.0-next.1 + - @backstage/plugin-auth-backend-module-github-provider@0.1.5-next.1 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.5-next.1 + - @backstage/plugin-auth-backend-module-google-provider@0.1.5-next.1 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.1.5-next.1 + - @backstage/plugin-auth-backend-module-okta-provider@0.0.1-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.2-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## @backstage/plugin-auth-backend-module-atlassian-provider@0.1.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## @backstage/plugin-auth-backend-module-github-provider@0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## @backstage/plugin-auth-backend-module-gitlab-provider@0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## @backstage/plugin-auth-backend-module-google-provider@0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## @backstage/plugin-auth-backend-module-microsoft-provider@0.1.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## @backstage/plugin-auth-backend-module-oauth2-provider@0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## @backstage/plugin-auth-backend-module-okta-provider@0.0.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## @backstage/plugin-auth-backend-module-pinniped-provider@0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## @backstage/plugin-auth-node@0.4.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-azure-devops@0.3.10-next.1 + +### Patch Changes + +- 043b724c56: Introduced new `AzureDevOpsAnnotatorProcessor` that adds the needed annotations automatically. Also, moved constants to common package so they can be shared more easily +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-azure-devops-common@0.3.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-azure-devops-common@0.3.2-next.0 + +### Patch Changes + +- 043b724c56: Introduced new `AzureDevOpsAnnotatorProcessor` that adds the needed annotations automatically. Also, moved constants to common package so they can be shared more easily + +## @backstage/plugin-azure-sites@0.1.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-azure-sites-common@0.1.1 + +## @backstage/plugin-azure-sites-backend@0.1.18-next.1 + +### Patch Changes + +- 99fb54183b: Updated dependency `@azure/identity` to `^4.0.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-azure-sites-common@0.1.1 + +## @backstage/plugin-badges@0.2.52-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-badges-backend@0.3.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## @backstage/plugin-bazaar@0.2.20-next.2 + +### Patch Changes + +- 5d796829bb: Internalize 'AboutField' to break catalog dependency +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-bazaar-backend@0.3.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## @backstage/plugin-bitbucket-cloud-common@0.2.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + +## @backstage/plugin-bitrise@0.1.55-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-catalog-backend@1.15.1-next.1 + +### Patch Changes + +- 38340678c3: Update the OpenAPI spec to support the use of `openapi-generator`. +- 7123c58b3d: Updated dependency `@types/glob` to `^8.0.0`. +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-openapi-utils@0.1.1-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-events-node@0.2.17-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.12-next.1 + +## @backstage/plugin-catalog-backend-module-aws@0.3.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## @backstage/plugin-catalog-backend-module-azure@0.1.27-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.1-next.1 + +### Patch Changes + +- eb44e92898: Support authenticated backends +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-openapi-utils@0.1.1-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## @backstage/plugin-catalog-backend-module-bitbucket@0.2.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-bitbucket-cloud-common@0.2.15-next.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.1.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-bitbucket-cloud-common@0.2.15-next.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-events-node@0.2.17-next.1 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.1.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## @backstage/plugin-catalog-backend-module-gcp@0.1.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## @backstage/plugin-catalog-backend-module-gerrit@0.1.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## @backstage/plugin-catalog-backend-module-github@0.4.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.15.1-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-events-node@0.2.17-next.1 + +## @backstage/plugin-catalog-backend-module-github-org@0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-backend-module-github@0.4.6-next.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## @backstage/plugin-catalog-backend-module-gitlab@0.3.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## @backstage/plugin-catalog-backend-module-incremental-ingestion@0.4.12-next.1 + +### Patch Changes + +- 43b2eb8f70: Ensure that cursors always come back as JSON on sqlite too +- Updated dependencies + - @backstage/plugin-catalog-backend@1.15.1-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-events-node@0.2.17-next.1 + - @backstage/plugin-permission-common@0.7.10 + +## @backstage/plugin-catalog-backend-module-ldap@0.5.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## @backstage/plugin-catalog-backend-module-msgraph@0.5.15-next.1 + +### Patch Changes + +- 99fb54183b: Updated dependency `@azure/identity` to `^4.0.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## @backstage/plugin-catalog-backend-module-openapi@0.1.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.15.1-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## @backstage/plugin-catalog-backend-module-puppetdb@0.1.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-scaffolder-common@1.4.3 + +## @backstage/plugin-catalog-backend-module-unprocessed@0.3.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## @backstage/plugin-catalog-graph@0.3.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-import@0.10.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/core-compat-api@0.0.1-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.18 + +## @backstage/plugin-catalog-node@1.5.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + +## @backstage/plugin-catalog-react@1.9.2-next.1 + +### Patch Changes + +- 53600976bb: Ensure that passed-in icons are taken advantage of in the presentation API + +- 08d9e67199: Add default icon for kind resource. + +- a5a04739e1: Internal refactor of alpha exports due to a change in how extension factories are defined. + +- e223f2264d: Breaking alpha-API change to entity visibility filter functions to accept a bare entity as their first argument, instead of an object with an entity property. + + Functions that accept such filters now also support the string expression form of filters. + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-common@0.7.10 + +## @backstage/plugin-catalog-unprocessed-entities@0.1.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-cicd-statistics@0.1.30-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-cicd-statistics-module-gitlab@0.1.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-cicd-statistics@0.1.30-next.1 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-circleci@0.3.28-next.1 + +### Patch Changes + +- 375b6f7d68: CircelCI plugin moved permanently +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-cloudbuild@0.3.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-code-climate@0.1.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-code-coverage@0.2.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-code-coverage-backend@0.2.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## @backstage/plugin-codescene@0.1.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-config-schema@0.1.48-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-cost-insights@0.12.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-cost-insights-common@0.1.2 + +## @backstage/plugin-devtools@0.1.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.6 + +## @backstage/plugin-devtools-backend@0.2.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.5.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-devtools-common@0.1.6 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + +## @backstage/plugin-dynatrace@8.0.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-entity-feedback@0.2.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## @backstage/plugin-entity-feedback-backend@0.2.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## @backstage/plugin-entity-validation@0.1.13-next.1 + +### Patch Changes + +- a518c5a25b: Updated dependency `@react-hookz/web` to `^23.0.0`. +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-catalog-common@1.0.18 + +## @backstage/plugin-events-backend@0.2.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.1 + +## @backstage/plugin-events-backend-module-aws-sqs@0.2.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.1 + +## @backstage/plugin-events-backend-module-azure@0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-events-node@0.2.17-next.1 + +## @backstage/plugin-events-backend-module-bitbucket-cloud@0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-events-node@0.2.17-next.1 + +## @backstage/plugin-events-backend-module-gerrit@0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-events-node@0.2.17-next.1 + +## @backstage/plugin-events-backend-module-github@0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.1 + +## @backstage/plugin-events-backend-module-gitlab@0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.1 + +## @backstage/plugin-events-backend-test-utils@0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.2.17-next.1 + +## @backstage/plugin-events-node@0.2.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + +## @backstage/plugin-explore@0.4.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-search-react@1.7.4-next.1 + - @backstage/plugin-explore-react@0.0.34-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-explore-backend@0.0.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-backend-module-explore@0.1.12-next.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-explore-react@0.0.34-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-explore-common@0.0.2 + +## @backstage/plugin-firehydrant@0.2.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-fossa@0.2.60-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-gcalendar@0.3.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-gcp-projects@0.3.44-next.1 + +### Patch Changes + +- a518c5a25b: Updated dependency `@react-hookz/web` to `^23.0.0`. +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-git-release-manager@0.3.40-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-github-actions@0.6.9-next.1 + +### Patch Changes + +- 08d7e4676a: Github Workflow Runs UI is modified to show in optional Card view instead of table, with branch selection option +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-github-deployments@0.1.59-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-github-issues@0.2.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-github-pull-requests-board@0.1.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-gitops-profiles@0.3.43-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-gocd@0.1.34-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-graphiql@0.3.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/core-compat-api@0.0.1-next.1 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-graphql-voyager@0.1.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-home-react@0.1.6-next.1 + +### Patch Changes + +- 2b725913c1: Updated dependency `@rjsf/utils` to `5.14.3`. + Updated dependency `@rjsf/core` to `5.14.3`. + Updated dependency `@rjsf/material-ui` to `5.14.3`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.3`. +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @backstage/plugin-ilert@0.2.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-jenkins@0.9.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-jenkins-common@0.1.21 + +## @backstage/plugin-jenkins-backend@0.3.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-jenkins-common@0.1.21 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + +## @backstage/plugin-kafka@0.3.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-kafka-backend@0.3.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-kubernetes@0.11.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + - @backstage/plugin-kubernetes-react@0.1.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-kubernetes-backend@0.14.0-next.1 + +### Patch Changes + +- ae94d3ce6f: Updated dependency `@aws-crypto/sha256-js` to `^5.0.0`. +- 99fb54183b: Updated dependency `@azure/identity` to `^4.0.0`. +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-kubernetes-node@0.1.2-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + +## @backstage/plugin-kubernetes-cluster@0.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + - @backstage/plugin-kubernetes-react@0.1.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-kubernetes-common@0.7.2-next.1 + +### Patch Changes + +- 5d796829bb: Remove unused dependency +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.10 + +## @backstage/plugin-kubernetes-node@0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-kubernetes-react@0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-lighthouse@0.4.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-lighthouse-common@0.1.4 + +## @backstage/plugin-lighthouse-backend@0.3.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-lighthouse-common@0.1.4 + +## @backstage/plugin-linguist@0.1.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-linguist-common@0.1.2 + +## @backstage/plugin-linguist-backend@0.5.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-linguist-common@0.1.2 + +## @backstage/plugin-microsoft-calendar@0.1.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-newrelic@0.3.43-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-newrelic-dashboard@0.3.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-nomad@0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-nomad-backend@0.1.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-octopus-deploy@0.2.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-opencost@0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-org@0.6.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-org-react@0.1.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-periskop@0.1.26-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-periskop-backend@0.2.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + +## @backstage/plugin-permission-backend@0.5.31-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + +## @backstage/plugin-permission-backend-module-allow-all-policy@0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + +## @backstage/plugin-permission-node@0.7.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-permission-common@0.7.10 + +## @backstage/plugin-permission-react@0.4.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-permission-common@0.7.10 + +## @backstage/plugin-playlist@0.2.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-search-react@1.7.4-next.1 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-playlist-common@0.1.12 + +## @backstage/plugin-playlist-backend@0.3.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + - @backstage/plugin-playlist-common@0.1.12 + +## @backstage/plugin-proxy-backend@0.4.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + +## @backstage/plugin-puppetdb@0.1.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-rollbar@0.4.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-rollbar-backend@0.1.53-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/config@1.1.1 + +## @backstage/plugin-scaffolder@1.16.2-next.1 + +### Patch Changes + +- 2b725913c1: Updated dependency `@rjsf/utils` to `5.14.3`. + Updated dependency `@rjsf/core` to `5.14.3`. + Updated dependency `@rjsf/material-ui` to `5.14.3`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.3`. +- a518c5a25b: Updated dependency `@react-hookz/web` to `^23.0.0`. +- b5fa6918dc: Fixing `headerOptions` not being passed through the `TemplatePage` component +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/plugin-scaffolder-react@1.6.2-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-scaffolder-common@1.4.3 + +## @backstage/plugin-scaffolder-backend@1.19.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.15.1-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.5-next.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + - @backstage/plugin-scaffolder-common@1.4.3 + - @backstage/plugin-scaffolder-node@0.2.9-next.1 + +## @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.9-next.1 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.2.32-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.9-next.1 + +## @backstage/plugin-scaffolder-backend-module-gitlab@0.2.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-scaffolder-node@0.2.9-next.1 + +## @backstage/plugin-scaffolder-backend-module-rails@0.4.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.9-next.1 + +## @backstage/plugin-scaffolder-backend-module-sentry@0.1.16-next.1 + +### Patch Changes + +- 7f8a801e6d: Added examples for `sentry:project:create` scaffolder action and unit tests. +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-scaffolder-node@0.2.9-next.1 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.2.29-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.9-next.1 + +## @backstage/plugin-scaffolder-node@0.2.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-common@1.4.3 + +## @backstage/plugin-scaffolder-react@1.6.2-next.1 + +### Patch Changes + +- fa66d1b5b3: Fixed bug in `ReviewState` where `enum` value was displayed in step review instead of the corresponding label when using `enumNames` +- 2aee53bbeb: Add horizontal slider if stepper overflows +- 2b725913c1: Updated dependency `@rjsf/utils` to `5.14.3`. + Updated dependency `@rjsf/core` to `5.14.3`. + Updated dependency `@rjsf/material-ui` to `5.14.3`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.3`. +- a518c5a25b: Updated dependency `@react-hookz/web` to `^23.0.0`. +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-scaffolder-common@1.4.3 + +## @backstage/plugin-search@1.4.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-search-react@1.7.4-next.1 + - @backstage/core-compat-api@0.0.1-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend@1.4.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-openapi-utils@0.1.1-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + - @backstage/plugin-search-backend-node@1.2.12-next.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-module-catalog@0.1.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-search-backend-node@1.2.12-next.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-module-elasticsearch@1.3.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/integration-aws-node@0.1.8 + - @backstage/plugin-search-backend-node@1.2.12-next.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-module-explore@0.1.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-backend-node@1.2.12-next.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-module-pg@0.5.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-search-backend-node@1.2.12-next.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-module-stack-overflow-collator@0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-search-backend-node@1.2.12-next.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-module-techdocs@0.1.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/plugin-techdocs-node@1.11.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-search-backend-node@1.2.12-next.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-node@1.2.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-react@1.7.4-next.1 + +### Patch Changes + +- a5a04739e1: Internal refactor of alpha exports due to a change in how extension factories are defined. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-sentry@0.5.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-shortcuts@0.3.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-sonarqube@0.7.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-sonarqube-react@0.1.11-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-sonarqube-backend@0.2.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-sonarqube-react@0.1.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-splunk-on-call@0.4.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-stack-overflow@0.1.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-search-react@1.7.4-next.1 + - @backstage/plugin-home-react@0.1.6-next.1 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-stack-overflow-backend@0.2.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-search-backend-module-stack-overflow-collator@0.1.1-next.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-stackstorm@0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-tech-insights@0.3.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-insights-backend@0.5.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + - @backstage/plugin-tech-insights-node@0.4.14-next.1 + +## @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.40-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-tech-insights-common@0.2.12 + - @backstage/plugin-tech-insights-node@0.4.14-next.1 + +## @backstage/plugin-tech-insights-node@0.4.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-radar@0.6.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/core-compat-api@0.0.1-next.1 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-techdocs@1.9.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-search-react@1.7.4-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/core-compat-api@0.0.1-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-techdocs-react@1.1.14-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.25-next.2 + +### Patch Changes + +- 5d796829bb: Remove unnecessary catalog dependency +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-catalog@1.16.0-next.2 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/test-utils@1.4.6-next.1 + - @backstage/plugin-search-react@1.7.4-next.1 + - @backstage/plugin-techdocs@1.9.2-next.2 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-techdocs-react@1.1.14-next.1 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-techdocs-backend@1.9.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/plugin-techdocs-node@1.11.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-search-backend-module-techdocs@0.1.12-next.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-techdocs-module-addons-contrib@1.1.3-next.1 + +### Patch Changes + +- a518c5a25b: Updated dependency `@react-hookz/web` to `^23.0.0`. +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-techdocs-react@1.1.14-next.1 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-techdocs-node@1.11.0-next.1 + +### Patch Changes + +- 99fb54183b: Updated dependency `@azure/identity` to `^4.0.0`. +- 2666675457: Updated dependency `@google-cloud/storage` to `^7.0.0`. +- 4f773c15f6: Bumped the default TechDocs docker image version to the latest which was released several month ago +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-techdocs-react@1.1.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/plugin-todo@0.2.32-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-todo-backend@0.3.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-openapi-utils@0.1.1-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## @backstage/plugin-user-settings@0.7.14-next.2 + +### Patch Changes + +- fb8f3bdbc2: Updated alpha translation message keys to use nested format and camel case. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-compat-api@0.0.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-user-settings-backend@0.2.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## @backstage/plugin-vault@0.1.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## @backstage/plugin-vault-backend@0.4.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-vault-node@0.1.1-next.1 + +## @backstage/plugin-vault-node@0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + +## @backstage/plugin-xcmetrics@0.2.46-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## example-app@0.2.90-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-app-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/cli@0.25.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-catalog@1.16.0-next.2 + - @backstage/plugin-scaffolder-react@1.6.2-next.1 + - @backstage/plugin-home@0.6.0-next.1 + - @backstage/plugin-github-actions@0.6.9-next.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/plugin-search-react@1.7.4-next.1 + - @backstage/plugin-azure-devops@0.3.10-next.1 + - @backstage/plugin-scaffolder@1.16.2-next.1 + - @backstage/plugin-api-docs@0.10.2-next.2 + - @backstage/plugin-gcp-projects@0.3.44-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.3-next.1 + - @backstage/plugin-user-settings@0.7.14-next.2 + - @backstage/plugin-adr@0.6.11-next.1 + - @backstage/plugin-pagerduty@0.7.0-next.1 + - @backstage/plugin-catalog-import@0.10.4-next.2 + - @backstage/plugin-explore@0.4.14-next.1 + - @backstage/plugin-graphiql@0.3.1-next.2 + - @backstage/plugin-search@1.4.4-next.2 + - @backstage/plugin-stack-overflow@0.1.23-next.1 + - @backstage/plugin-tech-radar@0.6.11-next.2 + - @backstage/plugin-techdocs@1.9.2-next.2 + - @backstage/app-defaults@1.4.6-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-airbrake@0.3.28-next.1 + - @backstage/plugin-apache-airflow@0.2.18-next.1 + - @backstage/plugin-azure-sites@0.1.17-next.1 + - @backstage/plugin-badges@0.2.52-next.1 + - @backstage/plugin-catalog-graph@0.3.2-next.1 + - @backstage/plugin-catalog-unprocessed-entities@0.1.6-next.1 + - @backstage/plugin-cloudbuild@0.3.28-next.1 + - @backstage/plugin-code-coverage@0.2.21-next.1 + - @backstage/plugin-cost-insights@0.12.17-next.1 + - @backstage/plugin-devtools@0.1.7-next.1 + - @backstage/plugin-dynatrace@8.0.2-next.1 + - @backstage/plugin-entity-feedback@0.2.11-next.1 + - @backstage/plugin-gcalendar@0.3.21-next.1 + - @backstage/plugin-gocd@0.1.34-next.1 + - @backstage/plugin-jenkins@0.9.3-next.1 + - @backstage/plugin-kafka@0.3.28-next.1 + - @backstage/plugin-kubernetes@0.11.3-next.1 + - @backstage/plugin-kubernetes-cluster@0.0.4-next.1 + - @backstage/plugin-lighthouse@0.4.13-next.1 + - @backstage/plugin-linguist@0.1.13-next.1 + - @backstage/plugin-microsoft-calendar@0.1.10-next.1 + - @backstage/plugin-newrelic@0.3.43-next.1 + - @backstage/plugin-newrelic-dashboard@0.3.3-next.1 + - @backstage/plugin-nomad@0.1.9-next.1 + - @backstage/plugin-octopus-deploy@0.2.10-next.1 + - @backstage/plugin-org@0.6.18-next.1 + - @backstage/plugin-playlist@0.2.2-next.1 + - @backstage/plugin-puppetdb@0.1.11-next.1 + - @backstage/plugin-rollbar@0.4.28-next.1 + - @backstage/plugin-sentry@0.5.13-next.1 + - @backstage/plugin-shortcuts@0.3.17-next.1 + - @backstage/plugin-stackstorm@0.1.9-next.1 + - @backstage/plugin-tech-insights@0.3.20-next.1 + - @backstage/plugin-techdocs-react@1.1.14-next.1 + - @backstage/plugin-todo@0.2.32-next.1 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.8 + +## example-app-next@0.0.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/frontend-app-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/cli@0.25.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-catalog@1.16.0-next.2 + - @backstage/plugin-scaffolder-react@1.6.2-next.1 + - @backstage/plugin-home@0.6.0-next.1 + - @backstage/plugin-github-actions@0.6.9-next.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/plugin-search-react@1.7.4-next.1 + - @backstage/plugin-azure-devops@0.3.10-next.1 + - @backstage/plugin-scaffolder@1.16.2-next.1 + - @backstage/plugin-api-docs@0.10.2-next.2 + - @backstage/plugin-gcp-projects@0.3.44-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.3-next.1 + - @backstage/plugin-user-settings@0.7.14-next.2 + - @backstage/plugin-adr@0.6.11-next.1 + - @backstage/plugin-pagerduty@0.7.0-next.1 + - app-next-example-plugin@0.0.4-next.1 + - @backstage/core-compat-api@0.0.1-next.1 + - @backstage/plugin-catalog-import@0.10.4-next.2 + - @backstage/plugin-explore@0.4.14-next.1 + - @backstage/plugin-graphiql@0.3.1-next.2 + - @backstage/plugin-search@1.4.4-next.2 + - @backstage/plugin-tech-radar@0.6.11-next.2 + - @backstage/plugin-techdocs@1.9.2-next.2 + - @backstage/app-defaults@1.4.6-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-airbrake@0.3.28-next.1 + - @backstage/plugin-apache-airflow@0.2.18-next.1 + - @backstage/plugin-azure-sites@0.1.17-next.1 + - @backstage/plugin-badges@0.2.52-next.1 + - @backstage/plugin-catalog-graph@0.3.2-next.1 + - @backstage/plugin-catalog-unprocessed-entities@0.1.6-next.1 + - @backstage/plugin-cloudbuild@0.3.28-next.1 + - @backstage/plugin-code-coverage@0.2.21-next.1 + - @backstage/plugin-cost-insights@0.12.17-next.1 + - @backstage/plugin-devtools@0.1.7-next.1 + - @backstage/plugin-dynatrace@8.0.2-next.1 + - @backstage/plugin-entity-feedback@0.2.11-next.1 + - @backstage/plugin-gcalendar@0.3.21-next.1 + - @backstage/plugin-gocd@0.1.34-next.1 + - @backstage/plugin-jenkins@0.9.3-next.1 + - @backstage/plugin-kafka@0.3.28-next.1 + - @backstage/plugin-kubernetes@0.11.3-next.1 + - @backstage/plugin-lighthouse@0.4.13-next.1 + - @backstage/plugin-linguist@0.1.13-next.1 + - @backstage/plugin-microsoft-calendar@0.1.10-next.1 + - @backstage/plugin-newrelic@0.3.43-next.1 + - @backstage/plugin-newrelic-dashboard@0.3.3-next.1 + - @backstage/plugin-octopus-deploy@0.2.10-next.1 + - @backstage/plugin-org@0.6.18-next.1 + - @backstage/plugin-playlist@0.2.2-next.1 + - @backstage/plugin-puppetdb@0.1.11-next.1 + - @backstage/plugin-rollbar@0.4.28-next.1 + - @backstage/plugin-sentry@0.5.13-next.1 + - @backstage/plugin-shortcuts@0.3.17-next.1 + - @backstage/plugin-stackstorm@0.1.9-next.1 + - @backstage/plugin-tech-insights@0.3.20-next.1 + - @backstage/plugin-techdocs-react@1.1.14-next.1 + - @backstage/plugin-todo@0.2.32-next.1 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.8 + +## app-next-example-plugin@0.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + +## example-backend@0.2.90-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.20.1-next.1 + - @backstage/plugin-catalog-backend@1.15.1-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/plugin-azure-devops-backend@0.5.0-next.1 + - @backstage/plugin-kubernetes-backend@0.14.0-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/plugin-azure-sites-backend@0.1.18-next.1 + - @backstage/backend-common@0.20.0-next.1 + - example-app@0.2.90-next.2 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-adr-backend@0.4.5-next.1 + - @backstage/plugin-app-backend@0.3.56-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-badges-backend@0.3.5-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.5-next.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.5-next.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-code-coverage-backend@0.2.22-next.1 + - @backstage/plugin-devtools-backend@0.2.5-next.1 + - @backstage/plugin-entity-feedback-backend@0.2.5-next.1 + - @backstage/plugin-events-backend@0.2.17-next.1 + - @backstage/plugin-events-node@0.2.17-next.1 + - @backstage/plugin-explore-backend@0.0.18-next.1 + - @backstage/plugin-jenkins-backend@0.3.2-next.1 + - @backstage/plugin-kafka-backend@0.3.6-next.1 + - @backstage/plugin-lighthouse-backend@0.3.5-next.1 + - @backstage/plugin-linguist-backend@0.5.5-next.1 + - @backstage/plugin-nomad-backend@0.1.10-next.1 + - @backstage/plugin-permission-backend@0.5.31-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + - @backstage/plugin-playlist-backend@0.3.12-next.1 + - @backstage/plugin-proxy-backend@0.4.6-next.1 + - @backstage/plugin-rollbar-backend@0.1.53-next.1 + - @backstage/plugin-scaffolder-backend@1.19.2-next.1 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.9-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.25-next.1 + - @backstage/plugin-search-backend@1.4.8-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.12-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.11-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.12-next.1 + - @backstage/plugin-search-backend-module-pg@0.5.17-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.12-next.1 + - @backstage/plugin-search-backend-node@1.2.12-next.1 + - @backstage/plugin-search-common@1.2.8 + - @backstage/plugin-tech-insights-backend@0.5.22-next.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.40-next.1 + - @backstage/plugin-tech-insights-node@0.4.14-next.1 + - @backstage/plugin-techdocs-backend@1.9.1-next.1 + - @backstage/plugin-todo-backend@0.3.6-next.1 + +## example-backend-next@0.0.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.1-next.1 + - @backstage/plugin-catalog-backend@1.15.1-next.1 + - @backstage/plugin-azure-devops-backend@0.5.0-next.1 + - @backstage/plugin-kubernetes-backend@0.14.0-next.1 + - @backstage/backend-defaults@0.2.8-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/plugin-adr-backend@0.4.5-next.1 + - @backstage/plugin-app-backend@0.3.56-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-badges-backend@0.3.5-next.1 + - @backstage/plugin-catalog-backend-module-openapi@0.1.25-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.5-next.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.5-next.1 + - @backstage/plugin-devtools-backend@0.2.5-next.1 + - @backstage/plugin-entity-feedback-backend@0.2.5-next.1 + - @backstage/plugin-jenkins-backend@0.3.2-next.1 + - @backstage/plugin-lighthouse-backend@0.3.5-next.1 + - @backstage/plugin-linguist-backend@0.5.5-next.1 + - @backstage/plugin-nomad-backend@0.1.10-next.1 + - @backstage/plugin-permission-backend@0.5.31-next.1 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.5-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + - @backstage/plugin-playlist-backend@0.3.12-next.1 + - @backstage/plugin-proxy-backend@0.4.6-next.1 + - @backstage/plugin-scaffolder-backend@1.19.2-next.1 + - @backstage/plugin-search-backend@1.4.8-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.12-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.12-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.12-next.1 + - @backstage/plugin-search-backend-node@1.2.12-next.1 + - @backstage/plugin-sonarqube-backend@0.2.10-next.1 + - @backstage/plugin-techdocs-backend@1.9.1-next.1 + - @backstage/plugin-todo-backend@0.3.6-next.1 + +## @backstage/backend-plugin-manager@0.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.15.1-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-events-backend@0.2.17-next.1 + - @backstage/plugin-events-node@0.2.17-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + - @backstage/plugin-scaffolder-node@0.2.9-next.1 + - @backstage/plugin-search-backend-node@1.2.12-next.1 + - @backstage/plugin-search-common@1.2.8 + +## e2e-test@0.2.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.8-next.2 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + +## techdocs-cli-embedded-app@0.2.89-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/cli@0.25.0-next.1 + - @backstage/plugin-catalog@1.16.0-next.2 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/test-utils@1.4.6-next.1 + - @backstage/plugin-techdocs@1.9.2-next.2 + - @backstage/app-defaults@1.4.6-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-techdocs-react@1.1.14-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + +## @internal/plugin-todo-list@1.0.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.0 + +## @internal/plugin-todo-list-backend@1.0.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.1 diff --git a/docs/releases/v1.21.0-next.3-changelog.md b/docs/releases/v1.21.0-next.3-changelog.md new file mode 100644 index 0000000000..a45c6d6df0 --- /dev/null +++ b/docs/releases/v1.21.0-next.3-changelog.md @@ -0,0 +1,3025 @@ +# Release v1.21.0-next.3 + +## @backstage/config-loader@1.6.0-next.0 + +### Minor Changes + +- 24f5a85: Add "path" to `TransformFunc` context + +### Patch Changes + +- Updated dependencies + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/core-compat-api@0.1.0-next.2 + +### Minor Changes + +- cf5cc4c: Discover plugins and routes recursively beneath the root routes in `collectLecacyRoutes` + +### Patch Changes + +- 8226442: Added `compatWrapper`, which can be used to wrap any React element to provide bi-directional interoperability between the `@backstage/core-*-api` and `@backstage/frontend-*-api` APIs. +- 8f5d6c1: Updates to match the new extension input wrapping. +- b7adf24: Delete alpha DI compatibility helper for components, migrating components should be simple without a helper. +- 046e443: Updates for compatibility with the new extension IDs. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.2 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/frontend-app-api@0.4.0-next.2 + +### Minor Changes + +- ea06590: The app no longer provides the `AppContext` from `@backstage/core-plugin-api`. Components that require this context to be available should use the `compatWrapper` helper from `@backstage/core-compat-api`. + +### Patch Changes + +- aeb8008: Add support for translation extensions. +- b7adf24: Use the new plugin type for error boundary components. +- 8f5d6c1: Updates to match the new extension input wrapping. +- cb4197a: Forward ` node`` instead of `extensionId\` to resolved extension inputs. +- 8837a96: Updates to match the introduction of `ExtensionDefinition` and new extension ID naming patterns. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.2 + - @backstage/theme@0.5.0-next.1 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/frontend-plugin-api@0.4.0-next.2 + +### Minor Changes + +- 8f5d6c1: Extension inputs are now wrapped into an additional object when passed to the extension factory, with the previous values being available at the `output` property. The `ExtensionInputValues` type has also been replaced by `ResolvedExtensionInputs`. +- 8837a96: **BREAKING**: This version changes how extensions are created and how their IDs are determined. The `createExtension` function now accepts `kind`, `namespace` and `name` instead of `id`. All of the new options are optional, and are used to construct the final extension ID. By convention extension creators should set the `kind` to match their own name, for example `createNavItemExtension` sets the kind `nav-item`. + + The `createExtension` function as well as all extension creators now also return an `ExtensionDefinition` rather than an `Extension`, which in turn needs to be passed to `createPlugin` or `createExtensionOverrides` to be used. + +### Patch Changes + +- b7adf24: Update alpha component ref type to be more specific than any, delete boot page component and use new plugin type for error boundary component extensions. +- 73246ec: Added translation APIs as well as `createTranslationExtension`. +- cb4197a: Forward ` node`` instead of `extensionId\` to resolved extension inputs. +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/plugin-catalog-backend@1.16.0-next.2 + +### Minor Changes + +- 7804597: Permission rules can now be added for the Catalog plugin through the `CatalogPermissionExtensionPoint` interface. + +### Patch Changes + +- 50ee804: Wrap single `pipelineLoop` of TaskPipeline in a span for better traces +- a168507: Deprecated `EntitiesSearchFilter` and `EntityFilter`, which can now be imported from `@backstage/plugin-catalog-node` instead +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.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-search-backend-module-catalog@0.1.12-next.2 + - @backstage/backend-openapi-utils@0.1.1-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/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-events-node@0.2.17-next.2 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.2 + +## @backstage/plugin-catalog-node@1.6.0-next.2 + +### Minor Changes + +- a168507: Added `EntitiesSearchFilter` and `EntityFilter` from `@backstage/plugin-catalog-backend`, for reuse +- 7804597: Permission rules can now be added for the Catalog plugin through the `CatalogPermissionExtensionPoint` interface. + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.2 + +## @backstage/plugin-kubernetes-react@0.2.0-next.2 + +### Minor Changes + +- 899d71a: Change `formatClusterLink` to be an API and make it async for further customization possibilities. + + **BREAKING** + If you have a custom k8s page and used `formatClusterLink` directly, you need to migrate to new `kubernetesClusterLinkFormatterApiRef` + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + +## @backstage/plugin-lighthouse-backend@0.4.0-next.2 + +### Minor Changes + +- 7f0dbfd: Fixed crashes faced with custom schedule configuration. The configuration schema has been update to leverage the TaskScheduleDefinition interface. It is highly recommended to move the `lighthouse.shedule` and `lighthouse.timeout` respectively to `lighthouse.schedule.frequency` and `lighthouse.schedule.timeout`. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/backend-common@0.20.0-next.2 + - @backstage/catalog-client@1.5.0-next.1 + - @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/types@1.1.1 + - @backstage/plugin-lighthouse-common@0.1.4 + +## @backstage/app-defaults@1.4.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-permission-react@0.4.18-next.1 + +## @backstage/backend-app-api@0.5.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.6.0-next.0 + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/backend-tasks@0.5.13-next.2 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-node@0.7.19-next.2 + +## @backstage/backend-common@0.20.0-next.2 + +### Patch Changes + +- bc67498: Updated dependency `archiver` to `^6.0.0`. + Updated dependency `@types/archiver` to `^6.0.0`. +- Updated dependencies + - @backstage/config-loader@1.6.0-next.0 + - @backstage/backend-app-api@0.5.9-next.2 + - @backstage/backend-dev-utils@0.1.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + +## @backstage/backend-defaults@0.2.8-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/backend-app-api@0.5.9-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + +## @backstage/backend-openapi-utils@0.1.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/backend-plugin-api@0.6.8-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-tasks@0.5.13-next.2 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.10 + +## @backstage/backend-tasks@0.5.13-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/backend-test-utils@0.2.9-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-app-api@0.5.9-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/catalog-client@1.5.0-next.1 + +### Patch Changes + +- 82fa88b: Fixes a bug where some query parameters were double URL encoded. +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/cli@0.25.0-next.2 + +### Patch Changes + +- 32018ff: Enable the `tsx` loader to work on Node 18.19 and up +- a3edc18: Updated dependency `vite-plugin-node-polyfills` to `^0.17.0`. +- 627554e: Updated dependency `@rollup/plugin-node-resolve` to `^15.0.0`. +- c07cee5: Updated dependency `@rollup/plugin-json` to `^6.0.0`. +- 2565cc8: Updated dependency `@rollup/plugin-commonjs` to `^25.0.0`. +- Updated dependencies + - @backstage/config-loader@1.6.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/eslint-plugin@0.1.4-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/release-manifests@0.0.11 + - @backstage/types@1.1.1 + +## @backstage/core-components@0.13.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/version-bridge@1.0.7 + +## @backstage/create-app@0.5.8-next.3 + +### Patch Changes + +- a96c2d4: Include the `` for group entities by default +- Updated dependencies + - @backstage/cli-common@0.1.13 + +## @backstage/dev-utils@1.0.25-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/app-defaults@1.4.6-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/integration-react@1.1.22-next.1 + +## @backstage/frontend-test-utils@0.1.0-next.2 + +### Patch Changes + +- 818eea4: Updates for compatibility with the new extension IDs. +- b9aa6e4: Migrate `renderInTestApp` to `@backstage/frontend-test-utils` for testing individual React components in an app. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.2 + - @backstage/frontend-app-api@0.4.0-next.2 + - @backstage/test-utils@1.4.6-next.2 + - @backstage/types@1.1.1 + +## @backstage/repo-tools@0.5.0-next.1 + +### Patch Changes + +- f909e9d: Includes templates in @backstage/repo-tools package and use them in the CLI + +- da3c4db: Updates the `schema openapi generate-client` command to export all generated types from the generated directory. + +- 7959f23: The `api-reports` command now checks for api report files that no longer apply. + If it finds such files, it's treated basically the same as report errors do, and + the check fails. + + For example, if you had an `api-report-alpha.md` but then removed the alpha + export, the reports generator would now report that this file needs to be + deleted. + +- f49e237: Fixed a bug where `schema openapi init` created an invalid test command. + +- f91be2c: Updated dependency `@stoplight/types` to `^14.0.0`. + +- 45bfb20: Execute `openapi-generator-cli` from `@backstage/repo-tools` directory to force it to use our openapitools.json config file. + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/errors@1.2.3 + +## @techdocs/cli@1.8.0-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/plugin-techdocs-node@1.11.0-next.2 + +## @backstage/test-utils@1.4.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-react@0.4.18-next.1 + +## @backstage/theme@0.5.0-next.1 + +### Patch Changes + +- cd0dd4c: Align Material UI v5 `Paper` component background color in dark mode to v4. + +## @backstage/plugin-adr@0.6.11-next.2 + +### Patch Changes + +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.2 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/plugin-search-react@1.7.4-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-adr-common@0.2.18-next.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-adr-backend@0.4.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/plugin-adr-common@0.2.18-next.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-airbrake@0.3.28-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/dev-utils@1.0.25-next.2 + - @backstage/test-utils@1.4.6-next.2 + +## @backstage/plugin-airbrake-backend@0.3.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/config@1.1.1 + +## @backstage/plugin-allure@0.1.44-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @backstage/plugin-analytics-module-ga@0.1.36-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/config@1.1.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @backstage/plugin-analytics-module-ga4@0.1.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/config@1.1.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @backstage/plugin-analytics-module-newrelic-browser@0.0.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @backstage/plugin-apache-airflow@0.2.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @backstage/plugin-api-docs@0.10.2-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog@1.16.0-next.3 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @backstage/plugin-apollo-explorer@0.1.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @backstage/plugin-app-backend@0.3.56-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.6.0-next.0 + - @backstage/backend-common@0.20.0-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.8-next.2 + +## @backstage/plugin-app-node@0.1.8-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.2 + +## @backstage/plugin-auth-backend@0.20.1-next.2 + +### Patch Changes + +- 783797a: fix static token issuer not being able to initialize +- a62764b: Updated dependency `passport` to `^0.7.0`. +- Updated dependencies + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.0-next.1 + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.1.0-next.2 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.5-next.2 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.1.5-next.2 + - @backstage/plugin-auth-backend-module-okta-provider@0.0.1-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.2-next.2 + - @backstage/plugin-auth-backend-module-google-provider@0.1.5-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-backend-module-github-provider@0.1.5-next.2 + +## @backstage/plugin-auth-backend-module-atlassian-provider@0.1.0-next.2 + +### Patch Changes + +- a62764b: Updated dependency `passport` to `^0.7.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + +## @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.2-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-auth-backend-module-github-provider@0.1.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + +## @backstage/plugin-auth-backend-module-gitlab-provider@0.1.5-next.2 + +### Patch Changes + +- a62764b: Updated dependency `passport` to `^0.7.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + +## @backstage/plugin-auth-backend-module-google-provider@0.1.5-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + +## @backstage/plugin-auth-backend-module-microsoft-provider@0.1.3-next.2 + +### Patch Changes + +- a62764b: Updated dependency `passport` to `^0.7.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + +## @backstage/plugin-auth-backend-module-oauth2-provider@0.1.5-next.2 + +### Patch Changes + +- a62764b: Updated dependency `passport` to `^0.7.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + +## @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.0-next.1 + +### Patch Changes + +- a6be465: Exported the provider as default so it gets discovered when using `featureDiscoveryServiceFactory()` +- 510dab4: Change provider id from `oauth2ProxyProvider` to `oauth2Proxy` +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/errors@1.2.3 + +## @backstage/plugin-auth-backend-module-okta-provider@0.0.1-next.2 + +### Patch Changes + +- a62764b: Updated dependency `passport` to `^0.7.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + +## @backstage/plugin-auth-backend-module-pinniped-provider@0.1.2-next.2 + +### Patch Changes + +- a62764b: Updated dependency `passport` to `^0.7.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/config@1.1.1 + +## @backstage/plugin-auth-backend-module-vmware-cloud-provider@0.1.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-auth-node@0.4.2-next.2 + +### Patch Changes + +- a62764b: Updated dependency `passport` to `^0.7.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-azure-devops@0.3.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-azure-devops-common@0.3.2-next.0 + +## @backstage/plugin-azure-devops-backend@0.5.0-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/backend-common@0.20.0-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/plugin-azure-devops-common@0.3.2-next.0 + - @backstage/plugin-catalog-common@1.0.18 + +## @backstage/plugin-azure-sites@0.1.17-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-azure-sites-common@0.1.1 + +## @backstage/plugin-azure-sites-backend@0.1.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/config@1.1.1 + - @backstage/plugin-azure-sites-common@0.1.1 + +## @backstage/plugin-badges@0.2.52-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-badges-backend@0.3.5-next.2 + +### Patch Changes + +- Updated dependencies + - @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/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-bazaar@0.2.20-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-bazaar-backend@0.3.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-bitrise@0.1.55-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @backstage/plugin-catalog@1.16.0-next.3 + +### Patch Changes + +- a1227cc: Wrap `/alpha` export extension elements in backwards compatibility wrapper. +- 8f5d6c1: Updates to the `/alpha` exports to match the extension input wrapping change. +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.2 + - @backstage/theme@0.5.0-next.1 + - @backstage/core-compat-api@0.1.0-next.2 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/plugin-search-react@1.7.4-next.2 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-scaffolder-common@1.4.3 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-catalog-backend-module-aws@0.3.2-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/backend-common@0.20.0-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/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + +## @backstage/plugin-catalog-backend-module-azure@0.1.27-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/backend-common@0.20.0-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/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + +## @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/backend-common@0.20.0-next.2 + - @backstage/backend-openapi-utils@0.1.1-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/errors@1.2.3 + +## @backstage/plugin-catalog-backend-module-bitbucket@0.2.23-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/backend-common@0.20.0-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-bitbucket-cloud-common@0.2.15-next.1 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.1.23-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/backend-common@0.20.0-next.2 + - @backstage/catalog-client@1.5.0-next.1 + - @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-bitbucket-cloud-common@0.2.15-next.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-events-node@0.2.17-next.2 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.1.21-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/backend-common@0.20.0-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/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + +## @backstage/plugin-catalog-backend-module-gcp@0.1.8-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/backend-common@0.20.0-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/plugin-kubernetes-common@0.7.2-next.1 + +## @backstage/plugin-catalog-backend-module-gerrit@0.1.24-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/backend-common@0.20.0-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/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + +## @backstage/plugin-catalog-backend-module-github@0.4.6-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/plugin-catalog-backend@1.16.0-next.2 + - @backstage/backend-common@0.20.0-next.2 + - @backstage/catalog-client@1.5.0-next.1 + - @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-catalog-common@1.0.18 + - @backstage/plugin-events-node@0.2.17-next.2 + +## @backstage/plugin-catalog-backend-module-github-org@0.1.2-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-catalog-backend-module-github@0.4.6-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/backend-tasks@0.5.13-next.2 + - @backstage/config@1.1.1 + +## @backstage/plugin-catalog-backend-module-gitlab@0.3.5-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/backend-common@0.20.0-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-catalog-backend-module-incremental-ingestion@0.4.12-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/plugin-catalog-backend@1.16.0-next.2 + - @backstage/backend-common@0.20.0-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/errors@1.2.3 + - @backstage/plugin-events-node@0.2.17-next.2 + - @backstage/plugin-permission-common@0.7.10 + +## @backstage/plugin-catalog-backend-module-ldap@0.5.23-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/backend-tasks@0.5.13-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + +## @backstage/plugin-catalog-backend-module-msgraph@0.5.15-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/backend-common@0.20.0-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/plugin-catalog-common@1.0.18 + +## @backstage/plugin-catalog-backend-module-openapi@0.1.25-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/backend-common@0.20.0-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + +## @backstage/plugin-catalog-backend-module-puppetdb@0.1.13-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/backend-common@0.20.0-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/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.5-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/backend-common@0.20.0-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-scaffolder-common@1.4.3 + +## @backstage/plugin-catalog-backend-module-unprocessed@0.3.5-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-catalog-graph@0.3.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-import@0.10.4-next.3 + +### Patch Changes + +- a1227cc: Wrap `/alpha` export extension elements in backwards compatibility wrapper. +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.2 + - @backstage/core-compat-api@0.1.0-next.2 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-catalog-common@1.0.18 + +## @backstage/plugin-catalog-react@1.9.2-next.2 + +### Patch Changes + +- 8f5d6c1: Updates to the `/alpha` exports to match the extension input wrapping change. +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.2 + - @backstage/theme@0.5.0-next.1 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-react@0.4.18-next.1 + +## @backstage/plugin-catalog-unprocessed-entities@0.1.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-cicd-statistics@0.1.30-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @backstage/plugin-cicd-statistics-module-gitlab@0.1.24-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-cicd-statistics@0.1.30-next.2 + +## @backstage/plugin-circleci@0.3.28-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @backstage/plugin-cloudbuild@0.3.28-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @backstage/plugin-code-climate@0.1.28-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @backstage/plugin-code-coverage@0.2.21-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-code-coverage-backend@0.2.22-next.2 + +### Patch Changes + +- Updated dependencies + - @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/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + +## @backstage/plugin-codescene@0.1.20-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/config@1.1.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-config-schema@0.1.48-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/config@1.1.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-cost-insights@0.12.17-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-cost-insights-common@0.1.2 + +## @backstage/plugin-devtools@0.1.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.6 + - @backstage/plugin-permission-react@0.4.18-next.1 + +## @backstage/plugin-devtools-backend@0.2.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.6.0-next.0 + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.6 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.2 + +## @backstage/plugin-dynatrace@8.0.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @backstage/plugin-entity-feedback@0.2.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## @backstage/plugin-entity-feedback-backend@0.2.5-next.2 + +### Patch Changes + +- Updated dependencies + - @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/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## @backstage/plugin-entity-validation@0.1.13-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.18 + +## @backstage/plugin-events-backend@0.2.17-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.2 + +## @backstage/plugin-events-backend-module-aws-sqs@0.2.11-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/backend-tasks@0.5.13-next.2 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.2 + +## @backstage/plugin-events-backend-module-azure@0.1.18-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/plugin-events-node@0.2.17-next.2 + +## @backstage/plugin-events-backend-module-bitbucket-cloud@0.1.18-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/plugin-events-node@0.2.17-next.2 + +## @backstage/plugin-events-backend-module-gerrit@0.1.18-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/plugin-events-node@0.2.17-next.2 + +## @backstage/plugin-events-backend-module-github@0.1.18-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.2 + +## @backstage/plugin-events-backend-module-gitlab@0.1.18-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.2 + +## @backstage/plugin-events-backend-test-utils@0.1.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.2.17-next.2 + +## @backstage/plugin-events-node@0.2.17-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.2 + +## @backstage/plugin-explore@0.4.14-next.2 + +### Patch Changes + +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.2 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/plugin-search-react@1.7.4-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-explore-react@0.0.34-next.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-explore-backend@0.0.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-search-backend-module-explore@0.1.12-next.2 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-firehydrant@0.2.12-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @backstage/plugin-fossa@0.2.60-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-gcalendar@0.3.21-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-gcp-projects@0.3.44-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @backstage/plugin-git-release-manager@0.3.40-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/integration@1.8.0-next.1 + +## @backstage/plugin-github-actions@0.6.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-react@1.1.22-next.1 + +## @backstage/plugin-github-deployments@0.1.59-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-react@1.1.22-next.1 + +## @backstage/plugin-github-issues@0.2.17-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + +## @backstage/plugin-github-pull-requests-board@0.1.22-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/integration@1.8.0-next.1 + +## @backstage/plugin-gitops-profiles@0.3.43-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/config@1.1.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @backstage/plugin-gocd@0.1.34-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-graphiql@0.3.1-next.3 + +### Patch Changes + +- a1227cc: Wrap `/alpha` export extension elements in backwards compatibility wrapper. +- 8f5d6c1: Updates to the `/alpha` exports to match the extension input wrapping change. +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.2 + - @backstage/theme@0.5.0-next.1 + - @backstage/core-compat-api@0.1.0-next.2 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @backstage/plugin-graphql-voyager@0.1.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @backstage/plugin-home@0.6.0-next.2 + +### Patch Changes + +- a1227cc: Wrap `/alpha` export extension elements in backwards compatibility wrapper. +- 8f5d6c1: Updates to the `/alpha` exports to match the extension input wrapping change. +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.2 + - @backstage/theme@0.5.0-next.1 + - @backstage/core-compat-api@0.1.0-next.2 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-home-react@0.1.6-next.2 + +## @backstage/plugin-home-react@0.1.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @backstage/plugin-ilert@0.2.17-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-jenkins@0.9.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-jenkins-common@0.1.21 + +## @backstage/plugin-jenkins-backend@0.3.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.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/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-jenkins-common@0.1.21 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.2 + +## @backstage/plugin-kafka@0.3.28-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @backstage/plugin-kafka-backend@0.3.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-kubernetes@0.11.3-next.2 + +### Patch Changes + +- 899d71a: Change `formatClusterLink` to be an API and make it async for further customization possibilities. + + **BREAKING** + If you have a custom k8s page and used `formatClusterLink` directly, you need to migrate to new `kubernetesClusterLinkFormatterApiRef` + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-kubernetes-react@0.2.0-next.2 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + +## @backstage/plugin-kubernetes-backend@0.14.0-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.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/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + - @backstage/plugin-kubernetes-node@0.1.2-next.2 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.2 + +## @backstage/plugin-kubernetes-cluster@0.0.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-kubernetes-react@0.2.0-next.2 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + +## @backstage/plugin-kubernetes-node@0.1.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + +## @backstage/plugin-lighthouse@0.4.13-next.2 + +### Patch Changes + +- ffbf656: Updated README +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-lighthouse-common@0.1.4 + +## @backstage/plugin-linguist@0.1.13-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-linguist-common@0.1.2 + +## @backstage/plugin-linguist-backend@0.5.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.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/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/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-linguist-common@0.1.2 + +## @backstage/plugin-microsoft-calendar@0.1.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-newrelic@0.3.43-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @backstage/plugin-newrelic-dashboard@0.3.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-nomad@0.1.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @backstage/plugin-nomad-backend@0.1.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-octopus-deploy@0.2.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @backstage/plugin-opencost@0.2.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @backstage/plugin-org@0.6.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @backstage/plugin-org-react@0.1.17-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @backstage/plugin-pagerduty@0.7.0-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-home-react@0.1.6-next.2 + +## @backstage/plugin-periskop@0.1.26-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-periskop-backend@0.2.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/config@1.1.1 + +## @backstage/plugin-permission-backend@0.5.31-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.2 + +## @backstage/plugin-permission-backend-module-allow-all-policy@0.1.5-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.2 + +## @backstage/plugin-permission-node@0.7.19-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-permission-common@0.7.10 + +## @backstage/plugin-playlist@0.2.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/plugin-search-react@1.7.4-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/plugin-playlist-common@0.1.12 + +## @backstage/plugin-playlist-backend@0.3.12-next.2 + +### Patch Changes + +- Updated dependencies + - @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/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.2 + - @backstage/plugin-playlist-common@0.1.12 + +## @backstage/plugin-proxy-backend@0.4.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/config@1.1.1 + +## @backstage/plugin-puppetdb@0.1.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-rollbar@0.4.28-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @backstage/plugin-rollbar-backend@0.1.53-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/config@1.1.1 + +## @backstage/plugin-scaffolder@1.16.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/plugin-scaffolder-react@1.6.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/plugin-scaffolder-common@1.4.3 + +## @backstage/plugin-scaffolder-backend@1.19.2-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/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/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/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.2 + - @backstage/plugin-scaffolder-common@1.4.3 + - @backstage/plugin-scaffolder-node@0.2.9-next.2 + +## @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.9-next.2 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.2.32-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.9-next.2 + +## @backstage/plugin-scaffolder-backend-module-gitlab@0.2.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/plugin-scaffolder-node@0.2.9-next.2 + +## @backstage/plugin-scaffolder-backend-module-rails@0.4.25-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.9-next.2 + +## @backstage/plugin-scaffolder-backend-module-sentry@0.1.16-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-scaffolder-node@0.2.9-next.2 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.2.29-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.9-next.2 + +## @backstage/plugin-scaffolder-node@0.2.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-common@1.4.3 + +## @backstage/plugin-scaffolder-react@1.6.2-next.2 + +### Patch Changes + +- 5bb5240: Fixed issue for showing undefined for hidden form items +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-scaffolder-common@1.4.3 + +## @backstage/plugin-search@1.4.4-next.3 + +### Patch Changes + +- a1227cc: Wrap `/alpha` export extension elements in backwards compatibility wrapper. +- 8f5d6c1: Updates to the `/alpha` exports to match the extension input wrapping change. +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.2 + - @backstage/theme@0.5.0-next.1 + - @backstage/core-compat-api@0.1.0-next.2 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/plugin-search-react@1.7.4-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend@1.4.8-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-openapi-utils@0.1.1-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.2 + - @backstage/plugin-search-backend-node@1.2.12-next.2 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-module-catalog@0.1.12-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/backend-common@0.20.0-next.2 + - @backstage/catalog-client@1.5.0-next.1 + - @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/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-search-backend-node@1.2.12-next.2 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-module-elasticsearch@1.3.11-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/config@1.1.1 + - @backstage/integration-aws-node@0.1.8 + - @backstage/plugin-search-backend-node@1.2.12-next.2 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-module-explore@0.1.12-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/backend-tasks@0.5.13-next.2 + - @backstage/config@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-backend-node@1.2.12-next.2 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-module-pg@0.5.17-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/config@1.1.1 + - @backstage/plugin-search-backend-node@1.2.12-next.2 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-module-stack-overflow-collator@0.1.1-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/backend-tasks@0.5.13-next.2 + - @backstage/config@1.1.1 + - @backstage/plugin-search-backend-node@1.2.12-next.2 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-module-techdocs@0.1.12-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/backend-common@0.20.0-next.2 + - @backstage/catalog-client@1.5.0-next.1 + - @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/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-search-backend-node@1.2.12-next.2 + - @backstage/plugin-search-common@1.2.8 + - @backstage/plugin-techdocs-node@1.11.0-next.2 + +## @backstage/plugin-search-backend-node@1.2.12-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/backend-tasks@0.5.13-next.2 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-react@1.7.4-next.2 + +### Patch Changes + +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.2 + - @backstage/theme@0.5.0-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-sentry@0.5.13-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @backstage/plugin-shortcuts@0.3.17-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/types@1.1.1 + +## @backstage/plugin-sonarqube@0.7.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-sonarqube-react@0.1.11-next.1 + +## @backstage/plugin-sonarqube-backend@0.2.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-splunk-on-call@0.4.17-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @backstage/plugin-stack-overflow@0.1.23-next.2 + +### Patch Changes + +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.2 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-search-react@1.7.4-next.2 + - @backstage/config@1.1.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-home-react@0.1.6-next.2 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-stack-overflow-backend@0.2.12-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-search-backend-module-stack-overflow-collator@0.1.1-next.2 + - @backstage/config@1.1.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-stackstorm@0.1.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-tech-insights@0.3.20-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-insights-backend@0.5.22-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/backend-tasks@0.5.13-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + - @backstage/plugin-tech-insights-node@0.4.14-next.2 + +## @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.40-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-tech-insights-common@0.2.12 + - @backstage/plugin-tech-insights-node@0.4.14-next.2 + +## @backstage/plugin-tech-insights-node@0.4.14-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/backend-tasks@0.5.13-next.2 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-radar@0.6.11-next.3 + +### Patch Changes + +- a1227cc: Wrap `/alpha` export extension elements in backwards compatibility wrapper. +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.2 + - @backstage/theme@0.5.0-next.1 + - @backstage/core-compat-api@0.1.0-next.2 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @backstage/plugin-techdocs@1.9.2-next.3 + +### Patch Changes + +- a1227cc: Wrap `/alpha` export extension elements in backwards compatibility wrapper. +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.2 + - @backstage/theme@0.5.0-next.1 + - @backstage/core-compat-api@0.1.0-next.2 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/plugin-search-react@1.7.4-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-search-common@1.2.8 + - @backstage/plugin-techdocs-react@1.1.14-next.2 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.25-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-techdocs@1.9.2-next.3 + - @backstage/plugin-catalog@1.16.0-next.3 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/plugin-search-react@1.7.4-next.2 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/test-utils@1.4.6-next.2 + - @backstage/plugin-techdocs-react@1.1.14-next.2 + +## @backstage/plugin-techdocs-backend@1.9.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.12-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-search-common@1.2.8 + - @backstage/plugin-techdocs-node@1.11.0-next.2 + +## @backstage/plugin-techdocs-module-addons-contrib@1.1.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-techdocs-react@1.1.14-next.2 + +## @backstage/plugin-techdocs-node@1.11.0-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-aws-node@0.1.8 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-techdocs-react@1.1.14-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/plugin-todo@0.2.32-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-todo-backend@0.3.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/backend-common@0.20.0-next.2 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/backend-openapi-utils@0.1.1-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + +## @backstage/plugin-user-settings@0.7.14-next.3 + +### Patch Changes + +- a1227cc: Wrap `/alpha` export extension elements in backwards compatibility wrapper. +- 8f5d6c1: Updates to the `/alpha` exports to match the extension input wrapping change. +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.2 + - @backstage/theme@0.5.0-next.1 + - @backstage/core-compat-api@0.1.0-next.2 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-user-settings-backend@0.2.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-vault@0.1.23-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-vault-backend@0.4.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/backend-tasks@0.5.13-next.2 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-vault-node@0.1.1-next.2 + +## @backstage/plugin-vault-node@0.1.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.2 + +## @backstage/plugin-xcmetrics@0.2.46-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + +## example-app@0.2.90-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-app-api@0.4.0-next.2 + - @backstage/cli@0.25.0-next.2 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-kubernetes@0.11.3-next.2 + - @backstage/plugin-lighthouse@0.4.13-next.2 + - @backstage/plugin-catalog-import@0.10.4-next.3 + - @backstage/plugin-user-settings@0.7.14-next.3 + - @backstage/plugin-tech-radar@0.6.11-next.3 + - @backstage/plugin-graphiql@0.3.1-next.3 + - @backstage/plugin-techdocs@1.9.2-next.3 + - @backstage/plugin-catalog@1.16.0-next.3 + - @backstage/plugin-search@1.4.4-next.3 + - @backstage/plugin-home@0.6.0-next.2 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/plugin-stack-overflow@0.1.23-next.2 + - @backstage/plugin-search-react@1.7.4-next.2 + - @backstage/plugin-explore@0.4.14-next.2 + - @backstage/plugin-adr@0.6.11-next.2 + - @backstage/plugin-scaffolder-react@1.6.2-next.2 + - @backstage/app-defaults@1.4.6-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-airbrake@0.3.28-next.2 + - @backstage/plugin-apache-airflow@0.2.18-next.2 + - @backstage/plugin-api-docs@0.10.2-next.3 + - @backstage/plugin-azure-devops@0.3.10-next.2 + - @backstage/plugin-azure-sites@0.1.17-next.2 + - @backstage/plugin-badges@0.2.52-next.2 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-graph@0.3.2-next.2 + - @backstage/plugin-catalog-unprocessed-entities@0.1.6-next.2 + - @backstage/plugin-cloudbuild@0.3.28-next.2 + - @backstage/plugin-code-coverage@0.2.21-next.2 + - @backstage/plugin-cost-insights@0.12.17-next.2 + - @backstage/plugin-devtools@0.1.7-next.2 + - @backstage/plugin-dynatrace@8.0.2-next.2 + - @backstage/plugin-entity-feedback@0.2.11-next.2 + - @backstage/plugin-gcalendar@0.3.21-next.2 + - @backstage/plugin-gcp-projects@0.3.44-next.2 + - @backstage/plugin-github-actions@0.6.9-next.2 + - @backstage/plugin-gocd@0.1.34-next.2 + - @backstage/plugin-jenkins@0.9.3-next.2 + - @backstage/plugin-kafka@0.3.28-next.2 + - @backstage/plugin-kubernetes-cluster@0.0.4-next.2 + - @backstage/plugin-linguist@0.1.13-next.2 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-microsoft-calendar@0.1.10-next.2 + - @backstage/plugin-newrelic@0.3.43-next.2 + - @backstage/plugin-newrelic-dashboard@0.3.3-next.2 + - @backstage/plugin-nomad@0.1.9-next.2 + - @backstage/plugin-octopus-deploy@0.2.10-next.2 + - @backstage/plugin-org@0.6.18-next.2 + - @backstage/plugin-pagerduty@0.7.0-next.2 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/plugin-playlist@0.2.2-next.2 + - @backstage/plugin-puppetdb@0.1.11-next.2 + - @backstage/plugin-rollbar@0.4.28-next.2 + - @backstage/plugin-scaffolder@1.16.2-next.2 + - @backstage/plugin-search-common@1.2.8 + - @backstage/plugin-sentry@0.5.13-next.2 + - @backstage/plugin-shortcuts@0.3.17-next.2 + - @backstage/plugin-stackstorm@0.1.9-next.2 + - @backstage/plugin-tech-insights@0.3.20-next.2 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.3-next.2 + - @backstage/plugin-techdocs-react@1.1.14-next.2 + - @backstage/plugin-todo@0.2.32-next.2 + +## example-app-next@0.0.4-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.2 + - @backstage/frontend-app-api@0.4.0-next.2 + - @backstage/cli@0.25.0-next.2 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-kubernetes@0.11.3-next.2 + - @backstage/core-compat-api@0.1.0-next.2 + - @backstage/plugin-lighthouse@0.4.13-next.2 + - @backstage/plugin-catalog-import@0.10.4-next.3 + - @backstage/plugin-user-settings@0.7.14-next.3 + - @backstage/plugin-tech-radar@0.6.11-next.3 + - @backstage/plugin-graphiql@0.3.1-next.3 + - @backstage/plugin-techdocs@1.9.2-next.3 + - @backstage/plugin-catalog@1.16.0-next.3 + - @backstage/plugin-search@1.4.4-next.3 + - @backstage/plugin-home@0.6.0-next.2 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/plugin-search-react@1.7.4-next.2 + - @backstage/plugin-explore@0.4.14-next.2 + - @backstage/plugin-adr@0.6.11-next.2 + - @backstage/plugin-scaffolder-react@1.6.2-next.2 + - app-next-example-plugin@0.0.4-next.2 + - @backstage/app-defaults@1.4.6-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-airbrake@0.3.28-next.2 + - @backstage/plugin-apache-airflow@0.2.18-next.2 + - @backstage/plugin-api-docs@0.10.2-next.3 + - @backstage/plugin-azure-devops@0.3.10-next.2 + - @backstage/plugin-azure-sites@0.1.17-next.2 + - @backstage/plugin-badges@0.2.52-next.2 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-graph@0.3.2-next.2 + - @backstage/plugin-catalog-unprocessed-entities@0.1.6-next.2 + - @backstage/plugin-cloudbuild@0.3.28-next.2 + - @backstage/plugin-code-coverage@0.2.21-next.2 + - @backstage/plugin-cost-insights@0.12.17-next.2 + - @backstage/plugin-devtools@0.1.7-next.2 + - @backstage/plugin-dynatrace@8.0.2-next.2 + - @backstage/plugin-entity-feedback@0.2.11-next.2 + - @backstage/plugin-gcalendar@0.3.21-next.2 + - @backstage/plugin-gcp-projects@0.3.44-next.2 + - @backstage/plugin-github-actions@0.6.9-next.2 + - @backstage/plugin-gocd@0.1.34-next.2 + - @backstage/plugin-jenkins@0.9.3-next.2 + - @backstage/plugin-kafka@0.3.28-next.2 + - @backstage/plugin-linguist@0.1.13-next.2 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-microsoft-calendar@0.1.10-next.2 + - @backstage/plugin-newrelic@0.3.43-next.2 + - @backstage/plugin-newrelic-dashboard@0.3.3-next.2 + - @backstage/plugin-octopus-deploy@0.2.10-next.2 + - @backstage/plugin-org@0.6.18-next.2 + - @backstage/plugin-pagerduty@0.7.0-next.2 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/plugin-playlist@0.2.2-next.2 + - @backstage/plugin-puppetdb@0.1.11-next.2 + - @backstage/plugin-rollbar@0.4.28-next.2 + - @backstage/plugin-scaffolder@1.16.2-next.2 + - @backstage/plugin-search-common@1.2.8 + - @backstage/plugin-sentry@0.5.13-next.2 + - @backstage/plugin-shortcuts@0.3.17-next.2 + - @backstage/plugin-stackstorm@0.1.9-next.2 + - @backstage/plugin-tech-insights@0.3.20-next.2 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.3-next.2 + - @backstage/plugin-techdocs-react@1.1.14-next.2 + - @backstage/plugin-todo@0.2.32-next.2 + +## app-next-example-plugin@0.0.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.2 + - @backstage/core-components@0.13.9-next.2 + +## example-backend@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 + +## example-backend-next@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 + +## @backstage/backend-plugin-manager@0.0.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.16.0-next.2 + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/plugin-events-backend@0.2.17-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/backend-tasks@0.5.13-next.2 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.2 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.2 + - @backstage/plugin-scaffolder-node@0.2.9-next.2 + - @backstage/plugin-search-backend-node@1.2.12-next.2 + - @backstage/plugin-search-common@1.2.8 + +## e2e-test@0.2.10-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.8-next.3 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + +## techdocs-cli-embedded-app@0.2.89-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.25.0-next.2 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-techdocs@1.9.2-next.3 + - @backstage/plugin-catalog@1.16.0-next.3 + - @backstage/app-defaults@1.4.6-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/test-utils@1.4.6-next.2 + - @backstage/plugin-techdocs-react@1.1.14-next.2 + +## @internal/plugin-todo-list@1.0.20-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @internal/plugin-todo-list-backend@1.0.20-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 diff --git a/docs/releases/v1.21.0-next.4-changelog.md b/docs/releases/v1.21.0-next.4-changelog.md new file mode 100644 index 0000000000..d8ac20508c --- /dev/null +++ b/docs/releases/v1.21.0-next.4-changelog.md @@ -0,0 +1,2935 @@ +# Release v1.21.0-next.4 + +## @backstage/plugin-scaffolder-backend-module-azure@0.1.0-next.0 + +### Minor Changes + +- 219d7f0: Create new scaffolder module for external integrations + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.9-next.3 + - @backstage/backend-common@0.20.0-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + +## @backstage/plugin-scaffolder-backend-module-bitbucket@0.1.0-next.0 + +### Minor Changes + +- 219d7f0: Create new scaffolder module for external integrations + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.9-next.3 + - @backstage/backend-common@0.20.0-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + +## @backstage/plugin-scaffolder-backend-module-gerrit@0.1.0-next.0 + +### Minor Changes + +- 219d7f0: Create new scaffolder module for external integrations + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.9-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + +## @backstage/plugin-scaffolder-backend-module-github@0.1.0-next.0 + +### Minor Changes + +- 219d7f0: Create new scaffolder module for external integrations + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.9-next.3 + - @backstage/backend-common@0.20.0-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + +## @backstage/app-defaults@1.4.6-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-permission-react@0.4.18-next.1 + +## @backstage/backend-app-api@0.5.9-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.6.0-next.0 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.3 + - @backstage/plugin-permission-node@0.7.19-next.3 + +## @backstage/backend-common@0.20.0-next.3 + +### Patch Changes + +- d86a007: Fixed the AwsS3UrlReader host regex and host to allow the S3 reading for CN AWS domain +- Updated dependencies + - @backstage/backend-app-api@0.5.9-next.3 + - @backstage/backend-dev-utils@0.1.2 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.6.0-next.0 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + +## @backstage/backend-defaults@0.2.8-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-app-api@0.5.9-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + +## @backstage/backend-openapi-utils@0.1.1-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/backend-plugin-api@0.6.8-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.3 + - @backstage/plugin-permission-common@0.7.10 + +## @backstage/backend-tasks@0.5.13-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/backend-test-utils@0.2.9-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-app-api@0.5.9-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.3 + +## @backstage/cli@0.25.0-next.3 + +### Patch Changes + +- 219d7f0: Updating template generation for scaffolder module +- bd586a5: Updated dependency `bfj` to `^8.0.0`. +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.6.0-next.0 + - @backstage/errors@1.2.3 + - @backstage/eslint-plugin@0.1.4-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/release-manifests@0.0.11 + - @backstage/types@1.1.1 + +## @backstage/core-compat-api@0.1.0-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/frontend-plugin-api@0.4.0-next.3 + - @backstage/version-bridge@1.0.7 + +## @backstage/core-components@0.13.9-next.3 + +### Patch Changes + +- 175d86b: Fixed an issue where the `onChange` prop within `HeaderTabs` was triggering twice upon tab-switching. +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/create-app@0.5.8-next.4 + +### Patch Changes + +- Bumped create-app version. +- Updated dependencies + - @backstage/cli-common@0.1.13 + +## @backstage/dev-utils@1.0.25-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/app-defaults@1.4.6-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/frontend-app-api@0.4.0-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/frontend-plugin-api@0.4.0-next.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/frontend-plugin-api@0.4.0-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/frontend-test-utils@0.1.0-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-app-api@0.4.0-next.3 + - @backstage/frontend-plugin-api@0.4.0-next.3 + - @backstage/test-utils@1.4.6-next.2 + - @backstage/types@1.1.1 + +## @backstage/repo-tools@0.5.0-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/errors@1.2.3 + +## @techdocs/cli@1.8.0-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/plugin-techdocs-node@1.11.0-next.3 + +## @backstage/plugin-adr@0.6.11-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/frontend-plugin-api@0.4.0-next.3 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-adr-common@0.2.18-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + - @backstage/plugin-search-common@1.2.8 + - @backstage/plugin-search-react@1.7.4-next.3 + +## @backstage/plugin-adr-backend@0.4.5-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/plugin-adr-common@0.2.18-next.1 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-airbrake@0.3.28-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/dev-utils@1.0.25-next.3 + - @backstage/test-utils@1.4.6-next.2 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-airbrake-backend@0.3.5-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/config@1.1.1 + +## @backstage/plugin-allure@0.1.44-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-analytics-module-ga@0.1.36-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + +## @backstage/plugin-analytics-module-ga4@0.1.7-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + +## @backstage/plugin-analytics-module-newrelic-browser@0.0.5-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @backstage/plugin-apache-airflow@0.2.18-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @backstage/plugin-api-docs@0.10.2-next.4 + +### Patch Changes + +- 82fb18b: Updated dependency `@asyncapi/react-component` to `1.2.6`. +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog@1.16.0-next.4 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-apollo-explorer@0.1.18-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + +## @backstage/plugin-app-backend@0.3.56-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.6.0-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.8-next.3 + +## @backstage/plugin-app-node@0.1.8-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.3 + +## @backstage/plugin-auth-backend@0.20.1-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.1.0-next.3 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.2-next.3 + - @backstage/plugin-auth-backend-module-github-provider@0.1.5-next.3 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.5-next.3 + - @backstage/plugin-auth-backend-module-google-provider@0.1.5-next.3 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.1.5-next.3 + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.0-next.2 + - @backstage/plugin-auth-backend-module-okta-provider@0.0.1-next.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + - @backstage/plugin-catalog-node@1.6.0-next.3 + +## @backstage/plugin-auth-backend-module-atlassian-provider@0.1.0-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + +## @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.2-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.3 + +## @backstage/plugin-auth-backend-module-github-provider@0.1.5-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + +## @backstage/plugin-auth-backend-module-gitlab-provider@0.1.5-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + +## @backstage/plugin-auth-backend-module-google-provider@0.1.5-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + +## @backstage/plugin-auth-backend-module-microsoft-provider@0.1.3-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + +## @backstage/plugin-auth-backend-module-oauth2-provider@0.1.5-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + +## @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.0-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + +## @backstage/plugin-auth-backend-module-okta-provider@0.0.1-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + +## @backstage/plugin-auth-backend-module-pinniped-provider@0.1.2-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.3 + +## @backstage/plugin-auth-backend-module-vmware-cloud-provider@0.1.0-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + +## @backstage/plugin-auth-node@0.4.2-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-azure-devops@0.3.10-next.3 + +### Patch Changes + +- c70e4f5: Added multi-org support +- 7c9af0b: Added support for annotations that use a subpath for the host. Also validated that the annotations have the correct number of slashes. +- Updated dependencies + - @backstage/plugin-azure-devops-common@0.3.2-next.1 + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-azure-devops-backend@0.5.0-next.3 + +### Patch Changes + +- c70e4f5: Added multi-org support +- 646db72: Updated encoding of Org to use `encodeURIComponent` when building URL used to get credentials from credential provider +- Updated dependencies + - @backstage/plugin-azure-devops-common@0.3.2-next.1 + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.6.0-next.3 + +## @backstage/plugin-azure-devops-common@0.3.2-next.1 + +### Patch Changes + +- c70e4f5: Added multi-org support + +## @backstage/plugin-azure-sites@0.1.17-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-azure-sites-common@0.1.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-azure-sites-backend@0.1.18-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/config@1.1.1 + - @backstage/plugin-azure-sites-common@0.1.1 + +## @backstage/plugin-badges@0.2.52-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-badges-backend@0.3.5-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + +## @backstage/plugin-bazaar@0.2.20-next.4 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-bazaar-backend@0.3.6-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + +## @backstage/plugin-bitrise@0.1.55-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-catalog@1.16.0-next.4 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/core-compat-api@0.1.0-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/frontend-plugin-api@0.4.0-next.3 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-react@1.9.2-next.3 + - @backstage/plugin-scaffolder-common@1.4.3 + - @backstage/plugin-search-common@1.2.8 + - @backstage/plugin-search-react@1.7.4-next.3 + +## @backstage/plugin-catalog-backend@1.16.0-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-openapi-utils@0.1.1-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/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.3 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.6.0-next.3 + - @backstage/plugin-events-node@0.2.17-next.3 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.3 + - @backstage/plugin-search-backend-module-catalog@0.1.12-next.3 + +## @backstage/plugin-catalog-backend-module-aws@0.3.2-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.6.0-next.3 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + +## @backstage/plugin-catalog-backend-module-azure@0.1.27-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.6.0-next.3 + +## @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.1-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-openapi-utils@0.1.1-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-node@1.6.0-next.3 + +## @backstage/plugin-catalog-backend-module-bitbucket@0.2.23-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-bitbucket-cloud-common@0.2.15-next.1 + - @backstage/plugin-catalog-node@1.6.0-next.3 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.1.23-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-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-bitbucket-cloud-common@0.2.15-next.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.6.0-next.3 + - @backstage/plugin-events-node@0.2.17-next.3 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.1.21-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/plugin-catalog-node@1.6.0-next.3 + +## @backstage/plugin-catalog-backend-module-gcp@0.1.8-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-node@1.6.0-next.3 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + +## @backstage/plugin-catalog-backend-module-gerrit@0.1.24-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/plugin-catalog-node@1.6.0-next.3 + +## @backstage/plugin-catalog-backend-module-github@0.4.6-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-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-catalog-backend@1.16.0-next.3 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.6.0-next.3 + - @backstage/plugin-events-node@0.2.17-next.3 + +## @backstage/plugin-catalog-backend-module-github-org@0.1.2-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-backend-module-github@0.4.6-next.3 + - @backstage/plugin-catalog-node@1.6.0-next.3 + +## @backstage/plugin-catalog-backend-module-gitlab@0.3.5-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/plugin-catalog-node@1.6.0-next.3 + +## @backstage/plugin-catalog-backend-module-incremental-ingestion@0.4.12-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-backend@1.16.0-next.3 + - @backstage/plugin-catalog-node@1.6.0-next.3 + - @backstage/plugin-events-node@0.2.17-next.3 + - @backstage/plugin-permission-common@0.7.10 + +## @backstage/plugin-catalog-backend-module-ldap@0.5.23-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.6.0-next.3 + +## @backstage/plugin-catalog-backend-module-msgraph@0.5.15-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.6.0-next.3 + +## @backstage/plugin-catalog-backend-module-openapi@0.1.25-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-backend@1.16.0-next.3 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.6.0-next.3 + +## @backstage/plugin-catalog-backend-module-puppetdb@0.1.13-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-node@1.6.0-next.3 + +## @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.5-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.6.0-next.3 + - @backstage/plugin-scaffolder-common@1.4.3 + +## @backstage/plugin-catalog-backend-module-unprocessed@0.3.5-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + +## @backstage/plugin-catalog-graph@0.3.2-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-catalog-import@0.10.4-next.4 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-compat-api@0.1.0-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/frontend-plugin-api@0.4.0-next.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-catalog-node@1.6.0-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.3 + +## @backstage/plugin-catalog-react@1.9.2-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/frontend-plugin-api@0.4.0-next.3 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-react@0.4.18-next.1 + +## @backstage/plugin-catalog-unprocessed-entities@0.1.6-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + +## @backstage/plugin-cicd-statistics@0.1.30-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-cicd-statistics-module-gitlab@0.1.24-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-cicd-statistics@0.1.30-next.3 + +## @backstage/plugin-circleci@0.3.28-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-cloudbuild@0.3.28-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-code-climate@0.1.28-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-code-coverage@0.2.21-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-code-coverage-backend@0.2.22-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/plugin-auth-node@0.4.2-next.3 + +## @backstage/plugin-codescene@0.1.20-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + +## @backstage/plugin-config-schema@0.1.48-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/types@1.1.1 + +## @backstage/plugin-cost-insights@0.12.17-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + - @backstage/plugin-cost-insights-common@0.1.2 + +## @backstage/plugin-devtools@0.1.7-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.6 + - @backstage/plugin-permission-react@0.4.18-next.1 + +## @backstage/plugin-devtools-backend@0.2.5-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.6.0-next.0 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.3 + - @backstage/plugin-devtools-common@0.1.6 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.3 + +## @backstage/plugin-dynatrace@8.0.2-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-entity-feedback@0.2.11-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## @backstage/plugin-entity-feedback-backend@0.2.5-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.3 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## @backstage/plugin-entity-validation@0.1.13-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-events-backend@0.2.17-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.3 + +## @backstage/plugin-events-backend-module-aws-sqs@0.2.11-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.3 + +## @backstage/plugin-events-backend-module-azure@0.1.18-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/plugin-events-node@0.2.17-next.3 + +## @backstage/plugin-events-backend-module-bitbucket-cloud@0.1.18-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/plugin-events-node@0.2.17-next.3 + +## @backstage/plugin-events-backend-module-gerrit@0.1.18-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/plugin-events-node@0.2.17-next.3 + +## @backstage/plugin-events-backend-module-github@0.1.18-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.3 + +## @backstage/plugin-events-backend-module-gitlab@0.1.18-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.3 + +## @backstage/plugin-events-backend-test-utils@0.1.18-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.2.17-next.3 + +## @backstage/plugin-events-node@0.2.17-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.3 + +## @backstage/plugin-explore@0.4.14-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/frontend-plugin-api@0.4.0-next.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-explore-react@0.0.34-next.1 + - @backstage/plugin-search-common@1.2.8 + - @backstage/plugin-search-react@1.7.4-next.3 + +## @backstage/plugin-explore-backend@0.0.18-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-backend-module-explore@0.1.12-next.3 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-firehydrant@0.2.12-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-fossa@0.2.60-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-gcalendar@0.3.21-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + +## @backstage/plugin-gcp-projects@0.3.44-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + +## @backstage/plugin-git-release-manager@0.3.40-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/theme@0.5.0-next.1 + +## @backstage/plugin-github-actions@0.6.9-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-github-deployments@0.1.59-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-github-issues@0.2.17-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-github-pull-requests-board@0.1.22-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-gitops-profiles@0.3.43-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + +## @backstage/plugin-gocd@0.1.34-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-graphiql@0.3.1-next.4 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/core-compat-api@0.1.0-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/frontend-plugin-api@0.4.0-next.3 + - @backstage/theme@0.5.0-next.1 + +## @backstage/plugin-graphql-voyager@0.1.10-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + +## @backstage/plugin-home@0.6.0-next.3 + +### Patch Changes + +- 2633d64: Change user settings backend plugin id and fix when using user setting backend home page first will cause edit page loop render +- 64301d3: Updated dependency `@rjsf/utils` to `5.15.0`. + Updated dependency `@rjsf/core` to `5.15.0`. + Updated dependency `@rjsf/material-ui` to `5.15.0`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.0`. +- 54cef27: StarredEntities component calls `getEntitiesByRefs` instead of `getEntities` to improve performance since we have the `entityRefs` +- c8908d4: Use new option from RJSF 5.15 +- Updated dependencies + - @backstage/plugin-home-react@0.1.6-next.3 + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-compat-api@0.1.0-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/frontend-plugin-api@0.4.0-next.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-home-react@0.1.6-next.3 + +### Patch Changes + +- 64301d3: Updated dependency `@rjsf/utils` to `5.15.0`. + Updated dependency `@rjsf/core` to `5.15.0`. + Updated dependency `@rjsf/material-ui` to `5.15.0`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.0`. +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + +## @backstage/plugin-ilert@0.2.17-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-jenkins@0.9.3-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + - @backstage/plugin-jenkins-common@0.1.21 + +## @backstage/plugin-jenkins-backend@0.3.2-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + - @backstage/plugin-catalog-node@1.6.0-next.3 + - @backstage/plugin-jenkins-common@0.1.21 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.3 + +## @backstage/plugin-kafka@0.3.28-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-kafka-backend@0.3.6-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-kubernetes@0.11.3-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + - @backstage/plugin-kubernetes-react@0.2.0-next.3 + +## @backstage/plugin-kubernetes-backend@0.14.0-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.3 + - @backstage/plugin-catalog-node@1.6.0-next.3 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + - @backstage/plugin-kubernetes-node@0.1.2-next.3 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.3 + +## @backstage/plugin-kubernetes-cluster@0.0.4-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + - @backstage/plugin-kubernetes-react@0.2.0-next.3 + +## @backstage/plugin-kubernetes-node@0.1.2-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + +## @backstage/plugin-kubernetes-react@0.2.0-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + +## @backstage/plugin-lighthouse@0.4.13-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + - @backstage/plugin-lighthouse-common@0.1.4 + +## @backstage/plugin-lighthouse-backend@0.4.0-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-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/types@1.1.1 + - @backstage/plugin-catalog-node@1.6.0-next.3 + - @backstage/plugin-lighthouse-common@0.1.4 + +## @backstage/plugin-linguist@0.1.13-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + - @backstage/plugin-linguist-common@0.1.2 + +## @backstage/plugin-linguist-backend@0.5.5-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-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/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.3 + - @backstage/plugin-catalog-node@1.6.0-next.3 + - @backstage/plugin-linguist-common@0.1.2 + +## @backstage/plugin-microsoft-calendar@0.1.10-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + +## @backstage/plugin-newrelic@0.3.43-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + +## @backstage/plugin-newrelic-dashboard@0.3.3-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-nomad@0.1.9-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-nomad-backend@0.1.10-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-octopus-deploy@0.2.10-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-opencost@0.2.3-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + +## @backstage/plugin-org@0.6.18-next.3 + +### Patch Changes + +- 59c24b9: Fix issue where members inside of `` would be rendered as squished when the card itself was shrunk down. +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-org-react@0.1.17-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-pagerduty@0.7.0-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-home-react@0.1.6-next.3 + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-periskop@0.1.26-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-periskop-backend@0.2.6-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/config@1.1.1 + +## @backstage/plugin-permission-backend@0.5.31-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.3 + +## @backstage/plugin-permission-backend-module-allow-all-policy@0.1.5-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.3 + +## @backstage/plugin-permission-node@0.7.19-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + - @backstage/plugin-permission-common@0.7.10 + +## @backstage/plugin-playlist@0.2.2-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-react@1.9.2-next.3 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/plugin-playlist-common@0.1.12 + - @backstage/plugin-search-react@1.7.4-next.3 + +## @backstage/plugin-playlist-backend@0.3.12-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.3 + - @backstage/plugin-playlist-common@0.1.12 + +## @backstage/plugin-proxy-backend@0.4.6-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/config@1.1.1 + +## @backstage/plugin-puppetdb@0.1.11-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-rollbar@0.4.28-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-rollbar-backend@0.1.53-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/config@1.1.1 + +## @backstage/plugin-scaffolder@1.16.2-next.3 + +### Patch Changes + +- 64301d3: Updated dependency `@rjsf/utils` to `5.15.0`. + Updated dependency `@rjsf/core` to `5.15.0`. + Updated dependency `@rjsf/material-ui` to `5.15.0`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.0`. +- c8908d4: Use new option from RJSF 5.15 +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.6.2-next.3 + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-react@1.9.2-next.3 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/plugin-scaffolder-common@1.4.3 + +## @backstage/plugin-scaffolder-backend@1.19.2-next.3 + +### Patch Changes + +- 219d7f0: Refactor some methods to `-node` instead and use the new external modules +- Updated dependencies + - @backstage/plugin-scaffolder-backend-module-gitlab@0.2.11-next.3 + - @backstage/plugin-scaffolder-node@0.2.9-next.3 + - @backstage/backend-common@0.20.0-next.3 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.1.0-next.0 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.1.0-next.0 + - @backstage/plugin-scaffolder-backend-module-github@0.1.0-next.0 + - @backstage/plugin-scaffolder-backend-module-azure@0.1.0-next.0 + - @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/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.3 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.5-next.3 + - @backstage/plugin-catalog-node@1.6.0-next.3 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.3 + - @backstage/plugin-scaffolder-common@1.4.3 + +## @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.9-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.9-next.3 + - @backstage/backend-common@0.20.0-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.2.32-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.9-next.3 + - @backstage/backend-common@0.20.0-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-gitlab@0.2.11-next.3 + +### Patch Changes + +- 219d7f0: Extract some more actions to this library +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.9-next.3 + - @backstage/backend-common@0.20.0-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + +## @backstage/plugin-scaffolder-backend-module-rails@0.4.25-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.9-next.3 + - @backstage/backend-common@0.20.0-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-sentry@0.1.16-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.9-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.2.29-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.9-next.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-node@0.2.9-next.3 + +### Patch Changes + +- 219d7f0: Refactor some methods to `-node` instead and use the new external modules +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-common@1.4.3 + +## @backstage/plugin-scaffolder-react@1.6.2-next.3 + +### Patch Changes + +- 64301d3: Updated dependency `@rjsf/utils` to `5.15.0`. + Updated dependency `@rjsf/core` to `5.15.0`. + Updated dependency `@rjsf/material-ui` to `5.15.0`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.0`. +- c8908d4: Use new option from RJSF 5.15 +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-catalog-react@1.9.2-next.3 + - @backstage/plugin-scaffolder-common@1.4.3 + +## @backstage/plugin-search@1.4.4-next.4 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-compat-api@0.1.0-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/frontend-plugin-api@0.4.0-next.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-catalog-react@1.9.2-next.3 + - @backstage/plugin-search-common@1.2.8 + - @backstage/plugin-search-react@1.7.4-next.3 + +## @backstage/plugin-search-backend@1.4.8-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-openapi-utils@0.1.1-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.3 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.3 + - @backstage/plugin-search-backend-node@1.2.12-next.3 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-module-catalog@0.1.12-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-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/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.6.0-next.3 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-search-backend-node@1.2.12-next.3 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-module-elasticsearch@1.3.11-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/config@1.1.1 + - @backstage/integration-aws-node@0.1.8 + - @backstage/plugin-search-backend-node@1.2.12-next.3 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-module-explore@0.1.12-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/config@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-backend-node@1.2.12-next.3 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-module-pg@0.5.17-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/config@1.1.1 + - @backstage/plugin-search-backend-node@1.2.12-next.3 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-module-stack-overflow-collator@0.1.1-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/config@1.1.1 + - @backstage/plugin-search-backend-node@1.2.12-next.3 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-backend-module-techdocs@0.1.12-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-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/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.6.0-next.3 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-search-backend-node@1.2.12-next.3 + - @backstage/plugin-search-common@1.2.8 + - @backstage/plugin-techdocs-node@1.11.0-next.3 + +## @backstage/plugin-search-backend-node@1.2.12-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-search-react@1.7.4-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/frontend-plugin-api@0.4.0-next.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-sentry@0.5.13-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-shortcuts@0.3.17-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/types@1.1.1 + +## @backstage/plugin-sonarqube@0.7.10-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + - @backstage/plugin-sonarqube-react@0.1.11-next.1 + +## @backstage/plugin-sonarqube-backend@0.2.10-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-splunk-on-call@0.4.17-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-stack-overflow@0.1.23-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-home-react@0.1.6-next.3 + - @backstage/core-components@0.13.9-next.3 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/frontend-plugin-api@0.4.0-next.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-search-common@1.2.8 + - @backstage/plugin-search-react@1.7.4-next.3 + +## @backstage/plugin-stack-overflow-backend@0.2.12-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/config@1.1.1 + - @backstage/plugin-search-backend-module-stack-overflow-collator@0.1.1-next.3 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-stackstorm@0.1.9-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + +## @backstage/plugin-tech-insights@0.3.20-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-insights-backend@0.5.22-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-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/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + - @backstage/plugin-tech-insights-node@0.4.14-next.3 + +## @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.40-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-tech-insights-common@0.2.12 + - @backstage/plugin-tech-insights-node@0.4.14-next.3 + +## @backstage/plugin-tech-insights-node@0.4.14-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-radar@0.6.11-next.4 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/core-compat-api@0.1.0-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/frontend-plugin-api@0.4.0-next.3 + - @backstage/theme@0.5.0-next.1 + +## @backstage/plugin-techdocs@1.9.2-next.4 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-compat-api@0.1.0-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/frontend-plugin-api@0.4.0-next.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + - @backstage/plugin-search-common@1.2.8 + - @backstage/plugin-search-react@1.7.4-next.3 + - @backstage/plugin-techdocs-react@1.1.14-next.3 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.25-next.4 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/test-utils@1.4.6-next.2 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog@1.16.0-next.4 + - @backstage/plugin-catalog-react@1.9.2-next.3 + - @backstage/plugin-search-react@1.7.4-next.3 + - @backstage/plugin-techdocs@1.9.2-next.4 + - @backstage/plugin-techdocs-react@1.1.14-next.3 + +## @backstage/plugin-techdocs-backend@1.9.1-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-search-backend-module-techdocs@0.1.12-next.3 + - @backstage/plugin-search-common@1.2.8 + - @backstage/plugin-techdocs-node@1.11.0-next.3 + +## @backstage/plugin-techdocs-module-addons-contrib@1.1.3-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-techdocs-react@1.1.14-next.3 + +## @backstage/plugin-techdocs-node@1.11.0-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-aws-node@0.1.8 + - @backstage/plugin-search-common@1.2.8 + +## @backstage/plugin-techdocs-react@1.1.14-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/plugin-todo@0.2.32-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-todo-backend@0.3.6-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-openapi-utils@0.1.1-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/plugin-catalog-node@1.6.0-next.3 + +## @backstage/plugin-user-settings@0.7.14-next.4 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-compat-api@0.1.0-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/frontend-plugin-api@0.4.0-next.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-user-settings-backend@0.2.7-next.3 + +### Patch Changes + +- 2633d64: Change user settings backend plugin id and fix when using user setting backend home page first will cause edit page loop render +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.3 + +## @backstage/plugin-vault@0.1.23-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## @backstage/plugin-vault-backend@0.4.1-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-vault-node@0.1.1-next.3 + +## @backstage/plugin-vault-node@0.1.1-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.3 + +## @backstage/plugin-xcmetrics@0.2.46-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + +## example-app@0.2.90-next.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-home@0.6.0-next.3 + - @backstage/plugin-org@0.6.18-next.3 + - @backstage/plugin-azure-devops@0.3.10-next.3 + - @backstage/cli@0.25.0-next.3 + - @backstage/plugin-api-docs@0.10.2-next.4 + - @backstage/plugin-scaffolder-react@1.6.2-next.3 + - @backstage/plugin-scaffolder@1.16.2-next.3 + - @backstage/core-components@0.13.9-next.3 + - @backstage/app-defaults@1.4.6-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/frontend-app-api@0.4.0-next.3 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-adr@0.6.11-next.3 + - @backstage/plugin-airbrake@0.3.28-next.3 + - @backstage/plugin-apache-airflow@0.2.18-next.3 + - @backstage/plugin-azure-sites@0.1.17-next.3 + - @backstage/plugin-badges@0.2.52-next.3 + - @backstage/plugin-catalog@1.16.0-next.4 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-graph@0.3.2-next.3 + - @backstage/plugin-catalog-import@0.10.4-next.4 + - @backstage/plugin-catalog-react@1.9.2-next.3 + - @backstage/plugin-catalog-unprocessed-entities@0.1.6-next.3 + - @backstage/plugin-cloudbuild@0.3.28-next.3 + - @backstage/plugin-code-coverage@0.2.21-next.3 + - @backstage/plugin-cost-insights@0.12.17-next.3 + - @backstage/plugin-devtools@0.1.7-next.3 + - @backstage/plugin-dynatrace@8.0.2-next.3 + - @backstage/plugin-entity-feedback@0.2.11-next.3 + - @backstage/plugin-explore@0.4.14-next.3 + - @backstage/plugin-gcalendar@0.3.21-next.3 + - @backstage/plugin-gcp-projects@0.3.44-next.3 + - @backstage/plugin-github-actions@0.6.9-next.3 + - @backstage/plugin-gocd@0.1.34-next.3 + - @backstage/plugin-graphiql@0.3.1-next.4 + - @backstage/plugin-jenkins@0.9.3-next.3 + - @backstage/plugin-kafka@0.3.28-next.3 + - @backstage/plugin-kubernetes@0.11.3-next.3 + - @backstage/plugin-kubernetes-cluster@0.0.4-next.3 + - @backstage/plugin-lighthouse@0.4.13-next.3 + - @backstage/plugin-linguist@0.1.13-next.3 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-microsoft-calendar@0.1.10-next.3 + - @backstage/plugin-newrelic@0.3.43-next.3 + - @backstage/plugin-newrelic-dashboard@0.3.3-next.3 + - @backstage/plugin-nomad@0.1.9-next.3 + - @backstage/plugin-octopus-deploy@0.2.10-next.3 + - @backstage/plugin-pagerduty@0.7.0-next.3 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/plugin-playlist@0.2.2-next.3 + - @backstage/plugin-puppetdb@0.1.11-next.3 + - @backstage/plugin-rollbar@0.4.28-next.3 + - @backstage/plugin-search@1.4.4-next.4 + - @backstage/plugin-search-common@1.2.8 + - @backstage/plugin-search-react@1.7.4-next.3 + - @backstage/plugin-sentry@0.5.13-next.3 + - @backstage/plugin-shortcuts@0.3.17-next.3 + - @backstage/plugin-stack-overflow@0.1.23-next.3 + - @backstage/plugin-stackstorm@0.1.9-next.3 + - @backstage/plugin-tech-insights@0.3.20-next.3 + - @backstage/plugin-tech-radar@0.6.11-next.4 + - @backstage/plugin-techdocs@1.9.2-next.4 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.3-next.3 + - @backstage/plugin-techdocs-react@1.1.14-next.3 + - @backstage/plugin-todo@0.2.32-next.3 + - @backstage/plugin-user-settings@0.7.14-next.4 + +## example-app-next@0.0.4-next.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-home@0.6.0-next.3 + - @backstage/plugin-org@0.6.18-next.3 + - @backstage/plugin-azure-devops@0.3.10-next.3 + - @backstage/cli@0.25.0-next.3 + - @backstage/plugin-api-docs@0.10.2-next.4 + - @backstage/plugin-scaffolder-react@1.6.2-next.3 + - @backstage/plugin-scaffolder@1.16.2-next.3 + - @backstage/core-components@0.13.9-next.3 + - @backstage/app-defaults@1.4.6-next.3 + - app-next-example-plugin@0.0.4-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-compat-api@0.1.0-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/frontend-app-api@0.4.0-next.3 + - @backstage/frontend-plugin-api@0.4.0-next.3 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-adr@0.6.11-next.3 + - @backstage/plugin-airbrake@0.3.28-next.3 + - @backstage/plugin-apache-airflow@0.2.18-next.3 + - @backstage/plugin-azure-sites@0.1.17-next.3 + - @backstage/plugin-badges@0.2.52-next.3 + - @backstage/plugin-catalog@1.16.0-next.4 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-graph@0.3.2-next.3 + - @backstage/plugin-catalog-import@0.10.4-next.4 + - @backstage/plugin-catalog-react@1.9.2-next.3 + - @backstage/plugin-catalog-unprocessed-entities@0.1.6-next.3 + - @backstage/plugin-cloudbuild@0.3.28-next.3 + - @backstage/plugin-code-coverage@0.2.21-next.3 + - @backstage/plugin-cost-insights@0.12.17-next.3 + - @backstage/plugin-devtools@0.1.7-next.3 + - @backstage/plugin-dynatrace@8.0.2-next.3 + - @backstage/plugin-entity-feedback@0.2.11-next.3 + - @backstage/plugin-explore@0.4.14-next.3 + - @backstage/plugin-gcalendar@0.3.21-next.3 + - @backstage/plugin-gcp-projects@0.3.44-next.3 + - @backstage/plugin-github-actions@0.6.9-next.3 + - @backstage/plugin-gocd@0.1.34-next.3 + - @backstage/plugin-graphiql@0.3.1-next.4 + - @backstage/plugin-jenkins@0.9.3-next.3 + - @backstage/plugin-kafka@0.3.28-next.3 + - @backstage/plugin-kubernetes@0.11.3-next.3 + - @backstage/plugin-lighthouse@0.4.13-next.3 + - @backstage/plugin-linguist@0.1.13-next.3 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-microsoft-calendar@0.1.10-next.3 + - @backstage/plugin-newrelic@0.3.43-next.3 + - @backstage/plugin-newrelic-dashboard@0.3.3-next.3 + - @backstage/plugin-octopus-deploy@0.2.10-next.3 + - @backstage/plugin-pagerduty@0.7.0-next.3 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/plugin-playlist@0.2.2-next.3 + - @backstage/plugin-puppetdb@0.1.11-next.3 + - @backstage/plugin-rollbar@0.4.28-next.3 + - @backstage/plugin-search@1.4.4-next.4 + - @backstage/plugin-search-common@1.2.8 + - @backstage/plugin-search-react@1.7.4-next.3 + - @backstage/plugin-sentry@0.5.13-next.3 + - @backstage/plugin-shortcuts@0.3.17-next.3 + - @backstage/plugin-stackstorm@0.1.9-next.3 + - @backstage/plugin-tech-insights@0.3.20-next.3 + - @backstage/plugin-tech-radar@0.6.11-next.4 + - @backstage/plugin-techdocs@1.9.2-next.4 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.3-next.3 + - @backstage/plugin-techdocs-react@1.1.14-next.3 + - @backstage/plugin-todo@0.2.32-next.3 + - @backstage/plugin-user-settings@0.7.14-next.4 + +## app-next-example-plugin@0.0.4-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/frontend-plugin-api@0.4.0-next.3 + +## example-backend@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 + +## example-backend-next@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 + +## @backstage/backend-plugin-manager@0.0.4-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.9-next.3 + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.3 + - @backstage/plugin-catalog-backend@1.16.0-next.3 + - @backstage/plugin-events-backend@0.2.17-next.3 + - @backstage/plugin-events-node@0.2.17-next.3 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.3 + - @backstage/plugin-search-backend-node@1.2.12-next.3 + - @backstage/plugin-search-common@1.2.8 + +## e2e-test@0.2.10-next.4 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.8-next.4 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + +## techdocs-cli-embedded-app@0.2.89-next.4 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.25.0-next.3 + - @backstage/core-components@0.13.9-next.3 + - @backstage/app-defaults@1.4.6-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/test-utils@1.4.6-next.2 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog@1.16.0-next.4 + - @backstage/plugin-techdocs@1.9.2-next.4 + - @backstage/plugin-techdocs-react@1.1.14-next.3 + +## @internal/plugin-todo-list@1.0.20-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + +## @internal/plugin-todo-list-backend@1.0.20-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.3 diff --git a/docs/releases/v1.21.0.md b/docs/releases/v1.21.0.md new file mode 100644 index 0000000000..53e77f0021 --- /dev/null +++ b/docs/releases/v1.21.0.md @@ -0,0 +1,135 @@ +--- +id: v1.21.0 +title: v1.21.0 +description: Backstage Release v1.21.0 +--- + +These are the release notes for the v1.21.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 + +### New Frontend System Alpha + +This release marks the alpha release of the new frontend system, which has been in an experimental state since implementation began in the middle of 2023. This new system brings declarative integration of plugins, which is the ability to integrate new features into a Backstage app without writing any TypeScript code. Through this capability it also paves the way for supporting dynamic plugin installation at runtime. + +The alpha release is a point of increased stability following the earlier experimental phase. There is now a complete system that lets you build out a full application, supported by [documentation](https://backstage.io/docs/frontend-system/). From this point on any breaking changes will also be clearly marked in the changelog. + +There is still a long road ahead to a stable release, and this is not the time to migrate existing applications. There are only a few plugins that support this system so far, and if you want to add to a plugin that you own, please do so under an `/alpha` sub-path export. + +Still, we encourage you to explore this new system to see whether you are confident in this path forward. If you have feedback or want to know more you can reach out in the #declarative-integration channel on Discord, or join an [Adoption SIG](https://github.com/backstage/community/blob/main/sigs/sig-adoption/README.md) meeting where the new system is frequently discussed. You can also check out our [maintainer talk at KubeCon NA 2023](https://youtu.be/ONMBYnhxnNU?t=436), where we talk about this new system and show a couple of demos. + +### React Router Beta deprecation + +This release of Backstage officially deprecates, but does _not_ immediately remove, support for old beta versions of [`react-router` 6](https://reactrouter.com/). Actual support for beta versions will be removed entirely in an upcoming release of Backstage. Please upgrade your own Backstage project as soon as possible to a stable version of `react-router`, by [following this guide](https://backstage.io/docs/tutorials/react-router-stable-migration/). + +### New PostgreSQL versioning policy + +The Backstage project has now settled on [a clearer policy](https://backstage.io/docs/overview/versioning-policy/#postgresql-releases) for what versions of PostgreSQL that it supports. In short, we support the last five [released major versions](https://www.postgresql.org/support/versioning/), and actively test against the first and last of those five, in a rolling window over time. + +As part of this, the `TestDatabases` utility class now supports all of the last major versions of PostgreSQL in addition to the ones it supported before. You can also call `TestDatabases.setDefaults` inside your `setupTests.ts` file to configure the set of engines to test against, instead of enumerating them in every individual test. + +Contributed by [@awanlin](https://github.com/awanlin) in [#21510](https://github.com/backstage/backstage/pull/21510) + +### `UnifiedTheme` Now Supports Overrides + +You can now supply overrides for Backstage components when using `createUnifiedTheme`. We've updated the demo site’s Aperture theme to work with this and you can see the code for that [here](https://github.com/backstage/demo/blob/402cbb358cddacd59b339580bef0a4c5c2c7e013/packages/app/src/theme/aperture.ts#L85). + +If you are switching from the old way of defining a theme to `createUnifiedTheme`, note that it uses the MUI v5 overrides format. The style overrides are now nested in a `styleOverrides` key, and if you want access to the theme you’ll need to use a callback: + +```ts +BackstageHeaderTabs: { + styleOverrides: { + defaultTab: { + textTransform: 'none', + }, + }, +}, +MuiChip: { + styleOverrides: { + root: ({ theme }) => ({ + color: theme.palette.primary.dark, + }), + }, +}, +``` + +### Catalog pagination + +`CatalogIndexPage` now offers an optional pagination feature, designed to accommodate adopters managing extensive catalogs. This new capability allows for better handling of large amounts of data. + +To activate the pagination mode, simply update your `App.tsx` as follows: + +```diff + const routes = ( + + ... +- } /> ++ } /> + ... +``` + +In case you have a custom catalog page and you want to enable pagination, you need to pass the `pagination` prop to `EntityListProvider` instead. For now both column sorting and search filtering are still done locally, meaning they only apply to each individual page. This is something we will improve in the future and we still wanted to make this feature available early as it can greatly improve the performance of the catalog page. + +### Azure DevOps Multi-Org Support + +The Azure DevOps plugin now has multi-org support and there is a new processor to help with adding the needed annotations. Contributed by [@awanlin](https://github.com/awanlin) in [#19622](https://github.com/backstage/backstage/issues/19622) + +### New Authentication providers + +A new Atlassian authentication provider has been added to `@backstage/plugin-auth-backend`. Contributed by [@handsamtw](https://github.com/handsamtw) in [#21007](https://github.com/backstage/backstage/pull/21007) + +A new VMware Cloud authentication provider has been added to `@backstage/plugin-auth-backend`. Contributed by [@luchillo17](https://github.com/luchillo17) in [#21337](https://github.com/backstage/backstage/pull/21337) + +### Kubernetes single cluster selection + +You can now select a `single` kubernetes cluster that the entity is part of from all your defined kubernetes clusters, by providing the `backstage.io/kubernetes-cluster` annotation with the defined cluster name. + +If you do not specify the annotation then by default it fetches all defined kubernetes clusters. + +To apply, update your `catalog-info.yaml`as follows: + +```diff + metadata: + annotations: + 'backstage.io/kubernetes-id': dice-roller + 'backstage.io/kubernetes-namespace': dice-space ++ 'backstage.io/kubernetes-cluster': dice-cluster + 'backstage.io/kubernetes-label-selector': 'app=my-app,component=front-end' +``` + +Contributed by [@deepan10](https://github.com/deepan10) in [#20954](https://github.com/backstage/backstage/pull/20954) + +### BREAKING: Repo tools generated API Reports path changes + +API Reports generated for sub-path exports now place the name as a suffix rather than prefix, for example `api-report-alpha.md` instead of `alpha-api-report.md`. When upgrading to this version you'll need to re-create any such API reports and delete the old ones. + +### PagerDuty plugin changes home 🏡 + +The [PagerDuty](https://www.pagerduty.com/) plugin has been marked as deprecated in favor of [pagerduty/backstage-plugin](https://github.com/pagerduty/backstage-plugin) which is maintained by PagerDuty themselves! We encourage you to [migrate to @pagerduty/backstage-plugin](https://pagerduty.github.io/backstage-plugin-docs/migration/) in order to receive future updates. + +Congrats to the PagerDuty folks for taking ownership of the plugin 👏 + +Contributed by [@t1agob](https://github.com/t1agob) in [#21436](https://github.com/backstage/backstage/pull/21436) + +## 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.21.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.22.0-changelog.md b/docs/releases/v1.22.0-changelog.md new file mode 100644 index 0000000000..399d7e7016 --- /dev/null +++ b/docs/releases/v1.22.0-changelog.md @@ -0,0 +1,3239 @@ +# Release v1.22.0 + +## @backstage/backend-dynamic-feature-service@0.1.0 + +### Minor Changes + +- eb81f42: New `backend-dynamic-feature-service` package, for the discovery of dynamic frontend and backend plugins (and modules) and the loading of the backend ones inside the backend application. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/cli-node@0.2.2 + - @backstage/plugin-events-backend@0.2.18 + - @backstage/backend-plugin-api@0.6.9 + - @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-scaffolder-node@0.2.10 + - @backstage/plugin-search-backend-node@1.2.13 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.18 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/frontend-app-api@0.5.0 + +### Minor Changes + +- d4149bf: **BREAKING**: Renamed the `app/router` extension to `app/root`. +- 074dfe3: Attaching extensions to an input that does not exist is now a warning rather than an error. + +### Patch Changes + +- 7d63b32: Accepts sub route refs on the new `createPlugin` routes map. +- 516fd3e: Updated README to reflect release status +- c97fa1c: Added `elements`, `wrappers`, and `router` inputs to `app/root`, that let you add things to the root of the React tree above the layout. You can use the `createAppRootElementExtension`, `createAppRootWrapperExtension`, and `createRouterExtension` extension creator, respectively, to conveniently create such extensions. These are all optional, and if you do not supply a router a default one will be used (`BrowserRouter` in regular runs, `MemoryRouter` in tests/CI). +- 5fe6600: add oauth dialog and alert display to the root elements +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/frontend-plugin-api@0.5.0 + +### Minor Changes + +- d4149bf: **BREAKING**: Renamed the `app/router` extension to `app/root`. + +### Patch Changes + +- b2d370e: Exposed `createComponentRef`, and ensured that produced refs and feature bits have a `toString` for easier debugging +- 7d63b32: Accepts sub route refs on the new `createPlugin` routes map. +- 516fd3e: Updated README to reflect release status +- 4016f21: Remove some unused dependencies +- c97fa1c: Added `elements`, `wrappers`, and `router` inputs to `app/root`, that let you add things to the root of the React tree above the layout. You can use the `createAppRootElementExtension`, `createAppRootWrapperExtension`, and `createRouterExtension` extension creator, respectively, to conveniently create such extensions. These are all optional, and if you do not supply a router a default one will be used (`BrowserRouter` in regular runs, `MemoryRouter` in tests/CI). +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/plugin-app-visualizer@0.1.0 + +### Minor Changes + +- e57cc9f: Initial release of the app visualizer plugin. + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + +## @backstage/plugin-scaffolder-backend@1.20.0 + +### Minor Changes + +- a694f71: The Scaffolder builtin actions now contains an action for running pipelines from Bitbucket Cloud Rest API +- 7c522c5: Add `gitlab:repo:push` scaffolder action to push files to arbitrary branch without creating a Merge Request + +### Patch Changes + +- e9ab1c4: Fixed an issue where not passing a `value` to any of the action's permission conditions caused an error. +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-backend-module-github@0.1.1 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.2.12 + - @backstage/plugin-scaffolder-common@1.4.5 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.1.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-scaffolder-backend-module-azure@0.1.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.6 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.1.1 + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-user-settings@0.8.0 + +### Minor Changes + +- 56b2fb0: Updated the user settings selector to use a select component that displays native language names instead of language codes if possible. + +### Patch Changes + +- eea0849: add user-settings declarative integration core nav item +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-compat-api@0.1.1 + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/core-app-api@1.11.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + +## @backstage/app-defaults@1.4.7 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/core-app-api@1.11.3 + - @backstage/theme@0.5.0 + +## @backstage/backend-app-api@0.5.10 + +### Patch Changes + +- 516fd3e: Updated README to reflect release status +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/config-loader@1.6.1 + - @backstage/cli-node@0.2.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/backend-common@0.20.1 + +### Patch Changes + +- 3b24eae: Adding support for removing file from git index + +- 454d17c: Do not call fetch directly but rather use `fetchResponse` facility + +- b6b15b2: Use sha256 instead of md5 for hash key calculation in caches + + This can have a side effect of invalidating caches (when cache key was >250 characters) + This improves compliance with FIPS nodejs + +- Updated dependencies + - @backstage/config-loader@1.6.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-dev-utils@0.1.3 + - @backstage/backend-app-api@0.5.10 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + +## @backstage/backend-defaults@0.2.9 + +### Patch Changes + +- 516fd3e: Updated README to reflect release status +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-app-api@0.5.10 + +## @backstage/backend-dev-utils@0.1.3 + +### Patch Changes + +- 516fd3e: Updated README to reflect release status + +## @backstage/backend-openapi-utils@0.1.2 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/errors@1.2.3 + +## @backstage/backend-plugin-api@0.6.9 + +### Patch Changes + +- 516fd3e: Updated README to reflect release status +- Updated dependencies + - @backstage/plugin-permission-common@0.7.12 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## @backstage/backend-tasks@0.5.14 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/backend-test-utils@0.2.10 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-app-api@0.5.10 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/catalog-client@1.5.2 + +### Patch Changes + +- 883782e: Fix a bug in `getLocationByRef` that led to invalid backend calls +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/cli@0.25.1 + +### Patch Changes + +- b6b15b2: Use sha256 instead of md5 in build script cache key calculation + + Makes it possible to build on FIPS nodejs. + +- Updated dependencies + - @backstage/config-loader@1.6.1 + - @backstage/cli-node@0.2.2 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/eslint-plugin@0.1.4 + - @backstage/integration@1.8.0 + - @backstage/release-manifests@0.0.11 + - @backstage/types@1.1.1 + +## @backstage/cli-node@0.2.2 + +### Patch Changes + +- 7acbb5a: Removed `mock-fs` dev dependency. +- Updated dependencies + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/config-loader@1.6.1 + +### Patch Changes + +- 7acbb5a: Removed `mock-fs` dev dependency. +- Updated dependencies + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/core-app-api@1.11.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/core-compat-api@0.1.1 + +### Patch Changes + +- 4c1f50c: Make `convertLegacyApp` wrap discovered routes with `compatWrapper`. +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-plugin-api@1.8.2 + - @backstage/core-app-api@1.11.3 + - @backstage/version-bridge@1.0.7 + +## @backstage/core-components@0.13.10 + +### Patch Changes + +- d625f66: Fixed bug in Link where it was possible to select and copy a hidden element into clipboard +- 6878b1d: Removed unnecessary `history` and `immer` dependencies. +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0 + - @backstage/version-bridge@1.0.7 + +## @backstage/core-plugin-api@1.8.2 + +### Patch Changes + +- 6878b1d: Removed unnecessary `i18next` dependency. +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/create-app@0.5.9 + +### Patch Changes + +- c9f71fb: Bumped create-app version. +- ac277f3: Bumped create-app version. +- 7acbb5a: Removed `mock-fs` dev dependency. +- Updated dependencies + - @backstage/cli-common@0.1.13 + +## @backstage/dev-utils@1.0.26 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/app-defaults@1.4.7 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/core-app-api@1.11.3 + - @backstage/theme@0.5.0 + +## @backstage/frontend-test-utils@0.1.1 + +### Patch Changes + +- f7566f9: Updates to reflect the `app/router` extension having been renamed to `app/root`. +- 516fd3e: Updated README to reflect release status +- c97fa1c: Added `elements`, `wrappers`, and `router` inputs to `app/root`, that let you add things to the root of the React tree above the layout. You can use the `createAppRootElementExtension`, `createAppRootWrapperExtension`, and `createRouterExtension` extension creator, respectively, to conveniently create such extensions. These are all optional, and if you do not supply a router a default one will be used (`BrowserRouter` in regular runs, `MemoryRouter` in tests/CI). +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/frontend-app-api@0.5.0 + - @backstage/test-utils@1.4.7 + - @backstage/types@1.1.1 + +## @backstage/integration-react@1.1.23 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + +## @backstage/repo-tools@0.5.2 + +### Patch Changes + +- 883782e: Updated the OpenAPI template to export the `TypedResponse` interface so that client code can leverage it +- 7acbb5a: Removed `mock-fs` dev dependency. +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/cli-node@0.2.2 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + +## @techdocs/cli@1.8.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-techdocs-node@1.11.1 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + +## @backstage/test-utils@1.4.7 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.3 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-adr@0.6.12 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/plugin-search-react@1.7.5 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-adr-common@0.2.19 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-adr-backend@0.4.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/plugin-adr-common@0.2.19 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-adr-common@0.2.19 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/integration@1.8.0 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-airbrake@0.3.29 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/dev-utils@1.0.26 + - @backstage/catalog-model@1.4.3 + - @backstage/test-utils@1.4.7 + +## @backstage/plugin-airbrake-backend@0.3.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + +## @backstage/plugin-allure@0.1.45 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-analytics-module-ga@0.1.37 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/config@1.1.1 + +## @backstage/plugin-analytics-module-ga4@0.1.8 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/config@1.1.1 + +## @backstage/plugin-analytics-module-newrelic-browser@0.0.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/config@1.1.1 + +## @backstage/plugin-apache-airflow@0.2.19 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + +## @backstage/plugin-api-docs@0.10.3 + +### Patch Changes + +- 8a69cc9: Fix custom http resolvers for AsyncAPI widget. +- 062b8f2: Add permission check to Register Existing API button +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/plugin-catalog@1.16.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.20 + +## @backstage/plugin-apollo-explorer@0.1.19 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + +## @backstage/plugin-app-backend@0.3.57 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/config-loader@1.6.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.9 + +## @backstage/plugin-app-node@0.1.9 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + +## @backstage/plugin-auth-backend@0.20.3 + +### Patch Changes + +- 004499c: Fixed an issue where some Okta's resolvers were missing +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.1 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.1.1 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.3 + - @backstage/plugin-auth-backend-module-github-provider@0.1.6 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.6 + - @backstage/plugin-auth-backend-module-google-provider@0.1.6 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.1.6 + - @backstage/plugin-auth-backend-module-okta-provider@0.0.2 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-auth-backend-module-atlassian-provider@0.1.1 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + +## @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.3 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-auth-backend-module-github-provider@0.1.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + +## @backstage/plugin-auth-backend-module-gitlab-provider@0.1.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + +## @backstage/plugin-auth-backend-module-google-provider@0.1.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + +## @backstage/plugin-auth-backend-module-microsoft-provider@0.1.4 + +### Patch Changes + +- 928efbc: Deprecated the `authModuleMicrosoftProvider` export. A default export is now available and should be used like this in your backend: `backend.add(import('@backstage/plugin-auth-backend-module-microsoft-provider'));` +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + +## @backstage/plugin-auth-backend-module-oauth2-provider@0.1.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + +## @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.1 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-auth-backend-module-okta-provider@0.0.2 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + +## @backstage/plugin-auth-backend-module-pinniped-provider@0.1.3 + +### Patch Changes + +- 928efbc: Deprecated the `authModulePinnipedProvider` export. A default export is now available and should be used like this in your backend: `backend.add(import('@backstage/plugin-auth-backend-module-pinniped-provider'));` +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/config@1.1.1 + +## @backstage/plugin-auth-backend-module-vmware-cloud-provider@0.1.1 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-auth-node@0.4.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-azure-devops@0.3.11 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-azure-devops-common@0.3.2 + +## @backstage/plugin-azure-devops-backend@0.5.1 + +### Patch Changes + +- d076ee4: Updated dependency `azure-devops-node-api` to `^12.0.0`. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + - @backstage/plugin-azure-devops-common@0.3.2 + - @backstage/plugin-catalog-common@1.0.20 + +## @backstage/plugin-azure-sites@0.1.18 + +### Patch Changes + +- a31f688: Show Azure site tags in `EntityAzureSitesOverviewWidget`. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-azure-sites-common@0.1.1 + +## @backstage/plugin-azure-sites-backend@0.1.19 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/config@1.1.1 + - @backstage/plugin-azure-sites-common@0.1.1 + +## @backstage/plugin-badges@0.2.53 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-badges-backend@0.3.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-bazaar@0.2.21 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-bazaar-backend@0.3.7 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/config@1.1.1 + +## @backstage/plugin-bitrise@0.1.56 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-catalog@1.16.1 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-compat-api@0.1.1 + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/plugin-scaffolder-common@1.4.5 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/plugin-search-react@1.7.5 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.20 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-catalog-backend@1.16.1 + +### Patch Changes + +- c3249d6: Parse the URL using a different method rather than `git-url-parse` to support wildcards for URLs which are not VCS providers +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-search-backend-module-catalog@0.1.13 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-openapi-utils@0.1.2 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.20 + - @backstage/plugin-events-node@0.2.18 + +## @backstage/plugin-catalog-backend-module-aws@0.3.3 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- 22e88d0: Added status and e-mail as labels to the AWS Account Resource +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-kubernetes-common@0.7.3 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/integration-aws-node@0.1.8 + - @backstage/plugin-catalog-common@1.0.20 + +## @backstage/plugin-catalog-backend-module-azure@0.1.28 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + - @backstage/plugin-catalog-common@1.0.20 + +## @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.2 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-openapi-utils@0.1.2 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-catalog-backend-module-bitbucket@0.2.24 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.15 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.1.24 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.15 + - @backstage/plugin-catalog-common@1.0.20 + - @backstage/plugin-events-node@0.2.18 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.1.22 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## @backstage/plugin-catalog-backend-module-gcp@0.1.9 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-kubernetes-common@0.7.3 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + +## @backstage/plugin-catalog-backend-module-gerrit@0.1.25 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## @backstage/plugin-catalog-backend-module-github@0.4.7 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-catalog-backend@1.16.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + - @backstage/plugin-catalog-common@1.0.20 + - @backstage/plugin-events-node@0.2.18 + +## @backstage/plugin-catalog-backend-module-github-org@0.1.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-catalog-backend-module-github@0.4.7 + - @backstage/config@1.1.1 + +## @backstage/plugin-catalog-backend-module-gitlab@0.3.6 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + +## @backstage/plugin-catalog-backend-module-incremental-ingestion@0.4.13 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-catalog-backend@1.16.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-events-node@0.2.18 + +## @backstage/plugin-catalog-backend-module-ldap@0.5.24 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.20 + +## @backstage/plugin-catalog-backend-module-msgraph@0.5.16 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.20 + +## @backstage/plugin-catalog-backend-module-openapi@0.1.26 + +### Patch Changes + +- 4ebf99b: Add support for the new backend system. + + A new backend module for the catalog backend + was added and exported as `default`. + + You can use it with the new backend system like + + ```ts title="packages/backend/src/index.ts" + backend.add(import('@backstage/plugin-catalog-backend-module-openapi')); + ``` + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-catalog-backend@1.16.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.20 + +## @backstage/plugin-catalog-backend-module-puppetdb@0.1.14 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.4.5 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.20 + +## @backstage/plugin-catalog-backend-module-unprocessed@0.3.6 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-catalog-common@1.0.20 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.12 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-catalog-graph@0.3.3 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-import@0.10.5 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.1.1 + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/plugin-catalog-common@1.0.20 + +## @backstage/plugin-catalog-node@1.6.1 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.20 + +## @backstage/plugin-catalog-react@1.9.3 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-catalog-common@1.0.20 + +## @backstage/plugin-catalog-unprocessed-entities@0.1.7 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-cicd-statistics@0.1.31 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-cicd-statistics-module-gitlab@0.1.25 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-cicd-statistics@0.1.31 + +## @backstage/plugin-circleci@0.3.29 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-cloudbuild@0.3.29 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-code-climate@0.1.29 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-code-coverage@0.2.22 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-code-coverage-backend@0.2.23 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## @backstage/plugin-codescene@0.1.21 + +### Patch Changes + +- d5eda61: Updated Readme document in codescene plugin +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-config-schema@0.1.49 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-cost-insights@0.12.18 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0 + - @backstage/plugin-cost-insights-common@0.1.2 + +## @backstage/plugin-devtools@0.1.8 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/errors@1.2.3 + - @backstage/plugin-devtools-common@0.1.8 + +## @backstage/plugin-devtools-backend@0.2.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/config-loader@1.6.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.8 + +## @backstage/plugin-devtools-common@0.1.8 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.12 + - @backstage/types@1.1.1 + +## @backstage/plugin-dynatrace@8.0.3 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-entity-feedback@0.2.12 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## @backstage/plugin-entity-feedback-backend@0.2.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## @backstage/plugin-entity-validation@0.1.14 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.20 + +## @backstage/plugin-events-backend@0.2.18 + +### Patch Changes + +- 92ea615: Update `README.md` +- d5ddc4e: Add documentation on how to install the plugins with the new backend system. +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.18 + +## @backstage/plugin-events-backend-module-aws-sqs@0.2.12 + +### Patch Changes + +- 7b8e551: Fix errors when deleting SQS messages: + + - If zero messages were received, skip deletion to avoid `EmptyBatchRequest` error from the SQS client. + - If zero failures were returned from the SQS client during deletion, skip error logging. + +- d5ddc4e: Add documentation on how to install the plugins with the new backend system. + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-tasks@0.5.14 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.18 + +## @backstage/plugin-events-backend-module-azure@0.1.19 + +### Patch Changes + +- af76a95: Add default exports for the new backend system and documentation. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-events-node@0.2.18 + +## @backstage/plugin-events-backend-module-bitbucket-cloud@0.1.19 + +### Patch Changes + +- af76a95: Add default exports for the new backend system and documentation. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-events-node@0.2.18 + +## @backstage/plugin-events-backend-module-gerrit@0.1.19 + +### Patch Changes + +- af76a95: Add default exports for the new backend system and documentation. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-events-node@0.2.18 + +## @backstage/plugin-events-backend-module-github@0.1.19 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.18 + +## @backstage/plugin-events-backend-module-gitlab@0.1.19 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.18 + +## @backstage/plugin-events-backend-test-utils@0.1.19 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.2.18 + +## @backstage/plugin-events-node@0.2.18 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + +## @backstage/plugin-explore@0.4.15 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/plugin-explore-react@0.0.35 + - @backstage/plugin-search-react@1.7.5 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-explore-backend@0.0.19 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-search-backend-module-explore@0.1.13 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + +## @backstage/plugin-explore-react@0.0.35 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-explore-common@0.0.2 + +## @backstage/plugin-firehydrant@0.2.13 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-fossa@0.2.61 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-gcalendar@0.3.22 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/errors@1.2.3 + +## @backstage/plugin-gcp-projects@0.3.45 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + +## @backstage/plugin-git-release-manager@0.3.41 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/integration@1.8.0 + +## @backstage/plugin-github-actions@0.6.10 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/integration@1.8.0 + +## @backstage/plugin-github-deployments@0.1.60 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## @backstage/plugin-github-issues@0.2.18 + +### Patch Changes + +- bf92ae3: Updated dependency `octokit` to `^3.0.0`. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## @backstage/plugin-github-pull-requests-board@0.1.23 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/integration@1.8.0 + +## @backstage/plugin-gitops-profiles@0.3.44 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + +## @backstage/plugin-gocd@0.1.35 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-graphiql@0.3.2 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-compat-api@0.1.1 + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + +## @backstage/plugin-graphql-voyager@0.1.11 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + +## @backstage/plugin-home@0.6.1 + +### Patch Changes + +- 98ac5ab: Updated dependency `@rjsf/utils` to `5.15.1`. + Updated dependency `@rjsf/core` to `5.15.1`. + Updated dependency `@rjsf/material-ui` to `5.15.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.1`. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-compat-api@0.1.1 + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-home-react@0.1.7 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-app-api@1.11.3 + - @backstage/theme@0.5.0 + +## @backstage/plugin-home-react@0.1.7 + +### Patch Changes + +- 98ac5ab: Updated dependency `@rjsf/utils` to `5.15.1`. + Updated dependency `@rjsf/core` to `5.15.1`. + Updated dependency `@rjsf/material-ui` to `5.15.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.1`. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + +## @backstage/plugin-ilert@0.2.18 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-jenkins@0.9.4 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-jenkins-common@0.1.23 + +## @backstage/plugin-jenkins-backend@0.3.3 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-jenkins-common@0.1.23 + +## @backstage/plugin-jenkins-common@0.1.23 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-catalog-common@1.0.20 + +## @backstage/plugin-kafka@0.3.29 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-kafka-backend@0.3.7 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-kubernetes@0.11.4 + +### Patch Changes + +- d5d2c67: Add `authuser` search parameter to GKE cluster link formatter in k8s plugin + + Thanks to this, people with multiple simultaneously logged-in accounts in their GCP console will automatically view objects with the same email as the one signed in to the Google auth provider in Backstage. + +- 4016f21: Remove some unused dependencies + +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-kubernetes-react@0.2.1 + - @backstage/plugin-kubernetes-common@0.7.3 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-kubernetes-backend@0.14.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-kubernetes-common@0.7.3 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + - @backstage/plugin-kubernetes-node@0.1.3 + +## @backstage/plugin-kubernetes-cluster@0.0.5 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-kubernetes-react@0.2.1 + - @backstage/plugin-kubernetes-common@0.7.3 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-kubernetes-common@0.7.3 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/plugin-permission-common@0.7.12 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-kubernetes-node@0.1.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-kubernetes-common@0.7.3 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-kubernetes-react@0.2.1 + +### Patch Changes + +- d5d2c67: Add `authuser` search parameter to GKE cluster link formatter in k8s plugin + + Thanks to this, people with multiple simultaneously logged-in accounts in their GCP console will automatically view objects with the same email as the one signed in to the Google auth provider in Backstage. + +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-kubernetes-common@0.7.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-lighthouse@0.4.14 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-lighthouse-common@0.1.4 + +## @backstage/plugin-lighthouse-backend@0.4.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-lighthouse-common@0.1.4 + +## @backstage/plugin-linguist@0.1.14 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- 4f42918: Added alpha support for the New Frontend System (Declarative Integration) +- Updated dependencies + - @backstage/core-compat-api@0.1.1 + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-linguist-common@0.1.2 + +## @backstage/plugin-linguist-backend@0.5.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-linguist-common@0.1.2 + +## @backstage/plugin-microsoft-calendar@0.1.11 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/errors@1.2.3 + +## @backstage/plugin-newrelic@0.3.44 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + +## @backstage/plugin-newrelic-dashboard@0.3.4 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-nomad@0.1.10 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-nomad-backend@0.1.11 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-octopus-deploy@0.2.11 + +### Patch Changes + +- 7d96ba8: added install path and fixed import on plugin-octopus-deploy +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-opencost@0.2.4 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + +## @backstage/plugin-org@0.6.19 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.20 + +## @backstage/plugin-org-react@0.1.18 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-pagerduty@0.7.1 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-home-react@0.1.7 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-periskop@0.1.27 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-periskop-backend@0.2.7 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + +## @backstage/plugin-permission-backend@0.5.32 + +### Patch Changes + +- b1acd9b: Updated README +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-permission-backend-module-allow-all-policy@0.1.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/plugin-auth-node@0.4.3 + +## @backstage/plugin-permission-common@0.7.12 + +### Patch Changes + +- b1acd9b: Updated README +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-permission-node@0.7.20 + +### Patch Changes + +- b1acd9b: Updated README +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-permission-react@0.4.19 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- b1acd9b: Updated README +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/config@1.1.1 + +## @backstage/plugin-playlist@0.2.3 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-search-react@1.7.5 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.20 + - @backstage/plugin-playlist-common@0.1.14 + +## @backstage/plugin-playlist-backend@0.3.13 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-playlist-common@0.1.14 + +## @backstage/plugin-playlist-common@0.1.14 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.12 + +## @backstage/plugin-proxy-backend@0.4.7 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + +## @backstage/plugin-puppetdb@0.1.12 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-rollbar@0.4.29 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-rollbar-backend@0.1.54 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/config@1.1.1 + +## @backstage/plugin-scaffolder@1.17.1 + +### Patch Changes + +- 98ac5ab: Updated dependency `@rjsf/utils` to `5.15.1`. + Updated dependency `@rjsf/core` to `5.15.1`. + Updated dependency `@rjsf/material-ui` to `5.15.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.1`. +- 4016f21: Remove some unused dependencies +- df4bc9d: Minor internal refactor +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.7.1 + - @backstage/core-components@0.13.10 + - @backstage/plugin-scaffolder-common@1.4.5 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.20 + +## @backstage/plugin-scaffolder-backend-module-azure@0.1.1 + +### Patch Changes + +- d076ee4: Updated dependency `azure-devops-node-api` to `^12.0.0`. +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## @backstage/plugin-scaffolder-backend-module-bitbucket@0.1.1 + +### Patch Changes + +- a694f71: The Scaffolder builtin actions now contains an action for running pipelines from Bitbucket Cloud Rest API +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.10 + +### Patch Changes + +- 7acbb5a: Removed `mock-fs` dev dependency. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.2.33 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-gerrit@0.1.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## @backstage/plugin-scaffolder-backend-module-github@0.1.1 + +### Patch Changes + +- 5470300: Ensure `teamReviewers` list is unique before calling API +- bf92ae3: Updated dependency `octokit` to `^3.0.0`. +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## @backstage/plugin-scaffolder-backend-module-gitlab@0.2.12 + +### Patch Changes + +- 604c9dd: Add Scaffolder custom action that creates GitLab issues called `gitlab:issues:create` +- 7c522c5: Add `gitlab:repo:push` scaffolder action to push files to arbitrary branch without creating a Merge Request +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## @backstage/plugin-scaffolder-backend-module-rails@0.4.26 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-sentry@0.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.2.30 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-common@1.4.5 + +### Patch Changes + +- 178b8d8: Updated Template.v1beta3.schema.json, added a missing "presentation" field +- Updated dependencies + - @backstage/plugin-permission-common@0.7.12 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-node@0.2.10 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-common@1.4.5 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-react@1.7.1 + +### Patch Changes + +- c28f281: Scaffolder form now shows a list of errors at the top of the form. +- 0b9ce2b: Fix for a step with no properties +- 98ac5ab: Updated dependency `@rjsf/utils` to `5.15.1`. + Updated dependency `@rjsf/core` to `5.15.1`. + Updated dependency `@rjsf/material-ui` to `5.15.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.1`. +- 4016f21: Remove some unused dependencies +- d16f85f: Show first scaffolder output text by default +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/plugin-scaffolder-common@1.4.5 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/plugin-search@1.4.5 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-compat-api@0.1.1 + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/plugin-search-react@1.7.5 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-search-backend@1.4.9 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-openapi-utils@0.1.2 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/plugin-search-backend-node@1.2.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-search-backend-module-catalog@0.1.13 + +### Patch Changes + +- 2e6c56b: Update wording to show that the backend system no longer is in alpha +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-search-backend-node@1.2.13 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.20 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-search-backend-module-elasticsearch@1.3.12 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-search-backend-node@1.2.13 + - @backstage/config@1.1.1 + - @backstage/integration-aws-node@0.1.8 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-search-backend-module-explore@0.1.13 + +### Patch Changes + +- 2e6c56b: Update wording to show that the backend system no longer is in alpha +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-search-backend-node@1.2.13 + - @backstage/config@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-search-backend-module-pg@0.5.18 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-search-backend-node@1.2.13 + - @backstage/config@1.1.1 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-search-backend-module-stack-overflow-collator@0.1.2 + +### Patch Changes + +- 2e6c56b: Update wording to show that the backend system no longer is in alpha +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-search-backend-node@1.2.13 + - @backstage/config@1.1.1 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-search-backend-module-techdocs@0.1.13 + +### Patch Changes + +- 2e6c56b: Update wording to show that the backend system no longer is in alpha +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-search-backend-node@1.2.13 + - @backstage/plugin-techdocs-node@1.11.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.20 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-search-backend-node@1.2.13 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/backend-tasks@0.5.14 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-search-common@1.2.10 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.12 + - @backstage/types@1.1.1 + +## @backstage/plugin-search-react@1.7.5 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-sentry@0.5.14 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-shortcuts@0.3.18 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-sonarqube@0.7.11 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-sonarqube-react@0.1.12 + +## @backstage/plugin-sonarqube-backend@0.2.11 + +### Patch Changes + +- 53445cd: Updated README +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-sonarqube-react@0.1.12 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-splunk-on-call@0.4.18 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-stack-overflow@0.1.24 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-home-react@0.1.7 + - @backstage/plugin-search-react@1.7.5 + - @backstage/config@1.1.1 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-stack-overflow-backend@0.2.13 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/plugin-search-backend-module-stack-overflow-collator@0.1.2 + +## @backstage/plugin-stackstorm@0.1.10 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/errors@1.2.3 + +## @backstage/plugin-tech-insights@0.3.21 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-insights-backend@0.5.23 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-tech-insights-node@0.4.15 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.41 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-tech-insights-node@0.4.15 + - @backstage/errors@1.2.3 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-insights-node@0.4.15 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-radar@0.6.12 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-compat-api@0.1.1 + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + +## @backstage/plugin-techdocs@1.9.3 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-compat-api@0.1.1 + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-techdocs-react@1.1.15 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/plugin-search-react@1.7.5 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/theme@0.5.0 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.26 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-techdocs-react@1.1.15 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/plugin-techdocs@1.9.3 + - @backstage/plugin-catalog@1.16.1 + - @backstage/plugin-search-react@1.7.5 + - @backstage/integration-react@1.1.23 + - @backstage/core-app-api@1.11.3 + - @backstage/test-utils@1.4.7 + +## @backstage/plugin-techdocs-backend@1.9.2 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-search-backend-module-techdocs@0.1.13 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-techdocs-node@1.11.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/plugin-catalog-common@1.0.20 + +## @backstage/plugin-techdocs-module-addons-contrib@1.1.4 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-techdocs-react@1.1.15 + - @backstage/integration-react@1.1.23 + - @backstage/integration@1.8.0 + +## @backstage/plugin-techdocs-node@1.11.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/integration-aws-node@0.1.8 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-techdocs-react@1.1.15 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/plugin-todo@0.2.33 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-todo-backend@0.3.7 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-openapi-utils@0.1.2 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## @backstage/plugin-user-settings-backend@0.2.8 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-vault@0.1.24 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-vault-backend@0.4.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-tasks@0.5.14 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-vault-node@0.1.2 + +## @backstage/plugin-vault-node@0.1.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + +## @backstage/plugin-xcmetrics@0.2.47 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/errors@1.2.3 + +## example-app@0.2.91 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-api-docs@0.10.3 + - @backstage/plugin-scaffolder-react@1.7.1 + - @backstage/core-components@0.13.10 + - @backstage/plugin-user-settings@0.8.0 + - @backstage/plugin-azure-sites@0.1.18 + - @backstage/cli@0.25.1 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-octopus-deploy@0.2.11 + - @backstage/frontend-app-api@0.5.0 + - @backstage/plugin-kubernetes@0.11.4 + - @backstage/plugin-home@0.6.1 + - @backstage/plugin-scaffolder@1.17.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.4 + - @backstage/plugin-catalog-unprocessed-entities@0.1.7 + - @backstage/plugin-kubernetes-cluster@0.0.5 + - @backstage/plugin-microsoft-calendar@0.1.11 + - @backstage/plugin-newrelic-dashboard@0.3.4 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/plugin-entity-feedback@0.2.12 + - @backstage/plugin-apache-airflow@0.2.19 + - @backstage/plugin-github-actions@0.6.10 + - @backstage/plugin-stack-overflow@0.1.24 + - @backstage/plugin-techdocs-react@1.1.15 + - @backstage/plugin-catalog-graph@0.3.3 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/plugin-code-coverage@0.2.22 + - @backstage/plugin-cost-insights@0.12.18 + - @backstage/plugin-tech-insights@0.3.21 + - @backstage/plugin-azure-devops@0.3.11 + - @backstage/plugin-gcp-projects@0.3.45 + - @backstage/plugin-cloudbuild@0.3.29 + - @backstage/plugin-lighthouse@0.4.14 + - @backstage/plugin-stackstorm@0.1.10 + - @backstage/plugin-tech-radar@0.6.12 + - @backstage/plugin-dynatrace@8.0.3 + - @backstage/plugin-gcalendar@0.3.22 + - @backstage/plugin-pagerduty@0.7.1 + - @backstage/plugin-shortcuts@0.3.18 + - @backstage/plugin-airbrake@0.3.29 + - @backstage/plugin-devtools@0.1.8 + - @backstage/plugin-graphiql@0.3.2 + - @backstage/plugin-linguist@0.1.14 + - @backstage/plugin-newrelic@0.3.44 + - @backstage/plugin-playlist@0.2.3 + - @backstage/plugin-puppetdb@0.1.12 + - @backstage/plugin-techdocs@1.9.3 + - @backstage/plugin-catalog@1.16.1 + - @backstage/plugin-explore@0.4.15 + - @backstage/plugin-jenkins@0.9.4 + - @backstage/plugin-rollbar@0.4.29 + - @backstage/plugin-badges@0.2.53 + - @backstage/plugin-search@1.4.5 + - @backstage/plugin-sentry@0.5.14 + - @backstage/plugin-kafka@0.3.29 + - @backstage/plugin-nomad@0.1.10 + - @backstage/plugin-gocd@0.1.35 + - @backstage/plugin-todo@0.2.33 + - @backstage/plugin-adr@0.6.12 + - @backstage/plugin-org@0.6.19 + - @backstage/plugin-catalog-import@0.10.5 + - @backstage/plugin-search-react@1.7.5 + - @backstage/app-defaults@1.4.7 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.3 + - @backstage/theme@0.5.0 + - @backstage/plugin-catalog-common@1.0.20 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.10 + +## example-app-next@0.0.5 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-api-docs@0.10.3 + - @backstage/core-compat-api@0.1.1 + - @backstage/plugin-scaffolder-react@1.7.1 + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/plugin-user-settings@0.8.0 + - @backstage/plugin-azure-sites@0.1.18 + - @backstage/cli@0.25.1 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-octopus-deploy@0.2.11 + - @backstage/frontend-app-api@0.5.0 + - @backstage/plugin-kubernetes@0.11.4 + - @backstage/plugin-home@0.6.1 + - @backstage/plugin-scaffolder@1.17.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.4 + - @backstage/plugin-catalog-unprocessed-entities@0.1.7 + - @backstage/plugin-microsoft-calendar@0.1.11 + - @backstage/plugin-newrelic-dashboard@0.3.4 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/plugin-entity-feedback@0.2.12 + - @backstage/plugin-apache-airflow@0.2.19 + - @backstage/plugin-github-actions@0.6.10 + - @backstage/plugin-techdocs-react@1.1.15 + - @backstage/plugin-catalog-graph@0.3.3 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/plugin-code-coverage@0.2.22 + - @backstage/plugin-cost-insights@0.12.18 + - @backstage/plugin-tech-insights@0.3.21 + - @backstage/plugin-azure-devops@0.3.11 + - @backstage/plugin-gcp-projects@0.3.45 + - @backstage/plugin-cloudbuild@0.3.29 + - @backstage/plugin-lighthouse@0.4.14 + - @backstage/plugin-stackstorm@0.1.10 + - @backstage/plugin-tech-radar@0.6.12 + - @backstage/plugin-dynatrace@8.0.3 + - @backstage/plugin-gcalendar@0.3.22 + - @backstage/plugin-pagerduty@0.7.1 + - @backstage/plugin-shortcuts@0.3.18 + - @backstage/plugin-airbrake@0.3.29 + - @backstage/plugin-devtools@0.1.8 + - @backstage/plugin-graphiql@0.3.2 + - @backstage/plugin-linguist@0.1.14 + - @backstage/plugin-newrelic@0.3.44 + - @backstage/plugin-playlist@0.2.3 + - @backstage/plugin-puppetdb@0.1.12 + - @backstage/plugin-techdocs@1.9.3 + - @backstage/plugin-catalog@1.16.1 + - @backstage/plugin-explore@0.4.15 + - @backstage/plugin-jenkins@0.9.4 + - @backstage/plugin-rollbar@0.4.29 + - @backstage/plugin-badges@0.2.53 + - @backstage/plugin-search@1.4.5 + - @backstage/plugin-sentry@0.5.14 + - @backstage/plugin-kafka@0.3.29 + - @backstage/plugin-gocd@0.1.35 + - @backstage/plugin-todo@0.2.33 + - @backstage/plugin-adr@0.6.12 + - @backstage/plugin-org@0.6.19 + - @backstage/plugin-app-visualizer@0.1.0 + - @backstage/plugin-catalog-import@0.10.5 + - app-next-example-plugin@0.0.5 + - @backstage/plugin-search-react@1.7.5 + - @backstage/app-defaults@1.4.7 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/core-app-api@1.11.3 + - @backstage/theme@0.5.0 + - @backstage/plugin-catalog-common@1.0.20 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.10 + +## app-next-example-plugin@0.0.5 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + +## example-backend@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 + +## example-backend-next@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 + +## e2e-test@0.2.11 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.9 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + +## techdocs-cli-embedded-app@0.2.90 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/cli@0.25.1 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-techdocs-react@1.1.15 + - @backstage/plugin-techdocs@1.9.3 + - @backstage/plugin-catalog@1.16.1 + - @backstage/app-defaults@1.4.7 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.3 + - @backstage/test-utils@1.4.7 + - @backstage/theme@0.5.0 + +## @internal/plugin-todo-list@1.0.21 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + +## @internal/plugin-todo-list-backend@1.0.21 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/errors@1.2.3 + +## @internal/plugin-todo-list-common@1.0.17 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.12 diff --git a/docs/releases/v1.22.0-next.0-changelog.md b/docs/releases/v1.22.0-next.0-changelog.md new file mode 100644 index 0000000000..2505b29d9d --- /dev/null +++ b/docs/releases/v1.22.0-next.0-changelog.md @@ -0,0 +1,2974 @@ +# Release v1.22.0-next.0 + +## @backstage/app-defaults@1.4.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-permission-react@0.4.19-next.0 + - @backstage/core-app-api@1.11.2 + - @backstage/core-plugin-api@1.8.1 + - @backstage/theme@0.5.0 + +## @backstage/backend-app-api@0.5.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/backend-tasks@0.5.14-next.0 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.1 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.6.0 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.0 + - @backstage/plugin-permission-node@0.7.20-next.0 + +## @backstage/backend-common@0.20.1-next.0 + +### Patch Changes + +- b6b15b2: Use sha256 instead of md5 for hash key calculation in caches + + This can have a side effect of invalidating caches (when cache key was >250 characters) + This improves compliance with FIPS nodejs + +- Updated dependencies + - @backstage/backend-app-api@0.5.10-next.0 + - @backstage/backend-dev-utils@0.1.2 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.6.0 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + +## @backstage/backend-defaults@0.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-app-api@0.5.10-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + +## @backstage/backend-openapi-utils@0.1.2-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/errors@1.2.3 + +## @backstage/backend-plugin-api@0.6.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.14-next.0 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.0 + - @backstage/plugin-permission-common@0.7.11 + +## @backstage/backend-tasks@0.5.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/backend-test-utils@0.2.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-app-api@0.5.10-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.0 + +## @backstage/catalog-client@1.5.2-next.0 + +### Patch Changes + +- 883782e: Fix a bug in `getLocationByRef` that led to invalid backend calls +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/cli@0.25.1-next.0 + +### Patch Changes + +- b6b15b2: Use sha256 instead of md5 in build script cache key calculation + + Makes it possible to build on FIPS nodejs. + +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.1 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.6.0 + - @backstage/errors@1.2.3 + - @backstage/eslint-plugin@0.1.4 + - @backstage/integration@1.8.0 + - @backstage/release-manifests@0.0.11 + - @backstage/types@1.1.1 + +## @backstage/core-compat-api@0.1.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.1-next.0 + - @backstage/core-app-api@1.11.2 + - @backstage/core-plugin-api@1.8.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/core-components@0.13.10-next.0 + +### Patch Changes + +- d625f66: Fixed bug in Link where it was possible to select and copy a hidden element into clipboard +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0 + - @backstage/version-bridge@1.0.7 + +## @backstage/create-app@0.5.9-next.0 + +### Patch Changes + +- Bumped create-app version. +- Updated dependencies + - @backstage/cli-common@0.1.13 + +## @backstage/dev-utils@1.0.26-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/app-defaults@1.4.7-next.0 + - @backstage/integration-react@1.1.22 + - @backstage/catalog-model@1.4.3 + - @backstage/core-app-api@1.11.2 + - @backstage/core-plugin-api@1.8.1 + - @backstage/theme@0.5.0 + +## @backstage/frontend-app-api@0.4.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/frontend-plugin-api@0.4.1-next.0 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.2 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/frontend-plugin-api@0.4.1-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/frontend-test-utils@0.1.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.1-next.0 + - @backstage/frontend-app-api@0.4.1-next.0 + - @backstage/test-utils@1.4.7-next.0 + - @backstage/types@1.1.1 + +## @backstage/repo-tools@0.5.2-next.0 + +### Patch Changes + +- 883782e: Updated the OpenAPI template to export the `TypedResponse` interface so that client code can leverage it +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.1 + - @backstage/errors@1.2.3 + +## @techdocs/cli@1.8.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/plugin-techdocs-node@1.11.1-next.0 + +## @backstage/test-utils@1.4.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-react@0.4.19-next.0 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.2 + - @backstage/core-plugin-api@1.8.1 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.11 + +## @backstage/plugin-adr@0.6.12-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/frontend-plugin-api@0.4.1-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/integration-react@1.1.22 + - @backstage/plugin-search-react@1.7.5-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-adr-common@0.2.18 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-adr-backend@0.4.6-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/plugin-adr-common@0.2.18 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-airbrake@0.3.29-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/dev-utils@1.0.26-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/test-utils@1.4.7-next.0 + +## @backstage/plugin-airbrake-backend@0.3.6-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/config@1.1.1 + +## @backstage/plugin-allure@0.1.45-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + +## @backstage/plugin-analytics-module-ga@0.1.37-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1 + +## @backstage/plugin-analytics-module-ga4@0.1.8-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1 + +## @backstage/plugin-analytics-module-newrelic-browser@0.0.6-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1 + +## @backstage/plugin-apache-airflow@0.2.19-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/core-plugin-api@1.8.1 + +## @backstage/plugin-api-docs@0.10.3-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/plugin-catalog@1.16.1-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + +## @backstage/plugin-apollo-explorer@0.1.19-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/core-plugin-api@1.8.1 + +## @backstage/plugin-app-backend@0.3.57-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.6.0 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.9-next.0 + +## @backstage/plugin-app-node@0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + +## @backstage/plugin-auth-backend@0.20.3-next.0 + +### Patch Changes + +- 004499c: Fixed an issue where some Okta's resolvers were missing +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.1-next.0 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.1.1-next.0 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.3-next.0 + - @backstage/plugin-auth-backend-module-github-provider@0.1.6-next.0 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.6-next.0 + - @backstage/plugin-auth-backend-module-google-provider@0.1.6-next.0 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.1.6-next.0 + - @backstage/plugin-auth-backend-module-okta-provider@0.0.2-next.0 + - @backstage/plugin-catalog-node@1.6.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.3-next.0 + +## @backstage/plugin-auth-backend-module-atlassian-provider@0.1.1-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/plugin-auth-node@0.4.3-next.0 + +## @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.3-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.0 + +## @backstage/plugin-auth-backend-module-github-provider@0.1.6-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/plugin-auth-node@0.4.3-next.0 + +## @backstage/plugin-auth-backend-module-gitlab-provider@0.1.6-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/plugin-auth-node@0.4.3-next.0 + +## @backstage/plugin-auth-backend-module-google-provider@0.1.6-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/plugin-auth-node@0.4.3-next.0 + +## @backstage/plugin-auth-backend-module-microsoft-provider@0.1.4-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/plugin-auth-node@0.4.3-next.0 + +## @backstage/plugin-auth-backend-module-oauth2-provider@0.1.6-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/plugin-auth-node@0.4.3-next.0 + +## @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.1-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.3-next.0 + +## @backstage/plugin-auth-backend-module-okta-provider@0.0.2-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/plugin-auth-node@0.4.3-next.0 + +## @backstage/plugin-auth-backend-module-pinniped-provider@0.1.3-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.0 + +## @backstage/plugin-auth-backend-module-vmware-cloud-provider@0.1.1-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-auth-node@0.4.3-next.0 + +## @backstage/plugin-auth-node@0.4.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-azure-devops@0.3.11-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-azure-devops-common@0.3.2 + +## @backstage/plugin-azure-devops-backend@0.5.1-next.0 + +### Patch Changes + +- d076ee4: Updated dependency `azure-devops-node-api` to `^12.0.0`. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/plugin-catalog-node@1.6.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + - @backstage/plugin-azure-devops-common@0.3.2 + - @backstage/plugin-catalog-common@1.0.19 + +## @backstage/plugin-azure-sites@0.1.18-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-azure-sites-common@0.1.1 + +## @backstage/plugin-azure-sites-backend@0.1.19-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/config@1.1.1 + - @backstage/plugin-azure-sites-common@0.1.1 + +## @backstage/plugin-badges@0.2.53-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-badges-backend@0.3.6-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.3-next.0 + +## @backstage/plugin-bazaar@0.2.21-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-bazaar-backend@0.3.7-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.0 + +## @backstage/plugin-bitrise@0.1.56-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + +## @backstage/plugin-catalog@1.16.1-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/frontend-plugin-api@0.4.1-next.0 + - @backstage/plugin-permission-react@0.4.19-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/integration-react@1.1.22 + - @backstage/plugin-search-react@1.7.5-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-compat-api@0.1.1-next.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-scaffolder-common@1.4.4 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-catalog-backend@1.16.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.13-next.0 + - @backstage/backend-openapi-utils@0.1.2-next.0 + - @backstage/plugin-catalog-node@1.6.1-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/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.0 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-events-node@0.2.18-next.0 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.20-next.0 + +## @backstage/plugin-catalog-backend-module-aws@0.3.3-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/plugin-kubernetes-common@0.7.3-next.0 + - @backstage/plugin-catalog-node@1.6.1-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/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/integration-aws-node@0.1.8 + - @backstage/plugin-catalog-common@1.0.19 + +## @backstage/plugin-catalog-backend-module-azure@0.1.28-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/plugin-catalog-node@1.6.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/backend-tasks@0.5.14-next.0 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + - @backstage/plugin-catalog-common@1.0.19 + +## @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.2-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-openapi-utils@0.1.2-next.0 + - @backstage/plugin-catalog-node@1.6.1-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/errors@1.2.3 + +## @backstage/plugin-catalog-backend-module-bitbucket@0.2.24-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/plugin-catalog-node@1.6.1-next.0 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.15 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.1.24-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/plugin-catalog-node@1.6.1-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-bitbucket-cloud-common@0.2.15 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-events-node@0.2.18-next.0 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.1.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/plugin-catalog-node@1.6.1-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/errors@1.2.3 + - @backstage/integration@1.8.0 + +## @backstage/plugin-catalog-backend-module-gcp@0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/plugin-kubernetes-common@0.7.3-next.0 + - @backstage/plugin-catalog-node@1.6.1-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/plugin-catalog-backend-module-gerrit@0.1.25-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/plugin-catalog-node@1.6.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/backend-tasks@0.5.14-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## @backstage/plugin-catalog-backend-module-github@0.4.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/plugin-catalog-node@1.6.1-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-catalog-backend@1.16.1-next.0 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-events-node@0.2.18-next.0 + +## @backstage/plugin-catalog-backend-module-github-org@0.1.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/plugin-catalog-node@1.6.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/backend-tasks@0.5.14-next.0 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-backend-module-github@0.4.7-next.0 + +## @backstage/plugin-catalog-backend-module-gitlab@0.3.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/plugin-catalog-node@1.6.1-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-catalog-backend-module-incremental-ingestion@0.4.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/plugin-catalog-node@1.6.1-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/errors@1.2.3 + - @backstage/plugin-catalog-backend@1.16.1-next.0 + - @backstage/plugin-events-node@0.2.18-next.0 + - @backstage/plugin-permission-common@0.7.11 + +## @backstage/plugin-catalog-backend-module-ldap@0.5.24-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.1-next.0 + - @backstage/backend-tasks@0.5.14-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + +## @backstage/plugin-catalog-backend-module-msgraph@0.5.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/plugin-catalog-node@1.6.1-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/plugin-catalog-common@1.0.19 + +## @backstage/plugin-catalog-backend-module-openapi@0.1.26-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/plugin-catalog-node@1.6.1-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-backend@1.16.1-next.0 + - @backstage/plugin-catalog-common@1.0.19 + +## @backstage/plugin-catalog-backend-module-puppetdb@0.1.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/plugin-catalog-node@1.6.1-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/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.6-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-scaffolder-common@1.4.4 + +## @backstage/plugin-catalog-backend-module-unprocessed@0.3.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-auth-node@0.4.3-next.0 + +## @backstage/plugin-catalog-graph@0.3.3-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-import@0.10.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/frontend-plugin-api@0.4.1-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/integration-react@1.1.22 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-compat-api@0.1.1-next.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/plugin-catalog-common@1.0.19 + +## @backstage/plugin-catalog-node@1.6.1-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.20-next.0 + +## @backstage/plugin-catalog-react@1.9.3-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/frontend-plugin-api@0.4.1-next.0 + - @backstage/plugin-permission-react@0.4.19-next.0 + - @backstage/integration-react@1.1.22 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-permission-common@0.7.11 + +## @backstage/plugin-catalog-unprocessed-entities@0.1.7-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-cicd-statistics@0.1.31-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + +## @backstage/plugin-cicd-statistics-module-gitlab@0.1.25-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-cicd-statistics@0.1.31-next.0 + +## @backstage/plugin-circleci@0.3.29-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + +## @backstage/plugin-cloudbuild@0.3.29-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + +## @backstage/plugin-code-climate@0.1.29-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + +## @backstage/plugin-code-coverage@0.2.22-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-code-coverage-backend@0.2.23-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/plugin-auth-node@0.4.3-next.0 + +## @backstage/plugin-codescene@0.1.21-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-config-schema@0.1.49-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-cost-insights@0.12.18-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1 + - @backstage/theme@0.5.0 + - @backstage/plugin-cost-insights-common@0.1.2 + +## @backstage/plugin-devtools@0.1.8-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-permission-react@0.4.19-next.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-devtools-common@0.1.7 + +## @backstage/plugin-devtools-backend@0.2.6-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.6.0 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.0 + - @backstage/plugin-devtools-common@0.1.7 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.20-next.0 + +## @backstage/plugin-dynatrace@8.0.3-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + +## @backstage/plugin-entity-feedback@0.2.12-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## @backstage/plugin-entity-feedback-backend@0.2.6-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.0 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## @backstage/plugin-entity-validation@0.1.14-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.19 + +## @backstage/plugin-events-backend@0.2.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.18-next.0 + +## @backstage/plugin-events-backend-module-aws-sqs@0.2.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/backend-tasks@0.5.14-next.0 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.18-next.0 + +## @backstage/plugin-events-backend-module-azure@0.1.19-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/plugin-events-node@0.2.18-next.0 + +## @backstage/plugin-events-backend-module-bitbucket-cloud@0.1.19-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/plugin-events-node@0.2.18-next.0 + +## @backstage/plugin-events-backend-module-gerrit@0.1.19-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/plugin-events-node@0.2.18-next.0 + +## @backstage/plugin-events-backend-module-github@0.1.19-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.18-next.0 + +## @backstage/plugin-events-backend-module-gitlab@0.1.19-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.18-next.0 + +## @backstage/plugin-events-backend-test-utils@0.1.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.2.18-next.0 + +## @backstage/plugin-events-node@0.2.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + +## @backstage/plugin-explore@0.4.15-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/frontend-plugin-api@0.4.1-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/plugin-explore-react@0.0.35-next.0 + - @backstage/plugin-search-react@1.7.5-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-explore-backend@0.0.19-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/plugin-search-backend-module-explore@0.1.13-next.0 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + +## @backstage/plugin-explore-react@0.0.35-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-explore-common@0.0.2 + +## @backstage/plugin-firehydrant@0.2.13-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + +## @backstage/plugin-fossa@0.2.61-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-gcalendar@0.3.22-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-gcp-projects@0.3.45-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/core-plugin-api@1.8.1 + +## @backstage/plugin-git-release-manager@0.3.41-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/integration@1.8.0 + +## @backstage/plugin-github-actions@0.6.10-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/integration-react@1.1.22 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/integration@1.8.0 + +## @backstage/plugin-github-deployments@0.1.60-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/integration-react@1.1.22 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## @backstage/plugin-github-issues@0.2.18-next.0 + +### Patch Changes + +- bf92ae3: Updated dependency `octokit` to `^3.0.0`. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## @backstage/plugin-github-pull-requests-board@0.1.23-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/integration@1.8.0 + +## @backstage/plugin-gitops-profiles@0.3.44-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/core-plugin-api@1.8.1 + +## @backstage/plugin-gocd@0.1.35-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-graphiql@0.3.2-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/frontend-plugin-api@0.4.1-next.0 + - @backstage/core-compat-api@0.1.1-next.0 + - @backstage/core-plugin-api@1.8.1 + +## @backstage/plugin-graphql-voyager@0.1.11-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/core-plugin-api@1.8.1 + +## @backstage/plugin-home@0.6.1-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/frontend-plugin-api@0.4.1-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/plugin-home-react@0.1.7-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-app-api@1.11.2 + - @backstage/core-compat-api@0.1.1-next.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/theme@0.5.0 + +## @backstage/plugin-home-react@0.1.7-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/core-plugin-api@1.8.1 + +## @backstage/plugin-ilert@0.2.18-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-jenkins@0.9.4-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-jenkins-common@0.1.22 + +## @backstage/plugin-jenkins-backend@0.3.3-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/plugin-catalog-node@1.6.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.3-next.0 + - @backstage/plugin-jenkins-common@0.1.22 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.20-next.0 + +## @backstage/plugin-kafka@0.3.29-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + +## @backstage/plugin-kafka-backend@0.3.7-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-kubernetes@0.11.4-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-kubernetes-common@0.7.3-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/plugin-kubernetes-react@0.2.1-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + +## @backstage/plugin-kubernetes-backend@0.14.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/plugin-kubernetes-common@0.7.3-next.0 + - @backstage/plugin-catalog-node@1.6.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.0 + - @backstage/plugin-kubernetes-node@0.1.3-next.0 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.20-next.0 + +## @backstage/plugin-kubernetes-cluster@0.0.5-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-kubernetes-common@0.7.3-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/plugin-kubernetes-react@0.2.1-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + +## @backstage/plugin-kubernetes-common@0.7.3-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.11 + +## @backstage/plugin-kubernetes-node@0.1.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes-common@0.7.3-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-kubernetes-react@0.2.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-kubernetes-common@0.7.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-lighthouse@0.4.14-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-lighthouse-common@0.1.4 + +## @backstage/plugin-lighthouse-backend@0.4.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/plugin-catalog-node@1.6.1-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/types@1.1.1 + - @backstage/plugin-lighthouse-common@0.1.4 + +## @backstage/plugin-linguist@0.1.14-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-linguist-common@0.1.2 + +## @backstage/plugin-linguist-backend@0.5.6-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/plugin-catalog-node@1.6.1-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/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.0 + - @backstage/plugin-linguist-common@0.1.2 + +## @backstage/plugin-microsoft-calendar@0.1.11-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-newrelic@0.3.44-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/core-plugin-api@1.8.1 + +## @backstage/plugin-newrelic-dashboard@0.3.4-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-nomad@0.1.10-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + +## @backstage/plugin-nomad-backend@0.1.11-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-octopus-deploy@0.2.11-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + +## @backstage/plugin-opencost@0.2.4-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/core-plugin-api@1.8.1 + +## @backstage/plugin-org@0.6.19-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-common@1.0.19 + +## @backstage/plugin-org-react@0.1.18-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + +## @backstage/plugin-pagerduty@0.7.1-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/plugin-home-react@0.1.7-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-periskop@0.1.27-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-periskop-backend@0.2.7-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/config@1.1.1 + +## @backstage/plugin-permission-backend@0.5.32-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.3-next.0 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.20-next.0 + +## @backstage/plugin-permission-backend-module-allow-all-policy@0.1.6-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/plugin-auth-node@0.4.3-next.0 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.20-next.0 + +## @backstage/plugin-permission-node@0.7.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.3-next.0 + - @backstage/plugin-permission-common@0.7.11 + +## @backstage/plugin-permission-react@0.4.19-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-permission-common@0.7.11 + +## @backstage/plugin-playlist@0.2.3-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-permission-react@0.4.19-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/plugin-search-react@1.7.5-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-playlist-common@0.1.13 + +## @backstage/plugin-playlist-backend@0.3.13-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.3-next.0 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.20-next.0 + - @backstage/plugin-playlist-common@0.1.13 + +## @backstage/plugin-proxy-backend@0.4.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/config@1.1.1 + +## @backstage/plugin-puppetdb@0.1.12-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-rollbar@0.4.29-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + +## @backstage/plugin-rollbar-backend@0.1.54-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/config@1.1.1 + +## @backstage/plugin-scaffolder@1.17.1-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.7.1-next.0 + - @backstage/core-components@0.13.10-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/plugin-permission-react@0.4.19-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/integration-react@1.1.22 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-scaffolder-common@1.4.4 + +## @backstage/plugin-scaffolder-backend@1.19.3-next.0 + +### Patch Changes + +- e9ab1c4: Fixed an issue where not passing a `value` to any of the action's permission conditions caused an error. +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/plugin-scaffolder-backend-module-github@0.1.1-next.0 + - @backstage/plugin-scaffolder-backend-module-azure@0.1.1-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.6-next.0 + - @backstage/plugin-catalog-node@1.6.1-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/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.0 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.20-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.1.1-next.0 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.1.1-next.0 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.2.12-next.0 + - @backstage/plugin-scaffolder-common@1.4.4 + - @backstage/plugin-scaffolder-node@0.2.10-next.0 + +## @backstage/plugin-scaffolder-backend-module-azure@0.1.1-next.0 + +### Patch Changes + +- d076ee4: Updated dependency `azure-devops-node-api` to `^12.0.0`. +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/plugin-scaffolder-node@0.2.10-next.0 + +## @backstage/plugin-scaffolder-backend-module-bitbucket@0.1.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/plugin-scaffolder-node@0.2.10-next.0 + +## @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.10-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/plugin-scaffolder-node@0.2.10-next.0 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.2.33-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.10-next.0 + +## @backstage/plugin-scaffolder-backend-module-gerrit@0.1.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/plugin-scaffolder-node@0.2.10-next.0 + +## @backstage/plugin-scaffolder-backend-module-github@0.1.1-next.0 + +### Patch Changes + +- bf92ae3: Updated dependency `octokit` to `^3.0.0`. +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/plugin-scaffolder-node@0.2.10-next.0 + +## @backstage/plugin-scaffolder-backend-module-gitlab@0.2.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/plugin-scaffolder-node@0.2.10-next.0 + +## @backstage/plugin-scaffolder-backend-module-rails@0.4.26-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.10-next.0 + +## @backstage/plugin-scaffolder-backend-module-sentry@0.1.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-scaffolder-node@0.2.10-next.0 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.2.30-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.10-next.0 + +## @backstage/plugin-scaffolder-node@0.2.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-common@1.4.4 + +## @backstage/plugin-scaffolder-react@1.7.1-next.0 + +### Patch Changes + +- c28f281: Scaffolder form now shows a list of errors at the top of the form. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-scaffolder-common@1.4.4 + +## @backstage/plugin-search@1.4.5-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/frontend-plugin-api@0.4.1-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/plugin-search-react@1.7.5-next.0 + - @backstage/core-compat-api@0.1.1-next.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-search-backend@1.4.9-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-openapi-utils@0.1.2-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.0 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.20-next.0 + - @backstage/plugin-search-backend-node@1.2.13-next.0 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-search-backend-module-catalog@0.1.13-next.0 + +### Patch Changes + +- 2e6c56b: Update wording to show that the backend system no longer is in alpha +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/plugin-catalog-node@1.6.1-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/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-search-backend-node@1.2.13-next.0 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-search-backend-module-elasticsearch@1.3.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/config@1.1.1 + - @backstage/integration-aws-node@0.1.8 + - @backstage/plugin-search-backend-node@1.2.13-next.0 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-search-backend-module-explore@0.1.13-next.0 + +### Patch Changes + +- 2e6c56b: Update wording to show that the backend system no longer is in alpha +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/backend-tasks@0.5.14-next.0 + - @backstage/config@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-backend-node@1.2.13-next.0 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-search-backend-module-pg@0.5.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/config@1.1.1 + - @backstage/plugin-search-backend-node@1.2.13-next.0 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-search-backend-module-stack-overflow-collator@0.1.2-next.0 + +### Patch Changes + +- 2e6c56b: Update wording to show that the backend system no longer is in alpha +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/backend-tasks@0.5.14-next.0 + - @backstage/config@1.1.1 + - @backstage/plugin-search-backend-node@1.2.13-next.0 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-search-backend-module-techdocs@0.1.13-next.0 + +### Patch Changes + +- 2e6c56b: Update wording to show that the backend system no longer is in alpha +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/plugin-catalog-node@1.6.1-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/plugin-catalog-common@1.0.19 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-search-backend-node@1.2.13-next.0 + - @backstage/plugin-search-common@1.2.9 + - @backstage/plugin-techdocs-node@1.11.1-next.0 + +## @backstage/plugin-search-backend-node@1.2.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/backend-tasks@0.5.14-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-search-react@1.7.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/frontend-plugin-api@0.4.1-next.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-sentry@0.5.14-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + +## @backstage/plugin-shortcuts@0.3.18-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-sonarqube@0.7.11-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-sonarqube-react@0.1.11 + +## @backstage/plugin-sonarqube-backend@0.2.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-splunk-on-call@0.4.18-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + +## @backstage/plugin-stack-overflow@0.1.24-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/frontend-plugin-api@0.4.1-next.0 + - @backstage/plugin-home-react@0.1.7-next.0 + - @backstage/plugin-search-react@1.7.5-next.0 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-stack-overflow-backend@0.2.13-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/plugin-search-backend-module-stack-overflow-collator@0.1.2-next.0 + +## @backstage/plugin-stackstorm@0.1.10-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-tech-insights@0.3.21-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-insights-backend@0.5.23-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/plugin-tech-insights-node@0.4.15-next.0 + - @backstage/backend-tasks@0.5.14-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.41-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/plugin-tech-insights-node@0.4.15-next.0 + - @backstage/errors@1.2.3 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-insights-node@0.4.15-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-radar@0.6.12-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/frontend-plugin-api@0.4.1-next.0 + - @backstage/core-compat-api@0.1.1-next.0 + - @backstage/core-plugin-api@1.8.1 + +## @backstage/plugin-techdocs@1.9.3-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/frontend-plugin-api@0.4.1-next.0 + - @backstage/plugin-techdocs-react@1.1.15-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/integration-react@1.1.22 + - @backstage/plugin-search-react@1.7.5-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-compat-api@0.1.1-next.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/theme@0.5.0 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.26-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/plugin-techdocs-react@1.1.15-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/plugin-techdocs@1.9.3-next.0 + - @backstage/plugin-catalog@1.16.1-next.0 + - @backstage/integration-react@1.1.22 + - @backstage/plugin-search-react@1.7.5-next.0 + - @backstage/core-app-api@1.11.2 + - @backstage/core-plugin-api@1.8.1 + - @backstage/test-utils@1.4.7-next.0 + +## @backstage/plugin-techdocs-backend@1.9.2-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.13-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-techdocs-node@1.11.1-next.0 + +## @backstage/plugin-techdocs-module-addons-contrib@1.1.4-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-techdocs-react@1.1.15-next.0 + - @backstage/integration-react@1.1.22 + - @backstage/core-plugin-api@1.8.1 + - @backstage/integration@1.8.0 + +## @backstage/plugin-techdocs-node@1.11.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/integration-aws-node@0.1.8 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-techdocs-react@1.1.15-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/plugin-todo@0.2.33-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-todo-backend@0.3.7-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/backend-openapi-utils@0.1.2-next.0 + - @backstage/plugin-catalog-node@1.6.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## @backstage/plugin-user-settings@0.7.15-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/frontend-plugin-api@0.4.1-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/core-app-api@1.11.2 + - @backstage/core-compat-api@0.1.1-next.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-user-settings-backend@0.2.8-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.0 + +## @backstage/plugin-vault@0.1.24-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-vault-backend@0.4.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/backend-tasks@0.5.14-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-vault-node@0.1.2-next.0 + +## @backstage/plugin-vault-node@0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + +## @backstage/plugin-xcmetrics@0.2.47-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + +## example-app@0.2.91-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.7.1-next.0 + - @backstage/core-components@0.13.10-next.0 + - @backstage/cli@0.25.1-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.4-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.1.7-next.0 + - @backstage/plugin-kubernetes-cluster@0.0.5-next.0 + - @backstage/plugin-microsoft-calendar@0.1.11-next.0 + - @backstage/plugin-newrelic-dashboard@0.3.4-next.0 + - @backstage/plugin-permission-react@0.4.19-next.0 + - @backstage/plugin-entity-feedback@0.2.12-next.0 + - @backstage/plugin-apache-airflow@0.2.19-next.0 + - @backstage/plugin-github-actions@0.6.10-next.0 + - @backstage/plugin-octopus-deploy@0.2.11-next.0 + - @backstage/plugin-stack-overflow@0.1.24-next.0 + - @backstage/plugin-techdocs-react@1.1.15-next.0 + - @backstage/plugin-catalog-graph@0.3.3-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/plugin-code-coverage@0.2.22-next.0 + - @backstage/plugin-cost-insights@0.12.18-next.0 + - @backstage/plugin-tech-insights@0.3.21-next.0 + - @backstage/plugin-user-settings@0.7.15-next.0 + - @backstage/plugin-azure-devops@0.3.11-next.0 + - @backstage/plugin-gcp-projects@0.3.45-next.0 + - @backstage/plugin-azure-sites@0.1.18-next.0 + - @backstage/plugin-cloudbuild@0.3.29-next.0 + - @backstage/plugin-kubernetes@0.11.4-next.0 + - @backstage/plugin-lighthouse@0.4.14-next.0 + - @backstage/plugin-scaffolder@1.17.1-next.0 + - @backstage/plugin-stackstorm@0.1.10-next.0 + - @backstage/plugin-tech-radar@0.6.12-next.0 + - @backstage/plugin-dynatrace@8.0.3-next.0 + - @backstage/plugin-gcalendar@0.3.22-next.0 + - @backstage/plugin-pagerduty@0.7.1-next.0 + - @backstage/plugin-shortcuts@0.3.18-next.0 + - @backstage/plugin-airbrake@0.3.29-next.0 + - @backstage/plugin-api-docs@0.10.3-next.0 + - @backstage/plugin-devtools@0.1.8-next.0 + - @backstage/plugin-graphiql@0.3.2-next.0 + - @backstage/plugin-linguist@0.1.14-next.0 + - @backstage/plugin-newrelic@0.3.44-next.0 + - @backstage/plugin-playlist@0.2.3-next.0 + - @backstage/plugin-puppetdb@0.1.12-next.0 + - @backstage/plugin-techdocs@1.9.3-next.0 + - @backstage/plugin-catalog@1.16.1-next.0 + - @backstage/plugin-explore@0.4.15-next.0 + - @backstage/plugin-jenkins@0.9.4-next.0 + - @backstage/plugin-rollbar@0.4.29-next.0 + - @backstage/plugin-badges@0.2.53-next.0 + - @backstage/plugin-search@1.4.5-next.0 + - @backstage/plugin-sentry@0.5.14-next.0 + - @backstage/plugin-kafka@0.3.29-next.0 + - @backstage/plugin-nomad@0.1.10-next.0 + - @backstage/plugin-gocd@0.1.35-next.0 + - @backstage/plugin-home@0.6.1-next.0 + - @backstage/plugin-todo@0.2.33-next.0 + - @backstage/plugin-adr@0.6.12-next.0 + - @backstage/plugin-org@0.6.19-next.0 + - @backstage/app-defaults@1.4.7-next.0 + - @backstage/frontend-app-api@0.4.1-next.0 + - @backstage/integration-react@1.1.22 + - @backstage/plugin-catalog-import@0.10.5-next.0 + - @backstage/plugin-search-react@1.7.5-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.2 + - @backstage/core-plugin-api@1.8.1 + - @backstage/theme@0.5.0 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.9 + +## example-app-next@0.0.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.7.1-next.0 + - @backstage/core-components@0.13.10-next.0 + - @backstage/cli@0.25.1-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.4-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.1.7-next.0 + - @backstage/frontend-plugin-api@0.4.1-next.0 + - @backstage/plugin-microsoft-calendar@0.1.11-next.0 + - @backstage/plugin-newrelic-dashboard@0.3.4-next.0 + - @backstage/plugin-permission-react@0.4.19-next.0 + - @backstage/plugin-entity-feedback@0.2.12-next.0 + - @backstage/plugin-apache-airflow@0.2.19-next.0 + - @backstage/plugin-github-actions@0.6.10-next.0 + - @backstage/plugin-octopus-deploy@0.2.11-next.0 + - @backstage/plugin-techdocs-react@1.1.15-next.0 + - @backstage/plugin-catalog-graph@0.3.3-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/plugin-code-coverage@0.2.22-next.0 + - @backstage/plugin-cost-insights@0.12.18-next.0 + - @backstage/plugin-tech-insights@0.3.21-next.0 + - @backstage/plugin-user-settings@0.7.15-next.0 + - @backstage/plugin-azure-devops@0.3.11-next.0 + - @backstage/plugin-gcp-projects@0.3.45-next.0 + - @backstage/plugin-azure-sites@0.1.18-next.0 + - @backstage/plugin-cloudbuild@0.3.29-next.0 + - @backstage/plugin-kubernetes@0.11.4-next.0 + - @backstage/plugin-lighthouse@0.4.14-next.0 + - @backstage/plugin-scaffolder@1.17.1-next.0 + - @backstage/plugin-stackstorm@0.1.10-next.0 + - @backstage/plugin-tech-radar@0.6.12-next.0 + - @backstage/plugin-dynatrace@8.0.3-next.0 + - @backstage/plugin-gcalendar@0.3.22-next.0 + - @backstage/plugin-pagerduty@0.7.1-next.0 + - @backstage/plugin-shortcuts@0.3.18-next.0 + - @backstage/plugin-airbrake@0.3.29-next.0 + - @backstage/plugin-api-docs@0.10.3-next.0 + - @backstage/plugin-devtools@0.1.8-next.0 + - @backstage/plugin-graphiql@0.3.2-next.0 + - @backstage/plugin-linguist@0.1.14-next.0 + - @backstage/plugin-newrelic@0.3.44-next.0 + - @backstage/plugin-playlist@0.2.3-next.0 + - @backstage/plugin-puppetdb@0.1.12-next.0 + - @backstage/plugin-techdocs@1.9.3-next.0 + - @backstage/plugin-catalog@1.16.1-next.0 + - @backstage/plugin-explore@0.4.15-next.0 + - @backstage/plugin-jenkins@0.9.4-next.0 + - @backstage/plugin-rollbar@0.4.29-next.0 + - @backstage/plugin-badges@0.2.53-next.0 + - @backstage/plugin-search@1.4.5-next.0 + - @backstage/plugin-sentry@0.5.14-next.0 + - @backstage/plugin-kafka@0.3.29-next.0 + - @backstage/plugin-gocd@0.1.35-next.0 + - @backstage/plugin-home@0.6.1-next.0 + - @backstage/plugin-todo@0.2.33-next.0 + - @backstage/plugin-adr@0.6.12-next.0 + - @backstage/plugin-org@0.6.19-next.0 + - @backstage/app-defaults@1.4.7-next.0 + - app-next-example-plugin@0.0.5-next.0 + - @backstage/frontend-app-api@0.4.1-next.0 + - @backstage/integration-react@1.1.22 + - @backstage/plugin-catalog-import@0.10.5-next.0 + - @backstage/plugin-search-react@1.7.5-next.0 + - @backstage/plugin-visualizer@0.0.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-app-api@1.11.2 + - @backstage/core-compat-api@0.1.1-next.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/theme@0.5.0 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.9 + +## app-next-example-plugin@0.0.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/frontend-plugin-api@0.4.1-next.0 + +## example-backend@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 + +## example-backend-next@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 + +## @backstage/backend-plugin-manager@0.0.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/backend-tasks@0.5.14-next.0 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.0 + - @backstage/plugin-catalog-backend@1.16.1-next.0 + - @backstage/plugin-events-backend@0.2.18-next.0 + - @backstage/plugin-events-node@0.2.18-next.0 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.20-next.0 + - @backstage/plugin-scaffolder-node@0.2.10-next.0 + - @backstage/plugin-search-backend-node@1.2.13-next.0 + - @backstage/plugin-search-common@1.2.9 + +## e2e-test@0.2.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.9-next.0 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + +## techdocs-cli-embedded-app@0.2.90-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/cli@0.25.1-next.0 + - @backstage/plugin-techdocs-react@1.1.15-next.0 + - @backstage/plugin-techdocs@1.9.3-next.0 + - @backstage/plugin-catalog@1.16.1-next.0 + - @backstage/app-defaults@1.4.7-next.0 + - @backstage/integration-react@1.1.22 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.2 + - @backstage/core-plugin-api@1.8.1 + - @backstage/test-utils@1.4.7-next.0 + - @backstage/theme@0.5.0 + +## @internal/plugin-todo-list@1.0.21-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/core-plugin-api@1.8.1 + +## @internal/plugin-todo-list-backend@1.0.21-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.3-next.0 + +## @backstage/plugin-visualizer@0.0.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/frontend-plugin-api@0.4.1-next.0 + - @backstage/core-plugin-api@1.8.1 diff --git a/docs/releases/v1.22.0-next.1-changelog.md b/docs/releases/v1.22.0-next.1-changelog.md new file mode 100644 index 0000000000..88d8c7c9cb --- /dev/null +++ b/docs/releases/v1.22.0-next.1-changelog.md @@ -0,0 +1,2868 @@ +# Release v1.22.0-next.1 + +## @backstage/plugin-user-settings@0.8.0-next.1 + +### Minor Changes + +- 56b2fb0: Updated the user settings selector to use a select component that displays native language names instead of language codes if possible. + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/core-app-api@1.11.3-next.0 + - @backstage/core-compat-api@0.1.1-next.1 + - @backstage/frontend-plugin-api@0.4.1-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + +## @backstage/app-defaults@1.4.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/core-app-api@1.11.3-next.0 + - @backstage/plugin-permission-react@0.4.19-next.1 + - @backstage/theme@0.5.0 + +## @backstage/backend-app-api@0.5.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.6.1-next.0 + - @backstage/cli-node@0.2.2-next.0 + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/plugin-permission-node@0.7.20-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/backend-common@0.20.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.6.1-next.0 + - @backstage/backend-app-api@0.5.10-next.1 + - @backstage/integration@1.8.0 + - @backstage/integration-aws-node@0.1.8 + - @backstage/config@1.1.1 + - @backstage/backend-dev-utils@0.1.2 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/backend-defaults@0.2.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@0.5.10-next.1 + - @backstage/backend-common@0.20.1-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + +## @backstage/backend-openapi-utils@0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/errors@1.2.3 + +## @backstage/backend-plugin-api@0.6.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.11 + +## @backstage/backend-tasks@0.5.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/backend-test-utils@0.2.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@0.5.10-next.1 + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/cli@0.25.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.6.1-next.0 + - @backstage/cli-node@0.2.2-next.0 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/release-manifests@0.0.11 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + - @backstage/eslint-plugin@0.1.4 + - @backstage/types@1.1.1 + +## @backstage/cli-node@0.2.2-next.0 + +### Patch Changes + +- 7acbb5a: Removed `mock-fs` dev dependency. +- Updated dependencies + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/config-loader@1.6.1-next.0 + +### Patch Changes + +- 7acbb5a: Removed `mock-fs` dev dependency. +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/core-app-api@1.11.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/core-compat-api@0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-app-api@1.11.3-next.0 + - @backstage/frontend-plugin-api@0.4.1-next.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/core-components@0.13.10-next.1 + +### Patch Changes + +- 6878b1d: Removed unnecessary `history` and `immer` dependencies. +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0 + - @backstage/version-bridge@1.0.7 + +## @backstage/core-plugin-api@1.8.2-next.0 + +### Patch Changes + +- 6878b1d: Removed unnecessary `i18next` dependency. +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/create-app@0.5.9-next.1 + +### Patch Changes + +- 7acbb5a: Removed `mock-fs` dev dependency. +- Updated dependencies + - @backstage/cli-common@0.1.13 + +## @backstage/dev-utils@1.0.26-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/app-defaults@1.4.7-next.1 + - @backstage/core-app-api@1.11.3-next.0 + - @backstage/integration-react@1.1.23-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0 + +## @backstage/frontend-app-api@0.4.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/core-app-api@1.11.3-next.0 + - @backstage/frontend-plugin-api@0.4.1-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/frontend-plugin-api@0.4.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/frontend-test-utils@0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-app-api@0.4.1-next.1 + - @backstage/frontend-plugin-api@0.4.1-next.1 + - @backstage/test-utils@1.4.7-next.1 + - @backstage/types@1.1.1 + +## @backstage/integration-react@1.1.23-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + +## @backstage/repo-tools@0.5.2-next.1 + +### Patch Changes + +- 7acbb5a: Removed `mock-fs` dev dependency. +- Updated dependencies + - @backstage/cli-node@0.2.2-next.0 + - @backstage/backend-common@0.20.1-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + +## @techdocs/cli@1.8.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-techdocs-node@1.11.1-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + +## @backstage/test-utils@1.4.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-app-api@1.11.3-next.0 + - @backstage/plugin-permission-react@0.4.19-next.1 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.11 + +## @backstage/plugin-adr@0.6.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/frontend-plugin-api@0.4.1-next.1 + - @backstage/integration-react@1.1.23-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/plugin-search-react@1.7.5-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-adr-common@0.2.18 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-adr-backend@0.4.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-adr-common@0.2.18 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-airbrake@0.3.29-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/dev-utils@1.0.26-next.1 + - @backstage/test-utils@1.4.7-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-airbrake-backend@0.3.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + +## @backstage/plugin-allure@0.1.45-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-analytics-module-ga@0.1.37-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/config@1.1.1 + +## @backstage/plugin-analytics-module-ga4@0.1.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/config@1.1.1 + +## @backstage/plugin-analytics-module-newrelic-browser@0.0.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/config@1.1.1 + +## @backstage/plugin-apache-airflow@0.2.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + +## @backstage/plugin-api-docs@0.10.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog@1.16.1-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-apollo-explorer@0.1.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + +## @backstage/plugin-app-backend@0.3.57-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.6.1-next.0 + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.9-next.1 + +## @backstage/plugin-app-node@0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.1 + +## @backstage/plugin-auth-backend@0.20.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.1.1-next.1 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.3-next.1 + - @backstage/plugin-auth-backend-module-github-provider@0.1.6-next.1 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.6-next.1 + - @backstage/plugin-auth-backend-module-google-provider@0.1.6-next.1 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.1.6-next.1 + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.1-next.1 + - @backstage/plugin-auth-backend-module-okta-provider@0.0.2-next.1 + - @backstage/plugin-catalog-node@1.6.1-next.1 + +## @backstage/plugin-auth-backend-module-atlassian-provider@0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + +## @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-auth-backend-module-github-provider@0.1.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + +## @backstage/plugin-auth-backend-module-gitlab-provider@0.1.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + +## @backstage/plugin-auth-backend-module-google-provider@0.1.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + +## @backstage/plugin-auth-backend-module-microsoft-provider@0.1.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + +## @backstage/plugin-auth-backend-module-oauth2-provider@0.1.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + +## @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-auth-backend-module-okta-provider@0.0.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + +## @backstage/plugin-auth-backend-module-pinniped-provider@0.1.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + +## @backstage/plugin-auth-backend-module-vmware-cloud-provider@0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-auth-node@0.4.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-azure-devops@0.3.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-azure-devops-common@0.3.2 + +## @backstage/plugin-azure-devops-backend@0.5.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-azure-devops-common@0.3.2 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-catalog-node@1.6.1-next.1 + +## @backstage/plugin-azure-sites@0.1.18-next.1 + +### Patch Changes + +- a31f688: Show Azure site tags in `EntityAzureSitesOverviewWidget`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-azure-sites-common@0.1.1 + +## @backstage/plugin-azure-sites-backend@0.1.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-azure-sites-common@0.1.1 + +## @backstage/plugin-badges@0.2.53-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-badges-backend@0.3.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-bazaar@0.2.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-bazaar-backend@0.3.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + +## @backstage/plugin-bitrise@0.1.56-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-catalog@1.16.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/core-compat-api@0.1.1-next.1 + - @backstage/frontend-plugin-api@0.4.1-next.1 + - @backstage/integration-react@1.1.23-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/plugin-permission-react@0.4.19-next.1 + - @backstage/plugin-search-react@1.7.5-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-scaffolder-common@1.4.4 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-catalog-backend@1.16.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/plugin-permission-node@0.7.20-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.13-next.1 + - @backstage/backend-openapi-utils@0.1.2-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + - @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-catalog-backend-module-aws@0.3.3-next.1 + +### Patch Changes + +- 22e88d0: Added status and e-mail as labels to the AWS Account Resource +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/integration-aws-node@0.1.8 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-catalog-node@1.6.1-next.1 + - @backstage/plugin-kubernetes-common@0.7.3-next.0 + +## @backstage/plugin-catalog-backend-module-azure@0.1.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-catalog-node@1.6.1-next.1 + +## @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/backend-openapi-utils@0.1.2-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-node@1.6.1-next.1 + +## @backstage/plugin-catalog-backend-module-bitbucket@0.2.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/plugin-bitbucket-cloud-common@0.2.15 + - @backstage/plugin-catalog-node@1.6.1-next.1 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.1.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-bitbucket-cloud-common@0.2.15 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-catalog-node@1.6.1-next.1 + - @backstage/plugin-events-node@0.2.18-next.1 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.1.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-node@1.6.1-next.1 + +## @backstage/plugin-catalog-backend-module-gcp@0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-node@1.6.1-next.1 + - @backstage/plugin-kubernetes-common@0.7.3-next.0 + +## @backstage/plugin-catalog-backend-module-gerrit@0.1.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-node@1.6.1-next.1 + +## @backstage/plugin-catalog-backend-module-github@0.4.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/plugin-catalog-backend@1.16.1-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-catalog-node@1.6.1-next.1 + - @backstage/plugin-events-node@0.2.18-next.1 + +## @backstage/plugin-catalog-backend-module-github-org@0.1.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/plugin-catalog-backend-module-github@0.4.7-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/plugin-catalog-node@1.6.1-next.1 + +## @backstage/plugin-catalog-backend-module-gitlab@0.3.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-node@1.6.1-next.1 + +## @backstage/plugin-catalog-backend-module-incremental-ingestion@0.4.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/plugin-catalog-backend@1.16.1-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @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-catalog-backend-module-ldap@0.5.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-catalog-node@1.6.1-next.1 + +## @backstage/plugin-catalog-backend-module-msgraph@0.5.16-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-catalog-node@1.6.1-next.1 + +## @backstage/plugin-catalog-backend-module-openapi@0.1.26-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-backend@1.16.1-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-catalog-node@1.6.1-next.1 + +## @backstage/plugin-catalog-backend-module-puppetdb@0.1.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-node@1.6.1-next.1 + +## @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-catalog-node@1.6.1-next.1 + - @backstage/plugin-scaffolder-common@1.4.4 + +## @backstage/plugin-catalog-backend-module-unprocessed@0.3.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-catalog-graph@0.3.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-import@0.10.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/core-compat-api@0.1.1-next.1 + - @backstage/frontend-plugin-api@0.4.1-next.1 + - @backstage/integration-react@1.1.23-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.19 + +## @backstage/plugin-catalog-node@1.6.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-node@0.7.20-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-permission-common@0.7.11 + +## @backstage/plugin-catalog-react@1.9.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/frontend-plugin-api@0.4.1-next.1 + - @backstage/integration-react@1.1.23-next.0 + - @backstage/plugin-permission-react@0.4.19-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-permission-common@0.7.11 + +## @backstage/plugin-catalog-unprocessed-entities@0.1.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-cicd-statistics@0.1.31-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-cicd-statistics-module-gitlab@0.1.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/plugin-cicd-statistics@0.1.31-next.1 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-circleci@0.3.29-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-cloudbuild@0.3.29-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-code-climate@0.1.29-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-code-coverage@0.2.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-code-coverage-backend@0.2.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-codescene@0.1.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-config-schema@0.1.49-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-cost-insights@0.12.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/config@1.1.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0 + - @backstage/plugin-cost-insights-common@0.1.2 + +## @backstage/plugin-devtools@0.1.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-permission-react@0.4.19-next.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-devtools-common@0.1.7 + +## @backstage/plugin-devtools-backend@0.2.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.6.1-next.0 + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/plugin-permission-node@0.7.20-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.7 + - @backstage/plugin-permission-common@0.7.11 + +## @backstage/plugin-dynatrace@8.0.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-entity-feedback@0.2.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## @backstage/plugin-entity-feedback-backend@0.2.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## @backstage/plugin-entity-validation@0.1.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.19 + +## @backstage/plugin-events-backend@0.2.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/plugin-events-node@0.2.18-next.1 + +## @backstage/plugin-events-backend-module-aws-sqs@0.2.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.18-next.1 + +## @backstage/plugin-events-backend-module-azure@0.1.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/plugin-events-node@0.2.18-next.1 + +## @backstage/plugin-events-backend-module-bitbucket-cloud@0.1.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/plugin-events-node@0.2.18-next.1 + +## @backstage/plugin-events-backend-module-gerrit@0.1.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/plugin-events-node@0.2.18-next.1 + +## @backstage/plugin-events-backend-module-github@0.1.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/plugin-events-node@0.2.18-next.1 + +## @backstage/plugin-events-backend-module-gitlab@0.1.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/plugin-events-node@0.2.18-next.1 + +## @backstage/plugin-events-backend-test-utils@0.1.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.2.18-next.1 + +## @backstage/plugin-events-node@0.2.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.1 + +## @backstage/plugin-explore@0.4.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/frontend-plugin-api@0.4.1-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/plugin-explore-react@0.0.35-next.1 + - @backstage/plugin-search-react@1.7.5-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-explore-backend@0.0.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-search-backend-module-explore@0.1.13-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + +## @backstage/plugin-explore-react@0.0.35-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/plugin-explore-common@0.0.2 + +## @backstage/plugin-firehydrant@0.2.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-fossa@0.2.61-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-gcalendar@0.3.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-gcp-projects@0.3.45-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + +## @backstage/plugin-git-release-manager@0.3.41-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/integration@1.8.0 + +## @backstage/plugin-github-actions@0.6.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/integration-react@1.1.23-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/integration@1.8.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-github-deployments@0.1.60-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/integration-react@1.1.23-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/integration@1.8.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-github-issues@0.2.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/integration@1.8.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-github-pull-requests-board@0.1.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/integration@1.8.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-gitops-profiles@0.3.44-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + +## @backstage/plugin-gocd@0.1.35-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-graphiql@0.3.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/core-compat-api@0.1.1-next.1 + - @backstage/frontend-plugin-api@0.4.1-next.1 + +## @backstage/plugin-graphql-voyager@0.1.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + +## @backstage/plugin-home@0.6.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/core-app-api@1.11.3-next.0 + - @backstage/core-compat-api@0.1.1-next.1 + - @backstage/frontend-plugin-api@0.4.1-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/plugin-home-react@0.1.7-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0 + +## @backstage/plugin-home-react@0.1.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + +## @backstage/plugin-ilert@0.2.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-jenkins@0.9.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-jenkins-common@0.1.22 + +## @backstage/plugin-jenkins-backend@0.3.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/plugin-permission-node@0.7.20-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-node@1.6.1-next.1 + - @backstage/plugin-jenkins-common@0.1.22 + - @backstage/plugin-permission-common@0.7.11 + +## @backstage/plugin-kafka@0.3.29-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-kafka-backend@0.3.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-kubernetes@0.11.4-next.1 + +### Patch Changes + +- d5d2c67: Add `authuser` search parameter to GKE cluster link formatter in k8s plugin + + Thanks to this, people with multiple simultaneously logged-in accounts in their GCP console will automatically view objects with the same email as the one signed in to the Google auth provider in Backstage. + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/plugin-kubernetes-react@0.2.1-next.1 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-kubernetes-common@0.7.3-next.0 + +## @backstage/plugin-kubernetes-backend@0.14.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration-aws-node@0.1.8 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/plugin-permission-node@0.7.20-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-node@1.6.1-next.1 + - @backstage/plugin-kubernetes-common@0.7.3-next.0 + - @backstage/plugin-kubernetes-node@0.1.3-next.1 + - @backstage/plugin-permission-common@0.7.11 + +## @backstage/plugin-kubernetes-cluster@0.0.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/plugin-kubernetes-react@0.2.1-next.1 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-kubernetes-common@0.7.3-next.0 + +## @backstage/plugin-kubernetes-node@0.1.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + - @backstage/plugin-kubernetes-common@0.7.3-next.0 + +## @backstage/plugin-kubernetes-react@0.2.1-next.1 + +### Patch Changes + +- d5d2c67: Add `authuser` search parameter to GKE cluster link formatter in k8s plugin + + Thanks to this, people with multiple simultaneously logged-in accounts in their GCP console will automatically view objects with the same email as the one signed in to the Google auth provider in Backstage. + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-kubernetes-common@0.7.3-next.0 + +## @backstage/plugin-lighthouse@0.4.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-lighthouse-common@0.1.4 + +## @backstage/plugin-lighthouse-backend@0.4.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-node@1.6.1-next.1 + - @backstage/plugin-lighthouse-common@0.1.4 + +## @backstage/plugin-linguist@0.1.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-linguist-common@0.1.2 + +## @backstage/plugin-linguist-backend@0.5.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-node@1.6.1-next.1 + - @backstage/plugin-linguist-common@0.1.2 + +## @backstage/plugin-microsoft-calendar@0.1.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-newrelic@0.3.44-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + +## @backstage/plugin-newrelic-dashboard@0.3.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-nomad@0.1.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-nomad-backend@0.1.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-octopus-deploy@0.2.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-opencost@0.2.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + +## @backstage/plugin-org@0.6.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.19 + +## @backstage/plugin-org-react@0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-pagerduty@0.7.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/plugin-home-react@0.1.7-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-periskop@0.1.27-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-periskop-backend@0.2.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + +## @backstage/plugin-permission-backend@0.5.32-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/plugin-permission-node@0.7.20-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-permission-common@0.7.11 + +## @backstage/plugin-permission-backend-module-allow-all-policy@0.1.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/plugin-permission-node@0.7.20-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/plugin-permission-common@0.7.11 + +## @backstage/plugin-permission-node@0.7.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-permission-common@0.7.11 + +## @backstage/plugin-permission-react@0.4.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/config@1.1.1 + - @backstage/plugin-permission-common@0.7.11 + +## @backstage/plugin-playlist@0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/plugin-permission-react@0.4.19-next.1 + - @backstage/plugin-search-react@1.7.5-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-playlist-common@0.1.13 + +## @backstage/plugin-playlist-backend@0.3.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/plugin-permission-node@0.7.20-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-playlist-common@0.1.13 + +## @backstage/plugin-proxy-backend@0.4.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + +## @backstage/plugin-puppetdb@0.1.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-rollbar@0.4.29-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-rollbar-backend@0.1.54-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + +## @backstage/plugin-scaffolder@1.17.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/integration-react@1.1.23-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/plugin-permission-react@0.4.19-next.1 + - @backstage/plugin-scaffolder-react@1.7.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-scaffolder-common@1.4.4 + +## @backstage/plugin-scaffolder-backend@1.19.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.2.12-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/plugin-permission-node@0.7.20-next.1 + - @backstage/plugin-scaffolder-backend-module-azure@0.1.1-next.1 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.1.1-next.1 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.1.1-next.1 + - @backstage/plugin-scaffolder-backend-module-github@0.1.1-next.1 + - @backstage/plugin-scaffolder-node@0.2.10-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.6-next.1 + - @backstage/plugin-catalog-node@1.6.1-next.1 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-scaffolder-common@1.4.4 + +## @backstage/plugin-scaffolder-backend-module-azure@0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.10-next.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-scaffolder-backend-module-bitbucket@0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.10-next.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.10-next.1 + +### Patch Changes + +- 7acbb5a: Removed `mock-fs` dev dependency. +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.10-next.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.2.33-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.10-next.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-gerrit@0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.10-next.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-scaffolder-backend-module-github@0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.10-next.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-scaffolder-backend-module-gitlab@0.2.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.10-next.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-scaffolder-backend-module-rails@0.4.26-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.10-next.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-sentry@0.1.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.10-next.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.2.30-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.10-next.1 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-node@0.2.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-common@1.4.4 + +## @backstage/plugin-scaffolder-react@1.7.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-scaffolder-common@1.4.4 + +## @backstage/plugin-search@1.4.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/core-compat-api@0.1.1-next.1 + - @backstage/frontend-plugin-api@0.4.1-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/plugin-search-react@1.7.5-next.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-search-backend@1.4.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/plugin-permission-node@0.7.20-next.1 + - @backstage/plugin-search-backend-node@1.2.13-next.1 + - @backstage/backend-openapi-utils@0.1.2-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-search-backend-module-catalog@0.1.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/plugin-search-backend-node@1.2.13-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-catalog-node@1.6.1-next.1 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-search-backend-module-elasticsearch@1.3.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration-aws-node@0.1.8 + - @backstage/config@1.1.1 + - @backstage/plugin-search-backend-node@1.2.13-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-search-backend-module-explore@0.1.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/plugin-search-backend-node@1.2.13-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-search-backend-module-pg@0.5.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-search-backend-node@1.2.13-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-search-backend-module-stack-overflow-collator@0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/plugin-search-backend-node@1.2.13-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-search-backend-module-techdocs@0.1.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/plugin-search-backend-node@1.2.13-next.1 + - @backstage/plugin-techdocs-node@1.11.1-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-catalog-node@1.6.1-next.1 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-search-backend-node@1.2.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-search-react@1.7.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/frontend-plugin-api@0.4.1-next.1 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-sentry@0.5.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-shortcuts@0.3.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-sonarqube@0.7.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/plugin-sonarqube-react@0.1.12-next.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-sonarqube-backend@0.2.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-sonarqube-react@0.1.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-splunk-on-call@0.4.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-stack-overflow@0.1.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/frontend-plugin-api@0.4.1-next.1 + - @backstage/plugin-home-react@0.1.7-next.1 + - @backstage/plugin-search-react@1.7.5-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-stack-overflow-backend@0.2.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-module-stack-overflow-collator@0.1.2-next.1 + +## @backstage/plugin-stackstorm@0.1.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-tech-insights@0.3.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-insights-backend@0.5.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/plugin-tech-insights-node@0.4.15-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.41-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/plugin-tech-insights-node@0.4.15-next.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-insights-node@0.4.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-radar@0.6.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/core-compat-api@0.1.1-next.1 + - @backstage/frontend-plugin-api@0.4.1-next.1 + +## @backstage/plugin-techdocs@1.9.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/core-compat-api@0.1.1-next.1 + - @backstage/frontend-plugin-api@0.4.1-next.1 + - @backstage/integration-react@1.1.23-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/plugin-search-react@1.7.5-next.1 + - @backstage/plugin-techdocs-react@1.1.15-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.26-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-app-api@1.11.3-next.0 + - @backstage/integration-react@1.1.23-next.0 + - @backstage/test-utils@1.4.7-next.1 + - @backstage/plugin-catalog@1.16.1-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/plugin-search-react@1.7.5-next.1 + - @backstage/plugin-techdocs@1.9.3-next.1 + - @backstage/plugin-techdocs-react@1.1.15-next.1 + +## @backstage/plugin-techdocs-backend@1.9.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.13-next.1 + - @backstage/plugin-techdocs-node@1.11.1-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-permission-common@0.7.11 + +## @backstage/plugin-techdocs-module-addons-contrib@1.1.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/integration-react@1.1.23-next.0 + - @backstage/plugin-techdocs-react@1.1.15-next.1 + - @backstage/integration@1.8.0 + +## @backstage/plugin-techdocs-node@1.11.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/integration-aws-node@0.1.8 + - @backstage/config@1.1.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-search-common@1.2.9 + +## @backstage/plugin-techdocs-react@1.1.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/config@1.1.1 + - @backstage/catalog-model@1.4.3 + - @backstage/version-bridge@1.0.7 + +## @backstage/plugin-todo@0.2.33-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-todo-backend@0.3.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/backend-openapi-utils@0.1.2-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-node@1.6.1-next.1 + +## @backstage/plugin-user-settings-backend@0.2.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-vault@0.1.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-vault-backend@0.4.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-vault-node@0.1.2-next.1 + +## @backstage/plugin-vault-node@0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.1 + +## @backstage/plugin-xcmetrics@0.2.47-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/errors@1.2.3 + +## example-app@0.2.91-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-azure-sites@0.1.18-next.1 + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/plugin-user-settings@0.8.0-next.1 + - @backstage/plugin-kubernetes@0.11.4-next.1 + - @backstage/core-components@0.13.10-next.1 + - @backstage/app-defaults@1.4.7-next.1 + - @backstage/cli@0.25.1-next.1 + - @backstage/core-app-api@1.11.3-next.0 + - @backstage/frontend-app-api@0.4.1-next.1 + - @backstage/integration-react@1.1.23-next.0 + - @backstage/plugin-adr@0.6.12-next.1 + - @backstage/plugin-airbrake@0.3.29-next.1 + - @backstage/plugin-apache-airflow@0.2.19-next.1 + - @backstage/plugin-api-docs@0.10.3-next.1 + - @backstage/plugin-azure-devops@0.3.11-next.1 + - @backstage/plugin-badges@0.2.53-next.1 + - @backstage/plugin-catalog@1.16.1-next.1 + - @backstage/plugin-catalog-graph@0.3.3-next.1 + - @backstage/plugin-catalog-import@0.10.5-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/plugin-catalog-unprocessed-entities@0.1.7-next.1 + - @backstage/plugin-cloudbuild@0.3.29-next.1 + - @backstage/plugin-code-coverage@0.2.22-next.1 + - @backstage/plugin-cost-insights@0.12.18-next.1 + - @backstage/plugin-devtools@0.1.8-next.1 + - @backstage/plugin-dynatrace@8.0.3-next.1 + - @backstage/plugin-entity-feedback@0.2.12-next.1 + - @backstage/plugin-explore@0.4.15-next.1 + - @backstage/plugin-gcalendar@0.3.22-next.1 + - @backstage/plugin-gcp-projects@0.3.45-next.1 + - @backstage/plugin-github-actions@0.6.10-next.1 + - @backstage/plugin-gocd@0.1.35-next.1 + - @backstage/plugin-graphiql@0.3.2-next.1 + - @backstage/plugin-home@0.6.1-next.1 + - @backstage/plugin-jenkins@0.9.4-next.1 + - @backstage/plugin-kafka@0.3.29-next.1 + - @backstage/plugin-kubernetes-cluster@0.0.5-next.1 + - @backstage/plugin-lighthouse@0.4.14-next.1 + - @backstage/plugin-linguist@0.1.14-next.1 + - @backstage/plugin-microsoft-calendar@0.1.11-next.1 + - @backstage/plugin-newrelic@0.3.44-next.1 + - @backstage/plugin-newrelic-dashboard@0.3.4-next.1 + - @backstage/plugin-nomad@0.1.10-next.1 + - @backstage/plugin-octopus-deploy@0.2.11-next.1 + - @backstage/plugin-org@0.6.19-next.1 + - @backstage/plugin-pagerduty@0.7.1-next.1 + - @backstage/plugin-permission-react@0.4.19-next.1 + - @backstage/plugin-playlist@0.2.3-next.1 + - @backstage/plugin-puppetdb@0.1.12-next.1 + - @backstage/plugin-rollbar@0.4.29-next.1 + - @backstage/plugin-scaffolder@1.17.1-next.1 + - @backstage/plugin-scaffolder-react@1.7.1-next.1 + - @backstage/plugin-search@1.4.5-next.1 + - @backstage/plugin-search-react@1.7.5-next.1 + - @backstage/plugin-sentry@0.5.14-next.1 + - @backstage/plugin-shortcuts@0.3.18-next.1 + - @backstage/plugin-stack-overflow@0.1.24-next.1 + - @backstage/plugin-stackstorm@0.1.10-next.1 + - @backstage/plugin-tech-insights@0.3.21-next.1 + - @backstage/plugin-tech-radar@0.6.12-next.1 + - @backstage/plugin-techdocs@1.9.3-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.4-next.1 + - @backstage/plugin-techdocs-react@1.1.15-next.1 + - @backstage/plugin-todo@0.2.33-next.1 + - @backstage/config@1.1.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.9 + +## example-app-next@0.0.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-azure-sites@0.1.18-next.1 + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/plugin-user-settings@0.8.0-next.1 + - @backstage/plugin-kubernetes@0.11.4-next.1 + - @backstage/core-components@0.13.10-next.1 + - @backstage/app-defaults@1.4.7-next.1 + - @backstage/cli@0.25.1-next.1 + - @backstage/core-app-api@1.11.3-next.0 + - @backstage/core-compat-api@0.1.1-next.1 + - @backstage/frontend-app-api@0.4.1-next.1 + - @backstage/frontend-plugin-api@0.4.1-next.1 + - @backstage/integration-react@1.1.23-next.0 + - @backstage/plugin-adr@0.6.12-next.1 + - @backstage/plugin-airbrake@0.3.29-next.1 + - @backstage/plugin-apache-airflow@0.2.19-next.1 + - @backstage/plugin-api-docs@0.10.3-next.1 + - @backstage/plugin-azure-devops@0.3.11-next.1 + - @backstage/plugin-badges@0.2.53-next.1 + - @backstage/plugin-catalog@1.16.1-next.1 + - @backstage/plugin-catalog-graph@0.3.3-next.1 + - @backstage/plugin-catalog-import@0.10.5-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/plugin-catalog-unprocessed-entities@0.1.7-next.1 + - @backstage/plugin-cloudbuild@0.3.29-next.1 + - @backstage/plugin-code-coverage@0.2.22-next.1 + - @backstage/plugin-cost-insights@0.12.18-next.1 + - @backstage/plugin-devtools@0.1.8-next.1 + - @backstage/plugin-dynatrace@8.0.3-next.1 + - @backstage/plugin-entity-feedback@0.2.12-next.1 + - @backstage/plugin-explore@0.4.15-next.1 + - @backstage/plugin-gcalendar@0.3.22-next.1 + - @backstage/plugin-gcp-projects@0.3.45-next.1 + - @backstage/plugin-github-actions@0.6.10-next.1 + - @backstage/plugin-gocd@0.1.35-next.1 + - @backstage/plugin-graphiql@0.3.2-next.1 + - @backstage/plugin-home@0.6.1-next.1 + - @backstage/plugin-jenkins@0.9.4-next.1 + - @backstage/plugin-kafka@0.3.29-next.1 + - @backstage/plugin-lighthouse@0.4.14-next.1 + - @backstage/plugin-linguist@0.1.14-next.1 + - @backstage/plugin-microsoft-calendar@0.1.11-next.1 + - @backstage/plugin-newrelic@0.3.44-next.1 + - @backstage/plugin-newrelic-dashboard@0.3.4-next.1 + - @backstage/plugin-octopus-deploy@0.2.11-next.1 + - @backstage/plugin-org@0.6.19-next.1 + - @backstage/plugin-pagerduty@0.7.1-next.1 + - @backstage/plugin-permission-react@0.4.19-next.1 + - @backstage/plugin-playlist@0.2.3-next.1 + - @backstage/plugin-puppetdb@0.1.12-next.1 + - @backstage/plugin-rollbar@0.4.29-next.1 + - @backstage/plugin-scaffolder@1.17.1-next.1 + - @backstage/plugin-scaffolder-react@1.7.1-next.1 + - @backstage/plugin-search@1.4.5-next.1 + - @backstage/plugin-search-react@1.7.5-next.1 + - @backstage/plugin-sentry@0.5.14-next.1 + - @backstage/plugin-shortcuts@0.3.18-next.1 + - @backstage/plugin-stackstorm@0.1.10-next.1 + - @backstage/plugin-tech-insights@0.3.21-next.1 + - @backstage/plugin-tech-radar@0.6.12-next.1 + - @backstage/plugin-techdocs@1.9.3-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.4-next.1 + - @backstage/plugin-techdocs-react@1.1.15-next.1 + - @backstage/plugin-todo@0.2.33-next.1 + - @backstage/plugin-visualizer@0.0.2-next.1 + - app-next-example-plugin@0.0.5-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.9 + +## app-next-example-plugin@0.0.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.10-next.1 + - @backstage/frontend-plugin-api@0.4.1-next.1 + +## example-backend@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 + +## example-backend-next@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 + +## @backstage/backend-plugin-manager@0.0.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/cli-node@0.2.2-next.0 + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/plugin-catalog-backend@1.16.1-next.1 + - @backstage/plugin-events-backend@0.2.18-next.1 + - @backstage/plugin-permission-node@0.7.20-next.1 + - @backstage/plugin-scaffolder-node@0.2.10-next.1 + - @backstage/plugin-search-backend-node@1.2.13-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.18-next.1 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-search-common@1.2.9 + +## e2e-test@0.2.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.9-next.1 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + +## techdocs-cli-embedded-app@0.2.90-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/app-defaults@1.4.7-next.1 + - @backstage/cli@0.25.1-next.1 + - @backstage/core-app-api@1.11.3-next.0 + - @backstage/integration-react@1.1.23-next.0 + - @backstage/test-utils@1.4.7-next.1 + - @backstage/plugin-catalog@1.16.1-next.1 + - @backstage/plugin-techdocs@1.9.3-next.1 + - @backstage/plugin-techdocs-react@1.1.15-next.1 + - @backstage/config@1.1.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0 + +## @internal/plugin-todo-list@1.0.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + +## @internal/plugin-todo-list-backend@1.0.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-visualizer@0.0.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/frontend-plugin-api@0.4.1-next.1 diff --git a/docs/releases/v1.22.0-next.2-changelog.md b/docs/releases/v1.22.0-next.2-changelog.md new file mode 100644 index 0000000000..c9dcfeff98 --- /dev/null +++ b/docs/releases/v1.22.0-next.2-changelog.md @@ -0,0 +1,1835 @@ +# Release v1.22.0-next.2 + +## @backstage/backend-app-api@0.5.10-next.2 + +### Patch Changes + +- 516fd3e: Updated README to reflect release status +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + - @backstage/plugin-permission-node@0.7.20-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + - @backstage/cli-node@0.2.2-next.0 + - @backstage/config-loader@1.6.1-next.0 + +## @backstage/backend-common@0.20.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-dev-utils@0.1.3-next.0 + - @backstage/backend-app-api@0.5.10-next.2 + - @backstage/config-loader@1.6.1-next.0 + +## @backstage/backend-defaults@0.2.9-next.2 + +### Patch Changes + +- 516fd3e: Updated README to reflect release status +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-app-api@0.5.10-next.2 + - @backstage/backend-common@0.20.1-next.2 + +## @backstage/backend-dev-utils@0.1.3-next.0 + +### Patch Changes + +- 516fd3e: Updated README to reflect release status + +## @backstage/backend-openapi-utils@0.1.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + +## @backstage/backend-plugin-api@0.6.9-next.2 + +### Patch Changes + +- 516fd3e: Updated README to reflect release status +- Updated dependencies + - @backstage/plugin-auth-node@0.4.3-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## @backstage/backend-tasks@0.5.14-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.2 + +## @backstage/backend-test-utils@0.2.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-app-api@0.5.10-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## @backstage/core-compat-api@0.1.1-next.2 + +### Patch Changes + +- 4c1f50c: Make `convertLegacyApp` wrap discovered routes with `compatWrapper`. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.1-next.2 + +## @backstage/create-app@0.5.9-next.2 + +### Patch Changes + +- Bumped create-app version. + +## @backstage/dev-utils@1.0.26-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + - @backstage/integration-react@1.1.23-next.0 + +## @backstage/frontend-app-api@0.4.1-next.2 + +### Patch Changes + +- 516fd3e: Updated README to reflect release status +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.1-next.2 + +## @backstage/frontend-plugin-api@0.4.1-next.2 + +### Patch Changes + +- 516fd3e: Updated README to reflect release status + +## @backstage/frontend-test-utils@0.1.1-next.2 + +### Patch Changes + +- 516fd3e: Updated README to reflect release status +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.1-next.2 + - @backstage/frontend-app-api@0.4.1-next.2 + +## @backstage/repo-tools@0.5.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.2 + - @backstage/cli-node@0.2.2-next.0 + +## @techdocs/cli@1.8.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-techdocs-node@1.11.1-next.2 + +## @backstage/plugin-adr@0.6.12-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.1-next.2 + - @backstage/plugin-catalog-react@1.9.3-next.2 + - @backstage/plugin-search-react@1.7.5-next.2 + - @backstage/integration-react@1.1.23-next.0 + +## @backstage/plugin-adr-backend@0.4.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + +## @backstage/plugin-airbrake@0.3.29-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + - @backstage/dev-utils@1.0.26-next.2 + +## @backstage/plugin-airbrake-backend@0.3.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + +## @backstage/plugin-allure@0.1.45-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-api-docs@0.10.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.16.1-next.2 + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-app-backend@0.3.57-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-app-node@0.1.9-next.2 + - @backstage/config-loader@1.6.1-next.0 + +## @backstage/plugin-app-node@0.1.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + +## @backstage/plugin-auth-backend@0.20.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.1.1-next.2 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.3-next.2 + - @backstage/plugin-auth-backend-module-github-provider@0.1.6-next.2 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.6-next.2 + - @backstage/plugin-auth-backend-module-google-provider@0.1.6-next.2 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.1.6-next.2 + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.1-next.2 + - @backstage/plugin-auth-backend-module-okta-provider@0.0.2-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + +## @backstage/plugin-auth-backend-module-atlassian-provider@0.1.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## @backstage/plugin-auth-backend-module-github-provider@0.1.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## @backstage/plugin-auth-backend-module-gitlab-provider@0.1.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## @backstage/plugin-auth-backend-module-google-provider@0.1.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## @backstage/plugin-auth-backend-module-microsoft-provider@0.1.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## @backstage/plugin-auth-backend-module-oauth2-provider@0.1.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## @backstage/plugin-auth-backend-module-okta-provider@0.0.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## @backstage/plugin-auth-backend-module-pinniped-provider@0.1.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## @backstage/plugin-auth-backend-module-vmware-cloud-provider@0.1.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## @backstage/plugin-auth-node@0.4.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + +## @backstage/plugin-azure-devops@0.3.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-azure-devops-backend@0.5.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + +## @backstage/plugin-azure-sites@0.1.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-azure-sites-backend@0.1.19-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.2 + +## @backstage/plugin-badges@0.2.53-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-badges-backend@0.3.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## @backstage/plugin-bazaar@0.2.21-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-bazaar-backend@0.3.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## @backstage/plugin-bitrise@0.1.56-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-catalog@1.16.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.1.1-next.2 + - @backstage/frontend-plugin-api@0.4.1-next.2 + - @backstage/plugin-catalog-react@1.9.3-next.2 + - @backstage/plugin-search-react@1.7.5-next.2 + - @backstage/integration-react@1.1.23-next.0 + +## @backstage/plugin-catalog-backend@1.16.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/backend-openapi-utils@0.1.2-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/plugin-events-node@0.2.18-next.2 + - @backstage/plugin-permission-node@0.7.20-next.2 + - @backstage/plugin-search-backend-module-catalog@0.1.13-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## @backstage/plugin-catalog-backend-module-aws@0.3.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## @backstage/plugin-catalog-backend-module-azure@0.1.28-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/backend-openapi-utils@0.1.2-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## @backstage/plugin-catalog-backend-module-bitbucket@0.2.24-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.1.24-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/plugin-events-node@0.2.18-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.1.22-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## @backstage/plugin-catalog-backend-module-gcp@0.1.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## @backstage/plugin-catalog-backend-module-gerrit@0.1.25-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## @backstage/plugin-catalog-backend-module-github@0.4.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-catalog-backend@1.16.1-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/plugin-events-node@0.2.18-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## @backstage/plugin-catalog-backend-module-github-org@0.1.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-catalog-backend-module-github@0.4.7-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## @backstage/plugin-catalog-backend-module-gitlab@0.3.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## @backstage/plugin-catalog-backend-module-incremental-ingestion@0.4.13-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-catalog-backend@1.16.1-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/plugin-events-node@0.2.18-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## @backstage/plugin-catalog-backend-module-ldap@0.5.24-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## @backstage/plugin-catalog-backend-module-msgraph@0.5.16-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## @backstage/plugin-catalog-backend-module-openapi@0.1.26-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-catalog-backend@1.16.1-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + +## @backstage/plugin-catalog-backend-module-puppetdb@0.1.14-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + +## @backstage/plugin-catalog-backend-module-unprocessed@0.3.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## @backstage/plugin-catalog-graph@0.3.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-catalog-import@0.10.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.1.1-next.2 + - @backstage/frontend-plugin-api@0.4.1-next.2 + - @backstage/plugin-catalog-react@1.9.3-next.2 + - @backstage/integration-react@1.1.23-next.0 + +## @backstage/plugin-catalog-node@1.6.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-permission-node@0.7.20-next.2 + +## @backstage/plugin-catalog-react@1.9.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.1-next.2 + - @backstage/integration-react@1.1.23-next.0 + +## @backstage/plugin-cicd-statistics@0.1.31-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-cicd-statistics-module-gitlab@0.1.25-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-cicd-statistics@0.1.31-next.2 + +## @backstage/plugin-circleci@0.3.29-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-cloudbuild@0.3.29-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-code-climate@0.1.29-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-code-coverage@0.2.22-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-code-coverage-backend@0.2.23-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## @backstage/plugin-cost-insights@0.12.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-devtools-backend@0.2.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + - @backstage/plugin-permission-node@0.7.20-next.2 + - @backstage/config-loader@1.6.1-next.0 + +## @backstage/plugin-dynatrace@8.0.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-entity-feedback@0.2.12-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-entity-feedback-backend@0.2.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## @backstage/plugin-entity-validation@0.1.14-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-events-backend@0.2.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-events-node@0.2.18-next.2 + +## @backstage/plugin-events-backend-module-aws-sqs@0.2.12-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-events-node@0.2.18-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## @backstage/plugin-events-backend-module-azure@0.1.19-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-events-node@0.2.18-next.2 + +## @backstage/plugin-events-backend-module-bitbucket-cloud@0.1.19-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-events-node@0.2.18-next.2 + +## @backstage/plugin-events-backend-module-gerrit@0.1.19-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-events-node@0.2.18-next.2 + +## @backstage/plugin-events-backend-module-github@0.1.19-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-events-node@0.2.18-next.2 + +## @backstage/plugin-events-backend-module-gitlab@0.1.19-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-events-node@0.2.18-next.2 + +## @backstage/plugin-events-backend-test-utils@0.1.19-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.2.18-next.2 + +## @backstage/plugin-events-node@0.2.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + +## @backstage/plugin-explore@0.4.15-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.1-next.2 + - @backstage/plugin-catalog-react@1.9.3-next.2 + - @backstage/plugin-search-react@1.7.5-next.2 + +## @backstage/plugin-explore-backend@0.0.19-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-search-backend-module-explore@0.1.13-next.2 + +## @backstage/plugin-firehydrant@0.2.13-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-fossa@0.2.61-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-github-actions@0.6.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + - @backstage/integration-react@1.1.23-next.0 + +## @backstage/plugin-github-deployments@0.1.60-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + - @backstage/integration-react@1.1.23-next.0 + +## @backstage/plugin-github-issues@0.2.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-github-pull-requests-board@0.1.23-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-gocd@0.1.35-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-graphiql@0.3.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.1.1-next.2 + - @backstage/frontend-plugin-api@0.4.1-next.2 + +## @backstage/plugin-home@0.6.1-next.2 + +### Patch Changes + +- 98ac5ab: Updated dependency `@rjsf/utils` to `5.15.1`. + Updated dependency `@rjsf/core` to `5.15.1`. + Updated dependency `@rjsf/material-ui` to `5.15.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.1`. +- Updated dependencies + - @backstage/core-compat-api@0.1.1-next.2 + - @backstage/frontend-plugin-api@0.4.1-next.2 + - @backstage/plugin-home-react@0.1.7-next.2 + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-home-react@0.1.7-next.2 + +### Patch Changes + +- 98ac5ab: Updated dependency `@rjsf/utils` to `5.15.1`. + Updated dependency `@rjsf/core` to `5.15.1`. + Updated dependency `@rjsf/material-ui` to `5.15.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.1`. + +## @backstage/plugin-ilert@0.2.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-jenkins@0.9.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-jenkins-backend@0.3.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/plugin-permission-node@0.7.20-next.2 + +## @backstage/plugin-kafka@0.3.29-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-kafka-backend@0.3.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + +## @backstage/plugin-kubernetes@0.11.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-kubernetes-backend@0.14.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/plugin-kubernetes-node@0.1.3-next.2 + - @backstage/plugin-permission-node@0.7.20-next.2 + +## @backstage/plugin-kubernetes-cluster@0.0.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-kubernetes-node@0.1.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + +## @backstage/plugin-lighthouse@0.4.14-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-lighthouse-backend@0.4.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## @backstage/plugin-linguist@0.1.14-next.2 + +### Patch Changes + +- 4f42918: Added alpha support for the New Frontend System (Declarative Integration) +- Updated dependencies + - @backstage/core-compat-api@0.1.1-next.2 + - @backstage/frontend-plugin-api@0.4.1-next.2 + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-linguist-backend@0.5.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## @backstage/plugin-newrelic-dashboard@0.3.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-nomad@0.1.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-nomad-backend@0.1.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + +## @backstage/plugin-octopus-deploy@0.2.11-next.2 + +### Patch Changes + +- 7d96ba8: added install path and fixed import on plugin-octopus-deploy +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-org@0.6.19-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-org-react@0.1.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-pagerduty@0.7.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-home-react@0.1.7-next.2 + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-periskop@0.1.27-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-periskop-backend@0.2.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + +## @backstage/plugin-permission-backend@0.5.32-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + - @backstage/plugin-permission-node@0.7.20-next.2 + +## @backstage/plugin-permission-backend-module-allow-all-policy@0.1.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + - @backstage/plugin-permission-node@0.7.20-next.2 + +## @backstage/plugin-permission-node@0.7.20-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## @backstage/plugin-playlist@0.2.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + - @backstage/plugin-search-react@1.7.5-next.2 + +## @backstage/plugin-playlist-backend@0.3.13-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + - @backstage/plugin-permission-node@0.7.20-next.2 + +## @backstage/plugin-proxy-backend@0.4.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + +## @backstage/plugin-puppetdb@0.1.12-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-rollbar@0.4.29-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-rollbar-backend@0.1.54-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.2 + +## @backstage/plugin-scaffolder@1.17.1-next.2 + +### Patch Changes + +- 98ac5ab: Updated dependency `@rjsf/utils` to `5.15.1`. + Updated dependency `@rjsf/core` to `5.15.1`. + Updated dependency `@rjsf/material-ui` to `5.15.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.1`. +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.7.1-next.2 + - @backstage/plugin-catalog-react@1.9.3-next.2 + - @backstage/integration-react@1.1.23-next.0 + +## @backstage/plugin-scaffolder-backend@1.19.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.6-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/plugin-permission-node@0.7.20-next.2 + - @backstage/plugin-scaffolder-node@0.2.10-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + - @backstage/plugin-scaffolder-backend-module-azure@0.1.1-next.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.1.1-next.2 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.1.1-next.2 + - @backstage/plugin-scaffolder-backend-module-github@0.1.1-next.2 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.2.12-next.2 + +## @backstage/plugin-scaffolder-backend-module-azure@0.1.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-scaffolder-node@0.2.10-next.2 + +## @backstage/plugin-scaffolder-backend-module-bitbucket@0.1.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-scaffolder-node@0.2.10-next.2 + +## @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-scaffolder-node@0.2.10-next.2 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.2.33-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-scaffolder-node@0.2.10-next.2 + +## @backstage/plugin-scaffolder-backend-module-gerrit@0.1.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.10-next.2 + +## @backstage/plugin-scaffolder-backend-module-github@0.1.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-scaffolder-node@0.2.10-next.2 + +## @backstage/plugin-scaffolder-backend-module-gitlab@0.2.12-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-scaffolder-node@0.2.10-next.2 + +## @backstage/plugin-scaffolder-backend-module-rails@0.4.26-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-scaffolder-node@0.2.10-next.2 + +## @backstage/plugin-scaffolder-backend-module-sentry@0.1.17-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.10-next.2 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.2.30-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.10-next.2 + +## @backstage/plugin-scaffolder-node@0.2.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + +## @backstage/plugin-scaffolder-react@1.7.1-next.2 + +### Patch Changes + +- 98ac5ab: Updated dependency `@rjsf/utils` to `5.15.1`. + Updated dependency `@rjsf/core` to `5.15.1`. + Updated dependency `@rjsf/material-ui` to `5.15.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.1`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-search@1.4.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.1.1-next.2 + - @backstage/frontend-plugin-api@0.4.1-next.2 + - @backstage/plugin-catalog-react@1.9.3-next.2 + - @backstage/plugin-search-react@1.7.5-next.2 + +## @backstage/plugin-search-backend@1.4.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/backend-openapi-utils@0.1.2-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + - @backstage/plugin-permission-node@0.7.20-next.2 + - @backstage/plugin-search-backend-node@1.2.13-next.2 + +## @backstage/plugin-search-backend-module-catalog@0.1.13-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/plugin-search-backend-node@1.2.13-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## @backstage/plugin-search-backend-module-elasticsearch@1.3.12-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-search-backend-node@1.2.13-next.2 + +## @backstage/plugin-search-backend-module-explore@0.1.13-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-search-backend-node@1.2.13-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## @backstage/plugin-search-backend-module-pg@0.5.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-search-backend-node@1.2.13-next.2 + +## @backstage/plugin-search-backend-module-stack-overflow-collator@0.1.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-search-backend-node@1.2.13-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## @backstage/plugin-search-backend-module-techdocs@0.1.13-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/plugin-search-backend-node@1.2.13-next.2 + - @backstage/plugin-techdocs-node@1.11.1-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## @backstage/plugin-search-backend-node@1.2.13-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## @backstage/plugin-search-react@1.7.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.1-next.2 + +## @backstage/plugin-sentry@0.5.14-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-sonarqube@0.7.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-sonarqube-backend@0.2.11-next.2 + +### Patch Changes + +- 53445cd: Updated README +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + +## @backstage/plugin-splunk-on-call@0.4.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-stack-overflow@0.1.24-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.1-next.2 + - @backstage/plugin-home-react@0.1.7-next.2 + - @backstage/plugin-search-react@1.7.5-next.2 + +## @backstage/plugin-stack-overflow-backend@0.2.13-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-module-stack-overflow-collator@0.1.2-next.2 + +## @backstage/plugin-tech-insights@0.3.21-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-tech-insights-backend@0.5.23-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + - @backstage/plugin-tech-insights-node@0.4.15-next.2 + +## @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.41-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-tech-insights-node@0.4.15-next.2 + +## @backstage/plugin-tech-insights-node@0.4.15-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.2 + +## @backstage/plugin-tech-radar@0.6.12-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.1.1-next.2 + - @backstage/frontend-plugin-api@0.4.1-next.2 + +## @backstage/plugin-techdocs@1.9.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.1.1-next.2 + - @backstage/frontend-plugin-api@0.4.1-next.2 + - @backstage/plugin-catalog-react@1.9.3-next.2 + - @backstage/plugin-search-react@1.7.5-next.2 + - @backstage/integration-react@1.1.23-next.0 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.26-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.16.1-next.2 + - @backstage/plugin-techdocs@1.9.3-next.2 + - @backstage/plugin-catalog-react@1.9.3-next.2 + - @backstage/plugin-search-react@1.7.5-next.2 + - @backstage/integration-react@1.1.23-next.0 + +## @backstage/plugin-techdocs-backend@1.9.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-search-backend-module-techdocs@0.1.13-next.2 + - @backstage/plugin-techdocs-node@1.11.1-next.2 + +## @backstage/plugin-techdocs-node@1.11.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + +## @backstage/plugin-todo@0.2.33-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-todo-backend@0.3.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/backend-openapi-utils@0.1.2-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + +## @backstage/plugin-user-settings@0.8.0-next.2 + +### Patch Changes + +- eea0849: add user-settings declarative integration core nav item +- Updated dependencies + - @backstage/core-compat-api@0.1.1-next.2 + - @backstage/frontend-plugin-api@0.4.1-next.2 + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-user-settings-backend@0.2.8-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## @backstage/plugin-vault@0.1.24-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## @backstage/plugin-vault-backend@0.4.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-vault-node@0.1.2-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## @backstage/plugin-vault-node@0.1.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + +## example-app@0.2.91-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-user-settings@0.8.0-next.2 + - @backstage/plugin-octopus-deploy@0.2.11-next.2 + - @backstage/frontend-app-api@0.4.1-next.2 + - @backstage/plugin-home@0.6.1-next.2 + - @backstage/plugin-scaffolder-react@1.7.1-next.2 + - @backstage/plugin-scaffolder@1.17.1-next.2 + - @backstage/plugin-linguist@0.1.14-next.2 + - @backstage/plugin-catalog@1.16.1-next.2 + - @backstage/plugin-catalog-import@0.10.5-next.2 + - @backstage/plugin-graphiql@0.3.2-next.2 + - @backstage/plugin-search@1.4.5-next.2 + - @backstage/plugin-tech-radar@0.6.12-next.2 + - @backstage/plugin-techdocs@1.9.3-next.2 + - @backstage/plugin-adr@0.6.12-next.2 + - @backstage/plugin-catalog-react@1.9.3-next.2 + - @backstage/plugin-explore@0.4.15-next.2 + - @backstage/plugin-search-react@1.7.5-next.2 + - @backstage/plugin-stack-overflow@0.1.24-next.2 + - @backstage/cli@0.25.1-next.1 + - @backstage/plugin-pagerduty@0.7.1-next.2 + - @backstage/plugin-api-docs@0.10.3-next.2 + - @backstage/plugin-catalog-graph@0.3.3-next.2 + - @backstage/plugin-org@0.6.19-next.2 + - @backstage/plugin-airbrake@0.3.29-next.2 + - @backstage/plugin-azure-devops@0.3.11-next.2 + - @backstage/plugin-azure-sites@0.1.18-next.2 + - @backstage/plugin-badges@0.2.53-next.2 + - @backstage/plugin-cloudbuild@0.3.29-next.2 + - @backstage/plugin-code-coverage@0.2.22-next.2 + - @backstage/plugin-cost-insights@0.12.18-next.2 + - @backstage/plugin-dynatrace@8.0.3-next.2 + - @backstage/plugin-entity-feedback@0.2.12-next.2 + - @backstage/plugin-github-actions@0.6.10-next.2 + - @backstage/plugin-gocd@0.1.35-next.2 + - @backstage/plugin-jenkins@0.9.4-next.2 + - @backstage/plugin-kafka@0.3.29-next.2 + - @backstage/plugin-kubernetes@0.11.4-next.2 + - @backstage/plugin-kubernetes-cluster@0.0.5-next.2 + - @backstage/plugin-lighthouse@0.4.14-next.2 + - @backstage/plugin-newrelic-dashboard@0.3.4-next.2 + - @backstage/plugin-nomad@0.1.10-next.2 + - @backstage/plugin-playlist@0.2.3-next.2 + - @backstage/plugin-puppetdb@0.1.12-next.2 + - @backstage/plugin-rollbar@0.4.29-next.2 + - @backstage/plugin-sentry@0.5.14-next.2 + - @backstage/plugin-tech-insights@0.3.21-next.2 + - @backstage/plugin-todo@0.2.33-next.2 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.4-next.1 + - @backstage/integration-react@1.1.23-next.0 + - @backstage/plugin-apache-airflow@0.2.19-next.1 + - @backstage/plugin-catalog-unprocessed-entities@0.1.7-next.1 + - @backstage/plugin-devtools@0.1.8-next.1 + - @backstage/plugin-gcalendar@0.3.22-next.1 + - @backstage/plugin-gcp-projects@0.3.45-next.1 + - @backstage/plugin-microsoft-calendar@0.1.11-next.1 + - @backstage/plugin-newrelic@0.3.44-next.1 + - @backstage/plugin-shortcuts@0.3.18-next.1 + - @backstage/plugin-stackstorm@0.1.10-next.1 + +## example-app-next@0.0.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.1.1-next.2 + - @backstage/plugin-user-settings@0.8.0-next.2 + - @backstage/plugin-octopus-deploy@0.2.11-next.2 + - @backstage/frontend-plugin-api@0.4.1-next.2 + - @backstage/frontend-app-api@0.4.1-next.2 + - @backstage/plugin-home@0.6.1-next.2 + - @backstage/plugin-scaffolder-react@1.7.1-next.2 + - @backstage/plugin-scaffolder@1.17.1-next.2 + - @backstage/plugin-linguist@0.1.14-next.2 + - @backstage/plugin-catalog@1.16.1-next.2 + - @backstage/plugin-catalog-import@0.10.5-next.2 + - @backstage/plugin-graphiql@0.3.2-next.2 + - @backstage/plugin-search@1.4.5-next.2 + - @backstage/plugin-tech-radar@0.6.12-next.2 + - @backstage/plugin-techdocs@1.9.3-next.2 + - app-next-example-plugin@0.0.5-next.2 + - @backstage/plugin-adr@0.6.12-next.2 + - @backstage/plugin-catalog-react@1.9.3-next.2 + - @backstage/plugin-explore@0.4.15-next.2 + - @backstage/plugin-search-react@1.7.5-next.2 + - @backstage/plugin-visualizer@0.0.2-next.2 + - @backstage/cli@0.25.1-next.1 + - @backstage/plugin-pagerduty@0.7.1-next.2 + - @backstage/plugin-api-docs@0.10.3-next.2 + - @backstage/plugin-catalog-graph@0.3.3-next.2 + - @backstage/plugin-org@0.6.19-next.2 + - @backstage/plugin-airbrake@0.3.29-next.2 + - @backstage/plugin-azure-devops@0.3.11-next.2 + - @backstage/plugin-azure-sites@0.1.18-next.2 + - @backstage/plugin-badges@0.2.53-next.2 + - @backstage/plugin-cloudbuild@0.3.29-next.2 + - @backstage/plugin-code-coverage@0.2.22-next.2 + - @backstage/plugin-cost-insights@0.12.18-next.2 + - @backstage/plugin-dynatrace@8.0.3-next.2 + - @backstage/plugin-entity-feedback@0.2.12-next.2 + - @backstage/plugin-github-actions@0.6.10-next.2 + - @backstage/plugin-gocd@0.1.35-next.2 + - @backstage/plugin-jenkins@0.9.4-next.2 + - @backstage/plugin-kafka@0.3.29-next.2 + - @backstage/plugin-kubernetes@0.11.4-next.2 + - @backstage/plugin-lighthouse@0.4.14-next.2 + - @backstage/plugin-newrelic-dashboard@0.3.4-next.2 + - @backstage/plugin-playlist@0.2.3-next.2 + - @backstage/plugin-puppetdb@0.1.12-next.2 + - @backstage/plugin-rollbar@0.4.29-next.2 + - @backstage/plugin-sentry@0.5.14-next.2 + - @backstage/plugin-tech-insights@0.3.21-next.2 + - @backstage/plugin-todo@0.2.33-next.2 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.4-next.1 + - @backstage/integration-react@1.1.23-next.0 + - @backstage/plugin-apache-airflow@0.2.19-next.1 + - @backstage/plugin-catalog-unprocessed-entities@0.1.7-next.1 + - @backstage/plugin-devtools@0.1.8-next.1 + - @backstage/plugin-gcalendar@0.3.22-next.1 + - @backstage/plugin-gcp-projects@0.3.45-next.1 + - @backstage/plugin-microsoft-calendar@0.1.11-next.1 + - @backstage/plugin-newrelic@0.3.44-next.1 + - @backstage/plugin-shortcuts@0.3.18-next.1 + - @backstage/plugin-stackstorm@0.1.10-next.1 + +## app-next-example-plugin@0.0.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.1-next.2 + +## example-backend@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 + +## example-backend-next@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 + +## @backstage/backend-plugin-manager@0.0.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + - @backstage/plugin-catalog-backend@1.16.1-next.2 + - @backstage/plugin-events-backend@0.2.18-next.2 + - @backstage/plugin-events-node@0.2.18-next.2 + - @backstage/plugin-permission-node@0.7.20-next.2 + - @backstage/plugin-scaffolder-node@0.2.10-next.2 + - @backstage/plugin-search-backend-node@1.2.13-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + - @backstage/cli-node@0.2.2-next.0 + +## e2e-test@0.2.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.9-next.2 + +## techdocs-cli-embedded-app@0.2.90-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.16.1-next.2 + - @backstage/plugin-techdocs@1.9.3-next.2 + - @backstage/cli@0.25.1-next.1 + - @backstage/integration-react@1.1.23-next.0 + +## @internal/plugin-todo-list-backend@1.0.21-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## @backstage/plugin-visualizer@0.0.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.1-next.2 diff --git a/docs/releases/v1.22.0.md b/docs/releases/v1.22.0.md new file mode 100644 index 0000000000..e5ce345ccc --- /dev/null +++ b/docs/releases/v1.22.0.md @@ -0,0 +1,69 @@ +--- +id: v1.22.0 +title: v1.22.0 +description: Backstage Release v1.22.0 +--- + +These are the release notes for the v1.22.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 + +### Updates to new frontend system + +There have been several updates to alpha packages in the new frontend system including a breaking change where the `app/router` extension was renamed to `app/root`. Furthermore `elements`, `wrappers`, and `router` were added as inputs to `app/root` making it possible to pass extensions into the root of the app. + +### Plugins and modules migrated to the New Backend System + +Some more features have been migrated to the new backend system: + +- `@backstage/plugin-auth-backend-module-microsoft-provider` +- `@backstage/plugin-auth-backend-module-pinniped-provider` +- `@backstage/plugin-catalog-backend-module-openapi` +- `@backstage/plugin-events-backend-module-azure` +- `@backstage/plugin-events-backend-module-bitbucket-cloud` +- `@backstage/plugin-events-backend-module-gerrit` +- `@backstage/plugin-linguist` + +### New plugin: App Visualizer + +This release includes the new `@backstage/plugin-app-visualizer` package. This plugin for the new frontend system lets you browse and view the extension structure of your app as a graph, detailed list, or in text form. + +### New feature: Dynamic Feature Service + +This release includes the new `@backstage/backend-dynamic-feature-service` package. +It is a new and experimental service that lets you dynamically detect and load local plugins and modules in your Backstage instance. + +Contributed by [@davidfestal](https://github.com/davidfestal) in [#18862](https://github.com/backstage/backstage/pull/18862) + +### New Scaffolder action `gitlab:issues:create` + +You can now create GitHub issues in your scaffolder flows! Contributed by [@elaine-mattos](https://github.com/elaine-mattos) in [#21929](https://github.com/backstage/backstage/pull/21929) + +### New Scaffolder action `gitlab:repo:push` + +You can now push raw branches to GitLab in your scaffolder flows! Contributed by [@gavlyukovskiy](https://github.com/gavlyukovskiy) in [#21977](https://github.com/backstage/backstage/pull/21977) + +## Security Fixes + +This release does not contain any security fixes. + +However, some updates were made to the build facilities in the CLI and the caches in the backend system, such that you can now perform builds on FIPS compliant systems. This may lead to some internal cache invalidation happening, since the hashing algorithms used were updated. This should not pose a problem unless caches were being used as reliable persistent storage systems. Please let us know if you encounter any issues that may be related to this. + +## 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.22.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/tutorials/migrate-to-mui5.md b/docs/tutorials/migrate-to-mui5.md new file mode 100644 index 0000000000..aaf8cff7f5 --- /dev/null +++ b/docs/tutorials/migrate-to-mui5.md @@ -0,0 +1,65 @@ +--- +id: migrate-to-mui5 +title: Migrating from Material UI v4 to v5 +description: Additional resources for the Material UI v5 migration guide specifically for Backstage +--- + +Backstage supports developing new plugins or components using Material UI v5. At the same time, large parts of the application as well as existing plugins will still be using Material UI v4. To support Material UI v4 and v5 at the same time, we have introduced a new concept called the `UnifiedTheme`. The goal of the `UnifiedTheme` is to allow gradual migration by running both versions in parallel, applying theme options similarly & supporting potential future versions of Material UI. + +By default, the `UnifiedThemeProvider` is already used. If you add a custom theme in your `createApp` function, you would need to replace the Material UI `ThemeProvider` with the `UnifiedThemeProvider`: + +```diff ts ++ import import { ++ UnifiedThemeProvider, ++ themes as builtinThemes, ++ } from '@backstage/theme'; + + const app = createApp({ + // ... + themes: [ + { + // ... + provider: ({ children }) => ( +- . +- {children}. +- + ), + } + ] + }); +``` + +Before making specific changes to your Backstage instance, it might be helpful to take a look at the [Migration Guide provided by Material UI](https://mui.com/material-ui/migration/migration-v4/) first. It breaks down the differences between v4 and v5, and will make it easier to understand the impact on your Backstage instance & plugins. + +It is worth noting that we are still using `@mui/styles` & `jss`. You may stumble upon documentation for migrating to `emotion` when using `makeStyles` or `withStyles`. It is not necessary to switch to `emotion`. + +Important to keep in mind is that Material UI v5 is meant to be used with React Version 17 or higher. This means if you intend to use the Material UI v5 components in your plugins, you have to enforce React Version to be at least 17 for these plugins: + +```json +... + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0", + "react-router-dom": "6.0.0-beta.0 || ^6.3.0" + }, +... +``` + +To comply with Material UI recommendations, we are enforcing a new linting rule that favors standard imports over named imports and also restricts 3rd-level imports as they are considered private ([Guide: Minimizing Bundle Size](https://mui.com/material-ui/guides/minimizing-bundle-size)). + +There are `core-components` as well as components exported from Backstage `*-react` plugins written in Material UI v4, which expect Material UI components as props. In these cases you will still be forced to use Material UI v4. + +For current known issues with the Material UI v5 migration, follow our [Milestone on GitHub](https://github.com/backstage/backstage/milestone/40). Please open a new issue if you run into different problems. + +### Plugins + +To migrate your plugin to Material UI v5, you can build on the resources available. + +1. Manually fix the imports from named to default imports to match the new [linting rules for minimizing bundle size](https://mui.com/material-ui/guides/minimizing-bundle-size). Note: you can use the [new `@backstage/no-top-level-material-ui-4-imports` ESLint](https://github.com/backstage/backstage/blob/master/packages/eslint-plugin/docs/rules/no-top-level-material-ui-4-imports.md) rule to help with this. +2. Run the migration `codemod` for the path of the specific plugin: `npx @mui/codemod v5.0.0/preset-safe plugins/`. +3. Take a look at possible `TODO:` items the `codemod` could not fix. +4. Remove types & methods from `@backstage/theme` which are marked as `@deprecated`. +5. Ensure you are using `"react": "^17.0.0"` (or newer) as a peer dependency + +You can follow the [migration of the GraphiQL plugin](https://github.com/backstage/backstage/pull/17696) as an example of a plugin migration. diff --git a/docs/tutorials/setup-opentelemetry.md b/docs/tutorials/setup-opentelemetry.md new file mode 100644 index 0000000000..b85cbd4398 --- /dev/null +++ b/docs/tutorials/setup-opentelemetry.md @@ -0,0 +1,69 @@ +--- +id: setup-opentelemetry +title: Setup OpenTelemetry +description: Tutorial to setup OpenTelemetry metrics and traces exporters in Backstage +--- + +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. + +## 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. +The `auto-instrumentations-node` will automatically create spans for code called in libraries like Express. + +```bash +yarn --cwd packages/backend add @opentelemetry/sdk-node \ + @opentelemetry/auto-instrumentations-node \ + @opentelemetry/sdk-metrics +``` + +## Configure + +In your `packages/backend/src` folder, create an `instrumentation.ts` file. + +```typescript +import { NodeSDK } from '@opentelemetry/sdk-node'; +import { ConsoleSpanExporter } from '@opentelemetry/sdk-trace-node'; +import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'; +import { + PeriodicExportingMetricReader, + ConsoleMetricExporter, +} from '@opentelemetry/sdk-metrics'; + +const sdk = new NodeSDK({ + traceExporter: new ConsoleSpanExporter(), + metricReader: new PeriodicExportingMetricReader({ + exporter: new ConsoleMetricExporter(), + }), + instrumentations: [getNodeAutoInstrumentations()], +}); + +sdk.start(); +``` + +In the `index.ts`, import this file **at the beginning**: + +```typescript +import './instrumentation'; // Setup the OpenTelemetry instrumentation + +// other imports and backend init... +``` + +It's important to setup the NodeSDK and the automatic instrumentation **before** importing any library. + +## Run Backstage + +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 using [OTLP exporters](https://opentelemetry.io/docs/instrumentation/js/exporters/). + +## References + +- [Getting started with OpenTelemetry Node.js](https://opentelemetry.io/docs/instrumentation/js/getting-started/nodejs/) +- [OpenTelemetry NodeSDK API](https://open-telemetry.github.io/opentelemetry-js/classes/_opentelemetry_sdk_node.NodeSDK.html) diff --git a/microsite/blog/2023-02-15-backend-system-alpha.mdx b/microsite/blog/2023-02-15-backend-system-alpha.mdx index 28ff7bdf6b..24004d00b6 100644 --- a/microsite/blog/2023-02-15-backend-system-alpha.mdx +++ b/microsite/blog/2023-02-15-backend-system-alpha.mdx @@ -7,6 +7,8 @@ authorImageURL: https://avatars.githubusercontent.com/u/4984472?v=4 ![backend system alpha header image](assets/2023-02-15/backend-system-alpha.gif) +> UPDATE: The backend system is now released! See [the v1.18 release notes](https://backstage.io/docs/releases/v1.18.0). + For the past year, the Backstage maintainer team has been spending time to give the [old Backstage backend system](https://backstage.io/docs/plugins/backend-plugin) a much needed revamp. Our goal was not to build something completely new from scratch, but rather to solidify the existing foundations that have grown organically. We wanted to make plugin installation a lot simpler, while maintaining and even improving the ways in which you can customize your backend setups. We’re happy to announce that the [v1.11](https://backstage.io/docs/releases/v1.11.0) release includes the public alpha of the [new Backstage backend system](https://backstage.io/docs/backend-system/)! The system has already been available to use for some time, as some of you have already found, but this alpha release marks the point where we are finally ready to encourage widespread adoption by plugin builders. We still don’t recommend that you use this new system in your production setups just yet, more on that later. diff --git a/microsite/blog/2023-11-15-backstagecon-kubecon-23.mdx b/microsite/blog/2023-11-15-backstagecon-kubecon-23.mdx new file mode 100644 index 0000000000..7b7f7c0f0b --- /dev/null +++ b/microsite/blog/2023-11-15-backstagecon-kubecon-23.mdx @@ -0,0 +1,72 @@ +--- +# prettier-ignore +title: "Wrap up: BackstageCon ‘23, KubeCon + Cloud Native NA" +author: Jorge Lainfiesta, Spotify +authorURL: https://www.linkedin.com/in/jrlainfiesta/ +authorImageURL: https://avatars.githubusercontent.com/u/4451393?v=4 +--- + +![BackstageCon ‘23, KubeCon + Cloud Native NA](assets/23-11-15/00-cover.png) + +tl;dr BackstageCon North America is officially in the books! We had a blast in Chicago talking about Backstage non-stop throughout the week at both BackstageCon and KubeCon. If you weren't able to join us, the [BackstageCon talks are available](https://www.youtube.com/playlist?list=PLj6h78yzYM2PxiInfZi2OKu1KluNfbLtc) for replay on the CNCF YouTube channel. +{/* truncate */} + +Obviously we're biased, but Backstage was definitely one of the big topics at [KubeCon + CloudNativeCon North America](https://events.linuxfoundation.org/kubecon-cloudnativecon-north-america/) this year. Recently, the CNCF announced that Backstage was the [third fastest-growing project](https://www.cncf.io/blog/2023/10/27/october-2023-where-we-are-with-velocity-of-cncf-lf-and-top-30-open-source-projects/) of the year (up from the fifth last year). And you could confirm it with your own eyes during BackstageCon and KubeCon: hundreds of people flocked through the event, talks, and the project booth sharing their enthusiasm and asking more questions about the project. + +### BackstageCon: A growing community  + +With a whopping peak attendance of 400+ people, the crowd nearly doubled from last year,[ taking the center stage of the conference](https://www.forbes.com/sites/janakirammsv/2023/11/14/backstage-project-takes-center-stage-at-kubecon-north-america-2023/?sh=1972303a6539), as reported by Forbes. For some, BackstageCon was their first entry point into the community, but the event also boasted lots of  familiar faces, mostly from some of the most mature adopters such as Dynatrace, Lunar, and US Bank. We also got to hear from new voices in the community like Comcast and Grafana Labs. + +We hear a lot of great questions such as: + +- How do I make more developers use my developer portal? + +- Will generative AI take my Backstage instance to the next level? + +- What's all the fuss around the upcoming Declarative Integration in Backstage? + +The community got together to discuss these and more questions with exciting talks and debates. The talks were all recorded and are [up on YouTube](https://www.youtube.com/playlist?list=PLj6h78yzYM2PxiInfZi2OKu1KluNfbLtc), so make sure to check them out. + +**Driving Backstage adoption** + +Growing adoption was top of mind during BackstageCon. David Tuite, CEO of Roadie, shared the lessons learned from interviewing 20 adopters, which revealed that the Scaffolder was a prime place to get started when adopting Backstage, as it lets stakeholders get an easily measurable ROI. + +![Panel of Backstage adopters](assets/23-11-15/10-panel.jpg) + +Helen Greul, Head of Engineering for Backstage at Spotify, hosted [a panel discussion](https://www.youtube.com/watch?v=Iti5glzYOG8&list=PLj6h78yzYM2PxiInfZi2OKu1KluNfbLtc&index=10) with four adopters that are using Backstage at scale: Twilio, Lunar Bank, US Bank, and Expedia. The crucial role of Backstage in fostering inner sourcing and simplifying new hires onboarding were a few of the subjects covered in the panel. + +How adopters are using Backstage was also a highlight of the day. B3, Brazil's Stock Exchange, shared [how they're building their developer portal](https://www.youtube.com/watch?v=FyWCKIVYO7g&list=PLj6h78yzYM2PxiInfZi2OKu1KluNfbLtc&index=14). And from Grafana Labs, we heard how they're using [Backstage along Crossplane to drive GitOps](https://www.youtube.com/watch?v=q-JUWob69Hw&list=PLj6h78yzYM2PxiInfZi2OKu1KluNfbLtc&index=10). + +**What's next with Backstage?** + +The discussion on how Backstage is evolving was featured in a few talks, through live demos that — remarkably — did not go wrong even once! Ben ([benjdlambert](https://github.com/benjdlambert)) and Patrik ([Rugvip](https://github.com/Rugvip)), core maintainers, presented an introduction to the plans around [Declarative Integration](https://www.youtube.com/watch?v=8hVMNMXXN44&list=PLj6h78yzYM2PxiInfZi2OKu1KluNfbLtc&index=8), which will allow people to install plugins without dealing with TypeScript or React. On the other hand, Djamaile and Mitch, from Spotify, [introduced the upcoming Quickstart](https://www.youtube.com/watch?v=bUdaO9NKXJY&list=PLj6h78yzYM2PxiInfZi2OKu1KluNfbLtc&index=12), a tool from Spotify in private-beta that will allow anyone to get started with Backstage through a GUI in a few steps. + +**A thriving community** + +People gathered outside the conference room where BackstageCon was happening to catch up with each other and learn from the event sponsors. It was great to connect with everyone and talk about how everyone is using Backstage. + +![KubeCon Attendees](assets/23-11-15/20-booth.jpg) + +![Spotify at BackstageCon](assets/23-11-15/30-spotify-kubecon.jpg) + +### Mom, Backstage is not a phase + +The interest from the cloud-native community in Backstage did not waver this year. Instead, the Backstage booth in the KubeCon Project Pavillion saw a nonstop flux of visitors asking more about the project. There were three talks featuring Backstage during KubeCon. + +**Backstage talks during KubeCon NA '23** + +The first talk touching on Backstage of the schedule was Tim Hansen's ([timbonicus](https://github.com/timbonicus)) "Everything Is Code: Embracing GitOps at Spotify," who achieved rockstar status thanks to his phenomenal insights. The queue to ask questions after the talk's questions was surreal! + +![KubeCon Attendees](assets/23-11-15/40-tim-talk.jpg) + +Backstage maintainers Ben and Patrik addressed a full-room during their talk “Simplifying Backstage - Breaking the Code Barrier” in which they explained Declarative Integration, how it works and the expected migration path. Declarative Integration will enable adopters to install the plugins they use—and even customize them—without dealing with TypeScript or React. + +![KubeCon Attendees](assets/23-11-15/50-patrik-ben-full.jpg) + +And to close the event, Ritesh Patel, Nirmata and David Murphy, Upbound, introduced the BACK Stack, which stands for Backstage, Argo, Crossplane, and Kyverno. These four tools make up a powerful combo that can enable self-service workflows secure and scalable. After a great demo, the speakers presented a reference architecture that can help guide an approach to using Backstage to build your platform. + +![KubeCon Attendees](assets/23-11-15/60-back-stack.jpg) + +### See you next year! + +The next KubeCon Europe is scheduled for March 18-22 in Paris. We're looking forward to meeting you all there! [KubeCon EU](https://events.linuxfoundation.org/kubecon-cloudnativecon-europe/program/cfp/) and[ BackstageCon EU](https://events.linuxfoundation.org/kubecon-cloudnativecon-europe/co-located-events/backstagecon/) are accepting CFPs, submit your proposal now! diff --git a/microsite/blog/assets/23-11-15/00-cover.png b/microsite/blog/assets/23-11-15/00-cover.png new file mode 100644 index 0000000000..18da63a930 Binary files /dev/null and b/microsite/blog/assets/23-11-15/00-cover.png differ diff --git a/microsite/blog/assets/23-11-15/10-panel.jpg b/microsite/blog/assets/23-11-15/10-panel.jpg new file mode 100644 index 0000000000..a6ebf8dcae Binary files /dev/null and b/microsite/blog/assets/23-11-15/10-panel.jpg differ diff --git a/microsite/blog/assets/23-11-15/20-booth.jpg b/microsite/blog/assets/23-11-15/20-booth.jpg new file mode 100644 index 0000000000..4faa5a5f1f Binary files /dev/null and b/microsite/blog/assets/23-11-15/20-booth.jpg differ diff --git a/microsite/blog/assets/23-11-15/30-spotify-kubecon.jpg b/microsite/blog/assets/23-11-15/30-spotify-kubecon.jpg new file mode 100644 index 0000000000..fa64ec451f Binary files /dev/null and b/microsite/blog/assets/23-11-15/30-spotify-kubecon.jpg differ diff --git a/microsite/blog/assets/23-11-15/40-tim-talk.jpg b/microsite/blog/assets/23-11-15/40-tim-talk.jpg new file mode 100644 index 0000000000..73873bcb4c Binary files /dev/null and b/microsite/blog/assets/23-11-15/40-tim-talk.jpg differ diff --git a/microsite/blog/assets/23-11-15/50-patrik-ben-full.jpg b/microsite/blog/assets/23-11-15/50-patrik-ben-full.jpg new file mode 100644 index 0000000000..2048dd2f5a Binary files /dev/null and b/microsite/blog/assets/23-11-15/50-patrik-ben-full.jpg differ diff --git a/microsite/blog/assets/23-11-15/60-back-stack.jpg b/microsite/blog/assets/23-11-15/60-back-stack.jpg new file mode 100644 index 0000000000..668fc407da Binary files /dev/null and b/microsite/blog/assets/23-11-15/60-back-stack.jpg differ diff --git a/microsite/data/plugins/announcements.yaml b/microsite/data/plugins/announcements.yaml index d03c1a1bd7..4d53f4157a 100644 --- a/microsite/data/plugins/announcements.yaml +++ b/microsite/data/plugins/announcements.yaml @@ -1,10 +1,10 @@ --- title: Announcements -author: K-Phoen -authorUrl: https://github.com/K-Phoen +author: procore-oss +authorUrl: https://github.com/procore-oss category: Discovery description: Write and share announcements within Backstage. -documentation: https://github.com/K-Phoen/backstage-plugin-announcements/ +documentation: https://github.com/procore-oss/backstage-plugin-announcements/ iconUrl: /img/plugin-announcements-logo.png -npmPackageName: '@k-phoen/backstage-plugin-announcements' +npmPackageName: '@procore-oss/backstage-plugin-announcements' addedDate: '2022-11-09' diff --git a/microsite/data/plugins/api-wsdl.yaml b/microsite/data/plugins/api-wsdl.yaml new file mode 100644 index 0000000000..6523531f1d --- /dev/null +++ b/microsite/data/plugins/api-wsdl.yaml @@ -0,0 +1,10 @@ +--- +title: WSDL / SOAP viewer +author: dweber019 +authorUrl: https://github.com/dweber019 +category: Discovery +description: An API docs extension to render WSDL / SOAP web services human readable. +documentation: https://github.com/dweber019/backstage-plugin-api-docs-module-wsdl +iconUrl: https://raw.githubusercontent.com/dweber019/backstage-plugin-api-docs-module-wsdl/main/docs/logo.png +npmPackageName: '@dweber019/backstage-plugin-api-docs-module-wsdl' +addedDate: '2023-12-22' diff --git a/microsite/data/plugins/azure-storage.yaml b/microsite/data/plugins/azure-storage.yaml new file mode 100644 index 0000000000..655a6421ed --- /dev/null +++ b/microsite/data/plugins/azure-storage.yaml @@ -0,0 +1,14 @@ +--- +title: Azure Storage Explorer +author: Deepankumar +authorUrl: https://github.com/deepan10 +category: Infrastructure +description: Explore Azure Storage Blobs in Backstage. +documentation: https://github.com/deepan10/backstage-plugins/tree/main/plugins/azure-storage +iconUrl: /img/azure-storage-folder.png +npmPackageName: 'backstage-plugin-azure-storage' +tags: + - Azure + - Azure Storage + - Infrastructure +addedDate: '2023-12-01' diff --git a/microsite/data/plugins/circleci.yaml b/microsite/data/plugins/circleci.yaml index 5d7978624b..5980f8cf45 100644 --- a/microsite/data/plugins/circleci.yaml +++ b/microsite/data/plugins/circleci.yaml @@ -1,12 +1,12 @@ --- title: CircleCI -author: Spotify -authorUrl: https://github.com/spotify +author: CircleCI +authorUrl: https://circleci.com/ category: CI/CD description: Automate your development process with CI hosted in the cloud or on a private server. -documentation: https://github.com/backstage/backstage/tree/master/plugins/circleci +documentation: https://github.com/CircleCI-Public/backstage-plugin/tree/main/plugins/circleci iconUrl: /img/circleci.png -npmPackageName: '@backstage/plugin-circleci' +npmPackageName: '@circleci/backstage-plugin' tags: - ci - cd diff --git a/microsite/data/plugins/dev-quotes.yaml b/microsite/data/plugins/dev-quotes.yaml new file mode 100644 index 0000000000..ad2ac91e4c --- /dev/null +++ b/microsite/data/plugins/dev-quotes.yaml @@ -0,0 +1,10 @@ +--- +title: Dev Quotes +author: Peter Macdonald +authorUrl: https://github.com/Parsifal-M +category: Humor +description: Displays a coding/progamming related quote designed as a footer for the Homepage, although to be honest it can be used anywhere you like! +documentation: https://github.com/Parsifal-M/backstage-dev-quotes?tab=readme-ov-file#dev-quotes-homepage +iconUrl: /img/dqicon.png +npmPackageName: '@parsifal-m/plugin-dev-quotes-homepage' +addedDate: '2023-12-13' diff --git a/microsite/data/plugins/festive-fun.yaml b/microsite/data/plugins/festive-fun.yaml new file mode 100644 index 0000000000..33995eca27 --- /dev/null +++ b/microsite/data/plugins/festive-fun.yaml @@ -0,0 +1,10 @@ +--- +title: Festive Fun +author: benjmac +authorUrl: https://github.com/benjmac +category: Humor +description: Festive, seasonal, animations to spice up your instance of Backstage! +documentation: https://github.com/benjmac/backstage-plugin-festive-fun/ +iconUrl: https://raw.githubusercontent.com/benjmac/backstage-plugin-festive-fun/main/docs/festive-fun-logo.png +npmPackageName: 'backstage-plugin-festive-fun' +addedDate: '2023-11-20' diff --git a/microsite/data/plugins/harness-srm.yaml b/microsite/data/plugins/harness-srm.yaml new file mode 100644 index 0000000000..d55c60ea04 --- /dev/null +++ b/microsite/data/plugins/harness-srm.yaml @@ -0,0 +1,14 @@ +--- +title: Harness Service Reliability Management +author: harness.io +authorUrl: https://github.com/harness/backstage-plugins +category: Quality +description: This plugin tracks the defined SLOs and Error Budgets for your Monitored services in Harness SRM Module. +documentation: https://github.com/harness/backstage-plugins/tree/main/plugins/harness-srm +iconUrl: https://static.harness.io/ng-static/images/favicon.png +npmPackageName: '@harnessio/backstage-plugin-harness-srm' +tags: + - service-reliability-management + - slo + - sli +addedDate: '2023-11-17' diff --git a/microsite/data/plugins/hcp-consul.yaml b/microsite/data/plugins/hcp-consul.yaml new file mode 100644 index 0000000000..6dabad582e --- /dev/null +++ b/microsite/data/plugins/hcp-consul.yaml @@ -0,0 +1,10 @@ +--- +title: HCP Consul +author: Hashicorp +authorUrl: https://www.hashicorp.com/ +category: Infrastructure +description: View your HCP Consul clusters, services, instances in Backstage. +documentation: https://github.com/hashicorp-forge/backstage-plugin-hcp-consul/tree/main +iconUrl: /img/hcp-consul.svg +npmPackageName: '@hashicorp/plugin-hcp-consul' +addedDate: '2023-11-24' diff --git a/microsite/data/plugins/highlights.yaml b/microsite/data/plugins/highlights.yaml new file mode 100644 index 0000000000..82d303f4ed --- /dev/null +++ b/microsite/data/plugins/highlights.yaml @@ -0,0 +1,12 @@ +--- +title: Highlights +author: RSC Labs +authorUrl: https://rsoftcon.com/ +category: Discovery +description: Highlight what is important for you and put it on front for the quick view and access. Built-in support of Git information from GitHub and GitLab. +documentation: https://github.com/RSC-Labs/backstage-highlights-plugin/blob/main/README.md +iconUrl: https://raw.githubusercontent.com/RSC-Labs/backstage-highlights-plugin/main/docs/highlighter.png +npmPackageName: '@rsc-labs/backstage-highlights-plugin' +tags: + - highlights +addedDate: '2023-11-20' diff --git a/microsite/data/plugins/jira-dashboard.yaml b/microsite/data/plugins/jira-dashboard.yaml new file mode 100644 index 0000000000..8cb9351c8d --- /dev/null +++ b/microsite/data/plugins/jira-dashboard.yaml @@ -0,0 +1,10 @@ +--- +title: Jira Dashboard +author: AxisCommunications +authorUrl: https://github.com/AxisCommunications +category: Agile Planning +description: Allows you to fetch and display Jira issues for your entity. You get quickly access to issue summaries to achieve better task visibility and more efficient project management. +documentation: https://github.com/AxisCommunications/backstage-plugins/blob/main/plugins/jira-dashboard/README.md +iconUrl: https://raw.githubusercontent.com/AxisCommunications/backstage-plugins/main/plugins/jira-dashboard/media/jira-logo.png +npmPackageName: '@axis-backstage/plugin-jira-dashboard' +addedDate: '2023-12-07' diff --git a/microsite/data/plugins/nobl9.yaml b/microsite/data/plugins/nobl9.yaml new file mode 100644 index 0000000000..ee447fd626 --- /dev/null +++ b/microsite/data/plugins/nobl9.yaml @@ -0,0 +1,10 @@ +--- +title: Nobl9 +author: Nobl9 +authorUrl: https://nobl9.com +category: Reliability +description: View and drill down into the reliability of your services via Nobl9 SLOs and error budgets. +documentation: https://github.com/nobl9/nobl9-backstage-plugin/blob/main/README.MD +iconUrl: /img/nobl9.svg +npmPackageName: '@nobl9/nobl9-backstage-plugin' +addedDate: '2023-12-15' diff --git a/microsite/data/plugins/open-dora.yaml b/microsite/data/plugins/open-dora.yaml new file mode 100644 index 0000000000..16b4c63969 --- /dev/null +++ b/microsite/data/plugins/open-dora.yaml @@ -0,0 +1,10 @@ +--- +title: OpenDORA +author: Devoteam +authorUrl: https://www.devoteam.com/ +category: Monitoring +description: View DORA metrics within Backstage using DevLake. +documentation: https://github.com/DevoteamNL/opendora/tree/main/backstage-plugin/plugins/open-dora#readme +iconUrl: /img/open-dora-icon.png +npmPackageName: '@devoteam-nl/open-dora-backstage-plugin' +addedDate: '2023-11-29' diff --git a/microsite/data/plugins/opencost.yaml b/microsite/data/plugins/opencost.yaml index dbf65979ca..950b0606a7 100644 --- a/microsite/data/plugins/opencost.yaml +++ b/microsite/data/plugins/opencost.yaml @@ -5,6 +5,6 @@ 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 -iconUrl: img/opencost.png +iconUrl: /img/opencost.png npmPackageName: '@backstage/plugin-opencost' addedDate: '2023-10-26' diff --git a/microsite/data/plugins/pager-duty.yaml b/microsite/data/plugins/pager-duty.yaml index a4e6e42d47..7d603a37c1 100644 --- a/microsite/data/plugins/pager-duty.yaml +++ b/microsite/data/plugins/pager-duty.yaml @@ -1,12 +1,12 @@ --- title: PagerDuty -author: Spotify -authorUrl: https://github.com/spotify +author: PagerDuty +authorUrl: https://github.com/pagerduty category: Monitoring -description: PagerDuty offers a simple way to identify any active incidents for an entity and the escalation policy. -documentation: https://github.com/backstage/backstage/tree/master/plugins/pagerduty +description: Bring the power of PagerDuty to Backstage, reduce cognitive load, improve service visibility and enforce incident management best practices. +documentation: https://pagerduty.github.io/backstage-plugin-docs/index.html iconUrl: https://avatars2.githubusercontent.com/u/766800?s=200&v=4 -npmPackageName: '@backstage/plugin-pagerduty' +npmPackageName: '@pagerduty/backstage-plugin' tags: - monitoring - errors diff --git a/microsite/data/plugins/readme.yaml b/microsite/data/plugins/readme.yaml new file mode 100644 index 0000000000..c914efe355 --- /dev/null +++ b/microsite/data/plugins/readme.yaml @@ -0,0 +1,10 @@ +--- +title: Readme +author: AxisCommunications +authorUrl: https://github.com/AxisCommunications +category: Metadata +description: The Readme-plugin enables easy access and viewing of the README.md file in your entity overview. +documentation: https://github.com/AxisCommunications/backstage-plugins/blob/main/plugins/readme/README.md +iconUrl: https://raw.githubusercontent.com/AxisCommunications/backstage-plugins/main/plugins/readme/media/readme.png +npmPackageName: '@axis-backstage/plugin-readme' +addedDate: '2023-12-07' diff --git a/microsite/data/plugins/scaffolder-backend-odo.yaml b/microsite/data/plugins/scaffolder-backend-odo.yaml new file mode 100644 index 0000000000..954d51ecb2 --- /dev/null +++ b/microsite/data/plugins/scaffolder-backend-odo.yaml @@ -0,0 +1,10 @@ +--- +title: Scaffolder odo CLI actions +author: Red Hat +authorUrl: https://developers.redhat.com +category: Scaffolder +description: Collection of actions to run odo CLI commands. odo is a developer-focused CLI for container-based application development on Podman and Kubernetes. +documentation: https://github.com/redhat-developer/backstage-odo-devfile-plugin/blob/main/packages/scaffolder-odo-actions-backend/README.md +iconUrl: https://odo.dev/img/logo.png +npmPackageName: '@redhat-developer/plugin-scaffolder-odo-actions' +addedDate: '2023-12-08' diff --git a/microsite/data/plugins/scaffolder-backend-slack.yaml b/microsite/data/plugins/scaffolder-backend-slack.yaml index dce7b60eb7..a726751eaf 100644 --- a/microsite/data/plugins/scaffolder-backend-slack.yaml +++ b/microsite/data/plugins/scaffolder-backend-slack.yaml @@ -5,6 +5,6 @@ authorUrl: https://github.com/arhill05 category: Scaffolder description: Interact with Slack from scaffolder templates documentation: https://github.com/arhill05/backstage-plugin-scaffolder-backend-module-slack#readme -iconUrl: img/Slack-mark-RGB.png +iconUrl: /img/Slack-mark-RGB.png npmPackageName: '@mdude2314/backstage-plugin-scaffolder-backend-module-slack' addedDate: '2023-08-04' diff --git a/microsite/data/plugins/scaffolder-frontend-devfile-field.yaml b/microsite/data/plugins/scaffolder-frontend-devfile-field.yaml new file mode 100644 index 0000000000..3215c63795 --- /dev/null +++ b/microsite/data/plugins/scaffolder-frontend-devfile-field.yaml @@ -0,0 +1,10 @@ +--- +title: Devfile Selector Field Extension +author: Red Hat +authorUrl: https://developers.redhat.com +category: Scaffolder +description: Devfile Selector Field Extension to use in your Software Templates. Devfile is an open standard defining containerized development environments. +documentation: https://github.com/redhat-developer/backstage-odo-devfile-plugin/blob/main/packages/devfile-field-extension/README.md +iconUrl: https://landscape.cncf.io/logos/devfile.svg +npmPackageName: '@redhat-developer/plugin-scaffolder-frontend-module-devfile-field' +addedDate: '2023-12-08' diff --git a/microsite/data/plugins/search-backend-module-azure-devops-wiki.yaml b/microsite/data/plugins/search-backend-module-azure-devops-wiki.yaml index 02d4131cce..cc8849ee08 100644 --- a/microsite/data/plugins/search-backend-module-azure-devops-wiki.yaml +++ b/microsite/data/plugins/search-backend-module-azure-devops-wiki.yaml @@ -5,6 +5,6 @@ authorUrl: https://github.com/arhill05 category: Search description: Index wiki articles from an Azure DevOps wiki into Backstage to allow you to search them with the Backstage Search feature. documentation: https://github.com/arhill05/backstage-plugin-search-backend-module-azure-devops-wiki#readme -iconUrl: img/ado-wiki-search-icon.png +iconUrl: /img/ado-wiki-search-icon.png npmPackageName: '@mdude2314/backstage-plugin-search-backend-module-azure-devops-wiki' addedDate: '2023-06-13' diff --git a/microsite/data/plugins/snyk-security.yaml b/microsite/data/plugins/snyk-security.yaml index 4abd068247..8c22d44510 100644 --- a/microsite/data/plugins/snyk-security.yaml +++ b/microsite/data/plugins/snyk-security.yaml @@ -5,6 +5,6 @@ authorUrl: https://snyk.io category: Security description: View Snyk scanned vulnerabilities and license compliance of your components directly in Backstage. documentation: https://github.com/snyk-tech-services/backstage-plugin-snyk/blob/main/README.md -iconUrl: https://storage.googleapis.com/snyk-technical-services.appspot.com/snyk-logo-vertical-black.png +iconUrl: https://github.com/snyk-tech-services/backstage-plugin-snyk/assets/109112986/95eb1b06-b3e8-4910-9233-11926e02fa18 npmPackageName: 'backstage-plugin-snyk' addedDate: '2021-01-22' diff --git a/microsite/docusaurus.config.js b/microsite/docusaurus.config.js index f4dd76b8e3..3d175fb892 100644 --- a/microsite/docusaurus.config.js +++ b/microsite/docusaurus.config.js @@ -140,6 +140,10 @@ module.exports = { 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', + }, ], }, ], @@ -178,7 +182,7 @@ module.exports = { position: 'left', }, { - to: 'docs/releases/v1.19.0', + to: 'docs/releases/v1.22.0', label: 'Releases', position: 'left', }, @@ -200,7 +204,10 @@ module.exports = { { items: [ { - html: '', + html: ` + + + `, }, ], }, @@ -287,6 +294,9 @@ module.exports = { }, 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 { diff --git a/microsite/package.json b/microsite/package.json index 61bfcbd04a..53309fb358 100644 --- a/microsite/package.json +++ b/microsite/package.json @@ -6,6 +6,7 @@ "scripts": { "start": "node scripts/pre-build.js && docusaurus start", "build": "node scripts/pre-build.js && docusaurus build", + "prettier:fix": "prettier --write .", "prettier:check": "prettier --check .", "publish-gh-pages": "docusaurus-publish", "write-translations": "docusaurus-write-translations", @@ -33,7 +34,7 @@ "@docusaurus/plugin-client-redirects": "0.0.0-5703", "@docusaurus/preset-classic": "0.0.0-5703", "@swc/core": "^1.3.46", - "clsx": "^1.1.1", + "clsx": "^2.0.0", "docusaurus-plugin-sass": "^0.2.3", "luxon": "^3.0.0", "prism-react-renderer": "^1.3.5", diff --git a/microsite/sidebars.json b/microsite/sidebars.json index 8d8cb39eaa..c54e59f45c 100644 --- a/microsite/sidebars.json +++ b/microsite/sidebars.json @@ -1,6 +1,9 @@ { "releases": { "Release Notes": [ + "releases/v1.22.0", + "releases/v1.21.0", + "releases/v1.20.0", "releases/v1.19.0", "releases/v1.18.0", "releases/v1.17.0", @@ -116,7 +119,7 @@ "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/testing-scaffolder-alpha", + "features/software-templates/migrating-to-rjsf-v5", "features/software-templates/migrating-from-v1beta2-to-v1beta3" ] }, @@ -247,6 +250,15 @@ "plugins/internationalization", "plugins/analytics", "plugins/feature-flags", + { + "type": "category", + "label": "OpenAPI", + "items": [ + "openapi/01-getting-started", + "openapi/generate-client", + "openapi/test-case-validation" + ] + }, { "type": "category", "label": "Backends and APIs", @@ -379,6 +391,40 @@ "items": ["backend-system/core-services/index"] } ], + "New Frontend System": [ + "frontend-system/index", + { + "type": "category", + "label": "Architecture", + "items": [ + "frontend-system/architecture/index", + "frontend-system/architecture/app", + "frontend-system/architecture/extensions", + "frontend-system/architecture/plugins", + "frontend-system/architecture/extension-overrides", + "frontend-system/architecture/utility-apis", + "frontend-system/architecture/routes", + "frontend-system/architecture/naming-patterns", + "frontend-system/architecture/references" + ] + }, + { + "type": "category", + "label": "Building Plugins", + "items": ["frontend-system/building-plugins/testing"] + }, + { + "type": "category", + "label": "Utility APIs", + "items": [ + "frontend-system/utility-apis/index", + "frontend-system/utility-apis/creating", + "frontend-system/utility-apis/consuming", + "frontend-system/utility-apis/configuring", + "frontend-system/utility-apis/migrating" + ] + } + ], "Designing for Backstage": [ "dls/design", "dls/component-design-guidelines", @@ -407,7 +453,9 @@ "tutorials/configuring-plugin-databases", "tutorials/switching-sqlite-postgres", "tutorials/using-backstage-proxy-within-plugin", - "tutorials/yarn-migration" + "tutorials/yarn-migration", + "tutorials/migrate-to-mui5", + "tutorials/setup-opentelemetry" ], "Architecture Decision Records (ADRs)": [ "architecture-decisions/adrs-overview", diff --git a/microsite/src/pages/community/index.tsx b/microsite/src/pages/community/index.tsx index 82dd69d1a0..9b10183ea4 100644 --- a/microsite/src/pages/community/index.tsx +++ b/microsite/src/pages/community/index.tsx @@ -110,6 +110,11 @@ const Community = () => { url: 'https://frontside.com/backstage/', logo: 'img/partner-logo-frontside.png', }, + { + name: 'RedHat', + url: 'https://www.redhat.com/', + logo: 'img/partner-logo-redhat.png', + }, { name: 'Roadie', url: 'https://roadie.io/', diff --git a/microsite/src/pages/home/_home.tsx b/microsite/src/pages/home/_home.tsx index ddcfed7d03..5cf0f85072 100644 --- a/microsite/src/pages/home/_home.tsx +++ b/microsite/src/pages/home/_home.tsx @@ -95,10 +95,12 @@ const HomePage = () => { Illustration of a laptop Animated Backstage Logo diff --git a/microsite/src/pages/plugins/index.tsx b/microsite/src/pages/plugins/index.tsx index 006b7d4807..2abdbabf4b 100644 --- a/microsite/src/pages/plugins/index.tsx +++ b/microsite/src/pages/plugins/index.tsx @@ -151,6 +151,12 @@ const Plugins = () => { {showOtherPlugins && (

All Plugins

+

+ Friendly reminder: While we love the variety and contributions of + our open source plugins, they haven't been fully vetted by the + core Backstage team. We encourage you to exercise caution and do + your due diligence before installing. Happy exploring! +

{plugins.otherPlugins .filter( diff --git a/microsite/src/pages/plugins/plugins.module.scss b/microsite/src/pages/plugins/plugins.module.scss index 80ac60cf98..dbd0c62c75 100644 --- a/microsite/src/pages/plugins/plugins.module.scss +++ b/microsite/src/pages/plugins/plugins.module.scss @@ -78,6 +78,8 @@ :global(.dropdown) { float: right; margin-bottom: 1rem; + text-overflow: ellipsis; + white-space: nowrap; } :global(.button--info) { diff --git a/microsite/src/theme/customTheme.scss b/microsite/src/theme/customTheme.scss index f216762418..57e1f8828e 100644 --- a/microsite/src/theme/customTheme.scss +++ b/microsite/src/theme/customTheme.scss @@ -8,6 +8,14 @@ --ifm-color-primary-darkest: #268271; } +#__docusaurus { + .theme-doc-markdown { + a { + text-decoration: underline; + } + } +} + .footerLogo { background-image: url(/img/logo.svg); background-repeat: no-repeat; diff --git a/microsite/static/img/azure-storage-folder.png b/microsite/static/img/azure-storage-folder.png new file mode 100644 index 0000000000..479340c5b3 Binary files /dev/null and b/microsite/static/img/azure-storage-folder.png differ diff --git a/microsite/static/img/dqicon.png b/microsite/static/img/dqicon.png new file mode 100644 index 0000000000..3746841cd8 Binary files /dev/null and b/microsite/static/img/dqicon.png differ diff --git a/microsite/static/img/hcp-consul.svg b/microsite/static/img/hcp-consul.svg new file mode 100644 index 0000000000..d84972585c --- /dev/null +++ b/microsite/static/img/hcp-consul.svg @@ -0,0 +1,17 @@ + +Consul Logo + + + + + + + + + + + + + + + diff --git a/microsite/static/img/nobl9.svg b/microsite/static/img/nobl9.svg new file mode 100644 index 0000000000..a4065df602 --- /dev/null +++ b/microsite/static/img/nobl9.svg @@ -0,0 +1,4 @@ + + + + diff --git a/microsite/static/img/open-dora-icon.png b/microsite/static/img/open-dora-icon.png new file mode 100644 index 0000000000..3612fb06af Binary files /dev/null and b/microsite/static/img/open-dora-icon.png differ diff --git a/microsite/static/img/partner-logo-redhat.png b/microsite/static/img/partner-logo-redhat.png new file mode 100644 index 0000000000..ad9bc9ceba Binary files /dev/null and b/microsite/static/img/partner-logo-redhat.png differ diff --git a/microsite/yarn.lock b/microsite/yarn.lock index 10ad6d0d68..5e976cce69 100644 --- a/microsite/yarn.lock +++ b/microsite/yarn.lock @@ -2701,90 +2701,90 @@ __metadata: languageName: node linkType: hard -"@swc/core-darwin-arm64@npm:1.3.96": - version: 1.3.96 - resolution: "@swc/core-darwin-arm64@npm:1.3.96" +"@swc/core-darwin-arm64@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-darwin-arm64@npm:1.3.104" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@swc/core-darwin-x64@npm:1.3.96": - version: 1.3.96 - resolution: "@swc/core-darwin-x64@npm:1.3.96" +"@swc/core-darwin-x64@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-darwin-x64@npm:1.3.104" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@swc/core-linux-arm-gnueabihf@npm:1.3.96": - version: 1.3.96 - resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.96" +"@swc/core-linux-arm-gnueabihf@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.104" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@swc/core-linux-arm64-gnu@npm:1.3.96": - version: 1.3.96 - resolution: "@swc/core-linux-arm64-gnu@npm:1.3.96" +"@swc/core-linux-arm64-gnu@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-linux-arm64-gnu@npm:1.3.104" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-arm64-musl@npm:1.3.96": - version: 1.3.96 - resolution: "@swc/core-linux-arm64-musl@npm:1.3.96" +"@swc/core-linux-arm64-musl@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-linux-arm64-musl@npm:1.3.104" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@swc/core-linux-x64-gnu@npm:1.3.96": - version: 1.3.96 - resolution: "@swc/core-linux-x64-gnu@npm:1.3.96" +"@swc/core-linux-x64-gnu@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-linux-x64-gnu@npm:1.3.104" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-x64-musl@npm:1.3.96": - version: 1.3.96 - resolution: "@swc/core-linux-x64-musl@npm:1.3.96" +"@swc/core-linux-x64-musl@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-linux-x64-musl@npm:1.3.104" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@swc/core-win32-arm64-msvc@npm:1.3.96": - version: 1.3.96 - resolution: "@swc/core-win32-arm64-msvc@npm:1.3.96" +"@swc/core-win32-arm64-msvc@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-win32-arm64-msvc@npm:1.3.104" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@swc/core-win32-ia32-msvc@npm:1.3.96": - version: 1.3.96 - resolution: "@swc/core-win32-ia32-msvc@npm:1.3.96" +"@swc/core-win32-ia32-msvc@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-win32-ia32-msvc@npm:1.3.104" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@swc/core-win32-x64-msvc@npm:1.3.96": - version: 1.3.96 - resolution: "@swc/core-win32-x64-msvc@npm:1.3.96" +"@swc/core-win32-x64-msvc@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-win32-x64-msvc@npm:1.3.104" conditions: os=win32 & cpu=x64 languageName: node linkType: hard "@swc/core@npm:^1.3.46": - version: 1.3.96 - resolution: "@swc/core@npm:1.3.96" + version: 1.3.104 + resolution: "@swc/core@npm:1.3.104" dependencies: - "@swc/core-darwin-arm64": 1.3.96 - "@swc/core-darwin-x64": 1.3.96 - "@swc/core-linux-arm-gnueabihf": 1.3.96 - "@swc/core-linux-arm64-gnu": 1.3.96 - "@swc/core-linux-arm64-musl": 1.3.96 - "@swc/core-linux-x64-gnu": 1.3.96 - "@swc/core-linux-x64-musl": 1.3.96 - "@swc/core-win32-arm64-msvc": 1.3.96 - "@swc/core-win32-ia32-msvc": 1.3.96 - "@swc/core-win32-x64-msvc": 1.3.96 + "@swc/core-darwin-arm64": 1.3.104 + "@swc/core-darwin-x64": 1.3.104 + "@swc/core-linux-arm-gnueabihf": 1.3.104 + "@swc/core-linux-arm64-gnu": 1.3.104 + "@swc/core-linux-arm64-musl": 1.3.104 + "@swc/core-linux-x64-gnu": 1.3.104 + "@swc/core-linux-x64-musl": 1.3.104 + "@swc/core-win32-arm64-msvc": 1.3.104 + "@swc/core-win32-ia32-msvc": 1.3.104 + "@swc/core-win32-x64-msvc": 1.3.104 "@swc/counter": ^0.1.1 "@swc/types": ^0.1.5 peerDependencies: @@ -2813,7 +2813,7 @@ __metadata: peerDependenciesMeta: "@swc/helpers": optional: true - checksum: 41d4a4461b2952aaf8d3be945d373d0f3bd126115ee1aad0f76f2690e2b5635b6ec5bb54a7638deb9afedb1ad6f7d8453468a704e54e5fbb8234dd4a43b80205 + checksum: 95fbf1412c8685d311cf2d7efbfa43e082d2d9e84ece48c4d8d96d6c67c5923569bfb26352451eb3e4d98adcb556dcfac65271c0fba77f078bb755fe2f64b295 languageName: node linkType: hard @@ -3055,9 +3055,9 @@ __metadata: linkType: hard "@types/luxon@npm:^3.0.0": - version: 3.3.4 - resolution: "@types/luxon@npm:3.3.4" - checksum: aa4862bd62d748e7966f9a0ec76058e9d74397ee426c7d64f61c677d83de0303c303cc78515001833df3f4ad16c95f572b0e2ffaee6e55bc50b80857e8437f3a + version: 3.3.8 + resolution: "@types/luxon@npm:3.3.8" + checksum: 026711b4aefc01c6e233e359c693b6d4c0873acc3f52a08661ea3751b2cf3e34d1ce1d5b0b99b0e40a059a2a3755acc20498d37db5f9a5a4f0f330cdf72db3db languageName: node linkType: hard @@ -3897,7 +3897,7 @@ __metadata: "@tsconfig/docusaurus": ^2.0.0 "@types/luxon": ^3.0.0 "@types/webpack-env": ^1.18.0 - clsx: ^1.1.1 + clsx: ^2.0.0 docusaurus-plugin-sass: ^0.2.3 js-yaml: ^4.1.0 luxon: ^3.0.0 @@ -4375,13 +4375,20 @@ __metadata: languageName: node linkType: hard -"clsx@npm:^1.1.1, clsx@npm:^1.2.1": +"clsx@npm:^1.2.1": version: 1.2.1 resolution: "clsx@npm:1.2.1" checksum: 30befca8019b2eb7dbad38cff6266cf543091dae2825c856a62a8ccf2c3ab9c2907c4d12b288b73101196767f66812365400a227581484a05f968b0307cfaf12 languageName: node linkType: hard +"clsx@npm:^2.0.0": + version: 2.0.0 + resolution: "clsx@npm:2.0.0" + checksum: a2cfb2351b254611acf92faa0daf15220f4cd648bdf96ce369d729813b85336993871a4bf6978ddea2b81b5a130478339c20d9d0b5c6fc287e5147f0c059276e + languageName: node + linkType: hard + "color-convert@npm:^1.9.0": version: 1.9.3 resolution: "color-convert@npm:1.9.3" @@ -5867,12 +5874,12 @@ __metadata: linkType: hard "follow-redirects@npm:^1.0.0, follow-redirects@npm:^1.14.9": - version: 1.15.2 - resolution: "follow-redirects@npm:1.15.2" + version: 1.15.4 + resolution: "follow-redirects@npm:1.15.4" peerDependenciesMeta: debug: optional: true - checksum: faa66059b66358ba65c234c2f2a37fcec029dc22775f35d9ad6abac56003268baf41e55f9ee645957b32c7d9f62baf1f0b906e68267276f54ec4b4c597c2b190 + checksum: e178d1deff8b23d5d24ec3f7a94cde6e47d74d0dc649c35fc9857041267c12ec5d44650a0c5597ef83056ada9ea6ca0c30e7c4f97dbf07d035086be9e6a5b7b6 languageName: node linkType: hard @@ -10810,15 +10817,15 @@ __metadata: linkType: hard "sass@npm:^1.57.1": - version: 1.69.5 - resolution: "sass@npm:1.69.5" + version: 1.69.7 + resolution: "sass@npm:1.69.7" dependencies: chokidar: ">=3.0.0 <4.0.0" immutable: ^4.0.0 source-map-js: ">=0.6.2 <2.0.0" bin: sass: sass.js - checksum: c66f4f02882e7aa7aa49703824dadbb5a174dcd05e3cd96f17f73687889aab6027d078b518e2c04b594dfd89b2f574824bf935c7aee46c770aa6be9aafcc49f2 + checksum: c67cd32b69fb26a50e4535353e4145de8cbc8187db07c467cc335157fd56d03cae98754f86efe43b880b29f20c0a168ab972c7f74ebfe234e2bd2dfb868890cb languageName: node linkType: hard diff --git a/mkdocs.yml b/mkdocs.yml index de66c97884..bf4024759b 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -128,6 +128,10 @@ nav: - Composability System: 'plugins/composability.md' - Plugin Analytics: 'plugins/analytics.md' - Feature Flags: 'plugins/feature-flags.md' + - OpenAPI: + - Schema-first plugins with OpenAPI (Experimental): 'openapi/01-getting-started.md' + - Generate a client from your OpenAPI spec: 'openapi/generate-client.md' + - Validate your OpenAPI spec against test data: 'openapi/test-case-validation.md' - Backends and APIs: - Proxying: 'plugins/proxying.md' - Backend plugin: 'plugins/backend-plugin.md' @@ -193,6 +197,8 @@ nav: - Switching Backstage from SQLite to PostgreSQL: 'tutorials/switching-sqlite-postgres.md' - Using the Backstage Proxy from Within a Plugin: 'tutorials/using-backstage-proxy-within-plugin.md' - Migration to Yarn 3: 'tutorials/yarn-migration.md' + - Migration to Material UI v5: 'tutorials/migrate-to-mui5.md' + - Setup OpenTelemetry: 'tutorials/setup-opentelemetry.md' - Architecture Decision Records (ADRs): - Overview: 'architecture-decisions/index.md' - ADR001 - Architecture Decision Record (ADR) log: 'architecture-decisions/adr001-add-adr-log.md' diff --git a/package.json b/package.json index a676d2c2d3..4edc266ba1 100644 --- a/package.json +++ b/package.json @@ -6,8 +6,11 @@ }, "scripts": { "dev": "concurrently 'yarn start' 'yarn start-backend'", + "dev:next": "concurrently 'yarn start:next' 'yarn start-backend:next'", "start": "yarn workspace example-app start", "start-backend": "yarn workspace example-backend start", + "start:next": "yarn workspace example-app-next start", + "start-backend:next": "yarn workspace example-backend-next start", "build:backend": "yarn workspace example-backend build", "build:all": "backstage-cli repo build --all", "build:api-reports": "yarn build:api-reports:only --tsc", @@ -50,14 +53,12 @@ "@types/react": "^18", "@types/react-dom": "^18", "jest-haste-map@^29.7.0": "patch:jest-haste-map@npm%3A29.7.0#./.yarn/patches/jest-haste-map-npm-29.7.0-e3be419eff.patch", - "mock-fs@^5.2.0": "patch:mock-fs@npm%3A5.2.0#./.yarn/patches/mock-fs-npm-5.2.0-5103a7b507.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", "@material-ui/pickers@^3.2.10": "patch:@material-ui/pickers@npm%3A3.3.11#./.yarn/patches/@material-ui-pickers-npm-3.3.11-1c8f68ea20.patch" }, - "version": "1.20.0-next.2", + "version": "1.22.0", "dependencies": { "@backstage/errors": "workspace:^", - "@changesets/changelog-github": "^0.4.8", "@manypkg/get-packages": "^1.1.3", "@useoptic/optic": "^0.50.10", "lodash": "^4.17.21" @@ -93,7 +94,7 @@ "semver": "^7.5.3", "shx": "^0.3.2", "ts-node": "^10.4.0", - "typescript": "~5.0.0" + "typescript": "~5.2.0" }, "prettier": "@spotify/prettier-config", "lint-staged": { diff --git a/packages/app-defaults/CHANGELOG.md b/packages/app-defaults/CHANGELOG.md index 647cf987b6..5f815f4b0e 100644 --- a/packages/app-defaults/CHANGELOG.md +++ b/packages/app-defaults/CHANGELOG.md @@ -1,5 +1,105 @@ # @backstage/app-defaults +## 1.4.7 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/core-app-api@1.11.3 + - @backstage/theme@0.5.0 + +## 1.4.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/core-app-api@1.11.3-next.0 + - @backstage/plugin-permission-react@0.4.19-next.1 + - @backstage/theme@0.5.0 + +## 1.4.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-permission-react@0.4.19-next.0 + - @backstage/core-app-api@1.11.2 + - @backstage/core-plugin-api@1.8.1 + - @backstage/theme@0.5.0 + +## 1.4.6 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/core-app-api@1.11.2 + - @backstage/plugin-permission-react@0.4.18 + +## 1.4.6-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-permission-react@0.4.18-next.1 + +## 1.4.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-permission-react@0.4.18-next.1 + +## 1.4.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/theme@0.5.0-next.0 + +## 1.4.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/core-app-api@1.11.2-next.0 + - @backstage/plugin-permission-react@0.4.18-next.0 + +## 1.4.5 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-permission-react@0.4.17 + - @backstage/core-app-api@1.11.1 + - @backstage/theme@0.4.4 + ## 1.4.5-next.2 ### Patch Changes diff --git a/packages/app-defaults/package.json b/packages/app-defaults/package.json index 875213f678..bf7b56f8c2 100644 --- a/packages/app-defaults/package.json +++ b/packages/app-defaults/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/app-defaults", "description": "Provides the default wiring of a Backstage App", - "version": "1.4.5-next.2", + "version": "1.4.7", "publishConfig": { "access": "public", "main": "dist/index.esm.js", diff --git a/packages/app-next-example-plugin/CHANGELOG.md b/packages/app-next-example-plugin/CHANGELOG.md index 373a0b61d0..6f0545a801 100644 --- a/packages/app-next-example-plugin/CHANGELOG.md +++ b/packages/app-next-example-plugin/CHANGELOG.md @@ -1,5 +1,84 @@ # app-next-example-plugin +## 0.0.5 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + +## 0.0.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.1-next.2 + +## 0.0.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.10-next.1 + - @backstage/frontend-plugin-api@0.4.1-next.1 + +## 0.0.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/frontend-plugin-api@0.4.1-next.0 + +## 0.0.4 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0 + - @backstage/core-components@0.13.9 + +## 0.0.4-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/frontend-plugin-api@0.4.0-next.3 + +## 0.0.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.2 + - @backstage/core-components@0.13.9-next.2 + +## 0.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + +## 0.0.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.0 + - @backstage/frontend-plugin-api@0.3.1-next.0 + +## 0.0.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/frontend-plugin-api@0.3.0 + ## 0.0.3-next.2 ### Patch Changes diff --git a/packages/app-next-example-plugin/package.json b/packages/app-next-example-plugin/package.json index 5ea5bb1406..c7669d93cb 100644 --- a/packages/app-next-example-plugin/package.json +++ b/packages/app-next-example-plugin/package.json @@ -1,7 +1,7 @@ { "name": "app-next-example-plugin", "description": "Backstage internal example plugin", - "version": "0.0.3-next.2", + "version": "0.0.5", "publishConfig": { "access": "public", "main": "dist/index.esm.js", diff --git a/packages/app-next-example-plugin/src/plugin.tsx b/packages/app-next-example-plugin/src/plugin.tsx index a3c95e900c..99c377b7e5 100644 --- a/packages/app-next-example-plugin/src/plugin.tsx +++ b/packages/app-next-example-plugin/src/plugin.tsx @@ -21,7 +21,6 @@ import { } from '@backstage/frontend-plugin-api'; export const ExamplePage = createPageExtension({ - id: 'example.page', defaultPath: '/example', loader: () => import('./Component').then(m => ), }); diff --git a/packages/app-next/CHANGELOG.md b/packages/app-next/CHANGELOG.md index 194160771d..6272ef11df 100644 --- a/packages/app-next/CHANGELOG.md +++ b/packages/app-next/CHANGELOG.md @@ -1,5 +1,778 @@ # example-app-next +## 0.0.5 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-api-docs@0.10.3 + - @backstage/core-compat-api@0.1.1 + - @backstage/plugin-scaffolder-react@1.7.1 + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/plugin-user-settings@0.8.0 + - @backstage/plugin-azure-sites@0.1.18 + - @backstage/cli@0.25.1 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-octopus-deploy@0.2.11 + - @backstage/frontend-app-api@0.5.0 + - @backstage/plugin-kubernetes@0.11.4 + - @backstage/plugin-home@0.6.1 + - @backstage/plugin-scaffolder@1.17.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.4 + - @backstage/plugin-catalog-unprocessed-entities@0.1.7 + - @backstage/plugin-microsoft-calendar@0.1.11 + - @backstage/plugin-newrelic-dashboard@0.3.4 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/plugin-entity-feedback@0.2.12 + - @backstage/plugin-apache-airflow@0.2.19 + - @backstage/plugin-github-actions@0.6.10 + - @backstage/plugin-techdocs-react@1.1.15 + - @backstage/plugin-catalog-graph@0.3.3 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/plugin-code-coverage@0.2.22 + - @backstage/plugin-cost-insights@0.12.18 + - @backstage/plugin-tech-insights@0.3.21 + - @backstage/plugin-azure-devops@0.3.11 + - @backstage/plugin-gcp-projects@0.3.45 + - @backstage/plugin-cloudbuild@0.3.29 + - @backstage/plugin-lighthouse@0.4.14 + - @backstage/plugin-stackstorm@0.1.10 + - @backstage/plugin-tech-radar@0.6.12 + - @backstage/plugin-dynatrace@8.0.3 + - @backstage/plugin-gcalendar@0.3.22 + - @backstage/plugin-pagerduty@0.7.1 + - @backstage/plugin-shortcuts@0.3.18 + - @backstage/plugin-airbrake@0.3.29 + - @backstage/plugin-devtools@0.1.8 + - @backstage/plugin-graphiql@0.3.2 + - @backstage/plugin-linguist@0.1.14 + - @backstage/plugin-newrelic@0.3.44 + - @backstage/plugin-playlist@0.2.3 + - @backstage/plugin-puppetdb@0.1.12 + - @backstage/plugin-techdocs@1.9.3 + - @backstage/plugin-catalog@1.16.1 + - @backstage/plugin-explore@0.4.15 + - @backstage/plugin-jenkins@0.9.4 + - @backstage/plugin-rollbar@0.4.29 + - @backstage/plugin-badges@0.2.53 + - @backstage/plugin-search@1.4.5 + - @backstage/plugin-sentry@0.5.14 + - @backstage/plugin-kafka@0.3.29 + - @backstage/plugin-gocd@0.1.35 + - @backstage/plugin-todo@0.2.33 + - @backstage/plugin-adr@0.6.12 + - @backstage/plugin-org@0.6.19 + - @backstage/plugin-app-visualizer@0.1.0 + - @backstage/plugin-catalog-import@0.10.5 + - app-next-example-plugin@0.0.5 + - @backstage/plugin-search-react@1.7.5 + - @backstage/app-defaults@1.4.7 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/core-app-api@1.11.3 + - @backstage/theme@0.5.0 + - @backstage/plugin-catalog-common@1.0.20 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.10 + +## 0.0.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.1.1-next.2 + - @backstage/plugin-user-settings@0.8.0-next.2 + - @backstage/plugin-octopus-deploy@0.2.11-next.2 + - @backstage/frontend-plugin-api@0.4.1-next.2 + - @backstage/frontend-app-api@0.4.1-next.2 + - @backstage/plugin-home@0.6.1-next.2 + - @backstage/plugin-scaffolder-react@1.7.1-next.2 + - @backstage/plugin-scaffolder@1.17.1-next.2 + - @backstage/plugin-linguist@0.1.14-next.2 + - @backstage/plugin-catalog@1.16.1-next.2 + - @backstage/plugin-catalog-import@0.10.5-next.2 + - @backstage/plugin-graphiql@0.3.2-next.2 + - @backstage/plugin-search@1.4.5-next.2 + - @backstage/plugin-tech-radar@0.6.12-next.2 + - @backstage/plugin-techdocs@1.9.3-next.2 + - app-next-example-plugin@0.0.5-next.2 + - @backstage/plugin-adr@0.6.12-next.2 + - @backstage/plugin-catalog-react@1.9.3-next.2 + - @backstage/plugin-explore@0.4.15-next.2 + - @backstage/plugin-search-react@1.7.5-next.2 + - @backstage/plugin-visualizer@0.0.2-next.2 + - @backstage/cli@0.25.1-next.1 + - @backstage/plugin-pagerduty@0.7.1-next.2 + - @backstage/plugin-api-docs@0.10.3-next.2 + - @backstage/plugin-catalog-graph@0.3.3-next.2 + - @backstage/plugin-org@0.6.19-next.2 + - @backstage/plugin-airbrake@0.3.29-next.2 + - @backstage/plugin-azure-devops@0.3.11-next.2 + - @backstage/plugin-azure-sites@0.1.18-next.2 + - @backstage/plugin-badges@0.2.53-next.2 + - @backstage/plugin-cloudbuild@0.3.29-next.2 + - @backstage/plugin-code-coverage@0.2.22-next.2 + - @backstage/plugin-cost-insights@0.12.18-next.2 + - @backstage/plugin-dynatrace@8.0.3-next.2 + - @backstage/plugin-entity-feedback@0.2.12-next.2 + - @backstage/plugin-github-actions@0.6.10-next.2 + - @backstage/plugin-gocd@0.1.35-next.2 + - @backstage/plugin-jenkins@0.9.4-next.2 + - @backstage/plugin-kafka@0.3.29-next.2 + - @backstage/plugin-kubernetes@0.11.4-next.2 + - @backstage/plugin-lighthouse@0.4.14-next.2 + - @backstage/plugin-newrelic-dashboard@0.3.4-next.2 + - @backstage/plugin-playlist@0.2.3-next.2 + - @backstage/plugin-puppetdb@0.1.12-next.2 + - @backstage/plugin-rollbar@0.4.29-next.2 + - @backstage/plugin-sentry@0.5.14-next.2 + - @backstage/plugin-tech-insights@0.3.21-next.2 + - @backstage/plugin-todo@0.2.33-next.2 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.4-next.1 + - @backstage/integration-react@1.1.23-next.0 + - @backstage/plugin-apache-airflow@0.2.19-next.1 + - @backstage/plugin-catalog-unprocessed-entities@0.1.7-next.1 + - @backstage/plugin-devtools@0.1.8-next.1 + - @backstage/plugin-gcalendar@0.3.22-next.1 + - @backstage/plugin-gcp-projects@0.3.45-next.1 + - @backstage/plugin-microsoft-calendar@0.1.11-next.1 + - @backstage/plugin-newrelic@0.3.44-next.1 + - @backstage/plugin-shortcuts@0.3.18-next.1 + - @backstage/plugin-stackstorm@0.1.10-next.1 + +## 0.0.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-azure-sites@0.1.18-next.1 + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/plugin-user-settings@0.8.0-next.1 + - @backstage/plugin-kubernetes@0.11.4-next.1 + - @backstage/core-components@0.13.10-next.1 + - @backstage/app-defaults@1.4.7-next.1 + - @backstage/cli@0.25.1-next.1 + - @backstage/core-app-api@1.11.3-next.0 + - @backstage/core-compat-api@0.1.1-next.1 + - @backstage/frontend-app-api@0.4.1-next.1 + - @backstage/frontend-plugin-api@0.4.1-next.1 + - @backstage/integration-react@1.1.23-next.0 + - @backstage/plugin-adr@0.6.12-next.1 + - @backstage/plugin-airbrake@0.3.29-next.1 + - @backstage/plugin-apache-airflow@0.2.19-next.1 + - @backstage/plugin-api-docs@0.10.3-next.1 + - @backstage/plugin-azure-devops@0.3.11-next.1 + - @backstage/plugin-badges@0.2.53-next.1 + - @backstage/plugin-catalog@1.16.1-next.1 + - @backstage/plugin-catalog-graph@0.3.3-next.1 + - @backstage/plugin-catalog-import@0.10.5-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/plugin-catalog-unprocessed-entities@0.1.7-next.1 + - @backstage/plugin-cloudbuild@0.3.29-next.1 + - @backstage/plugin-code-coverage@0.2.22-next.1 + - @backstage/plugin-cost-insights@0.12.18-next.1 + - @backstage/plugin-devtools@0.1.8-next.1 + - @backstage/plugin-dynatrace@8.0.3-next.1 + - @backstage/plugin-entity-feedback@0.2.12-next.1 + - @backstage/plugin-explore@0.4.15-next.1 + - @backstage/plugin-gcalendar@0.3.22-next.1 + - @backstage/plugin-gcp-projects@0.3.45-next.1 + - @backstage/plugin-github-actions@0.6.10-next.1 + - @backstage/plugin-gocd@0.1.35-next.1 + - @backstage/plugin-graphiql@0.3.2-next.1 + - @backstage/plugin-home@0.6.1-next.1 + - @backstage/plugin-jenkins@0.9.4-next.1 + - @backstage/plugin-kafka@0.3.29-next.1 + - @backstage/plugin-lighthouse@0.4.14-next.1 + - @backstage/plugin-linguist@0.1.14-next.1 + - @backstage/plugin-microsoft-calendar@0.1.11-next.1 + - @backstage/plugin-newrelic@0.3.44-next.1 + - @backstage/plugin-newrelic-dashboard@0.3.4-next.1 + - @backstage/plugin-octopus-deploy@0.2.11-next.1 + - @backstage/plugin-org@0.6.19-next.1 + - @backstage/plugin-pagerduty@0.7.1-next.1 + - @backstage/plugin-permission-react@0.4.19-next.1 + - @backstage/plugin-playlist@0.2.3-next.1 + - @backstage/plugin-puppetdb@0.1.12-next.1 + - @backstage/plugin-rollbar@0.4.29-next.1 + - @backstage/plugin-scaffolder@1.17.1-next.1 + - @backstage/plugin-scaffolder-react@1.7.1-next.1 + - @backstage/plugin-search@1.4.5-next.1 + - @backstage/plugin-search-react@1.7.5-next.1 + - @backstage/plugin-sentry@0.5.14-next.1 + - @backstage/plugin-shortcuts@0.3.18-next.1 + - @backstage/plugin-stackstorm@0.1.10-next.1 + - @backstage/plugin-tech-insights@0.3.21-next.1 + - @backstage/plugin-tech-radar@0.6.12-next.1 + - @backstage/plugin-techdocs@1.9.3-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.4-next.1 + - @backstage/plugin-techdocs-react@1.1.15-next.1 + - @backstage/plugin-todo@0.2.33-next.1 + - @backstage/plugin-visualizer@0.0.2-next.1 + - app-next-example-plugin@0.0.5-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.9 + +## 0.0.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.7.1-next.0 + - @backstage/core-components@0.13.10-next.0 + - @backstage/cli@0.25.1-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.4-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.1.7-next.0 + - @backstage/frontend-plugin-api@0.4.1-next.0 + - @backstage/plugin-microsoft-calendar@0.1.11-next.0 + - @backstage/plugin-newrelic-dashboard@0.3.4-next.0 + - @backstage/plugin-permission-react@0.4.19-next.0 + - @backstage/plugin-entity-feedback@0.2.12-next.0 + - @backstage/plugin-apache-airflow@0.2.19-next.0 + - @backstage/plugin-github-actions@0.6.10-next.0 + - @backstage/plugin-octopus-deploy@0.2.11-next.0 + - @backstage/plugin-techdocs-react@1.1.15-next.0 + - @backstage/plugin-catalog-graph@0.3.3-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/plugin-code-coverage@0.2.22-next.0 + - @backstage/plugin-cost-insights@0.12.18-next.0 + - @backstage/plugin-tech-insights@0.3.21-next.0 + - @backstage/plugin-user-settings@0.7.15-next.0 + - @backstage/plugin-azure-devops@0.3.11-next.0 + - @backstage/plugin-gcp-projects@0.3.45-next.0 + - @backstage/plugin-azure-sites@0.1.18-next.0 + - @backstage/plugin-cloudbuild@0.3.29-next.0 + - @backstage/plugin-kubernetes@0.11.4-next.0 + - @backstage/plugin-lighthouse@0.4.14-next.0 + - @backstage/plugin-scaffolder@1.17.1-next.0 + - @backstage/plugin-stackstorm@0.1.10-next.0 + - @backstage/plugin-tech-radar@0.6.12-next.0 + - @backstage/plugin-dynatrace@8.0.3-next.0 + - @backstage/plugin-gcalendar@0.3.22-next.0 + - @backstage/plugin-pagerduty@0.7.1-next.0 + - @backstage/plugin-shortcuts@0.3.18-next.0 + - @backstage/plugin-airbrake@0.3.29-next.0 + - @backstage/plugin-api-docs@0.10.3-next.0 + - @backstage/plugin-devtools@0.1.8-next.0 + - @backstage/plugin-graphiql@0.3.2-next.0 + - @backstage/plugin-linguist@0.1.14-next.0 + - @backstage/plugin-newrelic@0.3.44-next.0 + - @backstage/plugin-playlist@0.2.3-next.0 + - @backstage/plugin-puppetdb@0.1.12-next.0 + - @backstage/plugin-techdocs@1.9.3-next.0 + - @backstage/plugin-catalog@1.16.1-next.0 + - @backstage/plugin-explore@0.4.15-next.0 + - @backstage/plugin-jenkins@0.9.4-next.0 + - @backstage/plugin-rollbar@0.4.29-next.0 + - @backstage/plugin-badges@0.2.53-next.0 + - @backstage/plugin-search@1.4.5-next.0 + - @backstage/plugin-sentry@0.5.14-next.0 + - @backstage/plugin-kafka@0.3.29-next.0 + - @backstage/plugin-gocd@0.1.35-next.0 + - @backstage/plugin-home@0.6.1-next.0 + - @backstage/plugin-todo@0.2.33-next.0 + - @backstage/plugin-adr@0.6.12-next.0 + - @backstage/plugin-org@0.6.19-next.0 + - @backstage/app-defaults@1.4.7-next.0 + - app-next-example-plugin@0.0.5-next.0 + - @backstage/frontend-app-api@0.4.1-next.0 + - @backstage/integration-react@1.1.22 + - @backstage/plugin-catalog-import@0.10.5-next.0 + - @backstage/plugin-search-react@1.7.5-next.0 + - @backstage/plugin-visualizer@0.0.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-app-api@1.11.2 + - @backstage/core-compat-api@0.1.1-next.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/theme@0.5.0 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.9 + +## 0.0.4 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.1.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/frontend-plugin-api@0.4.0 + - @backstage/frontend-app-api@0.4.0 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/plugin-api-docs@0.10.2 + - @backstage/core-components@0.13.9 + - @backstage/cli@0.25.0 + - @backstage/theme@0.5.0 + - @backstage/plugin-scaffolder@1.17.0 + - @backstage/plugin-home@0.6.0 + - @backstage/plugin-catalog@1.16.0 + - @backstage/plugin-scaffolder-react@1.7.0 + - @backstage/plugin-kubernetes@0.11.3 + - @backstage/plugin-org@0.6.18 + - @backstage/plugin-github-actions@0.6.9 + - @backstage/plugin-azure-devops@0.3.10 + - @backstage/core-app-api@1.11.2 + - @backstage/plugin-lighthouse@0.4.13 + - @backstage/plugin-explore@0.4.14 + - @backstage/plugin-catalog-import@0.10.4 + - @backstage/plugin-user-settings@0.7.14 + - @backstage/plugin-tech-radar@0.6.11 + - @backstage/plugin-graphiql@0.3.1 + - @backstage/plugin-techdocs@1.9.2 + - @backstage/plugin-search@1.4.4 + - @backstage/plugin-search-react@1.7.4 + - @backstage/plugin-adr@0.6.11 + - @backstage/plugin-gcp-projects@0.3.44 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.3 + - @backstage/plugin-pagerduty@0.7.0 + - @backstage/app-defaults@1.4.6 + - @backstage/integration-react@1.1.22 + - @backstage/plugin-airbrake@0.3.28 + - @backstage/plugin-apache-airflow@0.2.18 + - @backstage/plugin-azure-sites@0.1.17 + - @backstage/plugin-badges@0.2.52 + - @backstage/plugin-catalog-graph@0.3.2 + - @backstage/plugin-catalog-unprocessed-entities@0.1.6 + - @backstage/plugin-cloudbuild@0.3.28 + - @backstage/plugin-code-coverage@0.2.21 + - @backstage/plugin-cost-insights@0.12.17 + - @backstage/plugin-devtools@0.1.7 + - @backstage/plugin-dynatrace@8.0.2 + - @backstage/plugin-entity-feedback@0.2.11 + - @backstage/plugin-gcalendar@0.3.21 + - @backstage/plugin-gocd@0.1.34 + - @backstage/plugin-jenkins@0.9.3 + - @backstage/plugin-kafka@0.3.28 + - @backstage/plugin-linguist@0.1.13 + - @backstage/plugin-microsoft-calendar@0.1.10 + - @backstage/plugin-newrelic@0.3.43 + - @backstage/plugin-newrelic-dashboard@0.3.3 + - @backstage/plugin-octopus-deploy@0.2.10 + - @backstage/plugin-permission-react@0.4.18 + - @backstage/plugin-playlist@0.2.2 + - @backstage/plugin-puppetdb@0.1.11 + - @backstage/plugin-rollbar@0.4.28 + - @backstage/plugin-sentry@0.5.13 + - @backstage/plugin-shortcuts@0.3.17 + - @backstage/plugin-stackstorm@0.1.9 + - @backstage/plugin-tech-insights@0.3.20 + - @backstage/plugin-techdocs-react@1.1.14 + - @backstage/plugin-todo@0.2.32 + - @backstage/plugin-visualizer@0.0.1 + - app-next-example-plugin@0.0.4 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.9 + +## 0.0.4-next.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-home@0.6.0-next.3 + - @backstage/plugin-org@0.6.18-next.3 + - @backstage/plugin-azure-devops@0.3.10-next.3 + - @backstage/cli@0.25.0-next.3 + - @backstage/plugin-api-docs@0.10.2-next.4 + - @backstage/plugin-scaffolder-react@1.6.2-next.3 + - @backstage/plugin-scaffolder@1.16.2-next.3 + - @backstage/core-components@0.13.9-next.3 + - @backstage/app-defaults@1.4.6-next.3 + - app-next-example-plugin@0.0.4-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-compat-api@0.1.0-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/frontend-app-api@0.4.0-next.3 + - @backstage/frontend-plugin-api@0.4.0-next.3 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-adr@0.6.11-next.3 + - @backstage/plugin-airbrake@0.3.28-next.3 + - @backstage/plugin-apache-airflow@0.2.18-next.3 + - @backstage/plugin-azure-sites@0.1.17-next.3 + - @backstage/plugin-badges@0.2.52-next.3 + - @backstage/plugin-catalog@1.16.0-next.4 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-graph@0.3.2-next.3 + - @backstage/plugin-catalog-import@0.10.4-next.4 + - @backstage/plugin-catalog-react@1.9.2-next.3 + - @backstage/plugin-catalog-unprocessed-entities@0.1.6-next.3 + - @backstage/plugin-cloudbuild@0.3.28-next.3 + - @backstage/plugin-code-coverage@0.2.21-next.3 + - @backstage/plugin-cost-insights@0.12.17-next.3 + - @backstage/plugin-devtools@0.1.7-next.3 + - @backstage/plugin-dynatrace@8.0.2-next.3 + - @backstage/plugin-entity-feedback@0.2.11-next.3 + - @backstage/plugin-explore@0.4.14-next.3 + - @backstage/plugin-gcalendar@0.3.21-next.3 + - @backstage/plugin-gcp-projects@0.3.44-next.3 + - @backstage/plugin-github-actions@0.6.9-next.3 + - @backstage/plugin-gocd@0.1.34-next.3 + - @backstage/plugin-graphiql@0.3.1-next.4 + - @backstage/plugin-jenkins@0.9.3-next.3 + - @backstage/plugin-kafka@0.3.28-next.3 + - @backstage/plugin-kubernetes@0.11.3-next.3 + - @backstage/plugin-lighthouse@0.4.13-next.3 + - @backstage/plugin-linguist@0.1.13-next.3 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-microsoft-calendar@0.1.10-next.3 + - @backstage/plugin-newrelic@0.3.43-next.3 + - @backstage/plugin-newrelic-dashboard@0.3.3-next.3 + - @backstage/plugin-octopus-deploy@0.2.10-next.3 + - @backstage/plugin-pagerduty@0.7.0-next.3 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/plugin-playlist@0.2.2-next.3 + - @backstage/plugin-puppetdb@0.1.11-next.3 + - @backstage/plugin-rollbar@0.4.28-next.3 + - @backstage/plugin-search@1.4.4-next.4 + - @backstage/plugin-search-common@1.2.8 + - @backstage/plugin-search-react@1.7.4-next.3 + - @backstage/plugin-sentry@0.5.13-next.3 + - @backstage/plugin-shortcuts@0.3.17-next.3 + - @backstage/plugin-stackstorm@0.1.9-next.3 + - @backstage/plugin-tech-insights@0.3.20-next.3 + - @backstage/plugin-tech-radar@0.6.11-next.4 + - @backstage/plugin-techdocs@1.9.2-next.4 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.3-next.3 + - @backstage/plugin-techdocs-react@1.1.14-next.3 + - @backstage/plugin-todo@0.2.32-next.3 + - @backstage/plugin-user-settings@0.7.14-next.4 + +## 0.0.4-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.2 + - @backstage/frontend-app-api@0.4.0-next.2 + - @backstage/cli@0.25.0-next.2 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-kubernetes@0.11.3-next.2 + - @backstage/core-compat-api@0.1.0-next.2 + - @backstage/plugin-lighthouse@0.4.13-next.2 + - @backstage/plugin-catalog-import@0.10.4-next.3 + - @backstage/plugin-user-settings@0.7.14-next.3 + - @backstage/plugin-tech-radar@0.6.11-next.3 + - @backstage/plugin-graphiql@0.3.1-next.3 + - @backstage/plugin-techdocs@1.9.2-next.3 + - @backstage/plugin-catalog@1.16.0-next.3 + - @backstage/plugin-search@1.4.4-next.3 + - @backstage/plugin-home@0.6.0-next.2 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/plugin-search-react@1.7.4-next.2 + - @backstage/plugin-explore@0.4.14-next.2 + - @backstage/plugin-adr@0.6.11-next.2 + - @backstage/plugin-scaffolder-react@1.6.2-next.2 + - app-next-example-plugin@0.0.4-next.2 + - @backstage/app-defaults@1.4.6-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-airbrake@0.3.28-next.2 + - @backstage/plugin-apache-airflow@0.2.18-next.2 + - @backstage/plugin-api-docs@0.10.2-next.3 + - @backstage/plugin-azure-devops@0.3.10-next.2 + - @backstage/plugin-azure-sites@0.1.17-next.2 + - @backstage/plugin-badges@0.2.52-next.2 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-graph@0.3.2-next.2 + - @backstage/plugin-catalog-unprocessed-entities@0.1.6-next.2 + - @backstage/plugin-cloudbuild@0.3.28-next.2 + - @backstage/plugin-code-coverage@0.2.21-next.2 + - @backstage/plugin-cost-insights@0.12.17-next.2 + - @backstage/plugin-devtools@0.1.7-next.2 + - @backstage/plugin-dynatrace@8.0.2-next.2 + - @backstage/plugin-entity-feedback@0.2.11-next.2 + - @backstage/plugin-gcalendar@0.3.21-next.2 + - @backstage/plugin-gcp-projects@0.3.44-next.2 + - @backstage/plugin-github-actions@0.6.9-next.2 + - @backstage/plugin-gocd@0.1.34-next.2 + - @backstage/plugin-jenkins@0.9.3-next.2 + - @backstage/plugin-kafka@0.3.28-next.2 + - @backstage/plugin-linguist@0.1.13-next.2 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-microsoft-calendar@0.1.10-next.2 + - @backstage/plugin-newrelic@0.3.43-next.2 + - @backstage/plugin-newrelic-dashboard@0.3.3-next.2 + - @backstage/plugin-octopus-deploy@0.2.10-next.2 + - @backstage/plugin-org@0.6.18-next.2 + - @backstage/plugin-pagerduty@0.7.0-next.2 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/plugin-playlist@0.2.2-next.2 + - @backstage/plugin-puppetdb@0.1.11-next.2 + - @backstage/plugin-rollbar@0.4.28-next.2 + - @backstage/plugin-scaffolder@1.16.2-next.2 + - @backstage/plugin-search-common@1.2.8 + - @backstage/plugin-sentry@0.5.13-next.2 + - @backstage/plugin-shortcuts@0.3.17-next.2 + - @backstage/plugin-stackstorm@0.1.9-next.2 + - @backstage/plugin-tech-insights@0.3.20-next.2 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.3-next.2 + - @backstage/plugin-techdocs-react@1.1.14-next.2 + - @backstage/plugin-todo@0.2.32-next.2 + +## 0.0.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/frontend-app-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/cli@0.25.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-catalog@1.16.0-next.2 + - @backstage/plugin-scaffolder-react@1.6.2-next.1 + - @backstage/plugin-home@0.6.0-next.1 + - @backstage/plugin-github-actions@0.6.9-next.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/plugin-search-react@1.7.4-next.1 + - @backstage/plugin-azure-devops@0.3.10-next.1 + - @backstage/plugin-scaffolder@1.16.2-next.1 + - @backstage/plugin-api-docs@0.10.2-next.2 + - @backstage/plugin-gcp-projects@0.3.44-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.3-next.1 + - @backstage/plugin-user-settings@0.7.14-next.2 + - @backstage/plugin-adr@0.6.11-next.1 + - @backstage/plugin-pagerduty@0.7.0-next.1 + - app-next-example-plugin@0.0.4-next.1 + - @backstage/core-compat-api@0.0.1-next.1 + - @backstage/plugin-catalog-import@0.10.4-next.2 + - @backstage/plugin-explore@0.4.14-next.1 + - @backstage/plugin-graphiql@0.3.1-next.2 + - @backstage/plugin-search@1.4.4-next.2 + - @backstage/plugin-tech-radar@0.6.11-next.2 + - @backstage/plugin-techdocs@1.9.2-next.2 + - @backstage/app-defaults@1.4.6-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-airbrake@0.3.28-next.1 + - @backstage/plugin-apache-airflow@0.2.18-next.1 + - @backstage/plugin-azure-sites@0.1.17-next.1 + - @backstage/plugin-badges@0.2.52-next.1 + - @backstage/plugin-catalog-graph@0.3.2-next.1 + - @backstage/plugin-catalog-unprocessed-entities@0.1.6-next.1 + - @backstage/plugin-cloudbuild@0.3.28-next.1 + - @backstage/plugin-code-coverage@0.2.21-next.1 + - @backstage/plugin-cost-insights@0.12.17-next.1 + - @backstage/plugin-devtools@0.1.7-next.1 + - @backstage/plugin-dynatrace@8.0.2-next.1 + - @backstage/plugin-entity-feedback@0.2.11-next.1 + - @backstage/plugin-gcalendar@0.3.21-next.1 + - @backstage/plugin-gocd@0.1.34-next.1 + - @backstage/plugin-jenkins@0.9.3-next.1 + - @backstage/plugin-kafka@0.3.28-next.1 + - @backstage/plugin-kubernetes@0.11.3-next.1 + - @backstage/plugin-lighthouse@0.4.13-next.1 + - @backstage/plugin-linguist@0.1.13-next.1 + - @backstage/plugin-microsoft-calendar@0.1.10-next.1 + - @backstage/plugin-newrelic@0.3.43-next.1 + - @backstage/plugin-newrelic-dashboard@0.3.3-next.1 + - @backstage/plugin-octopus-deploy@0.2.10-next.1 + - @backstage/plugin-org@0.6.18-next.1 + - @backstage/plugin-playlist@0.2.2-next.1 + - @backstage/plugin-puppetdb@0.1.11-next.1 + - @backstage/plugin-rollbar@0.4.28-next.1 + - @backstage/plugin-sentry@0.5.13-next.1 + - @backstage/plugin-shortcuts@0.3.17-next.1 + - @backstage/plugin-stackstorm@0.1.9-next.1 + - @backstage/plugin-tech-insights@0.3.20-next.1 + - @backstage/plugin-techdocs-react@1.1.14-next.1 + - @backstage/plugin-todo@0.2.32-next.1 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.8 + +## 0.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.0.1-next.0 + - @backstage/plugin-catalog@1.16.0-next.1 + - @backstage/plugin-catalog-import@0.10.4-next.1 + - @backstage/plugin-graphiql@0.3.1-next.1 + - @backstage/plugin-search@1.4.4-next.1 + - @backstage/plugin-tech-radar@0.6.11-next.1 + - @backstage/plugin-techdocs@1.9.2-next.1 + - @backstage/plugin-user-settings@0.7.14-next.1 + - @backstage/plugin-api-docs@0.10.2-next.1 + - @backstage/plugin-catalog-graph@0.3.2-next.0 + - @backstage/plugin-explore@0.4.14-next.0 + - @backstage/plugin-org@0.6.18-next.0 + - @backstage/plugin-scaffolder@1.16.2-next.0 + - @backstage/plugin-scaffolder-react@1.6.2-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.3-next.0 + +## 0.0.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.0.2-next.0 + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/plugin-api-docs@0.10.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/plugin-scaffolder@1.16.2-next.0 + - @backstage/plugin-catalog@1.16.0-next.0 + - @backstage/frontend-app-api@0.3.1-next.0 + - @backstage/plugin-org@0.6.18-next.0 + - @backstage/plugin-scaffolder-react@1.6.2-next.0 + - @backstage/plugin-catalog-import@0.10.4-next.0 + - @backstage/plugin-user-settings@0.7.14-next.0 + - @backstage/plugin-tech-radar@0.6.11-next.0 + - @backstage/plugin-graphiql@0.3.1-next.0 + - @backstage/plugin-techdocs@1.9.2-next.0 + - @backstage/plugin-search@1.4.4-next.0 + - @backstage/plugin-search-react@1.7.4-next.0 + - @backstage/cli@0.24.1-next.0 + - @backstage/plugin-home@0.5.12-next.0 + - @backstage/plugin-kubernetes@0.11.3-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/frontend-plugin-api@0.3.1-next.0 + - @backstage/app-defaults@1.4.6-next.0 + - @backstage/core-app-api@1.11.2-next.0 + - @backstage/integration-react@1.1.22-next.0 + - @backstage/plugin-adr@0.6.11-next.0 + - @backstage/plugin-airbrake@0.3.28-next.0 + - @backstage/plugin-apache-airflow@0.2.18-next.0 + - @backstage/plugin-azure-devops@0.3.10-next.0 + - @backstage/plugin-azure-sites@0.1.17-next.0 + - @backstage/plugin-badges@0.2.52-next.0 + - @backstage/plugin-catalog-graph@0.3.2-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.1.6-next.0 + - @backstage/plugin-circleci@0.3.28-next.0 + - @backstage/plugin-cloudbuild@0.3.28-next.0 + - @backstage/plugin-code-coverage@0.2.21-next.0 + - @backstage/plugin-cost-insights@0.12.17-next.0 + - @backstage/plugin-devtools@0.1.7-next.0 + - @backstage/plugin-dynatrace@8.0.2-next.0 + - @backstage/plugin-entity-feedback@0.2.11-next.0 + - @backstage/plugin-explore@0.4.14-next.0 + - @backstage/plugin-gcalendar@0.3.21-next.0 + - @backstage/plugin-gcp-projects@0.3.44-next.0 + - @backstage/plugin-github-actions@0.6.9-next.0 + - @backstage/plugin-gocd@0.1.34-next.0 + - @backstage/plugin-jenkins@0.9.3-next.0 + - @backstage/plugin-kafka@0.3.28-next.0 + - @backstage/plugin-lighthouse@0.4.13-next.0 + - @backstage/plugin-linguist@0.1.13-next.0 + - @backstage/plugin-microsoft-calendar@0.1.10-next.0 + - @backstage/plugin-newrelic@0.3.43-next.0 + - @backstage/plugin-newrelic-dashboard@0.3.3-next.0 + - @backstage/plugin-octopus-deploy@0.2.10-next.0 + - @backstage/plugin-pagerduty@0.6.9-next.0 + - @backstage/plugin-permission-react@0.4.18-next.0 + - @backstage/plugin-playlist@0.2.2-next.0 + - @backstage/plugin-puppetdb@0.1.11-next.0 + - @backstage/plugin-rollbar@0.4.28-next.0 + - @backstage/plugin-sentry@0.5.13-next.0 + - @backstage/plugin-shortcuts@0.3.17-next.0 + - @backstage/plugin-stackstorm@0.1.9-next.0 + - @backstage/plugin-tech-insights@0.3.20-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.3-next.0 + - @backstage/plugin-techdocs-react@1.1.14-next.0 + - @backstage/plugin-todo@0.2.32-next.0 + - app-next-example-plugin@0.0.4-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.8 + +## 0.0.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-api-docs@0.10.0 + - @backstage/plugin-catalog-import@0.10.2 + - @backstage/cli@0.24.0 + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/plugin-shortcuts@0.3.16 + - @backstage/plugin-home@0.5.10 + - @backstage/core-components@0.13.8 + - @backstage/frontend-plugin-api@0.3.0 + - @backstage/plugin-catalog@1.15.0 + - @backstage/plugin-graphiql@0.3.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.2 + - @backstage/plugin-techdocs@1.9.0 + - @backstage/plugin-cloudbuild@0.3.26 + - @backstage/plugin-scaffolder@1.16.0 + - @backstage/frontend-app-api@0.3.0 + - @backstage/plugin-user-settings@0.7.12 + - @backstage/plugin-tech-radar@0.6.10 + - @backstage/plugin-search@1.4.2 + - @backstage/plugin-catalog-unprocessed-entities@0.1.5 + - @backstage/integration-react@1.1.21 + - @backstage/plugin-microsoft-calendar@0.1.9 + - @backstage/plugin-newrelic-dashboard@0.3.1 + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-permission-react@0.4.17 + - @backstage/plugin-scaffolder-react@1.6.0 + - @backstage/plugin-entity-feedback@0.2.9 + - @backstage/plugin-apache-airflow@0.2.17 + - @backstage/plugin-github-actions@0.6.7 + - @backstage/plugin-octopus-deploy@0.2.8 + - @backstage/plugin-techdocs-react@1.1.13 + - @backstage/app-defaults@1.4.5 + - @backstage/core-app-api@1.11.1 + - @backstage/plugin-catalog-graph@0.3.0 + - @backstage/plugin-code-coverage@0.2.19 + - @backstage/plugin-cost-insights@0.12.15 + - @backstage/plugin-tech-insights@0.3.18 + - @backstage/plugin-azure-devops@0.3.8 + - @backstage/plugin-gcp-projects@0.3.43 + - @backstage/plugin-search-react@1.7.2 + - @backstage/plugin-azure-sites@0.1.15 + - @backstage/plugin-kubernetes@0.11.1 + - @backstage/plugin-lighthouse@0.4.11 + - @backstage/plugin-stackstorm@0.1.8 + - @backstage/plugin-dynatrace@8.0.0 + - @backstage/plugin-gcalendar@0.3.20 + - @backstage/plugin-pagerduty@0.6.7 + - @backstage/plugin-airbrake@0.3.26 + - @backstage/plugin-circleci@0.3.26 + - @backstage/plugin-devtools@0.1.6 + - @backstage/plugin-linguist@0.1.11 + - @backstage/plugin-newrelic@0.3.42 + - @backstage/plugin-playlist@0.2.0 + - @backstage/plugin-puppetdb@0.1.9 + - @backstage/plugin-explore@0.4.12 + - @backstage/plugin-jenkins@0.9.1 + - @backstage/plugin-rollbar@0.4.26 + - @backstage/theme@0.4.4 + - @backstage/plugin-badges@0.2.50 + - @backstage/plugin-sentry@0.5.11 + - @backstage/plugin-kafka@0.3.26 + - @backstage/plugin-gocd@0.1.32 + - @backstage/plugin-todo@0.2.30 + - @backstage/plugin-adr@0.6.9 + - @backstage/plugin-org@0.6.16 + - app-next-example-plugin@0.0.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-compat-api@0.0.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.8 + ## 0.0.3-next.2 ### Patch Changes diff --git a/packages/app-next/app-config.yaml b/packages/app-next/app-config.yaml index a46e119ac0..77f4284455 100644 --- a/packages/app-next/app-config.yaml +++ b/packages/app-next/app-config.yaml @@ -7,18 +7,17 @@ app: plugin.catalog.externalRoutes.viewTechDoc: plugin.techdocs.routes.docRoot extensions: - - apis.plugin.graphiql.browse.gitlab: true + # - apis.plugin.graphiql.browse.gitlab: true + - graphiql-endpoint:graphiql/gitlab: true - # Entity page cards - - entity.cards.about - - entity.cards.labels - - entity.cards.links: + - entity-card:catalog/about + - entity-card:catalog/labels + - entity-card:catalog/links: config: - filter: - - isKind: component - + filter: kind:component has:links + - entity-card:linguist/languages # Entity page content - - entity.content.techdocs + - entity-content:techdocs # scmAuthExtension: >- # createScmAuthExtension({ diff --git a/packages/app-next/package.json b/packages/app-next/package.json index 90108f9065..c51631aaa3 100644 --- a/packages/app-next/package.json +++ b/packages/app-next/package.json @@ -1,6 +1,6 @@ { "name": "example-app-next", - "version": "0.0.3-next.2", + "version": "0.0.5", "private": true, "backstage": { "role": "frontend" @@ -10,7 +10,6 @@ "@backstage/app-defaults": "workspace:^", "@backstage/catalog-model": "workspace:^", "@backstage/cli": "workspace:^", - "@backstage/config": "workspace:^", "@backstage/core-app-api": "workspace:^", "@backstage/core-compat-api": "workspace:^", "@backstage/core-components": "workspace:^", @@ -22,6 +21,7 @@ "@backstage/plugin-airbrake": "workspace:^", "@backstage/plugin-apache-airflow": "workspace:^", "@backstage/plugin-api-docs": "workspace:^", + "@backstage/plugin-app-visualizer": "workspace:^", "@backstage/plugin-azure-devops": "workspace:^", "@backstage/plugin-azure-sites": "workspace:^", "@backstage/plugin-badges": "workspace:^", @@ -31,7 +31,6 @@ "@backstage/plugin-catalog-import": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", "@backstage/plugin-catalog-unprocessed-entities": "workspace:^", - "@backstage/plugin-circleci": "workspace:^", "@backstage/plugin-cloudbuild": "workspace:^", "@backstage/plugin-code-coverage": "workspace:^", "@backstage/plugin-cost-insights": "workspace:^", @@ -77,6 +76,7 @@ "@backstage/plugin-todo": "workspace:^", "@backstage/plugin-user-settings": "workspace:^", "@backstage/theme": "workspace:^", + "@circleci/backstage-plugin": "^0.1.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", diff --git a/packages/app-next/src/App.tsx b/packages/app-next/src/App.tsx index 978c40ef44..ec333ce38f 100644 --- a/packages/app-next/src/App.tsx +++ b/packages/app-next/src/App.tsx @@ -17,6 +17,7 @@ import React from 'react'; import { createApp } from '@backstage/frontend-app-api'; import { pagesPlugin } from './examples/pagesPlugin'; +import notFoundErrorPage from './examples/notFoundErrorPageExtension'; import graphiqlPlugin from '@backstage/plugin-graphiql/alpha'; import techRadarPlugin from '@backstage/plugin-tech-radar/alpha'; import userSettingsPlugin from '@backstage/plugin-user-settings/alpha'; @@ -31,17 +32,26 @@ import { createExtensionOverrides, } from '@backstage/frontend-plugin-api'; import techdocsPlugin from '@backstage/plugin-techdocs/alpha'; +import appVisualizerPlugin from '@backstage/plugin-app-visualizer'; import { homePage } from './HomePage'; -import { collectLegacyRoutes } from '@backstage/core-compat-api'; +import { convertLegacyApp } from '@backstage/core-compat-api'; import { FlatRoutes } from '@backstage/core-app-api'; import { Route } from 'react-router'; import { CatalogImportPage } from '@backstage/plugin-catalog-import'; -import { createApiFactory, configApiRef } from '@backstage/core-plugin-api'; +import { + createApiFactory, + configApiRef, + SignInPageProps, +} from '@backstage/core-plugin-api'; import { ScmAuth, ScmIntegrationsApi, scmIntegrationsApiRef, } from '@backstage/integration-react'; +import { createSignInPageExtension } from '@backstage/frontend-plugin-api'; +import { SignInPage } from '@backstage/core-components'; + +import linguistPlugin from '@backstage/plugin-linguist/alpha'; /* @@ -73,7 +83,7 @@ TODO: /* app.tsx */ const homePageExtension = createExtension({ - id: 'myhomepage', + name: 'myhomepage', attachTo: { id: 'home', input: 'props' }, output: { children: coreExtensionData.reactElement, @@ -84,6 +94,12 @@ const homePageExtension = createExtension({ }, }); +const signInPage = createSignInPageExtension({ + name: 'guest', + loader: async () => (props: SignInPageProps) => + , +}); + const scmAuthExtension = createApiExtension({ factory: ScmAuth.createDefaultApiFactory(), }); @@ -96,7 +112,7 @@ const scmIntegrationApi = createApiExtension({ }), }); -const collectedLegacyPlugins = collectLegacyRoutes( +const collectedLegacyPlugins = convertLegacyApp( } /> , @@ -110,9 +126,17 @@ const app = createApp({ techdocsPlugin, userSettingsPlugin, homePlugin, + appVisualizerPlugin, + linguistPlugin, ...collectedLegacyPlugins, createExtensionOverrides({ - extensions: [homePageExtension, scmAuthExtension, scmIntegrationApi], + extensions: [ + homePageExtension, + scmAuthExtension, + scmIntegrationApi, + signInPage, + notFoundErrorPage, + ], }), ], /* Handled through config instead */ diff --git a/packages/app-next/src/examples/notFoundErrorPageExtension.tsx b/packages/app-next/src/examples/notFoundErrorPageExtension.tsx new file mode 100644 index 0000000000..f83671bc23 --- /dev/null +++ b/packages/app-next/src/examples/notFoundErrorPageExtension.tsx @@ -0,0 +1,56 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { + createComponentExtension, + coreComponentRefs, +} from '@backstage/frontend-plugin-api'; +import { Box, Typography } from '@material-ui/core'; +import { Button } from '@backstage/core-components'; + +export function CustomNotFoundErrorPage() { + return ( + + 404 + + Unable to locate this page. Please contact your support team if this + page used to exist. + + + + ); +} + +export default createComponentExtension({ + ref: coreComponentRefs.notFoundErrorPage, + loader: { sync: () => CustomNotFoundErrorPage }, +}); diff --git a/packages/app-next/src/examples/pagesPlugin.tsx b/packages/app-next/src/examples/pagesPlugin.tsx index 1e9409a5e4..c5069f99c3 100644 --- a/packages/app-next/src/examples/pagesPlugin.tsx +++ b/packages/app-next/src/examples/pagesPlugin.tsx @@ -36,7 +36,7 @@ export const pageXRouteRef = createRouteRef(); // }); const IndexPage = createPageExtension({ - id: 'index', + name: 'index', defaultPath: '/', routeRef: indexRouteRef, loader: async () => { @@ -68,7 +68,7 @@ const IndexPage = createPageExtension({ }); const Page1 = createPageExtension({ - id: 'page1', + name: 'page1', defaultPath: '/page1', routeRef: page1RouteRef, loader: async () => { @@ -102,7 +102,7 @@ const Page1 = createPageExtension({ }); const ExternalPage = createPageExtension({ - id: 'pageX', + name: 'pageX', defaultPath: '/pageX', routeRef: pageXRouteRef, loader: async () => { diff --git a/packages/app/CHANGELOG.md b/packages/app/CHANGELOG.md index 67166b089b..6cf62774c1 100644 --- a/packages/app/CHANGELOG.md +++ b/packages/app/CHANGELOG.md @@ -1,5 +1,775 @@ # example-app +## 0.2.91 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-api-docs@0.10.3 + - @backstage/plugin-scaffolder-react@1.7.1 + - @backstage/core-components@0.13.10 + - @backstage/plugin-user-settings@0.8.0 + - @backstage/plugin-azure-sites@0.1.18 + - @backstage/cli@0.25.1 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-octopus-deploy@0.2.11 + - @backstage/frontend-app-api@0.5.0 + - @backstage/plugin-kubernetes@0.11.4 + - @backstage/plugin-home@0.6.1 + - @backstage/plugin-scaffolder@1.17.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.4 + - @backstage/plugin-catalog-unprocessed-entities@0.1.7 + - @backstage/plugin-kubernetes-cluster@0.0.5 + - @backstage/plugin-microsoft-calendar@0.1.11 + - @backstage/plugin-newrelic-dashboard@0.3.4 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/plugin-entity-feedback@0.2.12 + - @backstage/plugin-apache-airflow@0.2.19 + - @backstage/plugin-github-actions@0.6.10 + - @backstage/plugin-stack-overflow@0.1.24 + - @backstage/plugin-techdocs-react@1.1.15 + - @backstage/plugin-catalog-graph@0.3.3 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/plugin-code-coverage@0.2.22 + - @backstage/plugin-cost-insights@0.12.18 + - @backstage/plugin-tech-insights@0.3.21 + - @backstage/plugin-azure-devops@0.3.11 + - @backstage/plugin-gcp-projects@0.3.45 + - @backstage/plugin-cloudbuild@0.3.29 + - @backstage/plugin-lighthouse@0.4.14 + - @backstage/plugin-stackstorm@0.1.10 + - @backstage/plugin-tech-radar@0.6.12 + - @backstage/plugin-dynatrace@8.0.3 + - @backstage/plugin-gcalendar@0.3.22 + - @backstage/plugin-pagerduty@0.7.1 + - @backstage/plugin-shortcuts@0.3.18 + - @backstage/plugin-airbrake@0.3.29 + - @backstage/plugin-devtools@0.1.8 + - @backstage/plugin-graphiql@0.3.2 + - @backstage/plugin-linguist@0.1.14 + - @backstage/plugin-newrelic@0.3.44 + - @backstage/plugin-playlist@0.2.3 + - @backstage/plugin-puppetdb@0.1.12 + - @backstage/plugin-techdocs@1.9.3 + - @backstage/plugin-catalog@1.16.1 + - @backstage/plugin-explore@0.4.15 + - @backstage/plugin-jenkins@0.9.4 + - @backstage/plugin-rollbar@0.4.29 + - @backstage/plugin-badges@0.2.53 + - @backstage/plugin-search@1.4.5 + - @backstage/plugin-sentry@0.5.14 + - @backstage/plugin-kafka@0.3.29 + - @backstage/plugin-nomad@0.1.10 + - @backstage/plugin-gocd@0.1.35 + - @backstage/plugin-todo@0.2.33 + - @backstage/plugin-adr@0.6.12 + - @backstage/plugin-org@0.6.19 + - @backstage/plugin-catalog-import@0.10.5 + - @backstage/plugin-search-react@1.7.5 + - @backstage/app-defaults@1.4.7 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.3 + - @backstage/theme@0.5.0 + - @backstage/plugin-catalog-common@1.0.20 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.10 + +## 0.2.91-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-user-settings@0.8.0-next.2 + - @backstage/plugin-octopus-deploy@0.2.11-next.2 + - @backstage/frontend-app-api@0.4.1-next.2 + - @backstage/plugin-home@0.6.1-next.2 + - @backstage/plugin-scaffolder-react@1.7.1-next.2 + - @backstage/plugin-scaffolder@1.17.1-next.2 + - @backstage/plugin-linguist@0.1.14-next.2 + - @backstage/plugin-catalog@1.16.1-next.2 + - @backstage/plugin-catalog-import@0.10.5-next.2 + - @backstage/plugin-graphiql@0.3.2-next.2 + - @backstage/plugin-search@1.4.5-next.2 + - @backstage/plugin-tech-radar@0.6.12-next.2 + - @backstage/plugin-techdocs@1.9.3-next.2 + - @backstage/plugin-adr@0.6.12-next.2 + - @backstage/plugin-catalog-react@1.9.3-next.2 + - @backstage/plugin-explore@0.4.15-next.2 + - @backstage/plugin-search-react@1.7.5-next.2 + - @backstage/plugin-stack-overflow@0.1.24-next.2 + - @backstage/cli@0.25.1-next.1 + - @backstage/plugin-pagerduty@0.7.1-next.2 + - @backstage/plugin-api-docs@0.10.3-next.2 + - @backstage/plugin-catalog-graph@0.3.3-next.2 + - @backstage/plugin-org@0.6.19-next.2 + - @backstage/plugin-airbrake@0.3.29-next.2 + - @backstage/plugin-azure-devops@0.3.11-next.2 + - @backstage/plugin-azure-sites@0.1.18-next.2 + - @backstage/plugin-badges@0.2.53-next.2 + - @backstage/plugin-cloudbuild@0.3.29-next.2 + - @backstage/plugin-code-coverage@0.2.22-next.2 + - @backstage/plugin-cost-insights@0.12.18-next.2 + - @backstage/plugin-dynatrace@8.0.3-next.2 + - @backstage/plugin-entity-feedback@0.2.12-next.2 + - @backstage/plugin-github-actions@0.6.10-next.2 + - @backstage/plugin-gocd@0.1.35-next.2 + - @backstage/plugin-jenkins@0.9.4-next.2 + - @backstage/plugin-kafka@0.3.29-next.2 + - @backstage/plugin-kubernetes@0.11.4-next.2 + - @backstage/plugin-kubernetes-cluster@0.0.5-next.2 + - @backstage/plugin-lighthouse@0.4.14-next.2 + - @backstage/plugin-newrelic-dashboard@0.3.4-next.2 + - @backstage/plugin-nomad@0.1.10-next.2 + - @backstage/plugin-playlist@0.2.3-next.2 + - @backstage/plugin-puppetdb@0.1.12-next.2 + - @backstage/plugin-rollbar@0.4.29-next.2 + - @backstage/plugin-sentry@0.5.14-next.2 + - @backstage/plugin-tech-insights@0.3.21-next.2 + - @backstage/plugin-todo@0.2.33-next.2 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.4-next.1 + - @backstage/integration-react@1.1.23-next.0 + - @backstage/plugin-apache-airflow@0.2.19-next.1 + - @backstage/plugin-catalog-unprocessed-entities@0.1.7-next.1 + - @backstage/plugin-devtools@0.1.8-next.1 + - @backstage/plugin-gcalendar@0.3.22-next.1 + - @backstage/plugin-gcp-projects@0.3.45-next.1 + - @backstage/plugin-microsoft-calendar@0.1.11-next.1 + - @backstage/plugin-newrelic@0.3.44-next.1 + - @backstage/plugin-shortcuts@0.3.18-next.1 + - @backstage/plugin-stackstorm@0.1.10-next.1 + +## 0.2.91-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-azure-sites@0.1.18-next.1 + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/plugin-user-settings@0.8.0-next.1 + - @backstage/plugin-kubernetes@0.11.4-next.1 + - @backstage/core-components@0.13.10-next.1 + - @backstage/app-defaults@1.4.7-next.1 + - @backstage/cli@0.25.1-next.1 + - @backstage/core-app-api@1.11.3-next.0 + - @backstage/frontend-app-api@0.4.1-next.1 + - @backstage/integration-react@1.1.23-next.0 + - @backstage/plugin-adr@0.6.12-next.1 + - @backstage/plugin-airbrake@0.3.29-next.1 + - @backstage/plugin-apache-airflow@0.2.19-next.1 + - @backstage/plugin-api-docs@0.10.3-next.1 + - @backstage/plugin-azure-devops@0.3.11-next.1 + - @backstage/plugin-badges@0.2.53-next.1 + - @backstage/plugin-catalog@1.16.1-next.1 + - @backstage/plugin-catalog-graph@0.3.3-next.1 + - @backstage/plugin-catalog-import@0.10.5-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/plugin-catalog-unprocessed-entities@0.1.7-next.1 + - @backstage/plugin-cloudbuild@0.3.29-next.1 + - @backstage/plugin-code-coverage@0.2.22-next.1 + - @backstage/plugin-cost-insights@0.12.18-next.1 + - @backstage/plugin-devtools@0.1.8-next.1 + - @backstage/plugin-dynatrace@8.0.3-next.1 + - @backstage/plugin-entity-feedback@0.2.12-next.1 + - @backstage/plugin-explore@0.4.15-next.1 + - @backstage/plugin-gcalendar@0.3.22-next.1 + - @backstage/plugin-gcp-projects@0.3.45-next.1 + - @backstage/plugin-github-actions@0.6.10-next.1 + - @backstage/plugin-gocd@0.1.35-next.1 + - @backstage/plugin-graphiql@0.3.2-next.1 + - @backstage/plugin-home@0.6.1-next.1 + - @backstage/plugin-jenkins@0.9.4-next.1 + - @backstage/plugin-kafka@0.3.29-next.1 + - @backstage/plugin-kubernetes-cluster@0.0.5-next.1 + - @backstage/plugin-lighthouse@0.4.14-next.1 + - @backstage/plugin-linguist@0.1.14-next.1 + - @backstage/plugin-microsoft-calendar@0.1.11-next.1 + - @backstage/plugin-newrelic@0.3.44-next.1 + - @backstage/plugin-newrelic-dashboard@0.3.4-next.1 + - @backstage/plugin-nomad@0.1.10-next.1 + - @backstage/plugin-octopus-deploy@0.2.11-next.1 + - @backstage/plugin-org@0.6.19-next.1 + - @backstage/plugin-pagerduty@0.7.1-next.1 + - @backstage/plugin-permission-react@0.4.19-next.1 + - @backstage/plugin-playlist@0.2.3-next.1 + - @backstage/plugin-puppetdb@0.1.12-next.1 + - @backstage/plugin-rollbar@0.4.29-next.1 + - @backstage/plugin-scaffolder@1.17.1-next.1 + - @backstage/plugin-scaffolder-react@1.7.1-next.1 + - @backstage/plugin-search@1.4.5-next.1 + - @backstage/plugin-search-react@1.7.5-next.1 + - @backstage/plugin-sentry@0.5.14-next.1 + - @backstage/plugin-shortcuts@0.3.18-next.1 + - @backstage/plugin-stack-overflow@0.1.24-next.1 + - @backstage/plugin-stackstorm@0.1.10-next.1 + - @backstage/plugin-tech-insights@0.3.21-next.1 + - @backstage/plugin-tech-radar@0.6.12-next.1 + - @backstage/plugin-techdocs@1.9.3-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.4-next.1 + - @backstage/plugin-techdocs-react@1.1.15-next.1 + - @backstage/plugin-todo@0.2.33-next.1 + - @backstage/config@1.1.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.9 + +## 0.2.91-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.7.1-next.0 + - @backstage/core-components@0.13.10-next.0 + - @backstage/cli@0.25.1-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.4-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.1.7-next.0 + - @backstage/plugin-kubernetes-cluster@0.0.5-next.0 + - @backstage/plugin-microsoft-calendar@0.1.11-next.0 + - @backstage/plugin-newrelic-dashboard@0.3.4-next.0 + - @backstage/plugin-permission-react@0.4.19-next.0 + - @backstage/plugin-entity-feedback@0.2.12-next.0 + - @backstage/plugin-apache-airflow@0.2.19-next.0 + - @backstage/plugin-github-actions@0.6.10-next.0 + - @backstage/plugin-octopus-deploy@0.2.11-next.0 + - @backstage/plugin-stack-overflow@0.1.24-next.0 + - @backstage/plugin-techdocs-react@1.1.15-next.0 + - @backstage/plugin-catalog-graph@0.3.3-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/plugin-code-coverage@0.2.22-next.0 + - @backstage/plugin-cost-insights@0.12.18-next.0 + - @backstage/plugin-tech-insights@0.3.21-next.0 + - @backstage/plugin-user-settings@0.7.15-next.0 + - @backstage/plugin-azure-devops@0.3.11-next.0 + - @backstage/plugin-gcp-projects@0.3.45-next.0 + - @backstage/plugin-azure-sites@0.1.18-next.0 + - @backstage/plugin-cloudbuild@0.3.29-next.0 + - @backstage/plugin-kubernetes@0.11.4-next.0 + - @backstage/plugin-lighthouse@0.4.14-next.0 + - @backstage/plugin-scaffolder@1.17.1-next.0 + - @backstage/plugin-stackstorm@0.1.10-next.0 + - @backstage/plugin-tech-radar@0.6.12-next.0 + - @backstage/plugin-dynatrace@8.0.3-next.0 + - @backstage/plugin-gcalendar@0.3.22-next.0 + - @backstage/plugin-pagerduty@0.7.1-next.0 + - @backstage/plugin-shortcuts@0.3.18-next.0 + - @backstage/plugin-airbrake@0.3.29-next.0 + - @backstage/plugin-api-docs@0.10.3-next.0 + - @backstage/plugin-devtools@0.1.8-next.0 + - @backstage/plugin-graphiql@0.3.2-next.0 + - @backstage/plugin-linguist@0.1.14-next.0 + - @backstage/plugin-newrelic@0.3.44-next.0 + - @backstage/plugin-playlist@0.2.3-next.0 + - @backstage/plugin-puppetdb@0.1.12-next.0 + - @backstage/plugin-techdocs@1.9.3-next.0 + - @backstage/plugin-catalog@1.16.1-next.0 + - @backstage/plugin-explore@0.4.15-next.0 + - @backstage/plugin-jenkins@0.9.4-next.0 + - @backstage/plugin-rollbar@0.4.29-next.0 + - @backstage/plugin-badges@0.2.53-next.0 + - @backstage/plugin-search@1.4.5-next.0 + - @backstage/plugin-sentry@0.5.14-next.0 + - @backstage/plugin-kafka@0.3.29-next.0 + - @backstage/plugin-nomad@0.1.10-next.0 + - @backstage/plugin-gocd@0.1.35-next.0 + - @backstage/plugin-home@0.6.1-next.0 + - @backstage/plugin-todo@0.2.33-next.0 + - @backstage/plugin-adr@0.6.12-next.0 + - @backstage/plugin-org@0.6.19-next.0 + - @backstage/app-defaults@1.4.7-next.0 + - @backstage/frontend-app-api@0.4.1-next.0 + - @backstage/integration-react@1.1.22 + - @backstage/plugin-catalog-import@0.10.5-next.0 + - @backstage/plugin-search-react@1.7.5-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.2 + - @backstage/core-plugin-api@1.8.1 + - @backstage/theme@0.5.0 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.9 + +## 0.2.90 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/frontend-app-api@0.4.0 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/plugin-api-docs@0.10.2 + - @backstage/core-components@0.13.9 + - @backstage/cli@0.25.0 + - @backstage/theme@0.5.0 + - @backstage/plugin-scaffolder@1.17.0 + - @backstage/plugin-home@0.6.0 + - @backstage/plugin-catalog@1.16.0 + - @backstage/plugin-scaffolder-react@1.7.0 + - @backstage/plugin-kubernetes@0.11.3 + - @backstage/plugin-org@0.6.18 + - @backstage/plugin-github-actions@0.6.9 + - @backstage/plugin-azure-devops@0.3.10 + - @backstage/core-app-api@1.11.2 + - @backstage/plugin-lighthouse@0.4.13 + - @backstage/plugin-explore@0.4.14 + - @backstage/plugin-catalog-import@0.10.4 + - @backstage/plugin-user-settings@0.7.14 + - @backstage/plugin-tech-radar@0.6.11 + - @backstage/plugin-graphiql@0.3.1 + - @backstage/plugin-techdocs@1.9.2 + - @backstage/plugin-search@1.4.4 + - @backstage/plugin-search-react@1.7.4 + - @backstage/plugin-stack-overflow@0.1.23 + - @backstage/plugin-adr@0.6.11 + - @backstage/plugin-gcp-projects@0.3.44 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.3 + - @backstage/plugin-pagerduty@0.7.0 + - @backstage/app-defaults@1.4.6 + - @backstage/integration-react@1.1.22 + - @backstage/plugin-airbrake@0.3.28 + - @backstage/plugin-apache-airflow@0.2.18 + - @backstage/plugin-azure-sites@0.1.17 + - @backstage/plugin-badges@0.2.52 + - @backstage/plugin-catalog-graph@0.3.2 + - @backstage/plugin-catalog-unprocessed-entities@0.1.6 + - @backstage/plugin-cloudbuild@0.3.28 + - @backstage/plugin-code-coverage@0.2.21 + - @backstage/plugin-cost-insights@0.12.17 + - @backstage/plugin-devtools@0.1.7 + - @backstage/plugin-dynatrace@8.0.2 + - @backstage/plugin-entity-feedback@0.2.11 + - @backstage/plugin-gcalendar@0.3.21 + - @backstage/plugin-gocd@0.1.34 + - @backstage/plugin-jenkins@0.9.3 + - @backstage/plugin-kafka@0.3.28 + - @backstage/plugin-kubernetes-cluster@0.0.4 + - @backstage/plugin-linguist@0.1.13 + - @backstage/plugin-microsoft-calendar@0.1.10 + - @backstage/plugin-newrelic@0.3.43 + - @backstage/plugin-newrelic-dashboard@0.3.3 + - @backstage/plugin-nomad@0.1.9 + - @backstage/plugin-octopus-deploy@0.2.10 + - @backstage/plugin-permission-react@0.4.18 + - @backstage/plugin-playlist@0.2.2 + - @backstage/plugin-puppetdb@0.1.11 + - @backstage/plugin-rollbar@0.4.28 + - @backstage/plugin-sentry@0.5.13 + - @backstage/plugin-shortcuts@0.3.17 + - @backstage/plugin-stackstorm@0.1.9 + - @backstage/plugin-tech-insights@0.3.20 + - @backstage/plugin-techdocs-react@1.1.14 + - @backstage/plugin-todo@0.2.32 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.9 + +## 0.2.90-next.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-home@0.6.0-next.3 + - @backstage/plugin-org@0.6.18-next.3 + - @backstage/plugin-azure-devops@0.3.10-next.3 + - @backstage/cli@0.25.0-next.3 + - @backstage/plugin-api-docs@0.10.2-next.4 + - @backstage/plugin-scaffolder-react@1.6.2-next.3 + - @backstage/plugin-scaffolder@1.16.2-next.3 + - @backstage/core-components@0.13.9-next.3 + - @backstage/app-defaults@1.4.6-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/frontend-app-api@0.4.0-next.3 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-adr@0.6.11-next.3 + - @backstage/plugin-airbrake@0.3.28-next.3 + - @backstage/plugin-apache-airflow@0.2.18-next.3 + - @backstage/plugin-azure-sites@0.1.17-next.3 + - @backstage/plugin-badges@0.2.52-next.3 + - @backstage/plugin-catalog@1.16.0-next.4 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-graph@0.3.2-next.3 + - @backstage/plugin-catalog-import@0.10.4-next.4 + - @backstage/plugin-catalog-react@1.9.2-next.3 + - @backstage/plugin-catalog-unprocessed-entities@0.1.6-next.3 + - @backstage/plugin-cloudbuild@0.3.28-next.3 + - @backstage/plugin-code-coverage@0.2.21-next.3 + - @backstage/plugin-cost-insights@0.12.17-next.3 + - @backstage/plugin-devtools@0.1.7-next.3 + - @backstage/plugin-dynatrace@8.0.2-next.3 + - @backstage/plugin-entity-feedback@0.2.11-next.3 + - @backstage/plugin-explore@0.4.14-next.3 + - @backstage/plugin-gcalendar@0.3.21-next.3 + - @backstage/plugin-gcp-projects@0.3.44-next.3 + - @backstage/plugin-github-actions@0.6.9-next.3 + - @backstage/plugin-gocd@0.1.34-next.3 + - @backstage/plugin-graphiql@0.3.1-next.4 + - @backstage/plugin-jenkins@0.9.3-next.3 + - @backstage/plugin-kafka@0.3.28-next.3 + - @backstage/plugin-kubernetes@0.11.3-next.3 + - @backstage/plugin-kubernetes-cluster@0.0.4-next.3 + - @backstage/plugin-lighthouse@0.4.13-next.3 + - @backstage/plugin-linguist@0.1.13-next.3 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-microsoft-calendar@0.1.10-next.3 + - @backstage/plugin-newrelic@0.3.43-next.3 + - @backstage/plugin-newrelic-dashboard@0.3.3-next.3 + - @backstage/plugin-nomad@0.1.9-next.3 + - @backstage/plugin-octopus-deploy@0.2.10-next.3 + - @backstage/plugin-pagerduty@0.7.0-next.3 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/plugin-playlist@0.2.2-next.3 + - @backstage/plugin-puppetdb@0.1.11-next.3 + - @backstage/plugin-rollbar@0.4.28-next.3 + - @backstage/plugin-search@1.4.4-next.4 + - @backstage/plugin-search-common@1.2.8 + - @backstage/plugin-search-react@1.7.4-next.3 + - @backstage/plugin-sentry@0.5.13-next.3 + - @backstage/plugin-shortcuts@0.3.17-next.3 + - @backstage/plugin-stack-overflow@0.1.23-next.3 + - @backstage/plugin-stackstorm@0.1.9-next.3 + - @backstage/plugin-tech-insights@0.3.20-next.3 + - @backstage/plugin-tech-radar@0.6.11-next.4 + - @backstage/plugin-techdocs@1.9.2-next.4 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.3-next.3 + - @backstage/plugin-techdocs-react@1.1.14-next.3 + - @backstage/plugin-todo@0.2.32-next.3 + - @backstage/plugin-user-settings@0.7.14-next.4 + +## 0.2.90-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-app-api@0.4.0-next.2 + - @backstage/cli@0.25.0-next.2 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-kubernetes@0.11.3-next.2 + - @backstage/plugin-lighthouse@0.4.13-next.2 + - @backstage/plugin-catalog-import@0.10.4-next.3 + - @backstage/plugin-user-settings@0.7.14-next.3 + - @backstage/plugin-tech-radar@0.6.11-next.3 + - @backstage/plugin-graphiql@0.3.1-next.3 + - @backstage/plugin-techdocs@1.9.2-next.3 + - @backstage/plugin-catalog@1.16.0-next.3 + - @backstage/plugin-search@1.4.4-next.3 + - @backstage/plugin-home@0.6.0-next.2 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/plugin-stack-overflow@0.1.23-next.2 + - @backstage/plugin-search-react@1.7.4-next.2 + - @backstage/plugin-explore@0.4.14-next.2 + - @backstage/plugin-adr@0.6.11-next.2 + - @backstage/plugin-scaffolder-react@1.6.2-next.2 + - @backstage/app-defaults@1.4.6-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-airbrake@0.3.28-next.2 + - @backstage/plugin-apache-airflow@0.2.18-next.2 + - @backstage/plugin-api-docs@0.10.2-next.3 + - @backstage/plugin-azure-devops@0.3.10-next.2 + - @backstage/plugin-azure-sites@0.1.17-next.2 + - @backstage/plugin-badges@0.2.52-next.2 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-graph@0.3.2-next.2 + - @backstage/plugin-catalog-unprocessed-entities@0.1.6-next.2 + - @backstage/plugin-cloudbuild@0.3.28-next.2 + - @backstage/plugin-code-coverage@0.2.21-next.2 + - @backstage/plugin-cost-insights@0.12.17-next.2 + - @backstage/plugin-devtools@0.1.7-next.2 + - @backstage/plugin-dynatrace@8.0.2-next.2 + - @backstage/plugin-entity-feedback@0.2.11-next.2 + - @backstage/plugin-gcalendar@0.3.21-next.2 + - @backstage/plugin-gcp-projects@0.3.44-next.2 + - @backstage/plugin-github-actions@0.6.9-next.2 + - @backstage/plugin-gocd@0.1.34-next.2 + - @backstage/plugin-jenkins@0.9.3-next.2 + - @backstage/plugin-kafka@0.3.28-next.2 + - @backstage/plugin-kubernetes-cluster@0.0.4-next.2 + - @backstage/plugin-linguist@0.1.13-next.2 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-microsoft-calendar@0.1.10-next.2 + - @backstage/plugin-newrelic@0.3.43-next.2 + - @backstage/plugin-newrelic-dashboard@0.3.3-next.2 + - @backstage/plugin-nomad@0.1.9-next.2 + - @backstage/plugin-octopus-deploy@0.2.10-next.2 + - @backstage/plugin-org@0.6.18-next.2 + - @backstage/plugin-pagerduty@0.7.0-next.2 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/plugin-playlist@0.2.2-next.2 + - @backstage/plugin-puppetdb@0.1.11-next.2 + - @backstage/plugin-rollbar@0.4.28-next.2 + - @backstage/plugin-scaffolder@1.16.2-next.2 + - @backstage/plugin-search-common@1.2.8 + - @backstage/plugin-sentry@0.5.13-next.2 + - @backstage/plugin-shortcuts@0.3.17-next.2 + - @backstage/plugin-stackstorm@0.1.9-next.2 + - @backstage/plugin-tech-insights@0.3.20-next.2 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.3-next.2 + - @backstage/plugin-techdocs-react@1.1.14-next.2 + - @backstage/plugin-todo@0.2.32-next.2 + +## 0.2.90-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-app-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/cli@0.25.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-catalog@1.16.0-next.2 + - @backstage/plugin-scaffolder-react@1.6.2-next.1 + - @backstage/plugin-home@0.6.0-next.1 + - @backstage/plugin-github-actions@0.6.9-next.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/plugin-search-react@1.7.4-next.1 + - @backstage/plugin-azure-devops@0.3.10-next.1 + - @backstage/plugin-scaffolder@1.16.2-next.1 + - @backstage/plugin-api-docs@0.10.2-next.2 + - @backstage/plugin-gcp-projects@0.3.44-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.3-next.1 + - @backstage/plugin-user-settings@0.7.14-next.2 + - @backstage/plugin-adr@0.6.11-next.1 + - @backstage/plugin-pagerduty@0.7.0-next.1 + - @backstage/plugin-catalog-import@0.10.4-next.2 + - @backstage/plugin-explore@0.4.14-next.1 + - @backstage/plugin-graphiql@0.3.1-next.2 + - @backstage/plugin-search@1.4.4-next.2 + - @backstage/plugin-stack-overflow@0.1.23-next.1 + - @backstage/plugin-tech-radar@0.6.11-next.2 + - @backstage/plugin-techdocs@1.9.2-next.2 + - @backstage/app-defaults@1.4.6-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-airbrake@0.3.28-next.1 + - @backstage/plugin-apache-airflow@0.2.18-next.1 + - @backstage/plugin-azure-sites@0.1.17-next.1 + - @backstage/plugin-badges@0.2.52-next.1 + - @backstage/plugin-catalog-graph@0.3.2-next.1 + - @backstage/plugin-catalog-unprocessed-entities@0.1.6-next.1 + - @backstage/plugin-cloudbuild@0.3.28-next.1 + - @backstage/plugin-code-coverage@0.2.21-next.1 + - @backstage/plugin-cost-insights@0.12.17-next.1 + - @backstage/plugin-devtools@0.1.7-next.1 + - @backstage/plugin-dynatrace@8.0.2-next.1 + - @backstage/plugin-entity-feedback@0.2.11-next.1 + - @backstage/plugin-gcalendar@0.3.21-next.1 + - @backstage/plugin-gocd@0.1.34-next.1 + - @backstage/plugin-jenkins@0.9.3-next.1 + - @backstage/plugin-kafka@0.3.28-next.1 + - @backstage/plugin-kubernetes@0.11.3-next.1 + - @backstage/plugin-kubernetes-cluster@0.0.4-next.1 + - @backstage/plugin-lighthouse@0.4.13-next.1 + - @backstage/plugin-linguist@0.1.13-next.1 + - @backstage/plugin-microsoft-calendar@0.1.10-next.1 + - @backstage/plugin-newrelic@0.3.43-next.1 + - @backstage/plugin-newrelic-dashboard@0.3.3-next.1 + - @backstage/plugin-nomad@0.1.9-next.1 + - @backstage/plugin-octopus-deploy@0.2.10-next.1 + - @backstage/plugin-org@0.6.18-next.1 + - @backstage/plugin-playlist@0.2.2-next.1 + - @backstage/plugin-puppetdb@0.1.11-next.1 + - @backstage/plugin-rollbar@0.4.28-next.1 + - @backstage/plugin-sentry@0.5.13-next.1 + - @backstage/plugin-shortcuts@0.3.17-next.1 + - @backstage/plugin-stackstorm@0.1.9-next.1 + - @backstage/plugin-tech-insights@0.3.20-next.1 + - @backstage/plugin-techdocs-react@1.1.14-next.1 + - @backstage/plugin-todo@0.2.32-next.1 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.8 + +## 0.2.90-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.16.0-next.1 + - @backstage/plugin-catalog-import@0.10.4-next.1 + - @backstage/plugin-graphiql@0.3.1-next.1 + - @backstage/plugin-search@1.4.4-next.1 + - @backstage/plugin-tech-radar@0.6.11-next.1 + - @backstage/plugin-techdocs@1.9.2-next.1 + - @backstage/plugin-user-settings@0.7.14-next.1 + - @backstage/plugin-api-docs@0.10.2-next.1 + - @backstage/plugin-catalog-graph@0.3.2-next.0 + - @backstage/plugin-explore@0.4.14-next.0 + - @backstage/plugin-org@0.6.18-next.0 + - @backstage/plugin-scaffolder@1.16.2-next.0 + - @backstage/plugin-scaffolder-react@1.6.2-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.3-next.0 + +## 0.2.90-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/plugin-api-docs@0.10.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/plugin-scaffolder@1.16.2-next.0 + - @backstage/plugin-catalog@1.16.0-next.0 + - @backstage/frontend-app-api@0.3.1-next.0 + - @backstage/plugin-org@0.6.18-next.0 + - @backstage/plugin-scaffolder-react@1.6.2-next.0 + - @backstage/plugin-catalog-import@0.10.4-next.0 + - @backstage/plugin-user-settings@0.7.14-next.0 + - @backstage/plugin-tech-radar@0.6.11-next.0 + - @backstage/plugin-graphiql@0.3.1-next.0 + - @backstage/plugin-techdocs@1.9.2-next.0 + - @backstage/plugin-search@1.4.4-next.0 + - @backstage/plugin-search-react@1.7.4-next.0 + - @backstage/cli@0.24.1-next.0 + - @backstage/plugin-home@0.5.12-next.0 + - @backstage/plugin-kubernetes@0.11.3-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/app-defaults@1.4.6-next.0 + - @backstage/core-app-api@1.11.2-next.0 + - @backstage/integration-react@1.1.22-next.0 + - @backstage/plugin-adr@0.6.11-next.0 + - @backstage/plugin-airbrake@0.3.28-next.0 + - @backstage/plugin-apache-airflow@0.2.18-next.0 + - @backstage/plugin-azure-devops@0.3.10-next.0 + - @backstage/plugin-azure-sites@0.1.17-next.0 + - @backstage/plugin-badges@0.2.52-next.0 + - @backstage/plugin-catalog-graph@0.3.2-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.1.6-next.0 + - @backstage/plugin-circleci@0.3.28-next.0 + - @backstage/plugin-cloudbuild@0.3.28-next.0 + - @backstage/plugin-code-coverage@0.2.21-next.0 + - @backstage/plugin-cost-insights@0.12.17-next.0 + - @backstage/plugin-devtools@0.1.7-next.0 + - @backstage/plugin-dynatrace@8.0.2-next.0 + - @backstage/plugin-entity-feedback@0.2.11-next.0 + - @backstage/plugin-explore@0.4.14-next.0 + - @backstage/plugin-gcalendar@0.3.21-next.0 + - @backstage/plugin-gcp-projects@0.3.44-next.0 + - @backstage/plugin-github-actions@0.6.9-next.0 + - @backstage/plugin-gocd@0.1.34-next.0 + - @backstage/plugin-jenkins@0.9.3-next.0 + - @backstage/plugin-kafka@0.3.28-next.0 + - @backstage/plugin-kubernetes-cluster@0.0.4-next.0 + - @backstage/plugin-lighthouse@0.4.13-next.0 + - @backstage/plugin-linguist@0.1.13-next.0 + - @backstage/plugin-microsoft-calendar@0.1.10-next.0 + - @backstage/plugin-newrelic@0.3.43-next.0 + - @backstage/plugin-newrelic-dashboard@0.3.3-next.0 + - @backstage/plugin-nomad@0.1.9-next.0 + - @backstage/plugin-octopus-deploy@0.2.10-next.0 + - @backstage/plugin-pagerduty@0.6.9-next.0 + - @backstage/plugin-permission-react@0.4.18-next.0 + - @backstage/plugin-playlist@0.2.2-next.0 + - @backstage/plugin-puppetdb@0.1.11-next.0 + - @backstage/plugin-rollbar@0.4.28-next.0 + - @backstage/plugin-sentry@0.5.13-next.0 + - @backstage/plugin-shortcuts@0.3.17-next.0 + - @backstage/plugin-stack-overflow@0.1.23-next.0 + - @backstage/plugin-stackstorm@0.1.9-next.0 + - @backstage/plugin-tech-insights@0.3.20-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.3-next.0 + - @backstage/plugin-techdocs-react@1.1.14-next.0 + - @backstage/plugin-todo@0.2.32-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.8 + +## 0.2.89 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-api-docs@0.10.0 + - @backstage/plugin-catalog-import@0.10.2 + - @backstage/cli@0.24.0 + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/plugin-shortcuts@0.3.16 + - @backstage/plugin-home@0.5.10 + - @backstage/core-components@0.13.8 + - @backstage/plugin-catalog@1.15.0 + - @backstage/plugin-graphiql@0.3.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.2 + - @backstage/plugin-techdocs@1.9.0 + - @backstage/plugin-cloudbuild@0.3.26 + - @backstage/plugin-scaffolder@1.16.0 + - @backstage/frontend-app-api@0.3.0 + - @backstage/plugin-user-settings@0.7.12 + - @backstage/plugin-tech-radar@0.6.10 + - @backstage/plugin-search@1.4.2 + - @backstage/plugin-catalog-unprocessed-entities@0.1.5 + - @backstage/integration-react@1.1.21 + - @backstage/plugin-kubernetes-cluster@0.0.2 + - @backstage/plugin-microsoft-calendar@0.1.9 + - @backstage/plugin-newrelic-dashboard@0.3.1 + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-permission-react@0.4.17 + - @backstage/plugin-scaffolder-react@1.6.0 + - @backstage/plugin-entity-feedback@0.2.9 + - @backstage/plugin-apache-airflow@0.2.17 + - @backstage/plugin-github-actions@0.6.7 + - @backstage/plugin-octopus-deploy@0.2.8 + - @backstage/plugin-stack-overflow@0.1.22 + - @backstage/plugin-techdocs-react@1.1.13 + - @backstage/app-defaults@1.4.5 + - @backstage/core-app-api@1.11.1 + - @backstage/plugin-catalog-graph@0.3.0 + - @backstage/plugin-code-coverage@0.2.19 + - @backstage/plugin-cost-insights@0.12.15 + - @backstage/plugin-tech-insights@0.3.18 + - @backstage/plugin-azure-devops@0.3.8 + - @backstage/plugin-gcp-projects@0.3.43 + - @backstage/plugin-search-react@1.7.2 + - @backstage/plugin-azure-sites@0.1.15 + - @backstage/plugin-kubernetes@0.11.1 + - @backstage/plugin-lighthouse@0.4.11 + - @backstage/plugin-stackstorm@0.1.8 + - @backstage/plugin-dynatrace@8.0.0 + - @backstage/plugin-gcalendar@0.3.20 + - @backstage/plugin-pagerduty@0.6.7 + - @backstage/plugin-airbrake@0.3.26 + - @backstage/plugin-circleci@0.3.26 + - @backstage/plugin-devtools@0.1.6 + - @backstage/plugin-linguist@0.1.11 + - @backstage/plugin-newrelic@0.3.42 + - @backstage/plugin-playlist@0.2.0 + - @backstage/plugin-puppetdb@0.1.9 + - @backstage/plugin-explore@0.4.12 + - @backstage/plugin-jenkins@0.9.1 + - @backstage/plugin-rollbar@0.4.26 + - @backstage/theme@0.4.4 + - @backstage/plugin-badges@0.2.50 + - @backstage/plugin-sentry@0.5.11 + - @backstage/plugin-kafka@0.3.26 + - @backstage/plugin-nomad@0.1.7 + - @backstage/plugin-gocd@0.1.32 + - @backstage/plugin-todo@0.2.30 + - @backstage/plugin-adr@0.6.9 + - @backstage/plugin-org@0.6.16 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.8 + ## 0.2.89-next.2 ### Patch Changes diff --git a/packages/app/package.json b/packages/app/package.json index 3655c38b13..fbbe6ce09d 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "example-app", - "version": "0.2.89-next.2", + "version": "0.2.91", "private": true, "backstage": { "role": "frontend" @@ -35,7 +35,6 @@ "@backstage/plugin-catalog-import": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", "@backstage/plugin-catalog-unprocessed-entities": "workspace:^", - "@backstage/plugin-circleci": "workspace:^", "@backstage/plugin-cloudbuild": "workspace:^", "@backstage/plugin-code-coverage": "workspace:^", "@backstage/plugin-cost-insights": "workspace:^", @@ -84,6 +83,7 @@ "@backstage/plugin-todo": "workspace:^", "@backstage/plugin-user-settings": "workspace:^", "@backstage/theme": "workspace:^", + "@circleci/backstage-plugin": "^0.1.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", @@ -102,7 +102,7 @@ "react-use": "^17.2.4", "vite": "^4.4.9", "vite-plugin-html": "^3.2.0", - "vite-plugin-node-polyfills": "^0.16.0", + "vite-plugin-node-polyfills": "^0.17.0", "zen-observable": "^0.10.0" }, "devDependencies": { diff --git a/packages/app/src/components/catalog/EntityPage.test.tsx b/packages/app/src/components/catalog/EntityPage.test.tsx index 68ce5fb497..25181db2c1 100644 --- a/packages/app/src/components/catalog/EntityPage.test.tsx +++ b/packages/app/src/components/catalog/EntityPage.test.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { EntityLayout } from '@backstage/plugin-catalog'; +import { EntityLayout, catalogPlugin } from '@backstage/plugin-catalog'; import { EntityProvider, starredEntitiesApiRef, @@ -51,6 +51,7 @@ describe('EntityPage Test', () => { listWorkflowRuns: jest.fn().mockResolvedValue([]), }; const mockPermissionApi = new MockPermissionApi(); + const rootRouteRef = catalogPlugin.routes.catalogIndex; describe('cicdContent', () => { it('Should render GitHub Actions View', async () => { @@ -70,6 +71,11 @@ describe('EntityPage Test', () => { , + { + mountedRoutes: { + '/catalog': rootRouteRef, + }, + }, ); expect(rendered.getByText('ExampleComponent')).toBeInTheDocument(); diff --git a/packages/app/src/components/catalog/EntityPage.tsx b/packages/app/src/components/catalog/EntityPage.tsx index ecc1f008b5..4d5f65cbbe 100644 --- a/packages/app/src/components/catalog/EntityPage.tsx +++ b/packages/app/src/components/catalog/EntityPage.tsx @@ -77,7 +77,7 @@ import { import { EntityCircleCIContent, isCircleCIAvailable, -} from '@backstage/plugin-circleci'; +} from '@circleci/backstage-plugin'; import { EntityCloudbuildContent, isCloudbuildAvailable, @@ -798,9 +798,12 @@ const groupPage = ( entityFilterKind={customEntityFilterKind} /> - + + + + diff --git a/packages/backend-app-api/CHANGELOG.md b/packages/backend-app-api/CHANGELOG.md index 256fa98f91..16106ee354 100644 --- a/packages/backend-app-api/CHANGELOG.md +++ b/packages/backend-app-api/CHANGELOG.md @@ -1,5 +1,178 @@ # @backstage/backend-app-api +## 0.5.10 + +### Patch Changes + +- 516fd3e: Updated README to reflect release status +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/config-loader@1.6.1 + - @backstage/cli-node@0.2.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.5.10-next.2 + +### Patch Changes + +- 516fd3e: Updated README to reflect release status +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + - @backstage/plugin-permission-node@0.7.20-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + - @backstage/cli-node@0.2.2-next.0 + - @backstage/config-loader@1.6.1-next.0 + +## 0.5.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.6.1-next.0 + - @backstage/cli-node@0.2.2-next.0 + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/plugin-permission-node@0.7.20-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.5.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/backend-tasks@0.5.14-next.0 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.1 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.6.0 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.0 + - @backstage/plugin-permission-node@0.7.20-next.0 + +## 0.5.9 + +### Patch Changes + +- 1da5f43: Ensure redaction of secrets that have accidental extra whitespace around them +- 9f8f266: Add redacting for secrets in stack traces of logs +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/config-loader@1.6.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/plugin-permission-node@0.7.19 + - @backstage/cli-node@0.2.1 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.5.9-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.6.0-next.0 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.3 + - @backstage/plugin-permission-node@0.7.19-next.3 + +## 0.5.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.6.0-next.0 + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/backend-tasks@0.5.13-next.2 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-node@0.7.19-next.2 + +## 0.5.9-next.1 + +### Patch Changes + +- 1da5f434f3: Ensure redaction of secrets that have accidental extra whitespace around them +- 9f8f266ff4: Add redacting for secrets in stack traces of logs +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.5.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-permission-node@0.7.19-next.1 + +## 0.5.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/plugin-permission-node@0.7.19-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.5.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.5.8 + +### Patch Changes + +- bc9a18d5ec: Added a workaround for double `default` wrapping when dynamically importing CommonJS modules with default exports. +- Updated dependencies + - @backstage/config-loader@1.5.3 + - @backstage/cli-node@0.2.0 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.1 + - @backstage/plugin-permission-node@0.7.18 + ## 0.5.8-next.2 ### Patch Changes diff --git a/packages/backend-app-api/README.md b/packages/backend-app-api/README.md index e5b80abeaf..3fd6170b4f 100644 --- a/packages/backend-app-api/README.md +++ b/packages/backend-app-api/README.md @@ -1,8 +1,6 @@ # @backstage/backend-app-api -**This package is EXPERIMENTAL, we recommend against using it for production deployments** - -This package provides the core API used by Backstage backend apps. +This package provides the framework API used by Backstage backend apps. ## Installation diff --git a/packages/backend-app-api/alpha-api-report.md b/packages/backend-app-api/api-report-alpha.md similarity index 100% rename from packages/backend-app-api/alpha-api-report.md rename to packages/backend-app-api/api-report-alpha.md diff --git a/packages/backend-app-api/package.json b/packages/backend-app-api/package.json index 8fc20cff33..37fa2c5258 100644 --- a/packages/backend-app-api/package.json +++ b/packages/backend-app-api/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-app-api", "description": "Core API used by Backstage backend apps", - "version": "0.5.8-next.2", + "version": "0.5.10", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend-app-api/src/logging/WinstonLogger.test.ts b/packages/backend-app-api/src/logging/WinstonLogger.test.ts index 5d8cfc9c90..c7173b1cbe 100644 --- a/packages/backend-app-api/src/logging/WinstonLogger.test.ts +++ b/packages/backend-app-api/src/logging/WinstonLogger.test.ts @@ -14,25 +14,37 @@ * limitations under the License. */ +import { TransformableInfo } from 'logform'; import { WinstonLogger } from './WinstonLogger'; -function msg(message: string) { - return { message, level: 'info' }; +function msg(info: TransformableInfo): TransformableInfo { + return { message: info.message, level: info.level, stack: info.stack }; } describe('WinstonLogger', () => { it('redacter should redact and escape regex', () => { const redacter = WinstonLogger.redacter(); - expect(redacter.format.transform(msg('hello (world)'))).toEqual( - msg('hello (world)'), + const log = { + level: 'error', + message: 'hello (world)', + stack: 'hello (world) from this file', + }; + expect(redacter.format.transform(msg(log))).toEqual(msg(log)); + redacter.add(['hello\n']); + expect(redacter.format.transform(msg(log))).toEqual( + msg({ + ...log, + message: '[REDACTED] (world)', + stack: '[REDACTED] (world) from this file', + }), ); - redacter.add(['hello']); - expect(redacter.format.transform(msg('hello (world)'))).toEqual( - msg('[REDACTED] (world)'), - ); - redacter.add(['(world)']); - expect(redacter.format.transform(msg('hello (world)'))).toEqual( - msg('[REDACTED] [REDACTED]'), + redacter.add(['(world']); + expect(redacter.format.transform(msg(log))).toEqual( + msg({ + ...log, + message: '[REDACTED] [REDACTED])', + stack: '[REDACTED] [REDACTED]) from this file', + }), ); }); }); diff --git a/packages/backend-app-api/src/logging/WinstonLogger.ts b/packages/backend-app-api/src/logging/WinstonLogger.ts index 06a189508b..7dd0ed80b0 100644 --- a/packages/backend-app-api/src/logging/WinstonLogger.ts +++ b/packages/backend-app-api/src/logging/WinstonLogger.ts @@ -82,11 +82,18 @@ export class WinstonLogger implements RootLoggerService { if (redactionPattern && typeof info.message === 'string') { info.message = info.message.replace(redactionPattern, '[REDACTED]'); } + if (redactionPattern && typeof info.stack === 'string') { + info.stack = info.stack.replace(redactionPattern, '[REDACTED]'); + } return info; })(), add(newRedactions) { let added = 0; - for (const redaction of newRedactions) { + for (const redactionToTrim of newRedactions) { + // Trimming the string ensures that we don't accdentally get extra + // newlines or other whitespace interfering with the redaction; this + // can happen for example when using string literals in yaml + const redaction = redactionToTrim.trim(); // Exclude secrets that are empty or just one character in length. These // typically mean that you are running local dev or tests, or using the // --lax flag which sets things to just 'x'. diff --git a/packages/backend-app-api/src/wiring/BackendInitializer.test.ts b/packages/backend-app-api/src/wiring/BackendInitializer.test.ts index 791b9b1c3a..b5b53083a9 100644 --- a/packages/backend-app-api/src/wiring/BackendInitializer.test.ts +++ b/packages/backend-app-api/src/wiring/BackendInitializer.test.ts @@ -102,7 +102,7 @@ describe('BackendInitializer', () => { init.add( createBackendModule({ pluginId: 'test', - moduleId: 'modA', + moduleId: 'mod-a', register(reg) { reg.registerInit({ deps: { extension: extensionPoint }, @@ -118,7 +118,7 @@ describe('BackendInitializer', () => { init.add( createBackendModule({ pluginId: 'test', - moduleId: 'modB', + moduleId: 'mod-b', register(reg) { const values = ['b']; reg.registerExtensionPoint(extensionPoint, { values }); @@ -135,7 +135,7 @@ describe('BackendInitializer', () => { init.add( createBackendModule({ pluginId: 'test', - moduleId: 'modC', + moduleId: 'mod-c', register(reg) { reg.registerInit({ deps: { extension: extensionPoint }, @@ -265,7 +265,7 @@ describe('BackendInitializer', () => { init.add( createBackendModule({ pluginId: 'test', - moduleId: 'modA', + moduleId: 'mod-a', register(reg) { reg.registerExtensionPoint(extA, 'a'); reg.registerInit({ @@ -278,7 +278,7 @@ describe('BackendInitializer', () => { init.add( createBackendModule({ pluginId: 'test', - moduleId: 'modB', + moduleId: 'mod-b', register(reg) { reg.registerExtensionPoint(extB, 'b'); reg.registerInit({ @@ -289,7 +289,7 @@ describe('BackendInitializer', () => { })(), ); await expect(init.start()).rejects.toThrow( - "Circular dependency detected for modules of plugin 'test', 'modA' -> 'modB' -> 'modA'", + "Circular dependency detected for modules of plugin 'test', 'mod-a' -> 'mod-b' -> 'mod-a'", ); }); @@ -298,7 +298,7 @@ describe('BackendInitializer', () => { const extA = createExtensionPoint({ id: 'a' }); init.add( createBackendPlugin({ - pluginId: 'testA', + pluginId: 'test-a', register(reg) { reg.registerExtensionPoint(extA, 'a'); reg.registerInit({ @@ -310,7 +310,7 @@ describe('BackendInitializer', () => { ); init.add( createBackendModule({ - pluginId: 'testB', + pluginId: 'test-b', moduleId: 'mod', register(reg) { reg.registerInit({ @@ -321,7 +321,7 @@ describe('BackendInitializer', () => { })(), ); await expect(init.start()).rejects.toThrow( - "Extension point registered for plugin 'testA' may not be used by module for plugin 'testB'", + "Extension point registered for plugin 'test-a' may not be used by module for plugin 'test-b'", ); }); }); diff --git a/packages/backend-common/CHANGELOG.md b/packages/backend-common/CHANGELOG.md index 8b9c65605d..de955b7ca1 100644 --- a/packages/backend-common/CHANGELOG.md +++ b/packages/backend-common/CHANGELOG.md @@ -1,5 +1,200 @@ # @backstage/backend-common +## 0.20.1 + +### Patch Changes + +- 3b24eae: Adding support for removing file from git index +- 454d17c: Do not call fetch directly but rather use `fetchResponse` facility +- b6b15b2: Use sha256 instead of md5 for hash key calculation in caches + + This can have a side effect of invalidating caches (when cache key was >250 characters) + This improves compliance with FIPS nodejs + +- Updated dependencies + - @backstage/config-loader@1.6.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-dev-utils@0.1.3 + - @backstage/backend-app-api@0.5.10 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + +## 0.20.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-dev-utils@0.1.3-next.0 + - @backstage/backend-app-api@0.5.10-next.2 + - @backstage/config-loader@1.6.1-next.0 + +## 0.20.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.6.1-next.0 + - @backstage/backend-app-api@0.5.10-next.1 + - @backstage/integration@1.8.0 + - @backstage/integration-aws-node@0.1.8 + - @backstage/config@1.1.1 + - @backstage/backend-dev-utils@0.1.2 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.20.1-next.0 + +### Patch Changes + +- b6b15b2: Use sha256 instead of md5 for hash key calculation in caches + + This can have a side effect of invalidating caches (when cache key was >250 characters) + This improves compliance with FIPS nodejs + +- Updated dependencies + - @backstage/backend-app-api@0.5.10-next.0 + - @backstage/backend-dev-utils@0.1.2 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.6.0 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + +## 0.20.0 + +### Minor Changes + +- 870db76: Implemented `readTree` for Gitea provider to support TechDocs functionality + +### Patch Changes + +- 7f04128: Allow a default cache TTL to be set through the app config +- 1ad8906: Use `Readable.from` to fix some of the stream issues +- d86a007: Fixed the AwsS3UrlReader host regex and host to allow the S3 reading for CN AWS domain +- bc67498: Updated dependency `archiver` to `^6.0.0`. + Updated dependency `@types/archiver` to `^6.0.0`. +- 706fc3a: Updated dependency `@kubernetes/client-node` to `0.20.0`. +- 2666675: Updated dependency `@google-cloud/storage` to `^7.0.0`. +- d15d483: Add command `--runAsDefaultUser` for `@techdocs/cli generate` to bypass running the docker builds as host user for macOS and Linux. +- d1e00aa: Expose an `onAuth` handler for `git` actions to provide custom credentials +- Updated dependencies + - @backstage/config-loader@1.6.0 + - @backstage/backend-app-api@0.5.9 + - @backstage/integration@1.8.0 + - @backstage/backend-dev-utils@0.1.2 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + +## 0.20.0-next.3 + +### Patch Changes + +- d86a007: Fixed the AwsS3UrlReader host regex and host to allow the S3 reading for CN AWS domain +- Updated dependencies + - @backstage/backend-app-api@0.5.9-next.3 + - @backstage/backend-dev-utils@0.1.2 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.6.0-next.0 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + +## 0.20.0-next.2 + +### Patch Changes + +- bc67498: Updated dependency `archiver` to `^6.0.0`. + Updated dependency `@types/archiver` to `^6.0.0`. +- Updated dependencies + - @backstage/config-loader@1.6.0-next.0 + - @backstage/backend-app-api@0.5.9-next.2 + - @backstage/backend-dev-utils@0.1.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + +## 0.20.0-next.1 + +### Patch Changes + +- 2666675457: Updated dependency `@google-cloud/storage` to `^7.0.0`. +- Updated dependencies + - @backstage/backend-app-api@0.5.9-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-dev-utils@0.1.2 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.5.3 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + +## 0.20.0-next.0 + +### Minor Changes + +- 870db76a45: Implemented `readTree` for Gitea provider to support TechDocs functionality + +### Patch Changes + +- 7f04128bbc: Allow a default cache TTL to be set through the app config +- 1ad8906a9e: Use `Readable.from` to fix some of the stream issues +- 706fc3a7e1: Updated dependency `@kubernetes/client-node` to `0.20.0`. +- d15d483a49: Add command `--runAsDefaultUser` for `@techdocs/cli generate` to bypass running the docker builds as host user for macOS and Linux. +- d1e00aa17a: Expose an `onAuth` handler for `git` actions to provide custom credentials +- Updated dependencies + - @backstage/integration@1.8.0-next.0 + - @backstage/backend-app-api@0.5.9-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/backend-dev-utils@0.1.2 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.5.3 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + +## 0.19.9 + +### Patch Changes + +- aa13482090: Limit the database creation concurrency to one, defensively +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. +- 3d043526f4: Updated dependency `aws-sdk-client-mock` to `^3.0.0`. +- Updated dependencies + - @backstage/config-loader@1.5.3 + - @backstage/integration@1.7.2 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/integration-aws-node@0.1.8 + - @backstage/backend-app-api@0.5.8 + - @backstage/backend-dev-utils@0.1.2 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + ## 0.19.9-next.2 ### Patch Changes diff --git a/packages/backend-common/alpha-api-report.md b/packages/backend-common/api-report-alpha.md similarity index 100% rename from packages/backend-common/alpha-api-report.md rename to packages/backend-common/api-report-alpha.md diff --git a/packages/backend-common/testUtils-api-report.md b/packages/backend-common/api-report-testUtils.md similarity index 100% rename from packages/backend-common/testUtils-api-report.md rename to packages/backend-common/api-report-testUtils.md diff --git a/packages/backend-common/api-report.md b/packages/backend-common/api-report.md index 4f1dcdbf81..2d0eb84619 100644 --- a/packages/backend-common/api-report.md +++ b/packages/backend-common/api-report.md @@ -7,6 +7,7 @@ /// import { AppConfig } from '@backstage/config'; +import { AuthCallback } from 'isomorphic-git'; import { AwsCredentialsManager } from '@backstage/integration-aws-node'; import { AwsS3Integration } from '@backstage/integration'; import { AzureDevOpsCredentialsProvider } from '@backstage/integration'; @@ -68,6 +69,12 @@ import { V1PodTemplateSpec } from '@kubernetes/client-node'; import * as winston from 'winston'; import { Writable } from 'stream'; +// @public +export type AuthCallbackOptions = { + onAuth: AuthCallback; + logger?: LoggerService; +}; + // @public export class AwsS3UrlReader implements UrlReader { constructor( @@ -385,12 +392,7 @@ export class Git { tags?: boolean; }): Promise; // (undocumented) - static fromAuth: (options: { - username?: string; - password?: string; - token?: string; - logger?: LoggerService; - }) => Git; + static fromAuth: (options: StaticAuthOptions | AuthCallbackOptions) => Git; // (undocumented) init(options: { dir: string; defaultBranch?: string }): Promise; log(options: { dir: string; ref?: string }): Promise; @@ -415,18 +417,24 @@ export class Git { force?: boolean; }): Promise; readCommit(options: { dir: string; sha: string }): Promise; + remove(options: { dir: string; filepath: string }): Promise; resolveRef(options: { dir: string; ref: string }): Promise; } // @public export class GiteaUrlReader implements UrlReader { - constructor(integration: GiteaIntegration); + constructor( + integration: GiteaIntegration, + deps: { + treeResponseFactory: ReadTreeResponseFactory; + }, + ); // (undocumented) static factory: ReaderFactory; // (undocumented) read(url: string): Promise; // (undocumented) - readTree(): Promise; + readTree(url: string, options?: ReadTreeOptions): Promise; // (undocumented) readUrl(url: string, options?: ReadUrlOptions): Promise; // (undocumented) @@ -684,6 +692,7 @@ export type RunContainerOptions = { workingDir?: string; envVars?: Record; pullImage?: boolean; + defaultUser?: boolean; }; export { SearchOptions }; @@ -745,6 +754,14 @@ export function setRootLogger(newLogger: winston.Logger): void; // @public @deprecated export const SingleHostDiscovery: typeof HostDiscovery_2; +// @public +export type StaticAuthOptions = { + username?: string; + password?: string; + token?: string; + logger?: LoggerService; +}; + // @public export type StatusCheck = () => Promise; diff --git a/packages/backend-common/config.d.ts b/packages/backend-common/config.d.ts index f6330d16bc..8bcc5465d5 100644 --- a/packages/backend-common/config.d.ts +++ b/packages/backend-common/config.d.ts @@ -149,6 +149,8 @@ export interface Config { cache?: | { store: 'memory'; + /** An optional default TTL (in milliseconds). */ + defaultTtl?: number; } | { store: 'redis'; @@ -157,6 +159,8 @@ export interface Config { * @visibility secret */ connection: string; + /** An optional default TTL (in milliseconds). */ + defaultTtl?: number; } | { store: 'memcache'; @@ -165,6 +169,8 @@ export interface Config { * @visibility secret */ connection: string; + /** An optional default TTL (in milliseconds). */ + defaultTtl?: number; }; cors?: { diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index 9c22d009e1..3d746044b0 100644 --- a/packages/backend-common/package.json +++ b/packages/backend-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-common", "description": "Common functionality library for Backstage backends", - "version": "0.19.9-next.2", + "version": "0.20.1", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { @@ -64,10 +64,10 @@ "@backstage/integration": "workspace:^", "@backstage/integration-aws-node": "workspace:^", "@backstage/types": "workspace:^", - "@google-cloud/storage": "^6.0.0", + "@google-cloud/storage": "^7.0.0", "@keyv/memcache": "^1.3.5", "@keyv/redis": "^2.5.3", - "@kubernetes/client-node": "0.19.0", + "@kubernetes/client-node": "0.20.0", "@manypkg/get-packages": "^1.1.3", "@octokit/rest": "^19.0.3", "@types/cors": "^2.8.6", @@ -75,7 +75,7 @@ "@types/express": "^4.17.6", "@types/luxon": "^3.0.0", "@types/webpack-env": "^1.15.2", - "archiver": "^5.0.2", + "archiver": "^6.0.0", "base64-stream": "^1.0.0", "compression": "^1.7.4", "concat-stream": "^2.0.0", @@ -118,7 +118,7 @@ "@aws-sdk/util-stream-node": "^3.350.0", "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", - "@types/archiver": "^5.1.0", + "@types/archiver": "^6.0.0", "@types/base64-stream": "^1.0.2", "@types/compression": "^1.7.0", "@types/concat-stream": "^2.0.0", diff --git a/packages/backend-common/src/cache/CacheClient.ts b/packages/backend-common/src/cache/CacheClient.ts index 24ee7ac455..aba62558d4 100644 --- a/packages/backend-common/src/cache/CacheClient.ts +++ b/packages/backend-common/src/cache/CacheClient.ts @@ -88,6 +88,6 @@ export class DefaultCacheClient implements CacheService { return wellFormedKey; } - return createHash('md5').update(candidateKey).digest('base64'); + return createHash('sha256').update(candidateKey).digest('base64'); } } diff --git a/packages/backend-common/src/cache/CacheManager.test.ts b/packages/backend-common/src/cache/CacheManager.test.ts index 13a4a0d599..4b7bb05efd 100644 --- a/packages/backend-common/src/cache/CacheManager.test.ts +++ b/packages/backend-common/src/cache/CacheManager.test.ts @@ -33,11 +33,13 @@ jest.mock('./CacheClient', () => { }; }); +const globalDefaultTtl = 1234; describe('CacheManager', () => { const defaultConfigOptions = { backend: { cache: { store: 'memory', + defaultTtl: globalDefaultTtl, }, }, }; @@ -49,9 +51,11 @@ describe('CacheManager', () => { 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); @@ -62,6 +66,9 @@ describe('CacheManager', () => { 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', () => { @@ -159,6 +166,20 @@ describe('CacheManager', () => { }); }); + 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'; @@ -201,6 +222,32 @@ describe('CacheManager', () => { 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( @@ -227,6 +274,32 @@ describe('CacheManager', () => { 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; diff --git a/packages/backend-common/src/cache/CacheManager.ts b/packages/backend-common/src/cache/CacheManager.ts index efaaf04e3a..c7298ab3e9 100644 --- a/packages/backend-common/src/cache/CacheManager.ts +++ b/packages/backend-common/src/cache/CacheManager.ts @@ -57,6 +57,7 @@ export class CacheManager { private readonly connection: string; private readonly useRedisSets: boolean; private readonly errorHandler: CacheManagerOptions['onError']; + private readonly defaultTtl?: number; /** * Creates a new {@link CacheManager} instance by reading from the `backend` @@ -71,6 +72,7 @@ export class CacheManager { // If no `backend.cache` config is provided, instantiate the CacheManager // with an in-memory cache client. const store = config.getOptionalString('backend.cache.store') || 'memory'; + const defaultTtl = config.getOptionalNumber('backend.cache.defaultTtl'); const connectionString = config.getOptionalString('backend.cache.connection') || ''; const useRedisSets = @@ -84,6 +86,7 @@ export class CacheManager { useRedisSets, logger, options.onError, + defaultTtl, ); } @@ -93,6 +96,7 @@ export class CacheManager { useRedisSets: boolean, logger: LoggerService, errorHandler: CacheManagerOptions['onError'], + defaultTtl?: number, ) { if (!this.storeFactories.hasOwnProperty(store)) { throw new Error(`Unknown cache store: ${store}`); @@ -102,6 +106,7 @@ export class CacheManager { this.connection = connectionString; this.useRedisSets = useRedisSets; this.errorHandler = errorHandler; + this.defaultTtl = defaultTtl; } /** @@ -116,7 +121,7 @@ export class CacheManager { const clientFactory = (options: CacheServiceOptions) => { const concreteClient = this.getClientWithTtl( pluginId, - options.defaultTtl, + options.defaultTtl ?? this.defaultTtl, ); // Always provide an error handler to avoid stopping the process. diff --git a/packages/backend-common/src/reading/AwsS3UrlReader.test.ts b/packages/backend-common/src/reading/AwsS3UrlReader.test.ts index b37a052c1d..e3247f190b 100644 --- a/packages/backend-common/src/reading/AwsS3UrlReader.test.ts +++ b/packages/backend-common/src/reading/AwsS3UrlReader.test.ts @@ -53,6 +53,39 @@ describe('parseUrl', () => { bucket: 'my.bucket-3', region: 'us-east-1', }); + expect( + parseUrl('https://s3.amazonaws.com.cn/my.bucket-3/a/puppy.jpg', { + host: 'amazonaws.com', + }), + ).toEqual({ + path: 'a/puppy.jpg', + bucket: 'my.bucket-3', + region: 'us-east-1', + }); + expect( + parseUrl( + 'https://ec-backstage-staging.s3.cn-north-1.amazonaws.com.cn/payments-prod-oas30.json', + { + host: 'amazonaws.com', + }, + ), + ).toEqual({ + path: 'payments-prod-oas30.json', + bucket: 'ec-backstage-staging', + region: 'cn-north-1', + }); + expect( + parseUrl( + 'https://ec-backstage-staging.s3.cn-north-1.amazonaws.com.cn/payments-prod-oas30.json', + { + host: 'amazonaws.com.cn', + }, + ), + ).toEqual({ + path: 'payments-prod-oas30.json', + bucket: 'ec-backstage-staging', + region: 'cn-north-1', + }); expect( parseUrl('https://s3.us-west-2.amazonaws.com/my.bucket-3/a/puppy.jpg', { host: 'amazonaws.com', diff --git a/packages/backend-common/src/reading/AwsS3UrlReader.ts b/packages/backend-common/src/reading/AwsS3UrlReader.ts index 4d4c28071f..23ef0f7b27 100644 --- a/packages/backend-common/src/reading/AwsS3UrlReader.ts +++ b/packages/backend-common/src/reading/AwsS3UrlReader.ts @@ -69,9 +69,9 @@ export function parseUrl( const host = parsedUrl.host; // Treat Amazon hosted separately because it has special region logic - if (config.host === 'amazonaws.com') { + if (config.host === 'amazonaws.com' || config.host === 'amazonaws.com.cn') { const match = host.match( - /^(?:([a-z0-9.-]+)\.)?s3(?:[.-]([a-z0-9-]+))?\.amazonaws\.com$/, + /^(?:([a-z0-9.-]+)\.)?s3(?:[.-]([a-z0-9-]+))?\.amazonaws\.com(\.cn)?$/, ); if (!match) { throw new Error(`Invalid AWS S3 URL ${url}`); diff --git a/packages/backend-common/src/reading/GerritUrlReader.ts b/packages/backend-common/src/reading/GerritUrlReader.ts index f4a5fdb9f5..665770815f 100644 --- a/packages/backend-common/src/reading/GerritUrlReader.ts +++ b/packages/backend-common/src/reading/GerritUrlReader.ts @@ -139,7 +139,7 @@ export class GerritUrlReader implements UrlReader { return Buffer.from(responseBody, 'base64'); }, stream: () => { - const readable = new Readable().wrap(response.body); + const readable = Readable.from(response.body); return readable.pipe(new Base64Decode()); }, }; diff --git a/packages/backend-common/src/reading/GiteaUrlReader.test.ts b/packages/backend-common/src/reading/GiteaUrlReader.test.ts index 1860d9f461..a941d2e5aa 100644 --- a/packages/backend-common/src/reading/GiteaUrlReader.test.ts +++ b/packages/backend-common/src/reading/GiteaUrlReader.test.ts @@ -26,6 +26,8 @@ import { DefaultReadTreeResponseFactory } from './tree'; import getRawBody from 'raw-body'; import { GiteaUrlReader } from './GiteaUrlReader'; import { NotFoundError, NotModifiedError } from '@backstage/errors'; +import fs from 'fs-extra'; +import path from 'path'; const treeResponseFactory = DefaultReadTreeResponseFactory.create({ config: new ConfigReader({}), @@ -47,6 +49,7 @@ const giteaProcessor = new GiteaUrlReader( }), ), ), + { treeResponseFactory }, ); const createReader = (config: JsonObject): UrlReaderPredicateTuple[] => { @@ -247,4 +250,82 @@ describe('GiteaUrlReader', () => { ).rejects.toThrow(NotModifiedError); }); }); + + describe('readTree', () => { + const commitHash = '3bdd5457286abdf920db4b77bf2fef79a06190c2'; + + const repoBuffer = fs.readFileSync( + path.resolve(__dirname, '__fixtures__/mock-main.tar.gz'), + ); + + beforeEach(() => { + worker.use( + rest.get( + 'https://gitea.com/api/v1/repos/owner/project/git/commits/branch2', + (_, res, ctx) => { + return res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json({ sha: commitHash }), + ); + }, + ), + ); + }); + + it('should be able to get archive', async () => { + worker.use( + rest.get( + 'https://gitea.com/api/v1/repos/owner/project/archive/branch2.tar.gz', + (_, res, ctx) => { + return res( + ctx.status(200), + ctx.set('Content-Type', 'application/gzip'), + ctx.set( + 'content-disposition', + 'attachment; filename=backstage-mock.tar.gz', + ), + ctx.body(repoBuffer), + ); + }, + ), + ); + + const response = await giteaProcessor.readTree( + 'https://gitea.com/owner/project/src/branch/branch2', + ); + expect(response.etag).toBe(commitHash); + + const files = await response.files(); + expect(files.length).toBe(2); + }); + + it('should return not modified', async () => { + await expect( + giteaProcessor.readTree( + 'https://gitea.com/owner/project/src/branch/branch2', + { + etag: commitHash, + }, + ), + ).rejects.toThrow(NotModifiedError); + }); + + it('should return not found', async () => { + worker.use( + rest.get( + 'https://gitea.com/api/v1/repos/owner/project/git/commits/branch3', + (_, res, ctx) => { + return res(ctx.status(404)); + }, + ), + ); + + await expect( + giteaProcessor.readTree( + 'https://gitea.com/owner/project/src/branch/branch3', + ), + ).rejects.toThrow(NotFoundError); + }); + }); }); diff --git a/packages/backend-common/src/reading/GiteaUrlReader.ts b/packages/backend-common/src/reading/GiteaUrlReader.ts index 34542e878e..c8fab45157 100644 --- a/packages/backend-common/src/reading/GiteaUrlReader.ts +++ b/packages/backend-common/src/reading/GiteaUrlReader.ts @@ -14,15 +14,21 @@ * limitations under the License. */ import { - getGiteaRequestOptions, getGiteaFileContentsUrl, + getGiteaArchiveUrl, + getGiteaLatestCommitUrl, + parseGiteaUrl, + getGiteaRequestOptions, GiteaIntegration, ScmIntegrations, } from '@backstage/integration'; -import { ReadUrlOptions, ReadUrlResponse } from './types'; import { ReaderFactory, + ReadTreeOptions, ReadTreeResponse, + ReadTreeResponseFactory, + ReadUrlOptions, + ReadUrlResponse, SearchResponse, UrlReader, } from './types'; @@ -42,11 +48,11 @@ import { parseLastModified } from './util'; * @public */ export class GiteaUrlReader implements UrlReader { - static factory: ReaderFactory = ({ config }) => { + static factory: ReaderFactory = ({ config, treeResponseFactory }) => { return ScmIntegrations.fromConfig(config) .gitea.list() .map(integration => { - const reader = new GiteaUrlReader(integration); + const reader = new GiteaUrlReader(integration, { treeResponseFactory }); const predicate = (url: URL) => { return url.host === integration.config.host; }; @@ -54,7 +60,12 @@ export class GiteaUrlReader implements UrlReader { }); }; - constructor(private readonly integration: GiteaIntegration) {} + constructor( + private readonly integration: GiteaIntegration, + private readonly deps: { + treeResponseFactory: ReadTreeResponseFactory; + }, + ) {} async read(url: string): Promise { const response = await this.readUrl(url); @@ -113,9 +124,38 @@ export class GiteaUrlReader implements UrlReader { throw new Error(message); } - readTree(): Promise { - throw new Error('GiteaUrlReader readTree not implemented.'); + async readTree( + url: string, + options?: ReadTreeOptions, + ): Promise { + const lastCommitHash = await this.getLastCommitHash(url); + if (options?.etag && options.etag === lastCommitHash) { + throw new NotModifiedError(); + } + + const archiveUri = getGiteaArchiveUrl(this.integration.config, url); + + let response: Response; + try { + response = await fetch(archiveUri, { + method: 'GET', + ...getGiteaRequestOptions(this.integration.config), + signal: options?.signal as any, + }); + } catch (e) { + throw new Error(`Unable to read ${archiveUri}, ${e}`); + } + + const parsedUri = parseGiteaUrl(this.integration.config, url); + + return this.deps.treeResponseFactory.fromTarArchive({ + stream: Readable.from(response.body), + subpath: parsedUri.path, + etag: lastCommitHash, + filter: options?.filter, + }); } + search(): Promise { throw new Error('GiteaUrlReader search not implemented.'); } @@ -126,4 +166,22 @@ export class GiteaUrlReader implements UrlReader { this.integration.config.password, )}}`; } + + private async getLastCommitHash(url: string): Promise { + const commitUri = getGiteaLatestCommitUrl(this.integration.config, url); + + const response = await fetch( + commitUri, + getGiteaRequestOptions(this.integration.config), + ); + if (!response.ok) { + const message = `Failed to retrieve latest commit information from ${commitUri}, ${response.status} ${response.statusText}`; + if (response.status === 404) { + throw new NotFoundError(message); + } + throw new Error(message); + } + + return (await response.json()).sha; + } } diff --git a/packages/backend-common/src/reading/GithubUrlReader.ts b/packages/backend-common/src/reading/GithubUrlReader.ts index 764431386d..67f6a975c1 100644 --- a/packages/backend-common/src/reading/GithubUrlReader.ts +++ b/packages/backend-common/src/reading/GithubUrlReader.ts @@ -105,58 +105,28 @@ export class GithubUrlReader implements UrlReader { credentials, ); - let response: Response; - try { - response = await fetch(ghUrl, { - headers: { - ...credentials?.headers, - ...(options?.etag && { 'If-None-Match': options.etag }), - ...(options?.lastModifiedAfter && { - 'If-Modified-Since': options.lastModifiedAfter.toUTCString(), - }), - Accept: 'application/vnd.github.v3.raw', - }, - // TODO(freben): The signal cast is there because pre-3.x versions of - // node-fetch have a very slightly deviating AbortSignal type signature. - // The difference does not affect us in practice however. The cast can - // be removed after we support ESM for CLI dependencies and migrate to - // version 3 of node-fetch. - // https://github.com/backstage/backstage/issues/8242 - signal: options?.signal as any, - }); - } catch (e) { - throw new Error(`Unable to read ${url}, ${e}`); - } + const response = await this.fetchResponse(ghUrl, { + headers: { + ...credentials?.headers, + ...(options?.etag && { 'If-None-Match': options.etag }), + ...(options?.lastModifiedAfter && { + 'If-Modified-Since': options.lastModifiedAfter.toUTCString(), + }), + Accept: 'application/vnd.github.v3.raw', + }, + // TODO(freben): The signal cast is there because pre-3.x versions of + // node-fetch have a very slightly deviating AbortSignal type signature. + // The difference does not affect us in practice however. The cast can + // be removed after we support ESM for CLI dependencies and migrate to + // version 3 of node-fetch. + // https://github.com/backstage/backstage/issues/8242 + signal: options?.signal as any, + }); - if (response.status === 304) { - throw new NotModifiedError(); - } - - if (response.ok) { - return ReadUrlResponseFactory.fromNodeJSReadable(response.body, { - etag: response.headers.get('ETag') ?? undefined, - lastModifiedAt: parseLastModified( - response.headers.get('Last-Modified'), - ), - }); - } - - let message = `${url} could not be read as ${ghUrl}, ${response.status} ${response.statusText}`; - if (response.status === 404) { - throw new NotFoundError(message); - } - - // GitHub returns a 403 response with a couple of headers indicating rate - // limit status. See more in the GitHub docs: - // https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting - if ( - response.status === 403 && - response.headers.get('X-RateLimit-Remaining') === '0' - ) { - message += ' (rate limit exceeded)'; - } - - throw new Error(message); + return ReadUrlResponseFactory.fromNodeJSReadable(response.body, { + etag: response.headers.get('ETag') ?? undefined, + lastModifiedAt: parseLastModified(response.headers.get('Last-Modified')), + }); } async readTree( @@ -350,10 +320,26 @@ export class GithubUrlReader implements UrlReader { const response = await fetch(urlAsString, init); if (!response.ok) { - const message = `Request failed for ${urlAsString}, ${response.status} ${response.statusText}`; + let message = `Request failed for ${urlAsString}, ${response.status} ${response.statusText}`; + + if (response.status === 304) { + throw new NotModifiedError(); + } + if (response.status === 404) { throw new NotFoundError(message); } + + // GitHub returns a 403 response with a couple of headers indicating rate + // limit status. See more in the GitHub docs: + // https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting + if ( + response.status === 403 && + response.headers.get('X-RateLimit-Remaining') === '0' + ) { + message += ' (rate limit exceeded)'; + } + throw new Error(message); } diff --git a/packages/backend-common/src/reading/ReadUrlResponseFactory.test.ts b/packages/backend-common/src/reading/ReadUrlResponseFactory.test.ts index 1eb18f5c1d..95d9099662 100644 --- a/packages/backend-common/src/reading/ReadUrlResponseFactory.test.ts +++ b/packages/backend-common/src/reading/ReadUrlResponseFactory.test.ts @@ -16,7 +16,7 @@ import { ConflictError } from '@backstage/errors'; import getRawBody from 'raw-body'; -import { Readable, Stream } from 'stream'; +import { Readable } from 'stream'; import { ReadUrlResponseFactory } from './ReadUrlResponseFactory'; describe('ReadUrlResponseFactory', () => { @@ -74,25 +74,10 @@ describe('ReadUrlResponseFactory', () => { describe("fromNodeJSReadable's", () => { const expectedText = 'expected text'; - const timeouts: NodeJS.Timeout[] = []; let readable: NodeJS.ReadableStream; beforeEach(() => { - readable = new Stream({ - encoding: 'utf-8', - }) as unknown as NodeJS.ReadableStream; - readable.readable = true; - - // Write data asynchronously, as soon as possible. - timeouts[0] = setTimeout(() => { - timeouts[1] = setTimeout(readable.emit.bind(readable, 'end'), 0); - readable.emit('data', expectedText); - }, 0); - }); - - afterEach(() => { - // Clear out timeouts so we don't emit data across tests. - timeouts.forEach(clearTimeout); + readable = Readable.from(Buffer.from(expectedText)); }); it('etag is passed through', async () => { diff --git a/packages/backend-common/src/reading/ReadUrlResponseFactory.ts b/packages/backend-common/src/reading/ReadUrlResponseFactory.ts index 69b9c6c16a..5eb4b2f5bc 100644 --- a/packages/backend-common/src/reading/ReadUrlResponseFactory.ts +++ b/packages/backend-common/src/reading/ReadUrlResponseFactory.ts @@ -72,7 +72,7 @@ export class ReadUrlResponseFactory { oldStyleStream: NodeJS.ReadableStream, options?: ReadUrlResponseFactoryFromStreamOptions, ): Promise { - const readable = new Readable().wrap(oldStyleStream); + const readable = Readable.from(oldStyleStream); return ReadUrlResponseFactory.fromReadable(readable, options); } } diff --git a/packages/backend-common/src/scm/git.test.ts b/packages/backend-common/src/scm/git.test.ts index 5ec960fc53..1c07dfb917 100644 --- a/packages/backend-common/src/scm/git.test.ts +++ b/packages/backend-common/src/scm/git.test.ts @@ -63,6 +63,22 @@ describe('Git', () => { }); }); + describe('remove', () => { + it('should call isomorphic-git remove with the correct arguments', async () => { + const git = Git.fromAuth({}); + const dir = 'mockdirectory'; + const filepath = 'mockfile/path'; + + await git.remove({ dir, filepath }); + + expect(isomorphic.remove).toHaveBeenCalledWith({ + fs, + dir, + filepath, + }); + }); + }); + describe('deleteRemote', () => { it('should call isomorphic-git with the correct arguments', async () => { const git = Git.fromAuth({}); @@ -190,7 +206,7 @@ describe('Git', () => { }); }); - it('should pass a function that returns the authorization as the onAuth handler', async () => { + it('should pass a function that returns the authorization as the onAuth handler when username and password are specified', async () => { const url = 'http://github.com/some/repo'; const dir = '/some/mock/dir'; const auth = { @@ -208,6 +224,25 @@ describe('Git', () => { expect(onAuth()).toEqual(auth); }); + it('should pass the provided callback as the onAuth handler when on auth is specified', async () => { + const url = 'http://github.com/some/repo'; + const dir = '/some/mock/dir'; + const auth = { + username: 'from', + password: 'callback', + }; + + const git = Git.fromAuth({ onAuth: () => auth }); + + await git.clone({ url, dir }); + + const { onAuth } = ( + isomorphic.clone as unknown as jest.Mock<(typeof isomorphic)['clone']> + ).mock.calls[0][0]!; + + expect(onAuth()).toEqual(auth); + }); + it('should propagate the data from the error handler', async () => { const url = 'http://github.com/some/repo'; const dir = '/some/mock/dir'; diff --git a/packages/backend-common/src/scm/git.ts b/packages/backend-common/src/scm/git.ts index 8ccdbeafbd..e7bad693fe 100644 --- a/packages/backend-common/src/scm/git.ts +++ b/packages/backend-common/src/scm/git.ts @@ -18,11 +18,40 @@ 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 + */ +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; +}; + /* provider username password Azure 'notempty' token @@ -42,6 +71,7 @@ instead of Basic Auth (e.g., Bitbucket Server). * * @public */ + export class Git { private readonly headers: { [x: string]: string; @@ -49,12 +79,13 @@ export class Git { private constructor( private readonly config: { - username?: string; - password?: string; + onAuth: AuthCallback; token?: string; logger?: LoggerService; }, ) { + this.onAuth = config.onAuth; + this.headers = { 'user-agent': 'git/@isomorphic-git', ...(config.token ? { Authorization: `Bearer ${config.token}` } : {}), @@ -269,6 +300,15 @@ export class Git { 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; @@ -288,10 +328,7 @@ export class Git { }); } - private onAuth = () => ({ - username: this.config.username, - password: this.config.password, - }); + private onAuth: AuthCallback; private onProgressHandler = (): ProgressCallback => { let currentPhase = ''; @@ -308,13 +345,13 @@ export class Git { }; }; - static fromAuth = (options: { - username?: string; - password?: string; - token?: string; - logger?: LoggerService; - }) => { + 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({ username, password, token, logger }); + return new Git({ onAuth: () => ({ username, password }), token, logger }); }; } diff --git a/packages/backend-common/src/scm/index.ts b/packages/backend-common/src/scm/index.ts index ceba752c9e..f9c59e99eb 100644 --- a/packages/backend-common/src/scm/index.ts +++ b/packages/backend-common/src/scm/index.ts @@ -15,3 +15,4 @@ */ export { Git } from './git'; +export type { StaticAuthOptions, AuthCallbackOptions } from './git'; diff --git a/packages/backend-common/src/util/ContainerRunner.ts b/packages/backend-common/src/util/ContainerRunner.ts index 22e40ec455..7dc12919b3 100644 --- a/packages/backend-common/src/util/ContainerRunner.ts +++ b/packages/backend-common/src/util/ContainerRunner.ts @@ -30,6 +30,7 @@ export type RunContainerOptions = { workingDir?: string; envVars?: Record; pullImage?: boolean; + defaultUser?: boolean; }; /** diff --git a/packages/backend-common/src/util/DockerContainerRunner.ts b/packages/backend-common/src/util/DockerContainerRunner.ts index 4d4684c814..986470eb98 100644 --- a/packages/backend-common/src/util/DockerContainerRunner.ts +++ b/packages/backend-common/src/util/DockerContainerRunner.ts @@ -46,6 +46,7 @@ export class DockerContainerRunner implements ContainerRunner { workingDir, envVars = {}, pullImage = true, + defaultUser = false, } = options; // Show a better error message when Docker is unavailable. @@ -71,7 +72,7 @@ export class DockerContainerRunner implements ContainerRunner { } const userOptions: UserOptions = {}; - if (process.getuid && process.getgid) { + if (!defaultUser && process.getuid && process.getgid) { // Files that are created inside the Docker container will be owned by // root on the host system on non Mac systems, because of reasons. Mainly the fact that // volume sharing is done using NFS on Mac and actual mounts in Linux world. diff --git a/packages/backend-defaults/CHANGELOG.md b/packages/backend-defaults/CHANGELOG.md index f5e8637475..b8bacd3732 100644 --- a/packages/backend-defaults/CHANGELOG.md +++ b/packages/backend-defaults/CHANGELOG.md @@ -1,5 +1,97 @@ # @backstage/backend-defaults +## 0.2.9 + +### Patch Changes + +- 516fd3e: Updated README to reflect release status +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-app-api@0.5.10 + +## 0.2.9-next.2 + +### Patch Changes + +- 516fd3e: Updated README to reflect release status +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-app-api@0.5.10-next.2 + - @backstage/backend-common@0.20.1-next.2 + +## 0.2.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@0.5.10-next.1 + - @backstage/backend-common@0.20.1-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + +## 0.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-app-api@0.5.10-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + +## 0.2.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/backend-app-api@0.5.9 + - @backstage/backend-plugin-api@0.6.8 + +## 0.2.8-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-app-api@0.5.9-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + +## 0.2.8-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/backend-app-api@0.5.9-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + +## 0.2.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@0.5.9-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + +## 0.2.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-app-api@0.5.9-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + +## 0.2.7 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-app-api@0.5.8 + ## 0.2.7-next.2 ### Patch Changes diff --git a/packages/backend-defaults/README.md b/packages/backend-defaults/README.md index 2dcc5766df..01e42d42c4 100644 --- a/packages/backend-defaults/README.md +++ b/packages/backend-defaults/README.md @@ -1,7 +1,5 @@ # @backstage/backend-defaults -**This package is EXPERIMENTAL, we recommend against using it for production deployments** - This package provides the default implementations and setup for a standard Backstage backend app. ## Installation diff --git a/packages/backend-defaults/package.json b/packages/backend-defaults/package.json index 7c7a5f8813..73a54720f5 100644 --- a/packages/backend-defaults/package.json +++ b/packages/backend-defaults/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-defaults", "description": "Backend defaults used by Backstage backend apps", - "version": "0.2.7-next.2", + "version": "0.2.9", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend-dev-utils/CHANGELOG.md b/packages/backend-dev-utils/CHANGELOG.md index f1d1887b78..1c4deba50a 100644 --- a/packages/backend-dev-utils/CHANGELOG.md +++ b/packages/backend-dev-utils/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/backend-dev-utils +## 0.1.3 + +### Patch Changes + +- 516fd3e: Updated README to reflect release status + +## 0.1.3-next.0 + +### Patch Changes + +- 516fd3e: Updated README to reflect release status + ## 0.1.2 ### Patch Changes diff --git a/packages/backend-dev-utils/README.md b/packages/backend-dev-utils/README.md index cebe591d50..744a9d2ca0 100644 --- a/packages/backend-dev-utils/README.md +++ b/packages/backend-dev-utils/README.md @@ -1,7 +1,5 @@ # @backstage/backend-dev-utils -**This package is EXPERIMENTAL, but we encourage use of it to add support for the new backend system in your own plugins** - This package helps set up local development environments for Backstage backend packages. ## Installation diff --git a/packages/backend-dev-utils/package.json b/packages/backend-dev-utils/package.json index b6156e622c..67fd763dcd 100644 --- a/packages/backend-dev-utils/package.json +++ b/packages/backend-dev-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-dev-utils", - "version": "0.1.2", + "version": "0.1.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/backend-plugin-manager/.eslintrc.js b/packages/backend-dynamic-feature-service/.eslintrc.js similarity index 100% rename from packages/backend-plugin-manager/.eslintrc.js rename to packages/backend-dynamic-feature-service/.eslintrc.js diff --git a/packages/backend-dynamic-feature-service/CHANGELOG.md b/packages/backend-dynamic-feature-service/CHANGELOG.md new file mode 100644 index 0000000000..4b80750865 --- /dev/null +++ b/packages/backend-dynamic-feature-service/CHANGELOG.md @@ -0,0 +1,452 @@ +# @backstage/backend-dynamic-feature-service + +## 0.1.0 + +### Minor Changes + +- eb81f42: New `backend-dynamic-feature-service` package, for the discovery of dynamic frontend and backend plugins (and modules) and the loading of the backend ones inside the backend application. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/cli-node@0.2.2 + - @backstage/plugin-events-backend@0.2.18 + - @backstage/backend-plugin-api@0.6.9 + - @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-scaffolder-node@0.2.10 + - @backstage/plugin-search-backend-node@1.2.13 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.18 + - @backstage/plugin-search-common@1.2.10 + +## 0.0.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + - @backstage/plugin-catalog-backend@1.16.1-next.2 + - @backstage/plugin-events-backend@0.2.18-next.2 + - @backstage/plugin-events-node@0.2.18-next.2 + - @backstage/plugin-permission-node@0.7.20-next.2 + - @backstage/plugin-scaffolder-node@0.2.10-next.2 + - @backstage/plugin-search-backend-node@1.2.13-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + - @backstage/cli-node@0.2.2-next.0 + +## 0.0.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/cli-node@0.2.2-next.0 + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/plugin-catalog-backend@1.16.1-next.1 + - @backstage/plugin-events-backend@0.2.18-next.1 + - @backstage/plugin-permission-node@0.7.20-next.1 + - @backstage/plugin-scaffolder-node@0.2.10-next.1 + - @backstage/plugin-search-backend-node@1.2.13-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.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.0.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/backend-tasks@0.5.14-next.0 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.0 + - @backstage/plugin-catalog-backend@1.16.1-next.0 + - @backstage/plugin-events-backend@0.2.18-next.0 + - @backstage/plugin-events-node@0.2.18-next.0 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.20-next.0 + - @backstage/plugin-scaffolder-node@0.2.10-next.0 + - @backstage/plugin-search-backend-node@1.2.13-next.0 + - @backstage/plugin-search-common@1.2.9 + +## 0.0.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-backend@1.16.0 + - @backstage/plugin-scaffolder-node@0.2.9 + - @backstage/backend-tasks@0.5.13 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.19 + - @backstage/cli-node@0.2.1 + - @backstage/plugin-events-backend@0.2.17 + - @backstage/plugin-search-backend-node@1.2.12 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.17 + - @backstage/plugin-search-common@1.2.9 + +## 0.0.4-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.9-next.3 + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.3 + - @backstage/plugin-catalog-backend@1.16.0-next.3 + - @backstage/plugin-events-backend@0.2.17-next.3 + - @backstage/plugin-events-node@0.2.17-next.3 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.3 + - @backstage/plugin-search-backend-node@1.2.12-next.3 + - @backstage/plugin-search-common@1.2.8 + +## 0.0.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.16.0-next.2 + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/plugin-events-backend@0.2.17-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/backend-tasks@0.5.13-next.2 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.2 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.2 + - @backstage/plugin-scaffolder-node@0.2.9-next.2 + - @backstage/plugin-search-backend-node@1.2.12-next.2 + - @backstage/plugin-search-common@1.2.8 + +## 0.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.15.1-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-events-backend@0.2.17-next.1 + - @backstage/plugin-events-node@0.2.17-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + - @backstage/plugin-scaffolder-node@0.2.9-next.1 + - @backstage/plugin-search-backend-node@1.2.12-next.1 + - @backstage/plugin-search-common@1.2.8 + +## 0.0.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/plugin-catalog-backend@1.15.1-next.0 + - @backstage/plugin-events-backend@0.2.17-next.0 + - @backstage/plugin-permission-node@0.7.19-next.0 + - @backstage/plugin-scaffolder-node@0.2.9-next.0 + - @backstage/plugin-search-backend-node@1.2.12-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.0 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-search-common@1.2.8 + +## 0.0.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.15.0 + - @backstage/cli-node@0.2.0 + - @backstage/plugin-search-backend-node@1.2.11 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-scaffolder-node@0.2.8 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.1 + - @backstage/plugin-events-backend@0.2.16 + - @backstage/plugin-events-node@0.2.16 + - @backstage/plugin-permission-node@0.7.18 + - @backstage/plugin-search-common@1.2.8 + +## 0.0.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.7-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-auth-node@0.4.1-next.2 + - @backstage/plugin-events-backend@0.2.16-next.2 + - @backstage/plugin-events-node@0.2.16-next.2 + - @backstage/plugin-permission-node@0.7.18-next.2 + - @backstage/plugin-scaffolder-node@0.2.8-next.2 + - @backstage/plugin-search-backend-node@1.2.11-next.2 + +## 0.0.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.15.0-next.1 + - @backstage/backend-common@0.19.9-next.1 + - @backstage/plugin-scaffolder-node@0.2.8-next.1 + - @backstage/backend-tasks@0.5.12-next.1 + - @backstage/plugin-auth-node@0.4.1-next.1 + - @backstage/plugin-events-backend@0.2.16-next.1 + - @backstage/plugin-permission-node@0.7.18-next.1 + - @backstage/plugin-search-backend-node@1.2.11-next.1 + - @backstage/backend-plugin-api@0.6.7-next.1 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.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.0.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/cli-node@0.2.0-next.0 + - @backstage/plugin-search-backend-node@1.2.11-next.0 + - @backstage/plugin-catalog-backend@1.15.0-next.0 + - @backstage/plugin-scaffolder-node@0.2.8-next.0 + - @backstage/backend-common@0.19.9-next.0 + - @backstage/backend-plugin-api@0.6.7-next.0 + - @backstage/backend-tasks@0.5.12-next.0 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.1-next.0 + - @backstage/plugin-events-backend@0.2.16-next.0 + - @backstage/plugin-events-node@0.2.16-next.0 + - @backstage/plugin-permission-common@0.7.9 + - @backstage/plugin-permission-node@0.7.18-next.0 + - @backstage/plugin-search-common@1.2.7 + +## 0.0.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/plugin-catalog-backend@1.14.0 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/errors@1.2.3 + - @backstage/cli-common@0.1.13 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-search-backend-node@1.2.10 + - @backstage/plugin-events-backend@0.2.15 + - @backstage/plugin-permission-node@0.7.17 + - @backstage/plugin-scaffolder-node@0.2.6 + - @backstage/cli-node@0.1.5 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.15 + - @backstage/plugin-permission-common@0.7.9 + - @backstage/plugin-search-common@1.2.7 + +## 0.0.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8-next.2 + - @backstage/plugin-auth-node@0.4.0-next.2 + - @backstage/plugin-catalog-backend@1.14.0-next.2 + - @backstage/errors@1.2.3-next.0 + - @backstage/backend-tasks@0.5.11-next.2 + - @backstage/plugin-events-backend@0.2.15-next.2 + - @backstage/plugin-permission-node@0.7.17-next.2 + - @backstage/plugin-scaffolder-node@0.2.6-next.2 + - @backstage/plugin-search-backend-node@1.2.10-next.2 + - @backstage/backend-plugin-api@0.6.6-next.2 + - @backstage/cli-common@0.1.13-next.0 + - @backstage/cli-node@0.1.5-next.1 + - @backstage/config@1.1.1-next.0 + - @backstage/types@1.1.1 + - @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.0.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-backend@1.14.0-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-search-backend-node@1.2.9-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/plugin-events-backend@0.2.14-next.1 + - @backstage/plugin-permission-node@0.7.16-next.1 + - @backstage/plugin-scaffolder-node@0.2.5-next.1 + - @backstage/config@1.1.0 + - @backstage/cli-common@0.1.13-next.0 + - @backstage/cli-node@0.1.5-next.0 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.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.0.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.14.0-next.0 + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/cli-common@0.1.13-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/plugin-scaffolder-node@0.2.5-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/cli-node@0.1.5-next.0 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-events-backend@0.2.14-next.0 + - @backstage/plugin-events-node@0.2.14-next.0 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-permission-node@0.7.16-next.0 + - @backstage/plugin-search-backend-node@1.2.9-next.0 + - @backstage/plugin-search-common@1.2.6 + +## 0.0.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.13.0 + - @backstage/plugin-events-backend@0.2.12 + - @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/errors@1.2.2 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-search-common@1.2.6 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-node@0.7.14 + - @backstage/backend-plugin-api@0.6.3 + - @backstage/cli-common@0.1.12 + - @backstage/cli-node@0.1.4 + - @backstage/plugin-events-node@0.2.12 + - @backstage/plugin-scaffolder-node@0.2.3 + - @backstage/plugin-search-backend-node@1.2.7 + +## 0.0.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.13.0-next.3 + - @backstage/plugin-events-backend@0.2.12-next.3 + - @backstage/config@1.1.0-next.2 + - @backstage/errors@1.2.2-next.0 + - @backstage/plugin-permission-common@0.7.8-next.2 + - @backstage/plugin-search-common@1.2.6-next.2 + - @backstage/types@1.1.1-next.0 + - @backstage/plugin-permission-node@0.7.14-next.3 + - @backstage/backend-plugin-api@0.6.3-next.3 + - @backstage/backend-common@0.19.5-next.3 + - @backstage/backend-tasks@0.5.8-next.3 + - @backstage/cli-common@0.1.12 + - @backstage/cli-node@0.1.4-next.0 + - @backstage/plugin-auth-node@0.3.0-next.3 + - @backstage/plugin-events-node@0.2.12-next.3 + - @backstage/plugin-scaffolder-node@0.2.3-next.3 + - @backstage/plugin-search-backend-node@1.2.7-next.3 + +## 0.0.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.13.0-next.2 + - @backstage/config@1.1.0-next.1 + - @backstage/backend-tasks@0.5.8-next.2 + - @backstage/backend-common@0.19.5-next.2 + - @backstage/plugin-auth-node@0.3.0-next.2 + - @backstage/plugin-events-backend@0.2.12-next.2 + - @backstage/plugin-permission-node@0.7.14-next.2 + - @backstage/backend-plugin-api@0.6.3-next.2 + - @backstage/plugin-permission-common@0.7.8-next.1 + - @backstage/plugin-scaffolder-node@0.2.3-next.2 + - @backstage/plugin-search-backend-node@1.2.7-next.2 + - @backstage/cli-common@0.1.12 + - @backstage/cli-node@0.1.3 + - @backstage/errors@1.2.1 + - @backstage/types@1.1.0 + - @backstage/plugin-events-node@0.2.12-next.2 + - @backstage/plugin-search-common@1.2.6-next.1 diff --git a/packages/backend-plugin-manager/README.md b/packages/backend-dynamic-feature-service/README.md similarity index 64% rename from packages/backend-plugin-manager/README.md rename to packages/backend-dynamic-feature-service/README.md index c9fd666fb3..211148ee10 100644 --- a/packages/backend-plugin-manager/README.md +++ b/packages/backend-dynamic-feature-service/README.md @@ -1,10 +1,6 @@ -# @backstage/backend-plugin-manager +# @backstage/backend-dynamic-feature-service -This package adds experimental support for **dynamic backend plugins**, according to the content of the proposal in [RFC 18390](https://github.com/backstage/backstage/issues/18390) - -## Status - -**This package is EXPERIMENTAL, and is subject to change according to the discussions and conclusions that happen around the RFC mentioned above.** +This package adds experimental support for **dynamic backend features (plugins and modules)**, according to the content of the proposal in [RFC 18390](https://github.com/backstage/backstage/issues/18390) ## Testing the backend dynamic plugins feature @@ -12,9 +8,9 @@ In order to test the dynamic backend plugins feature provided by this package, e ## How it works -The backend 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. +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-plugin-manager` as a dependency in the `package.json` and the following lines in the `src/index.ts` file: +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: ```ts const backend = createBackend(); @@ -36,9 +32,9 @@ Points 2 and 3 can be done by the `export-dynamic-plugin` CLI command used to pe ### About the `export-dynamic-plugin` command -The `export-dynamic-plugin` CLI command, used the dynamic plugin examples provided in the [showcase repository](https://github.com/janus-idp/dynamic-backend-plugins-showcase), is part of a `@backstage/cli` fork (`@dfatwork-pkgs/backstage-cli@0.22.9-next.6`), and can be used to help packaging the dynamic plugins according to the constraints mentioned above, in order to allow straightforward testing of the dynamic plugins feature. +The `export-dynamic-plugin` CLI command, used the dynamic plugin examples provided in the [showcase repository](https://github.com/janus-idp/dynamic-backend-plugins-showcase), is part of the `@janus-idp/cli` package, and can be used to help packaging the dynamic plugins according to the constraints mentioned above, in order to allow straightforward testing of the dynamic plugins feature. -However the `backend-plugin-manager` experimental package does **not** depend on the use of this additional CLI command, and in future steps of this backend dynamic plugin work, the use of such a dedicated command might not even be necessary. +However the `backend-dynamic-feature-service` experimental package does **not** depend on the use of this additional CLI command, and in future steps of this backend dynamic plugin work, the use of such a dedicated command might not even be necessary. ### About the support of the legacy backend system @@ -49,4 +45,4 @@ This is why the API related to the old backend is already marked as deprecated. ### Future work -The current implementation of the backend plugin manager is a first step towards the final implementation of the dynamic backend plugins feature, which will be completed / simplified in future steps, as the status of the backstage codebase allows it. +The current implementation of the dynamic plugin manager is a first step towards the final implementation of the dynamic features loading, which will be completed / simplified in future steps, as the status of the backstage codebase allows it. diff --git a/packages/backend-plugin-manager/api-report.md b/packages/backend-dynamic-feature-service/api-report.md similarity index 85% rename from packages/backend-plugin-manager/api-report.md rename to packages/backend-dynamic-feature-service/api-report.md index b4221007ae..caf2cf01ec 100644 --- a/packages/backend-plugin-manager/api-report.md +++ b/packages/backend-dynamic-feature-service/api-report.md @@ -1,4 +1,4 @@ -## API Report File for "@backstage/backend-plugin-manager" +## API Report File for "@backstage/backend-dynamic-feature-service" > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). @@ -65,6 +65,44 @@ export interface BaseDynamicPlugin { // @public (undocumented) export type DynamicPlugin = FrontendDynamicPlugin | BackendDynamicPlugin; +// @public (undocumented) +export class DynamicPluginManager implements DynamicPluginProvider { + // (undocumented) + addBackendPlugin(plugin: BackendDynamicPlugin): void; + // (undocumented) + get availablePackages(): ScannedPluginPackage[]; + // (undocumented) + backendPlugins(): BackendDynamicPlugin[]; + // (undocumented) + static create( + options: DynamicPluginManagerOptions, + ): Promise; + // (undocumented) + frontendPlugins(): FrontendDynamicPlugin[]; + // (undocumented) + plugins(): DynamicPlugin[]; +} + +// @public (undocumented) +export interface DynamicPluginManagerOptions { + // (undocumented) + config: Config; + // (undocumented) + logger: LoggerService; + // (undocumented) + moduleLoader?: ModuleLoader; + // (undocumented) + preferAlpha?: boolean; +} + +// @public (undocumented) +export interface DynamicPluginProvider + extends FrontendPluginProvider, + BackendPluginProvider { + // (undocumented) + plugins(): DynamicPlugin[]; +} + // @public (undocumented) export interface DynamicPluginsFactoryOptions { // (undocumented) @@ -80,11 +118,11 @@ export const dynamicPluginsFeatureDiscoveryServiceFactory: () => ServiceFactory< // @public (undocumented) export const dynamicPluginsServiceFactory: ( options?: DynamicPluginsFactoryOptions | undefined, -) => ServiceFactory; +) => ServiceFactory; // @public (undocumented) export const dynamicPluginsServiceRef: ServiceRef< - BackendPluginProvider, + DynamicPluginProvider, 'root' >; @@ -94,6 +132,12 @@ export interface FrontendDynamicPlugin extends BaseDynamicPlugin { platform: 'web'; } +// @public (undocumented) +export interface FrontendPluginProvider { + // (undocumented) + frontendPlugins(): FrontendDynamicPlugin[]; +} + // @public (undocumented) export function isBackendDynamicPluginInstaller( obj: any, @@ -161,25 +205,6 @@ export interface NewBackendPluginInstaller { kind: 'new'; } -// @public (undocumented) -export class PluginManager implements BackendPluginProvider { - // (undocumented) - addBackendPlugin(plugin: BackendDynamicPlugin): void; - // (undocumented) - get availablePackages(): ScannedPluginPackage[]; - // (undocumented) - backendPlugins(): BackendDynamicPlugin[]; - // (undocumented) - static fromConfig( - config: Config, - logger: LoggerService, - preferAlpha?: boolean, - moduleLoader?: ModuleLoader, - ): Promise; - // (undocumented) - readonly plugins: DynamicPlugin[]; -} - // @public (undocumented) export type ScannedPluginManifest = BackstagePackageJson & Required> & diff --git a/packages/backend-dynamic-feature-service/catalog-info.yaml b/packages/backend-dynamic-feature-service/catalog-info.yaml new file mode 100644 index 0000000000..1269a5c406 --- /dev/null +++ b/packages/backend-dynamic-feature-service/catalog-info.yaml @@ -0,0 +1,10 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: backstage-backend-dynamic-feature-service + title: '@backstage/backend-dynamic-feature-service' + description: Backstage backend service to handle dynamic features +spec: + lifecycle: experimental + type: backstage-node-library + owner: maintainers diff --git a/packages/backend-plugin-manager/config.d.ts b/packages/backend-dynamic-feature-service/config.d.ts similarity index 100% rename from packages/backend-plugin-manager/config.d.ts rename to packages/backend-dynamic-feature-service/config.d.ts diff --git a/packages/backend-plugin-manager/package.json b/packages/backend-dynamic-feature-service/package.json similarity index 92% rename from packages/backend-plugin-manager/package.json rename to packages/backend-dynamic-feature-service/package.json index f58c678c09..18bbd58550 100644 --- a/packages/backend-plugin-manager/package.json +++ b/packages/backend-dynamic-feature-service/package.json @@ -1,8 +1,7 @@ { - "name": "@backstage/backend-plugin-manager", - "description": "Backstage plugin management backend", - "version": "0.0.3-next.2", - "private": true, + "name": "@backstage/backend-dynamic-feature-service", + "description": "Backstage dynamic feature service", + "version": "0.1.0", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend-plugin-manager/src/__testUtils__/testUtils.ts b/packages/backend-dynamic-feature-service/src/__testUtils__/testUtils.ts similarity index 100% rename from packages/backend-plugin-manager/src/__testUtils__/testUtils.ts rename to packages/backend-dynamic-feature-service/src/__testUtils__/testUtils.ts diff --git a/packages/backend-plugin-manager/src/index.ts b/packages/backend-dynamic-feature-service/src/index.ts similarity index 100% rename from packages/backend-plugin-manager/src/index.ts rename to packages/backend-dynamic-feature-service/src/index.ts diff --git a/packages/backend-plugin-manager/src/loader/CommonJSModuleLoader.ts b/packages/backend-dynamic-feature-service/src/loader/CommonJSModuleLoader.ts similarity index 96% rename from packages/backend-plugin-manager/src/loader/CommonJSModuleLoader.ts rename to packages/backend-dynamic-feature-service/src/loader/CommonJSModuleLoader.ts index 06a08117cd..66af367cea 100644 --- a/packages/backend-plugin-manager/src/loader/CommonJSModuleLoader.ts +++ b/packages/backend-dynamic-feature-service/src/loader/CommonJSModuleLoader.ts @@ -49,6 +49,6 @@ export class CommonJSModuleLoader implements ModuleLoader { } async load(packagePath: string): Promise { - return await import(/* webpackIgnore: true */ packagePath); + return await require(/* webpackIgnore: true */ packagePath); } } diff --git a/packages/backend-plugin-manager/src/loader/index.ts b/packages/backend-dynamic-feature-service/src/loader/index.ts similarity index 100% rename from packages/backend-plugin-manager/src/loader/index.ts rename to packages/backend-dynamic-feature-service/src/loader/index.ts diff --git a/packages/backend-plugin-manager/src/loader/types.ts b/packages/backend-dynamic-feature-service/src/loader/types.ts similarity index 100% rename from packages/backend-plugin-manager/src/loader/types.ts rename to packages/backend-dynamic-feature-service/src/loader/types.ts diff --git a/packages/backend-plugin-manager/src/manager/index.ts b/packages/backend-dynamic-feature-service/src/manager/index.ts similarity index 85% rename from packages/backend-plugin-manager/src/manager/index.ts rename to packages/backend-dynamic-feature-service/src/manager/index.ts index a9cd163617..dd6aaacfe9 100644 --- a/packages/backend-plugin-manager/src/manager/index.ts +++ b/packages/backend-dynamic-feature-service/src/manager/index.ts @@ -25,14 +25,19 @@ export type { NewBackendPluginInstaller, LegacyBackendPluginInstaller, LegacyPluginEnvironment, + DynamicPluginProvider, + FrontendPluginProvider, BackendPluginProvider, } from './types'; export { - PluginManager, + DynamicPluginManager, dynamicPluginsFeatureDiscoveryServiceFactory, dynamicPluginsServiceFactory, dynamicPluginsServiceRef, } from './plugin-manager'; -export type { DynamicPluginsFactoryOptions } from './plugin-manager'; +export type { + DynamicPluginManagerOptions, + DynamicPluginsFactoryOptions, +} from './plugin-manager'; diff --git a/packages/backend-plugin-manager/src/manager/plugin-manager.test.ts b/packages/backend-dynamic-feature-service/src/manager/plugin-manager.test.ts similarity index 73% rename from packages/backend-plugin-manager/src/manager/plugin-manager.test.ts rename to packages/backend-dynamic-feature-service/src/manager/plugin-manager.test.ts index 4aabd2c072..487729687f 100644 --- a/packages/backend-plugin-manager/src/manager/plugin-manager.test.ts +++ b/packages/backend-dynamic-feature-service/src/manager/plugin-manager.test.ts @@ -14,7 +14,10 @@ * limitations under the License. */ -import { PluginManager, dynamicPluginsServiceFactory } from './plugin-manager'; +import { + DynamicPluginManager, + dynamicPluginsServiceFactory, +} from './plugin-manager'; import { BackendFeature, coreServices, @@ -44,7 +47,7 @@ import { PluginScanner } from '../scanner/plugin-scanner'; import { findPaths } from '@backstage/cli-common'; import { createMockDirectory } from '@backstage/backend-test-utils'; -describe('backend-plugin-manager', () => { +describe('backend-dynamic-feature-service', () => { const mockDir = createMockDirectory(); describe('loadPlugins', () => { @@ -113,6 +116,94 @@ describe('backend-plugin-manager', () => { >([]); }, }, + { + name: 'should successfully load a new backend plugin by the default BackendFeature', + packageManifest: { + name: 'backend-dynamic-plugin-test', + version: '0.0.0', + backstage: { + role: 'backend-plugin', + }, + main: 'dist/index.cjs.js', + }, + indexFile: { + retativePath: ['dist', 'index.cjs.js'], + content: `const alpha = { $$type: '@backstage/BackendFeature' }; exports["default"] = alpha;`, + }, + expectedLogs(location) { + return { + infos: [ + { + message: `loaded dynamic backend plugin 'backend-dynamic-plugin-test' from '${location}'`, + }, + ], + }; + }, + checkLoadedPlugins(plugins) { + expect(plugins).toMatchObject([ + { + name: 'backend-dynamic-plugin-test', + version: '0.0.0', + role: 'backend-plugin', + platform: 'node', + installer: { + kind: 'new', + }, + }, + ]); + const installer: NewBackendPluginInstaller = ( + plugins[0] as BackendDynamicPlugin + ).installer as NewBackendPluginInstaller; + expect(installer.install()).toEqual< + BackendFeature | BackendFeature[] + >({ $$type: '@backstage/BackendFeature' }); + }, + }, + { + name: 'should successfully load a new backend plugin by the default BackendFeatureFactory', + packageManifest: { + name: 'backend-dynamic-plugin-test', + version: '0.0.0', + backstage: { + role: 'backend-plugin', + }, + main: 'dist/index.cjs.js', + }, + indexFile: { + retativePath: ['dist', 'index.cjs.js'], + content: `const alpha = () => { return { $$type: '@backstage/BackendFeature' } }; + alpha.$$type = '@backstage/BackendFeatureFactory'; + exports["default"] = alpha;`, + }, + expectedLogs(location) { + return { + infos: [ + { + message: `loaded dynamic backend plugin 'backend-dynamic-plugin-test' from '${location}'`, + }, + ], + }; + }, + checkLoadedPlugins(plugins) { + expect(plugins).toMatchObject([ + { + name: 'backend-dynamic-plugin-test', + version: '0.0.0', + role: 'backend-plugin', + platform: 'node', + installer: { + kind: 'new', + }, + }, + ]); + const installer: NewBackendPluginInstaller = ( + plugins[0] as BackendDynamicPlugin + ).installer as NewBackendPluginInstaller; + expect(installer.install()).toEqual< + BackendFeature | BackendFeature[] + >({ $$type: '@backstage/BackendFeature' }); + }, + }, { name: 'should successfully load a new backend plugin module', packageManifest: { @@ -221,7 +312,7 @@ describe('backend-plugin-manager', () => { return { errors: [ { - message: `dynamic backend plugin 'backend-dynamic-plugin-test' could not be loaded from '${location}': the module should export a 'const dynamicPluginInstaller: BackendDynamicPluginInstaller' field.`, + message: `dynamic backend plugin 'backend-dynamic-plugin-test' could not be loaded from '${location}': the module should either export a 'BackendFeature' or 'BackendFeatureFactory' as default export, or export a 'const dynamicPluginInstaller: BackendDynamicPluginInstaller' field as dynamic loading entrypoint.`, }, ], }; @@ -249,7 +340,7 @@ describe('backend-plugin-manager', () => { return { errors: [ { - message: `dynamic backend plugin 'backend-dynamic-plugin-test' could not be loaded from '${location}': the module should export a 'const dynamicPluginInstaller: BackendDynamicPluginInstaller' field.`, + message: `dynamic backend plugin 'backend-dynamic-plugin-test' could not be loaded from '${location}': the module should either export a 'BackendFeature' or 'BackendFeatureFactory' as default export, or export a 'const dynamicPluginInstaller: BackendDynamicPluginInstaller' field as dynamic loading entrypoint.`, }, ], }; @@ -374,12 +465,16 @@ describe('backend-plugin-manager', () => { mockDir.setContent(mockedFiles); const logger = new MockedLogger(); - const pluginManager = new (PluginManager as any)(logger, [plugin], { + const pluginManager = new (DynamicPluginManager as any)( logger, - async bootstrap(_: string, __: string[]): Promise {}, - load: async (packagePath: string) => - await import(/* webpackIgnore: true */ packagePath), - }); + [plugin], + { + logger, + async bootstrap(_: string, __: string[]): Promise {}, + load: async (packagePath: string) => + await require(/* webpackIgnore: true */ packagePath), + }, + ); const loadedPlugins: DynamicPlugin[] = await pluginManager.loadPlugins(); @@ -395,7 +490,10 @@ describe('backend-plugin-manager', () => { describe('backendPlugins', () => { it('should return only backend plugins and modules', async () => { const logger = new MockedLogger(); - const pluginManager = new (PluginManager as any)(logger, '', []); + const pluginManager = new (DynamicPluginManager as any)( + logger, + [], + ) as DynamicPluginManager; const plugins: BaseDynamicPlugin[] = [ { name: 'a-frontend-plugin', @@ -416,7 +514,7 @@ describe('backend-plugin-manager', () => { version: '0.0.0', }, ]; - pluginManager.plugins = plugins; + (pluginManager as any)._plugins = plugins; expect(pluginManager.backendPlugins()).toEqual([ { name: 'a-backend-plugin', @@ -434,6 +532,57 @@ describe('backend-plugin-manager', () => { }); }); + describe('frontendPlugins', () => { + it('should return only frontend plugins', async () => { + const logger = new MockedLogger(); + const pluginManager = new (DynamicPluginManager as any)( + logger, + [], + ) as DynamicPluginManager; + const plugins: BaseDynamicPlugin[] = [ + { + name: 'a-frontend-plugin', + platform: 'web', + role: 'frontend-plugin', + version: '0.0.0', + }, + { + name: 'a-frontend-module', + platform: 'web', + role: 'frontend-plugin-module', + version: '0.0.0', + }, + { + name: 'a-backend-plugin', + platform: 'node', + role: 'backend-plugin', + version: '0.0.0', + }, + { + name: 'a-backend-module', + platform: 'node', + role: 'backend-plugin-module', + version: '0.0.0', + }, + ]; + (pluginManager as any)._plugins = plugins; + expect(pluginManager.frontendPlugins()).toEqual([ + { + name: 'a-frontend-plugin', + platform: 'web', + role: 'frontend-plugin', + version: '0.0.0', + }, + { + name: 'a-frontend-module', + platform: 'web', + role: 'frontend-plugin-module', + version: '0.0.0', + }, + ]); + }); + }); + describe('dynamicPluginsServiceFactory', () => { const otherMockDir = createMockDirectory(); @@ -459,27 +608,29 @@ describe('backend-plugin-manager', () => { 'a-dynamic-plugin': {}, }); - const fromConfigSpier = jest.spyOn(PluginManager, 'fromConfig'); + const fromConfigSpier = jest.spyOn(DynamicPluginManager, 'create'); const applyConfigSpier = jest .spyOn(PluginScanner.prototype as any, 'applyConfig') .mockImplementation(() => {}); const scanRootSpier = jest .spyOn(PluginScanner.prototype, 'scanRoot') - .mockImplementation(async () => [ - { - location: url.pathToFileURL( - mockDir.resolve('dynamic-plugins-root/a-dynamic-plugin'), - ), - manifest: { - name: 'test', - version: '0.0.0', - main: 'dist/index.cjs.js', - backstage: { - role: 'backend-plugin', + .mockImplementation(async () => ({ + packages: [ + { + location: url.pathToFileURL( + mockDir.resolve('dynamic-plugins-root/a-dynamic-plugin'), + ), + manifest: { + name: 'test', + version: '0.0.0', + main: 'dist/index.cjs.js', + backstage: { + role: 'backend-plugin', + }, }, }, - }, - ]); + ], + })); const mockedModuleLoader = { logger, bootstrap: jest.fn(), diff --git a/packages/backend-plugin-manager/src/manager/plugin-manager.ts b/packages/backend-dynamic-feature-service/src/manager/plugin-manager.ts similarity index 69% rename from packages/backend-plugin-manager/src/manager/plugin-manager.ts rename to packages/backend-dynamic-feature-service/src/manager/plugin-manager.ts index ad76c7529e..edc3e20f72 100644 --- a/packages/backend-plugin-manager/src/manager/plugin-manager.ts +++ b/packages/backend-dynamic-feature-service/src/manager/plugin-manager.ts @@ -15,10 +15,11 @@ */ import { Config } from '@backstage/config'; import { - BackendPluginProvider, + DynamicPluginProvider, BackendDynamicPlugin, isBackendDynamicPluginInstaller, DynamicPlugin, + FrontendDynamicPlugin, } from './types'; import { ScannedPluginPackage } from '../scanner'; import { PluginScanner } from '../scanner/plugin-scanner'; @@ -44,24 +45,37 @@ import { /** * @public */ -export class PluginManager implements BackendPluginProvider { - static async fromConfig( - config: Config, - logger: LoggerService, - preferAlpha: boolean = false, - moduleLoader: ModuleLoader = new CommonJSModuleLoader(logger), - ): Promise { +export interface DynamicPluginManagerOptions { + config: Config; + logger: LoggerService; + preferAlpha?: boolean; + moduleLoader?: ModuleLoader; +} + +/** + * @public + */ +export class DynamicPluginManager implements DynamicPluginProvider { + static async create( + options: DynamicPluginManagerOptions, + ): Promise { /* eslint-disable-next-line no-restricted-syntax */ const backstageRoot = findPaths(__dirname).targetRoot; - const scanner = new PluginScanner( - config, - logger, + const scanner = PluginScanner.create({ + config: options.config, + logger: options.logger, backstageRoot, - preferAlpha, - ); - const scannedPlugins = await scanner.scanRoot(); + preferAlpha: options.preferAlpha, + }); + const scannedPlugins = (await scanner.scanRoot()).packages; scanner.trackChanges(); - const manager = new PluginManager(logger, scannedPlugins, moduleLoader); + const moduleLoader = + options.moduleLoader || new CommonJSModuleLoader(options.logger); + const manager = new DynamicPluginManager( + options.logger, + scannedPlugins, + moduleLoader, + ); const dynamicPluginsPaths = scannedPlugins.map(p => fs.realpathSync( @@ -76,15 +90,15 @@ export class PluginManager implements BackendPluginProvider { moduleLoader.bootstrap(backstageRoot, dynamicPluginsPaths); scanner.subscribeToRootDirectoryChange(async () => { - manager._availablePackages = await scanner.scanRoot(); + manager._availablePackages = (await scanner.scanRoot()).packages; // TODO: do not store _scannedPlugins again, but instead store a diff of the changes }); - manager.plugins.push(...(await manager.loadPlugins())); + manager._plugins.push(...(await manager.loadPlugins())); return manager; } - readonly plugins: DynamicPlugin[]; + private readonly _plugins: DynamicPlugin[]; private _availablePackages: ScannedPluginPackage[]; private constructor( @@ -92,7 +106,7 @@ export class PluginManager implements BackendPluginProvider { private packages: ScannedPluginPackage[], private readonly moduleLoader: ModuleLoader, ) { - this.plugins = []; + this._plugins = []; this._availablePackages = packages; } @@ -101,7 +115,7 @@ export class PluginManager implements BackendPluginProvider { } addBackendPlugin(plugin: BackendDynamicPlugin): void { - this.plugins.push(plugin); + this._plugins.push(plugin); } private async loadPlugins(): Promise { @@ -140,12 +154,25 @@ export class PluginManager implements BackendPluginProvider { `${plugin.location}/${plugin.manifest.main}`, ); try { - const { dynamicPluginInstaller } = await this.moduleLoader.load( - packagePath, - ); + const pluginModule = await this.moduleLoader.load(packagePath); + + let dynamicPluginInstaller; + if (isBackendFeature(pluginModule.default)) { + dynamicPluginInstaller = { + kind: 'new', + install: () => pluginModule.default, + }; + } else if (isBackendFeatureFactory(pluginModule.default)) { + dynamicPluginInstaller = { + kind: 'new', + install: pluginModule.default, + }; + } else { + dynamicPluginInstaller = pluginModule.dynamicPluginInstaller; + } if (!isBackendDynamicPluginInstaller(dynamicPluginInstaller)) { this.logger.error( - `dynamic backend plugin '${plugin.manifest.name}' could not be loaded from '${plugin.location}': the module should export a 'const dynamicPluginInstaller: BackendDynamicPluginInstaller' field.`, + `dynamic backend plugin '${plugin.manifest.name}' could not be loaded from '${plugin.location}': the module should either export a 'BackendFeature' or 'BackendFeatureFactory' as default export, or export a 'const dynamicPluginInstaller: BackendDynamicPluginInstaller' field as dynamic loading entrypoint.`, ); return undefined; } @@ -169,16 +196,26 @@ export class PluginManager implements BackendPluginProvider { } backendPlugins(): BackendDynamicPlugin[] { - return this.plugins.filter( + return this._plugins.filter( (p): p is BackendDynamicPlugin => p.platform === 'node', ); } + + frontendPlugins(): FrontendDynamicPlugin[] { + return this._plugins.filter( + (p): p is FrontendDynamicPlugin => p.platform === 'web', + ); + } + + plugins(): DynamicPlugin[] { + return this._plugins; + } } /** * @public */ -export const dynamicPluginsServiceRef = createServiceRef( +export const dynamicPluginsServiceRef = createServiceRef( { id: 'core.dynamicplugins', scope: 'root', @@ -203,15 +240,12 @@ export const dynamicPluginsServiceFactory = createServiceFactory( logger: coreServices.rootLogger, }, async factory({ config, logger }) { - if (options?.moduleLoader) { - return await PluginManager.fromConfig( - config, - logger, - true, - options.moduleLoader(logger), - ); - } - return await PluginManager.fromConfig(config, logger, true); + return await DynamicPluginManager.create({ + config, + logger, + preferAlpha: true, + moduleLoader: options?.moduleLoader?.(logger), + }); }, }), ); @@ -220,7 +254,7 @@ class DynamicPluginsEnabledFeatureDiscoveryService implements FeatureDiscoveryService { constructor( - private readonly dynamicPlugins: BackendPluginProvider, + private readonly dynamicPlugins: DynamicPluginProvider, private readonly featureDiscoveryService?: FeatureDiscoveryService, ) {} @@ -263,3 +297,21 @@ export const dynamicPluginsFeatureDiscoveryServiceFactory = return new DynamicPluginsEnabledFeatureDiscoveryService(dynamicPlugins); }, }); + +function isBackendFeature(value: unknown): value is BackendFeature { + return ( + !!value && + typeof value === 'object' && + (value as BackendFeature).$$type === '@backstage/BackendFeature' + ); +} + +function isBackendFeatureFactory( + value: unknown, +): value is () => BackendFeature { + return ( + !!value && + typeof value === 'function' && + (value as any).$$type === '@backstage/BackendFeatureFactory' + ); +} diff --git a/packages/backend-plugin-manager/src/manager/types.ts b/packages/backend-dynamic-feature-service/src/manager/types.ts similarity index 94% rename from packages/backend-plugin-manager/src/manager/types.ts rename to packages/backend-dynamic-feature-service/src/manager/types.ts index 201941292d..0038470686 100644 --- a/packages/backend-plugin-manager/src/manager/types.ts +++ b/packages/backend-dynamic-feature-service/src/manager/types.ts @@ -67,6 +67,15 @@ export type LegacyPluginEnvironment = { pluginProvider: BackendPluginProvider; }; +/** + * @public + */ +export interface DynamicPluginProvider + extends FrontendPluginProvider, + BackendPluginProvider { + plugins(): DynamicPlugin[]; +} + /** * @public */ @@ -74,6 +83,13 @@ export interface BackendPluginProvider { backendPlugins(): BackendDynamicPlugin[]; } +/** + * @public + */ +export interface FrontendPluginProvider { + frontendPlugins(): FrontendDynamicPlugin[]; +} + /** * @public */ diff --git a/packages/backend-plugin-manager/src/scanner/index.ts b/packages/backend-dynamic-feature-service/src/scanner/index.ts similarity index 100% rename from packages/backend-plugin-manager/src/scanner/index.ts rename to packages/backend-dynamic-feature-service/src/scanner/index.ts diff --git a/packages/backend-plugin-manager/src/scanner/plugin-scanner-watcher.test.ts b/packages/backend-dynamic-feature-service/src/scanner/plugin-scanner-watcher.test.ts similarity index 93% rename from packages/backend-plugin-manager/src/scanner/plugin-scanner-watcher.test.ts rename to packages/backend-dynamic-feature-service/src/scanner/plugin-scanner-watcher.test.ts index e346bf749f..2d017d805b 100644 --- a/packages/backend-plugin-manager/src/scanner/plugin-scanner-watcher.test.ts +++ b/packages/backend-dynamic-feature-service/src/scanner/plugin-scanner-watcher.test.ts @@ -64,22 +64,23 @@ describe('plugin-scanner', () => { unsubscribe: configUnsubscribe, }; }; - const pluginScanner = new PluginScanner( + const pluginScanner = PluginScanner.create({ config, logger, - backstageRootDirectory, - false, - ); + backstageRoot: backstageRootDirectory, + preferAlpha: false, + }); await pluginScanner.trackChanges(); expect(onConfigChange).toBeDefined(); - let scannedPlugins: ScannedPluginPackage[] = - await pluginScanner.scanRoot(); + let scannedPlugins: ScannedPluginPackage[] = ( + await pluginScanner.scanRoot() + ).packages; expect(scannedPlugins).toEqual([]); const rootDirectorySubscriber = jest.fn(async () => { - scannedPlugins = await pluginScanner.scanRoot(); + scannedPlugins = (await pluginScanner.scanRoot()).packages; }); pluginScanner.subscribeToRootDirectoryChange(rootDirectorySubscriber); @@ -229,6 +230,7 @@ describe('plugin-scanner', () => { logger.logs = {}; const debug = jest.spyOn(logger, 'debug'); + const info = jest.spyOn(logger, 'info'); // Check that not all file changes trigger a new scan of plugins await mkdir( @@ -240,8 +242,11 @@ describe('plugin-scanner', () => { ), ); await waitForExpect(() => { - expect(debug).toHaveBeenCalledTimes(1); + expect(debug).toHaveBeenCalled(); }); + expect(info).toHaveBeenCalledTimes(0); + debug.mockClear(); + await writeFile( join( backstageRootDirectory, @@ -252,8 +257,11 @@ describe('plugin-scanner', () => { 'content', ); await waitForExpect(() => { - expect(debug).toHaveBeenCalledTimes(2); + expect(debug).toHaveBeenCalled(); }); + expect(info).toHaveBeenCalledTimes(0); + debug.mockClear(); + await rm( join( backstageRootDirectory, @@ -263,8 +271,11 @@ describe('plugin-scanner', () => { ), ); await waitForExpect(() => { - expect(debug).toHaveBeenCalledTimes(3); + expect(debug).toHaveBeenCalled(); }); + expect(info).toHaveBeenCalledTimes(0); + debug.mockClear(); + await rm( join( backstageRootDirectory, @@ -275,8 +286,10 @@ describe('plugin-scanner', () => { { recursive: true }, ); await waitForExpect(() => { - expect(debug).toHaveBeenCalledTimes(4); + expect(debug).toHaveBeenCalled(); }); + expect(info).toHaveBeenCalledTimes(0); + debug.mockClear(); const onWindows = path.sep === '\\'; // Order of events is not fixed on Windows. diff --git a/packages/backend-plugin-manager/src/scanner/plugin-scanner.test.ts b/packages/backend-dynamic-feature-service/src/scanner/plugin-scanner.test.ts similarity index 98% rename from packages/backend-plugin-manager/src/scanner/plugin-scanner.test.ts rename to packages/backend-dynamic-feature-service/src/scanner/plugin-scanner.test.ts index d4ab8940c9..e52eee87c4 100644 --- a/packages/backend-plugin-manager/src/scanner/plugin-scanner.test.ts +++ b/packages/backend-dynamic-feature-service/src/scanner/plugin-scanner.test.ts @@ -206,11 +206,11 @@ Please add '${mockDir.resolve( const logger = new MockedLogger(); const backstageRoot = tc.backstageRoot ? tc.backstageRoot : ''; function toTest(): PluginScanner { - return new PluginScanner( - new ConfigReader(tc.config), + return PluginScanner.create({ + config: new ConfigReader(tc.config), logger, backstageRoot, - ); + }); } if (tc.fileSystem) { mockDir.setContent(tc.fileSystem); @@ -609,8 +609,8 @@ Please add '${mockDir.resolve( const logger = new MockedLogger(); const backstageRoot = mockDir.resolve('backstageRoot'); async function toTest(): Promise { - const pluginScanner = new PluginScanner( - new ConfigReader( + const pluginScanner = PluginScanner.create({ + config: new ConfigReader( tc.fileSystem ? { dynamicPlugins: { @@ -621,9 +621,9 @@ Please add '${mockDir.resolve( ), logger, backstageRoot, - tc.preferAlpha === undefined ? false : tc.preferAlpha, - ); - return await pluginScanner.scanRoot(); + preferAlpha: tc.preferAlpha, + }); + return (await pluginScanner.scanRoot()).packages; } if (tc.fileSystem) { mockDir.setContent(tc.fileSystem); diff --git a/packages/backend-plugin-manager/src/scanner/plugin-scanner.ts b/packages/backend-dynamic-feature-service/src/scanner/plugin-scanner.ts similarity index 83% rename from packages/backend-plugin-manager/src/scanner/plugin-scanner.ts rename to packages/backend-dynamic-feature-service/src/scanner/plugin-scanner.ts index 51e38002e9..25e0d614dd 100644 --- a/packages/backend-plugin-manager/src/scanner/plugin-scanner.ts +++ b/packages/backend-dynamic-feature-service/src/scanner/plugin-scanner.ts @@ -24,28 +24,39 @@ import debounce from 'lodash/debounce'; import { PackagePlatform, PackageRoles } from '@backstage/cli-node'; import { LoggerService } from '@backstage/backend-plugin-api'; +export interface DynamicPluginScannerOptions { + config: Config; + backstageRoot: string; + logger: LoggerService; + preferAlpha?: boolean; +} + +export interface ScanRootResponse { + packages: ScannedPluginPackage[]; +} + export class PluginScanner { - private readonly logger: LoggerService; - private backstageRoot: string; - readonly #config: Config; private _rootDirectory?: string; - private readonly preferAlpha: boolean; private configUnsubscribe?: () => void; private rootDirectoryWatcher?: chokidar.FSWatcher; private subscribers: (() => void)[] = []; - constructor( - config: Config, - logger: LoggerService, - backstageRoot: string, - preferAlpha: boolean = false, - ) { - this.backstageRoot = backstageRoot; - this.logger = logger; - this.preferAlpha = preferAlpha; - this.#config = config; + private constructor( + private readonly config: Config, + private readonly logger: LoggerService, + private readonly backstageRoot: string, + private readonly preferAlpha: boolean, + ) {} - this.applyConfig(); + static create(options: DynamicPluginScannerOptions): PluginScanner { + const scanner = new PluginScanner( + options.config, + options.logger, + options.backstageRoot, + options.preferAlpha || false, + ); + scanner.applyConfig(); + return scanner; } subscribeToRootDirectoryChange(subscriber: () => void) { @@ -57,7 +68,7 @@ export class PluginScanner { } private applyConfig(): void | never { - const dynamicPlugins = this.#config.getOptional('dynamicPlugins'); + const dynamicPlugins = this.config.getOptional('dynamicPlugins'); if (!dynamicPlugins) { this.logger.info("'dynamicPlugins' config entry not found."); this._rootDirectory = undefined; @@ -114,9 +125,9 @@ export class PluginScanner { this._rootDirectory = dynamicPluginsRootPath; } - async scanRoot(): Promise { + async scanRoot(): Promise { if (!this._rootDirectory) { - return []; + return { packages: [] }; } const dynamicPluginsLocation = this._rootDirectory; @@ -189,7 +200,7 @@ export class PluginScanner { scannedPlugins.push(scannedPlugin); } - return scannedPlugins; + return { packages: scannedPlugins }; } private async scanDir(pluginHome: string): Promise { @@ -263,30 +274,28 @@ export class PluginScanner { }; await setupRootDirectoryWatcher(); - if (this.#config.subscribe) { - const { unsubscribe } = this.#config.subscribe( - async (): Promise => { - const oldRootDirectory = this._rootDirectory; - try { - this.applyConfig(); - } catch (e) { - this.logger.error( - 'failed to apply new config for dynamic plugins', - e, - ); + if (this.config.subscribe) { + const { unsubscribe } = this.config.subscribe(async (): Promise => { + const oldRootDirectory = this._rootDirectory; + try { + this.applyConfig(); + } catch (e) { + this.logger.error( + 'failed to apply new config for dynamic plugins', + e, + ); + } + if (oldRootDirectory !== this._rootDirectory) { + this.logger.info( + `rootDirectory changed in Config from '${oldRootDirectory}' to '${this._rootDirectory}'`, + ); + this.subscribers.forEach(s => s()); + if (this.rootDirectoryWatcher) { + await this.rootDirectoryWatcher.close(); } - if (oldRootDirectory !== this._rootDirectory) { - this.logger.info( - `rootDirectory changed in Config from '${oldRootDirectory}' to '${this._rootDirectory}'`, - ); - this.subscribers.forEach(s => s()); - if (this.rootDirectoryWatcher) { - await this.rootDirectoryWatcher.close(); - } - await setupRootDirectoryWatcher(); - } - }, - ); + await setupRootDirectoryWatcher(); + } + }); this.configUnsubscribe = unsubscribe; } } diff --git a/packages/backend-plugin-manager/src/scanner/types.ts b/packages/backend-dynamic-feature-service/src/scanner/types.ts similarity index 100% rename from packages/backend-plugin-manager/src/scanner/types.ts rename to packages/backend-dynamic-feature-service/src/scanner/types.ts diff --git a/packages/backend-next/CHANGELOG.md b/packages/backend-next/CHANGELOG.md index f94cc2b82d..96cb73808f 100644 --- a/packages/backend-next/CHANGELOG.md +++ b/packages/backend-next/CHANGELOG.md @@ -1,5 +1,414 @@ # example-backend-next +## 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 diff --git a/packages/backend-next/README.md b/packages/backend-next/README.md index 94fc0767c4..4634e5673f 100644 --- a/packages/backend-next/README.md +++ b/packages/backend-next/README.md @@ -1,5 +1,5 @@ # example-backend-next -This is an example backend for the new **EXPERIMENTAL** Backstage backend system. +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/package.json b/packages/backend-next/package.json index c26e97de3d..d6908f6e78 100644 --- a/packages/backend-next/package.json +++ b/packages/backend-next/package.json @@ -1,6 +1,6 @@ { "name": "example-backend-next", - "version": "0.0.17-next.2", + "version": "0.0.19", "main": "dist/index.cjs.js", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/backend-openapi-utils/CHANGELOG.md b/packages/backend-openapi-utils/CHANGELOG.md index 3ac4d9f3a8..9cbaa84947 100644 --- a/packages/backend-openapi-utils/CHANGELOG.md +++ b/packages/backend-openapi-utils/CHANGELOG.md @@ -1,5 +1,99 @@ # @backstage/backend-openapi-utils +## 0.1.2 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/errors@1.2.3 + +## 0.1.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + +## 0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/errors@1.2.3 + +## 0.1.2-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/errors@1.2.3 + +## 0.1.1 + +### Patch Changes + +- aaa6fb3: Minor updates for TypeScript 5.2.2+ compatibility +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.1.1-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.1.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.1.1-next.0 + +### Patch Changes + +- aaa6fb3bc9: Minor updates for TypeScript 5.2.2+ compatibility +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.1.0 + +### Minor Changes + +- 785fb1ea75: Adds a new route, `/openapi.json` to validated routers for displaying their full OpenAPI spec in a standard endpoint. + +### Patch Changes + +- 6694b369a3: Adds a new function `wrapInOpenApiTestServer` that allows for proxied requests at runtime. This will support the new `yarn backstage-repo-tools schema openapi test` command. +- Updated dependencies + - @backstage/backend-plugin-api@0.6.7 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + ## 0.1.0-next.2 ### Patch Changes diff --git a/packages/backend-openapi-utils/api-report.md b/packages/backend-openapi-utils/api-report.md index 67132ca74b..0d78ec9671 100644 --- a/packages/backend-openapi-utils/api-report.md +++ b/packages/backend-openapi-utils/api-report.md @@ -61,12 +61,13 @@ type ComponentTypes = Extract< >; // @public (undocumented) -type ConvertAll = []> = T extends [ - infer First extends JSONSchema7, - ...infer Rest, -] - ? ConvertAll]> - : R; +type ConvertAll> = { + [Index in keyof T]: T[Index] extends JSONSchema7 + ? FromSchema + : T[Index]; +} & { + length: T['length']; +}; // @public (undocumented) interface CookieObject extends ParameterObject { diff --git a/packages/backend-openapi-utils/package.json b/packages/backend-openapi-utils/package.json index 7517156d84..2ca6c3b716 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.0-next.2", + "version": "0.1.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -38,7 +38,6 @@ ], "dependencies": { "@backstage/backend-plugin-api": "workspace:^", - "@backstage/config": "workspace:^", "@backstage/errors": "workspace:^", "@types/express": "^4.17.6", "@types/express-serve-static-core": "^4.17.5", diff --git a/packages/backend-openapi-utils/src/types/common.ts b/packages/backend-openapi-utils/src/types/common.ts index c3c7284369..f9dedf2f84 100644 --- a/packages/backend-openapi-utils/src/types/common.ts +++ b/packages/backend-openapi-utils/src/types/common.ts @@ -220,12 +220,11 @@ export type TuplifyUnion< /** * @public */ -export type ConvertAll = []> = T extends [ - infer First extends JSONSchema7, - ...infer Rest, -] - ? ConvertAll]> - : R; +export type ConvertAll> = { + [Index in keyof T]: T[Index] extends JSONSchema7 + ? FromSchema + : T[Index]; +} & { length: T['length'] }; /** * @public diff --git a/packages/backend-plugin-api/CHANGELOG.md b/packages/backend-plugin-api/CHANGELOG.md index 8121b848e0..80f9026e21 100644 --- a/packages/backend-plugin-api/CHANGELOG.md +++ b/packages/backend-plugin-api/CHANGELOG.md @@ -1,5 +1,115 @@ # @backstage/backend-plugin-api +## 0.6.9 + +### Patch Changes + +- 516fd3e: Updated README to reflect release status +- Updated dependencies + - @backstage/plugin-permission-common@0.7.12 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## 0.6.9-next.2 + +### Patch Changes + +- 516fd3e: Updated README to reflect release status +- Updated dependencies + - @backstage/plugin-auth-node@0.4.3-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## 0.6.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.11 + +## 0.6.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.14-next.0 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.0 + - @backstage/plugin-permission-common@0.7.11 + +## 0.6.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.13 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## 0.6.8-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.3 + - @backstage/plugin-permission-common@0.7.10 + +## 0.6.8-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-tasks@0.5.13-next.2 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.10 + +## 0.6.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-permission-common@0.7.10 + +## 0.6.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.10 + +## 0.6.7 + +### Patch Changes + +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. +- Updated dependencies + - @backstage/backend-tasks@0.5.12 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.1 + ## 0.6.7-next.2 ### Patch Changes diff --git a/packages/backend-plugin-api/README.md b/packages/backend-plugin-api/README.md index a17c8715a7..b827ecc50c 100644 --- a/packages/backend-plugin-api/README.md +++ b/packages/backend-plugin-api/README.md @@ -1,8 +1,6 @@ # @backstage/backend-plugin-api -**This package is EXPERIMENTAL, but we encourage use of it to add support for the new backend system in your own plugins** - -This package provides the core API used by Backstage backend plugins and modules. +This package provides the framework API used by Backstage backend plugins and modules. ## Installation diff --git a/packages/backend-plugin-api/alpha-api-report.md b/packages/backend-plugin-api/api-report-alpha.md similarity index 100% rename from packages/backend-plugin-api/alpha-api-report.md rename to packages/backend-plugin-api/api-report-alpha.md diff --git a/packages/backend-plugin-api/package.json b/packages/backend-plugin-api/package.json index 458958ab29..618a537bf5 100644 --- a/packages/backend-plugin-api/package.json +++ b/packages/backend-plugin-api/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-plugin-api", "description": "Core API used by Backstage backend plugins", - "version": "0.6.7-next.2", + "version": "0.6.9", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend-plugin-manager/CHANGELOG.md b/packages/backend-plugin-manager/CHANGELOG.md deleted file mode 100644 index fd4bd03ba6..0000000000 --- a/packages/backend-plugin-manager/CHANGELOG.md +++ /dev/null @@ -1,224 +0,0 @@ -# @backstage/backend-plugin-manager - -## 0.0.3-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-plugin-api@0.6.7-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-auth-node@0.4.1-next.2 - - @backstage/plugin-events-backend@0.2.16-next.2 - - @backstage/plugin-events-node@0.2.16-next.2 - - @backstage/plugin-permission-node@0.7.18-next.2 - - @backstage/plugin-scaffolder-node@0.2.8-next.2 - - @backstage/plugin-search-backend-node@1.2.11-next.2 - -## 0.0.3-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-backend@1.15.0-next.1 - - @backstage/backend-common@0.19.9-next.1 - - @backstage/plugin-scaffolder-node@0.2.8-next.1 - - @backstage/backend-tasks@0.5.12-next.1 - - @backstage/plugin-auth-node@0.4.1-next.1 - - @backstage/plugin-events-backend@0.2.16-next.1 - - @backstage/plugin-permission-node@0.7.18-next.1 - - @backstage/plugin-search-backend-node@1.2.11-next.1 - - @backstage/backend-plugin-api@0.6.7-next.1 - - @backstage/cli-common@0.1.13 - - @backstage/cli-node@0.2.0-next.0 - - @backstage/config@1.1.1 - - @backstage/errors@1.2.3 - - @backstage/types@1.1.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.0.3-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/cli-node@0.2.0-next.0 - - @backstage/plugin-search-backend-node@1.2.11-next.0 - - @backstage/plugin-catalog-backend@1.15.0-next.0 - - @backstage/plugin-scaffolder-node@0.2.8-next.0 - - @backstage/backend-common@0.19.9-next.0 - - @backstage/backend-plugin-api@0.6.7-next.0 - - @backstage/backend-tasks@0.5.12-next.0 - - @backstage/cli-common@0.1.13 - - @backstage/config@1.1.1 - - @backstage/errors@1.2.3 - - @backstage/types@1.1.1 - - @backstage/plugin-auth-node@0.4.1-next.0 - - @backstage/plugin-events-backend@0.2.16-next.0 - - @backstage/plugin-events-node@0.2.16-next.0 - - @backstage/plugin-permission-common@0.7.9 - - @backstage/plugin-permission-node@0.7.18-next.0 - - @backstage/plugin-search-common@1.2.7 - -## 0.0.2 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-tasks@0.5.11 - - @backstage/backend-common@0.19.8 - - @backstage/plugin-catalog-backend@1.14.0 - - @backstage/plugin-auth-node@0.4.0 - - @backstage/errors@1.2.3 - - @backstage/cli-common@0.1.13 - - @backstage/backend-plugin-api@0.6.6 - - @backstage/plugin-search-backend-node@1.2.10 - - @backstage/plugin-events-backend@0.2.15 - - @backstage/plugin-permission-node@0.7.17 - - @backstage/plugin-scaffolder-node@0.2.6 - - @backstage/cli-node@0.1.5 - - @backstage/config@1.1.1 - - @backstage/types@1.1.1 - - @backstage/plugin-events-node@0.2.15 - - @backstage/plugin-permission-common@0.7.9 - - @backstage/plugin-search-common@1.2.7 - -## 0.0.2-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.19.8-next.2 - - @backstage/plugin-auth-node@0.4.0-next.2 - - @backstage/plugin-catalog-backend@1.14.0-next.2 - - @backstage/errors@1.2.3-next.0 - - @backstage/backend-tasks@0.5.11-next.2 - - @backstage/plugin-events-backend@0.2.15-next.2 - - @backstage/plugin-permission-node@0.7.17-next.2 - - @backstage/plugin-scaffolder-node@0.2.6-next.2 - - @backstage/plugin-search-backend-node@1.2.10-next.2 - - @backstage/backend-plugin-api@0.6.6-next.2 - - @backstage/cli-common@0.1.13-next.0 - - @backstage/cli-node@0.1.5-next.1 - - @backstage/config@1.1.1-next.0 - - @backstage/types@1.1.1 - - @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.0.2-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-tasks@0.5.10-next.1 - - @backstage/plugin-catalog-backend@1.14.0-next.1 - - @backstage/backend-common@0.19.7-next.1 - - @backstage/backend-plugin-api@0.6.5-next.1 - - @backstage/plugin-search-backend-node@1.2.9-next.1 - - @backstage/plugin-auth-node@0.3.2-next.1 - - @backstage/plugin-events-backend@0.2.14-next.1 - - @backstage/plugin-permission-node@0.7.16-next.1 - - @backstage/plugin-scaffolder-node@0.2.5-next.1 - - @backstage/config@1.1.0 - - @backstage/cli-common@0.1.13-next.0 - - @backstage/cli-node@0.1.5-next.0 - - @backstage/errors@1.2.2 - - @backstage/types@1.1.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.0.2-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-backend@1.14.0-next.0 - - @backstage/plugin-auth-node@0.3.2-next.0 - - @backstage/cli-common@0.1.13-next.0 - - @backstage/backend-common@0.19.7-next.0 - - @backstage/plugin-scaffolder-node@0.2.5-next.0 - - @backstage/config@1.1.0 - - @backstage/backend-plugin-api@0.6.5-next.0 - - @backstage/backend-tasks@0.5.10-next.0 - - @backstage/cli-node@0.1.5-next.0 - - @backstage/errors@1.2.2 - - @backstage/types@1.1.1 - - @backstage/plugin-events-backend@0.2.14-next.0 - - @backstage/plugin-events-node@0.2.14-next.0 - - @backstage/plugin-permission-common@0.7.8 - - @backstage/plugin-permission-node@0.7.16-next.0 - - @backstage/plugin-search-backend-node@1.2.9-next.0 - - @backstage/plugin-search-common@1.2.6 - -## 0.0.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-backend@1.13.0 - - @backstage/plugin-events-backend@0.2.12 - - @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/errors@1.2.2 - - @backstage/plugin-permission-common@0.7.8 - - @backstage/plugin-search-common@1.2.6 - - @backstage/types@1.1.1 - - @backstage/plugin-permission-node@0.7.14 - - @backstage/backend-plugin-api@0.6.3 - - @backstage/cli-common@0.1.12 - - @backstage/cli-node@0.1.4 - - @backstage/plugin-events-node@0.2.12 - - @backstage/plugin-scaffolder-node@0.2.3 - - @backstage/plugin-search-backend-node@1.2.7 - -## 0.0.1-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-backend@1.13.0-next.3 - - @backstage/plugin-events-backend@0.2.12-next.3 - - @backstage/config@1.1.0-next.2 - - @backstage/errors@1.2.2-next.0 - - @backstage/plugin-permission-common@0.7.8-next.2 - - @backstage/plugin-search-common@1.2.6-next.2 - - @backstage/types@1.1.1-next.0 - - @backstage/plugin-permission-node@0.7.14-next.3 - - @backstage/backend-plugin-api@0.6.3-next.3 - - @backstage/backend-common@0.19.5-next.3 - - @backstage/backend-tasks@0.5.8-next.3 - - @backstage/cli-common@0.1.12 - - @backstage/cli-node@0.1.4-next.0 - - @backstage/plugin-auth-node@0.3.0-next.3 - - @backstage/plugin-events-node@0.2.12-next.3 - - @backstage/plugin-scaffolder-node@0.2.3-next.3 - - @backstage/plugin-search-backend-node@1.2.7-next.3 - -## 0.0.1-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-backend@1.13.0-next.2 - - @backstage/config@1.1.0-next.1 - - @backstage/backend-tasks@0.5.8-next.2 - - @backstage/backend-common@0.19.5-next.2 - - @backstage/plugin-auth-node@0.3.0-next.2 - - @backstage/plugin-events-backend@0.2.12-next.2 - - @backstage/plugin-permission-node@0.7.14-next.2 - - @backstage/backend-plugin-api@0.6.3-next.2 - - @backstage/plugin-permission-common@0.7.8-next.1 - - @backstage/plugin-scaffolder-node@0.2.3-next.2 - - @backstage/plugin-search-backend-node@1.2.7-next.2 - - @backstage/cli-common@0.1.12 - - @backstage/cli-node@0.1.3 - - @backstage/errors@1.2.1 - - @backstage/types@1.1.0 - - @backstage/plugin-events-node@0.2.12-next.2 - - @backstage/plugin-search-common@1.2.6-next.1 diff --git a/packages/backend-plugin-manager/catalog-info.yaml b/packages/backend-plugin-manager/catalog-info.yaml deleted file mode 100644 index bc1845fe49..0000000000 --- a/packages/backend-plugin-manager/catalog-info.yaml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: backstage.io/v1alpha1 -kind: Component -metadata: - name: backstage-backend-plugin-manager - title: '@backstage/backend-plugin-manager' - description: Backstage plugin management backend -spec: - lifecycle: experimental - type: backstage-node-library - owner: maintainers diff --git a/packages/backend-tasks/CHANGELOG.md b/packages/backend-tasks/CHANGELOG.md index e2d9a7abda..d107e5b51d 100644 --- a/packages/backend-tasks/CHANGELOG.md +++ b/packages/backend-tasks/CHANGELOG.md @@ -1,5 +1,106 @@ # @backstage/backend-tasks +## 0.5.14 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.5.14-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.2 + +## 0.5.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.5.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.5.13 + +### Patch Changes + +- d8f488a: Allow tasks to run more often that the default work check interval, which is 5 seconds. +- 0cbb03b: Fixing regular expression ReDoS with zod packages. Upgrading to latest. ref: https://security.snyk.io/vuln/SNYK-JS-ZOD-5925617 +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.5.13-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.5.13-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.5.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.5.13-next.0 + +### Patch Changes + +- d8f488aaa8: Allow tasks to run more often that the default work check interval, which is 5 seconds. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.5.12 + +### Patch Changes + +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + ## 0.5.12-next.2 ### Patch Changes diff --git a/packages/backend-tasks/package.json b/packages/backend-tasks/package.json index 306dace806..4af6a3462a 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.12-next.2", + "version": "0.5.14", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { @@ -44,7 +44,7 @@ "luxon": "^3.0.0", "uuid": "^8.0.0", "winston": "^3.2.1", - "zod": "^3.21.4" + "zod": "^3.22.4" }, "devDependencies": { "@backstage/backend-test-utils": "workspace:^", diff --git a/packages/backend-tasks/src/migrations.test.ts b/packages/backend-tasks/src/migrations.test.ts index 1d701c971d..82208da975 100644 --- a/packages/backend-tasks/src/migrations.test.ts +++ b/packages/backend-tasks/src/migrations.test.ts @@ -42,9 +42,7 @@ async function migrateUntilBefore(knex: Knex, target: string): Promise { jest.setTimeout(60_000); describe('migrations', () => { - const databases = TestDatabases.create({ - ids: ['POSTGRES_13', 'POSTGRES_9', 'MYSQL_8', 'SQLITE_3'], - }); + const databases = TestDatabases.create(); it.each(databases.eachSupportedId())( '20210928160613_init.js, %p', diff --git a/packages/backend-tasks/src/setupTests.ts b/packages/backend-tasks/src/setupTests.ts index 5245d37c26..76619a2542 100644 --- a/packages/backend-tasks/src/setupTests.ts +++ b/packages/backend-tasks/src/setupTests.ts @@ -14,7 +14,12 @@ * limitations under the License. */ +import { TestDatabases } from '@backstage/backend-test-utils'; import { Settings } from 'luxon'; // 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; + +TestDatabases.setDefaults({ + ids: ['MYSQL_8', 'POSTGRES_16', 'POSTGRES_12', 'SQLITE_3'], +}); diff --git a/packages/backend-tasks/src/tasks/PluginTaskSchedulerImpl.test.ts b/packages/backend-tasks/src/tasks/PluginTaskSchedulerImpl.test.ts index 6247755bbd..4b40791cb5 100644 --- a/packages/backend-tasks/src/tasks/PluginTaskSchedulerImpl.test.ts +++ b/packages/backend-tasks/src/tasks/PluginTaskSchedulerImpl.test.ts @@ -36,7 +36,7 @@ jest.setTimeout(60_000); describe('PluginTaskManagerImpl', () => { const databases = TestDatabases.create({ - ids: ['POSTGRES_13', 'POSTGRES_9', 'SQLITE_3'], + ids: ['POSTGRES_16', 'POSTGRES_12', 'SQLITE_3'], }); beforeAll(async () => { diff --git a/packages/backend-tasks/src/tasks/PluginTaskSchedulerJanitor.test.ts b/packages/backend-tasks/src/tasks/PluginTaskSchedulerJanitor.test.ts index 50bea27d27..1f0363625e 100644 --- a/packages/backend-tasks/src/tasks/PluginTaskSchedulerJanitor.test.ts +++ b/packages/backend-tasks/src/tasks/PluginTaskSchedulerJanitor.test.ts @@ -40,8 +40,8 @@ describe('PluginTaskSchedulerJanitor', () => { const databases = TestDatabases.create({ ids: [ /* 'MYSQL_8' not supported yet */ - 'POSTGRES_13', - 'POSTGRES_9', + 'POSTGRES_16', + 'POSTGRES_12', 'SQLITE_3', 'MYSQL_8', ], diff --git a/packages/backend-tasks/src/tasks/TaskScheduler.test.ts b/packages/backend-tasks/src/tasks/TaskScheduler.test.ts index 8e419437bc..d286eaee38 100644 --- a/packages/backend-tasks/src/tasks/TaskScheduler.test.ts +++ b/packages/backend-tasks/src/tasks/TaskScheduler.test.ts @@ -25,9 +25,7 @@ jest.setTimeout(60_000); describe('TaskScheduler', () => { const logger = getVoidLogger(); - const databases = TestDatabases.create({ - ids: ['POSTGRES_13', 'POSTGRES_9', 'SQLITE_3', 'MYSQL_8'], - }); + const databases = TestDatabases.create(); const testScopedSignal = createTestScopedSignal(); async function createDatabase( diff --git a/packages/backend-tasks/src/tasks/TaskWorker.test.ts b/packages/backend-tasks/src/tasks/TaskWorker.test.ts index 45eb7d1003..a2ecdaa779 100644 --- a/packages/backend-tasks/src/tasks/TaskWorker.test.ts +++ b/packages/backend-tasks/src/tasks/TaskWorker.test.ts @@ -28,9 +28,7 @@ jest.setTimeout(60_000); describe('TaskWorker', () => { const logger = getVoidLogger(); - const databases = TestDatabases.create({ - ids: ['POSTGRES_13', 'POSTGRES_9', 'SQLITE_3', 'MYSQL_8'], - }); + const databases = TestDatabases.create(); const testScopedSignal = createTestScopedSignal(); beforeEach(() => { diff --git a/packages/backend-tasks/src/tasks/TaskWorker.ts b/packages/backend-tasks/src/tasks/TaskWorker.ts index 4e10f0b5b2..fe327b38d6 100644 --- a/packages/backend-tasks/src/tasks/TaskWorker.ts +++ b/packages/backend-tasks/src/tasks/TaskWorker.ts @@ -51,6 +51,15 @@ export class TaskWorker { `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 (;;) { @@ -69,7 +78,7 @@ export class TaskWorker { break; } - await sleep(this.workCheckFrequency, options?.signal); + await sleep(workCheckFrequency, options?.signal); } this.logger.info(`Task worker finished: ${this.taskId}`); diff --git a/packages/backend-test-utils/CHANGELOG.md b/packages/backend-test-utils/CHANGELOG.md index ea7e1927dd..66870f7f01 100644 --- a/packages/backend-test-utils/CHANGELOG.md +++ b/packages/backend-test-utils/CHANGELOG.md @@ -1,5 +1,140 @@ # @backstage/backend-test-utils +## 0.2.10 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-app-api@0.5.10 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.2.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-app-api@0.5.10-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## 0.2.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@0.5.10-next.1 + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.2.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-app-api@0.5.10-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.0 + +## 0.2.9 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- b7de76a: Added support for PostgreSQL versions 15 and 16 + + Also introduced a new `setDefaults(options: { ids?: TestDatabaseId[] })` static method that can be added to the `setupTests.ts` file to define the default database ids you want to use throughout your package. Usage would look like this: `TestDatabases.setDefaults({ ids: ['POSTGRES_12','POSTGRES_16'] })` and would result in PostgreSQL versions 12 and 16 being used for your tests. + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/backend-app-api@0.5.9 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.2.9-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-app-api@0.5.9-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.3 + +## 0.2.9-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-app-api@0.5.9-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.2.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@0.5.9-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## 0.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-app-api@0.5.9-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.2.8 + +### Patch Changes + +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. +- bb688f7b3b: Ensure recursive deletion of temporary directories in tests +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-app-api@0.5.8 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.1 + ## 0.2.8-next.2 ### Patch Changes diff --git a/packages/backend-test-utils/api-report.md b/packages/backend-test-utils/api-report.md index ac012e2f69..204e5dc84a 100644 --- a/packages/backend-test-utils/api-report.md +++ b/packages/backend-test-utils/api-report.md @@ -307,6 +307,8 @@ export interface TestBackendOptions { // @public export type TestDatabaseId = + | 'POSTGRES_16' + | 'POSTGRES_15' | 'POSTGRES_14' | 'POSTGRES_13' | 'POSTGRES_12' @@ -325,6 +327,8 @@ export class TestDatabases { eachSupportedId(): [TestDatabaseId][]; init(id: TestDatabaseId): Promise; // (undocumented) + static setDefaults(options: { ids?: TestDatabaseId[] }): void; + // (undocumented) supports(id: TestDatabaseId): boolean; } ``` diff --git a/packages/backend-test-utils/package.json b/packages/backend-test-utils/package.json index 41ffa38a57..8fcaff66ae 100644 --- a/packages/backend-test-utils/package.json +++ b/packages/backend-test-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-test-utils", "description": "Test helpers library for Backstage backends", - "version": "0.2.8-next.2", + "version": "0.2.10", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend-test-utils/src/database/TestDatabases.test.ts b/packages/backend-test-utils/src/database/TestDatabases.test.ts index d766d38815..64e4d76443 100644 --- a/packages/backend-test-utils/src/database/TestDatabases.test.ts +++ b/packages/backend-test-utils/src/database/TestDatabases.test.ts @@ -59,6 +59,68 @@ 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 () => { diff --git a/packages/backend-test-utils/src/database/TestDatabases.ts b/packages/backend-test-utils/src/database/TestDatabases.ts index 45d2899dbb..1913075b1f 100644 --- a/packages/backend-test-utils/src/database/TestDatabases.ts +++ b/packages/backend-test-utils/src/database/TestDatabases.ts @@ -44,6 +44,7 @@ const LARGER_POOL_CONFIG = { export class TestDatabases { private readonly instanceById: Map; private readonly supportedIds: TestDatabaseId[]; + private static defaultIds?: TestDatabaseId[]; /** * Creates an empty `TestDatabases` instance, and sets up Jest to clean up @@ -60,18 +61,19 @@ export class TestDatabases { ids?: TestDatabaseId[]; disableDocker?: boolean; }): TestDatabases { - const defaultOptions = { - ids: Object.keys(allDatabases) as TestDatabaseId[], - disableDocker: isDockerDisabledForTests(), - }; + const ids = options?.ids; + const disableDocker = options?.disableDocker ?? isDockerDisabledForTests(); - const { ids, disableDocker } = Object.assign( - {}, - defaultOptions, - options ?? {}, - ); + let testDatabaseIds: TestDatabaseId[]; + if (ids) { + testDatabaseIds = ids; + } else if (TestDatabases.defaultIds) { + testDatabaseIds = TestDatabases.defaultIds; + } else { + testDatabaseIds = Object.keys(allDatabases) as TestDatabaseId[]; + } - const supportedIds = ids.filter(id => { + const supportedIds = testDatabaseIds.filter(id => { const properties = allDatabases[id]; if (!properties) { return false; @@ -107,6 +109,10 @@ export class TestDatabases { return databases; } + static setDefaults(options: { ids?: TestDatabaseId[] }) { + TestDatabases.defaultIds = options.ids; + } + private constructor(supportedIds: TestDatabaseId[]) { this.instanceById = new Map(); this.supportedIds = supportedIds; diff --git a/packages/backend-test-utils/src/database/types.ts b/packages/backend-test-utils/src/database/types.ts index a7bfdeb12d..75c24dc725 100644 --- a/packages/backend-test-utils/src/database/types.ts +++ b/packages/backend-test-utils/src/database/types.ts @@ -24,6 +24,8 @@ import { getDockerImageForName } from '../util/getDockerImageForName'; * @public */ export type TestDatabaseId = + | 'POSTGRES_16' + | 'POSTGRES_15' | 'POSTGRES_14' | 'POSTGRES_13' | 'POSTGRES_12' @@ -47,6 +49,20 @@ export type Instance = { export const allDatabases: Record = Object.freeze({ + POSTGRES_16: { + name: 'Postgres 16.x', + driver: 'pg', + dockerImageName: getDockerImageForName('postgres:16'), + connectionStringEnvironmentVariableName: + 'BACKSTAGE_TEST_DATABASE_POSTGRES16_CONNECTION_STRING', + }, + POSTGRES_15: { + name: 'Postgres 15.x', + driver: 'pg', + dockerImageName: getDockerImageForName('postgres:15'), + connectionStringEnvironmentVariableName: + 'BACKSTAGE_TEST_DATABASE_POSTGRES15_CONNECTION_STRING', + }, POSTGRES_14: { name: 'Postgres 14.x', driver: 'pg', diff --git a/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts b/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts index b127712927..d71c774dd9 100644 --- a/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts +++ b/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts @@ -33,8 +33,8 @@ beforeAll(async () => { await startTestBackend({ features: [ createBackendModule({ - moduleId: 'test.module', pluginId: 'test', + moduleId: 'test-module', register(env) { env.registerInit({ deps: { lifecycle: coreServices.lifecycle }, @@ -128,8 +128,8 @@ describe('TestBackend', () => { }); const testModule = createBackendModule({ - moduleId: 'test.module', pluginId: 'test', + moduleId: 'test-module', register(env) { env.registerInit({ deps: { @@ -153,8 +153,8 @@ describe('TestBackend', () => { const shutdownSpy = jest.fn(); const testModule = createBackendModule({ - moduleId: 'test.module', pluginId: 'test', + moduleId: 'test-module', register(env) { env.registerInit({ deps: { diff --git a/packages/backend-test-utils/src/next/wiring/TestBackend.ts b/packages/backend-test-utils/src/next/wiring/TestBackend.ts index 21ae6159c9..14e8920390 100644 --- a/packages/backend-test-utils/src/next/wiring/TestBackend.ts +++ b/packages/backend-test-utils/src/next/wiring/TestBackend.ts @@ -156,7 +156,7 @@ function createExtensionPointTestModules( modules.push( createBackendModule({ pluginId, - moduleId: 'testExtensionPointRegistration', + moduleId: 'test-extension-point-registration', register(reg) { for (const id of pluginExtensionPointIds) { const tuple = extensionPointMap.get(id)!; diff --git a/packages/backend/CHANGELOG.md b/packages/backend/CHANGELOG.md index 44fd12f126..838b69f5ab 100644 --- a/packages/backend/CHANGELOG.md +++ b/packages/backend/CHANGELOG.md @@ -1,5 +1,580 @@ # example-backend +## 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 diff --git a/packages/backend/Dockerfile b/packages/backend/Dockerfile index 5667209330..e0e6ab8a31 100644 --- a/packages/backend/Dockerfile +++ b/packages/backend/Dockerfile @@ -47,7 +47,6 @@ COPY --chown=node:node .yarnrc.yml ./ COPY --chown=node:node yarn.lock package.json packages/backend/dist/skeleton.tar.gz ./ RUN tar xzf skeleton.tar.gz && rm skeleton.tar.gz -# Note that this install is not immutable, which is one of the reasons we don't recommend Yarn 3 yet RUN --mount=type=cache,target=/home/node/.yarn/berry/cache,sharing=locked,uid=1000,gid=1000 \ yarn workspaces focus --all --production diff --git a/packages/backend/package.json b/packages/backend/package.json index bb425e5a2c..4bcf627366 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -1,6 +1,6 @@ { "name": "example-backend", - "version": "0.2.89-next.2", + "version": "0.2.91", "main": "dist/index.cjs.js", "types": "src/index.ts", "license": "Apache-2.0", @@ -49,7 +49,6 @@ "@backstage/plugin-events-backend": "workspace:^", "@backstage/plugin-events-node": "workspace:^", "@backstage/plugin-explore-backend": "workspace:^", - "@backstage/plugin-graphql-backend": "workspace:^", "@backstage/plugin-jenkins-backend": "workspace:^", "@backstage/plugin-kafka-backend": "workspace:^", "@backstage/plugin-kubernetes-backend": "workspace:^", @@ -83,7 +82,7 @@ "@opentelemetry/api": "^1.4.1", "@opentelemetry/exporter-prometheus": "^0.45.0", "@opentelemetry/sdk-metrics": "^1.13.0", - "azure-devops-node-api": "^11.0.1", + "azure-devops-node-api": "^12.0.0", "better-sqlite3": "^9.0.0", "dockerode": "^3.3.1", "example-app": "link:../app", diff --git a/packages/catalog-client/CHANGELOG.md b/packages/catalog-client/CHANGELOG.md index b3c1aeb56f..78d126445e 100644 --- a/packages/catalog-client/CHANGELOG.md +++ b/packages/catalog-client/CHANGELOG.md @@ -1,5 +1,66 @@ # @backstage/catalog-client +## 1.5.2 + +### Patch Changes + +- 883782e: Fix a bug in `getLocationByRef` that led to invalid backend calls +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 1.5.2-next.0 + +### Patch Changes + +- 883782e: Fix a bug in `getLocationByRef` that led to invalid backend calls +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 1.5.0 + +### Minor Changes + +- 3834067: The internals of `CatalogClient` are now auto-generated using the `backstage-repo-tools schema openapi generate-client` command. + +### Patch Changes + +- 82fa88b: Fixes a bug where some query parameters were double URL encoded. +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 1.5.0-next.1 + +### Patch Changes + +- 82fa88b: Fixes a bug where some query parameters were double URL encoded. +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 1.5.0-next.0 + +### Minor Changes + +- 38340678c3: The internals of `CatalogClient` are now auto-generated using the `backstage-repo-tools schema openapi generate-client` command. + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 1.4.6 + +### Patch Changes + +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + ## 1.4.5 ### Patch Changes diff --git a/packages/catalog-client/package.json b/packages/catalog-client/package.json index c92516f094..cfa9399d97 100644 --- a/packages/catalog-client/package.json +++ b/packages/catalog-client/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/catalog-client", "description": "An isomorphic client for the catalog backend", - "version": "1.4.5", + "version": "1.5.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,7 +35,8 @@ "dependencies": { "@backstage/catalog-model": "workspace:^", "@backstage/errors": "workspace:^", - "cross-fetch": "^4.0.0" + "cross-fetch": "^4.0.0", + "uri-template": "^2.0.0" }, "devDependencies": { "@backstage/cli": "workspace:^", diff --git a/packages/catalog-client/src/CatalogClient.test.ts b/packages/catalog-client/src/CatalogClient.test.ts index f5c221569d..b8212fde96 100644 --- a/packages/catalog-client/src/CatalogClient.test.ts +++ b/packages/catalog-client/src/CatalogClient.test.ts @@ -86,9 +86,12 @@ describe('CatalogClient', () => { server.use( rest.get(`${mockBaseUrl}/entities`, (req, res, ctx) => { - expect(req.url.search).toBe( - '?filter=a=1,b=2,b=3,%C3%B6=%3D&filter=a=2&filter=c', - ); + const queryParams = new URLSearchParams(req.url.search); + expect(queryParams.getAll('filter')).toEqual([ + 'a=1,b=2,b=3,ö==', + 'a=2', + 'c', + ]); return res(ctx.json([])); }), ); @@ -120,7 +123,8 @@ describe('CatalogClient', () => { server.use( rest.get(`${mockBaseUrl}/entities`, (req, res, ctx) => { - expect(req.url.search).toBe('?filter=a=1,b=2,b=3,%C3%B6=%3D,c'); + const queryParams = new URLSearchParams(req.url.search); + expect(queryParams.getAll('filter')).toEqual(['a=1,b=2,b=3,ö==,c']); return res(ctx.json([])); }), ); @@ -140,12 +144,45 @@ describe('CatalogClient', () => { expect(response.items).toEqual([]); }); + it('builds search filters property even those with URL unsafe values', async () => { + const mockedEndpoint = jest + .fn() + .mockImplementation((_req, res, ctx) => + res(ctx.json({ items: [], totalItems: 0 })), + ); + + server.use(rest.get(`${mockBaseUrl}/entities/by-query`, mockedEndpoint)); + + const response = await client.queryEntities( + { + filter: [ + { + '!@#$%': 't?i=1&a:2', + '^&*(){}[]': ['t%^url*encoded2', 'url'], + }, + ], + }, + { token }, + ); + + expect(response).toEqual({ items: [], totalItems: 0 }); + expect(mockedEndpoint).toHaveBeenCalledTimes(1); + + const queryParams = new URLSearchParams( + mockedEndpoint.mock.calls[0][0].url.search, + ); + expect(queryParams.getAll('filter')).toEqual([ + '!@#$%=t?i=1&a:2,^&*(){}[]=t%^url*encoded2,^&*(){}[]=url', + ]); + }); + it('builds entity field selectors properly', async () => { expect.assertions(2); server.use( rest.get(`${mockBaseUrl}/entities`, (req, res, ctx) => { - expect(req.url.search).toBe('?fields=a.b,%C3%B6'); + const queryParams = new URLSearchParams(req.url.search); + expect(queryParams.getAll('fields')).toEqual(['a.b,ö']); return res(ctx.json([])); }), ); @@ -185,7 +222,7 @@ describe('CatalogClient', () => { server.use( rest.get(`${mockBaseUrl}/entities`, (req, res, ctx) => { - expect(req.url.search).toBe('?offset=1&limit=2&after=%3D'); + expect(req.url.search).toBe('?limit=2&offset=1&after=%3D'); return res(ctx.json([])); }), ); @@ -203,9 +240,11 @@ describe('CatalogClient', () => { server.use( rest.get(`${mockBaseUrl}/entities`, (req, res, ctx) => { - expect(req.url.search).toBe( - '?order=asc:kind&order=desc:metadata.name', - ); + const queryParams = new URLSearchParams(req.url.search); + expect(queryParams.getAll('order')).toEqual([ + 'asc:kind', + 'desc:metadata.name', + ]); return res(ctx.json([])); }), ); @@ -326,9 +365,46 @@ describe('CatalogClient', () => { expect(response).toEqual({ items: [], totalItems: 0 }); expect(mockedEndpoint).toHaveBeenCalledTimes(1); - expect(mockedEndpoint.mock.calls[0][0].url.search).toBe( - '?filter=a=1,b=2,b=3,%C3%B6=%3D&filter=a=2&filter=c', + + const queryParams = new URLSearchParams( + mockedEndpoint.mock.calls[0][0].url.search, ); + expect(queryParams.getAll('filter')).toEqual([ + 'a=1,b=2,b=3,ö==', + 'a=2', + 'c', + ]); + }); + + it('builds search filters property even those with URL unsafe values', async () => { + const mockedEndpoint = jest + .fn() + .mockImplementation((_req, res, ctx) => + res(ctx.json({ items: [], totalItems: 0 })), + ); + + server.use(rest.get(`${mockBaseUrl}/entities/by-query`, mockedEndpoint)); + + const response = await client.queryEntities( + { + filter: [ + { + '!@#$%': 't?i=1&a:2', + '^&*(){}[]': ['t%^url*encoded2', 'url'], + }, + ], + }, + { token }, + ); + + expect(response).toEqual({ items: [], totalItems: 0 }); + expect(mockedEndpoint).toHaveBeenCalledTimes(1); + const queryParams = new URLSearchParams( + mockedEndpoint.mock.calls[0][0].url.search, + ); + expect(queryParams.getAll('filter')).toEqual([ + '!@#$%=t?i=1&a:2,^&*(){}[]=t%^url*encoded2,^&*(){}[]=url', + ]); }); it('should send query params correctly on initial request', async () => { @@ -351,9 +427,17 @@ describe('CatalogClient', () => { { field: 'metadata.uid', order: 'desc' }, ], }); - expect(mockedEndpoint.mock.calls[0][0].url.search).toBe( - '?limit=100&orderField=metadata.name,asc&orderField=metadata.uid,desc&fields=a,b&fullTextFilterTerm=query', + + const queryParams = new URLSearchParams( + mockedEndpoint.mock.calls[0][0].url.search, ); + expect(queryParams.getAll('fields')).toEqual(['a,b']); + expect(queryParams.getAll('limit')).toEqual(['100']); + expect(queryParams.getAll('fullTextFilterTerm')).toEqual(['query']); + expect(queryParams.getAll('orderField')).toEqual([ + 'metadata.name,asc', + 'metadata.uid,desc', + ]); }); it('should ignore initial query params if cursor is passed', async () => { @@ -375,7 +459,7 @@ describe('CatalogClient', () => { cursor: 'cursor', }); expect(mockedEndpoint.mock.calls[0][0].url.search).toBe( - '?cursor=cursor&limit=100&fields=a,b', + '?fields=a,b&limit=100&cursor=cursor', ); }); diff --git a/packages/catalog-client/src/CatalogClient.ts b/packages/catalog-client/src/CatalogClient.ts index c388519e05..0d6bd6b926 100644 --- a/packages/catalog-client/src/CatalogClient.ts +++ b/packages/catalog-client/src/CatalogClient.ts @@ -22,7 +22,6 @@ import { stringifyLocationRef, } from '@backstage/catalog-model'; import { ResponseError } from '@backstage/errors'; -import crossFetch from 'cross-fetch'; import { CATALOG_FILTER_EXISTS, AddLocationRequest, @@ -40,12 +39,11 @@ import { GetEntitiesByRefsRequest, GetEntitiesByRefsResponse, QueryEntitiesRequest, - QueryEntitiesResponse, EntityFilterQuery, + QueryEntitiesResponse, } from './types/api'; -import { DiscoveryApi } from './types/discovery'; -import { FetchApi } from './types/fetch'; import { isQueryEntitiesInitialRequest } from './utils'; +import { DefaultApiClient, TypedResponse } from './generated'; /** * A frontend and backend compatible client for communicating with the Backstage @@ -54,15 +52,13 @@ import { isQueryEntitiesInitialRequest } from './utils'; * @public */ export class CatalogClient implements CatalogApi { - private readonly discoveryApi: DiscoveryApi; - private readonly fetchApi: FetchApi; + private readonly apiClient: DefaultApiClient; constructor(options: { discoveryApi: { getBaseUrl(pluginId: string): Promise }; fetchApi?: { fetch: typeof fetch }; }) { - this.discoveryApi = options.discoveryApi; - this.fetchApi = options.fetchApi || { fetch: crossFetch }; + this.apiClient = new DefaultApiClient(options); } /** @@ -72,13 +68,11 @@ export class CatalogClient implements CatalogApi { request: GetEntityAncestorsRequest, options?: CatalogRequestOptions, ): Promise { - const { kind, namespace, name } = parseEntityRef(request.entityRef); return await this.requestRequired( - 'GET', - `/entities/by-name/${encodeURIComponent(kind)}/${encodeURIComponent( - namespace, - )}/${encodeURIComponent(name)}/ancestry`, - options, + await this.apiClient.getEntityAncestryByName( + { path: parseEntityRef(request.entityRef) }, + options, + ), ); } @@ -90,9 +84,7 @@ export class CatalogClient implements CatalogApi { options?: CatalogRequestOptions, ): Promise { return await this.requestOptional( - 'GET', - `/locations/${encodeURIComponent(id)}`, - options, + await this.apiClient.getLocation({ path: { id } }, options), ); } @@ -111,39 +103,29 @@ export class CatalogClient implements CatalogApi { limit, after, } = request ?? {}; - const params = this.getParams(filter); - - if (fields.length) { - params.push(`fields=${fields.map(encodeURIComponent).join(',')}`); - } - + const encodedOrder = []; if (order) { for (const directive of [order].flat()) { if (directive) { - params.push( - `order=${encodeURIComponent(directive.order)}:${encodeURIComponent( - directive.field, - )}`, - ); + encodedOrder.push(`${directive.order}:${directive.field}`); } } } - if (offset !== undefined) { - params.push(`offset=${offset}`); - } - if (limit !== undefined) { - params.push(`limit=${limit}`); - } - if (after !== undefined) { - params.push(`after=${encodeURIComponent(after)}`); - } - - const query = params.length ? `?${params.join('&')}` : ''; - const entities: Entity[] = await this.requestRequired( - 'GET', - `/entities${query}`, - options, + const entities = await this.requestRequired( + await this.apiClient.getEntities( + { + query: { + fields, + limit, + filter: this.getFilterValue(filter), + offset, + after, + order: order ? encodedOrder : undefined, + }, + }, + options, + ), ); const refCompare = (a: Entity, b: Entity) => { @@ -178,22 +160,12 @@ export class CatalogClient implements CatalogApi { request: GetEntitiesByRefsRequest, options?: CatalogRequestOptions, ): Promise { - const body: any = { entityRefs: request.entityRefs }; - if (request.fields?.length) { - body.fields = request.fields; - } - - const baseUrl = await this.discoveryApi.getBaseUrl('catalog'); - const url = `${baseUrl}/entities/by-refs`; - - const response = await this.fetchApi.fetch(url, { - headers: { - 'Content-Type': 'application/json', - ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + const response = await this.apiClient.getEntitiesByRefs( + { + body: request, }, - method: 'POST', - body: JSON.stringify(body), - }); + options, + ); if (!response.ok) { throw await ResponseError.fromResponse(response); @@ -212,8 +184,10 @@ export class CatalogClient implements CatalogApi { async queryEntities( request: QueryEntitiesRequest = {}, options?: CatalogRequestOptions, - ) { - const params: string[] = []; + ): Promise { + const params: Partial< + Parameters[0]['query'] + > = {}; if (isQueryEntitiesInitialRequest(request)) { const { @@ -223,45 +197,42 @@ export class CatalogClient implements CatalogApi { orderFields, fullTextFilter, } = request; - params.push(...this.getParams(filter)); + params.filter = this.getFilterValue(filter); if (limit !== undefined) { - params.push(`limit=${limit}`); + params.limit = limit; } if (orderFields !== undefined) { - (Array.isArray(orderFields) ? orderFields : [orderFields]).forEach( - ({ field, order }) => params.push(`orderField=${field},${order}`), - ); + params.orderField = ( + Array.isArray(orderFields) ? orderFields : [orderFields] + ).map(({ field, order }) => `${field},${order}`); } if (fields.length) { - params.push(`fields=${fields.map(encodeURIComponent).join(',')}`); + params.fields = fields; } const normalizedFullTextFilterTerm = fullTextFilter?.term?.trim(); if (normalizedFullTextFilterTerm) { - params.push(`fullTextFilterTerm=${normalizedFullTextFilterTerm}`); + params.fullTextFilterTerm = normalizedFullTextFilterTerm; } if (fullTextFilter?.fields?.length) { - params.push(`fullTextFilterFields=${fullTextFilter.fields.join(',')}`); + params.fullTextFilterFields = fullTextFilter.fields; } } else { const { fields = [], limit, cursor } = request; - params.push(`cursor=${cursor}`); + params.cursor = cursor; if (limit !== undefined) { - params.push(`limit=${limit}`); + params.limit = limit; } if (fields.length) { - params.push(`fields=${fields.map(encodeURIComponent).join(',')}`); + params.fields = fields; } } - const query = params.length ? `?${params.join('&')}` : ''; - return this.requestRequired( - 'GET', - `/entities/by-query${query}`, - options, - ); + return this.apiClient + .getEntitiesByQuery({ query: params }, options) + .then(r => r.json()); } /** @@ -271,13 +242,13 @@ export class CatalogClient implements CatalogApi { entityRef: string | CompoundEntityRef, options?: CatalogRequestOptions, ): Promise { - const { kind, namespace, name } = parseEntityRef(entityRef); return this.requestOptional( - 'GET', - `/entities/by-name/${encodeURIComponent(kind)}/${encodeURIComponent( - namespace, - )}/${encodeURIComponent(name)}`, - options, + await this.apiClient.getEntityByName( + { + path: parseEntityRef(entityRef), + }, + options, + ), ); } @@ -294,11 +265,10 @@ export class CatalogClient implements CatalogApi { ): Promise { const { kind, namespace = 'default', name } = compoundName; return this.requestOptional( - 'GET', - `/entities/by-name/${encodeURIComponent(kind)}/${encodeURIComponent( - namespace, - )}/${encodeURIComponent(name)}`, - options, + await this.apiClient.getEntityByName( + { path: { kind, namespace, name } }, + options, + ), ); } @@ -306,16 +276,9 @@ export class CatalogClient implements CatalogApi { * {@inheritdoc CatalogApi.refreshEntity} */ async refreshEntity(entityRef: string, options?: CatalogRequestOptions) { - const response = await this.fetchApi.fetch( - `${await this.discoveryApi.getBaseUrl('catalog')}/refresh`, - { - headers: { - 'Content-Type': 'application/json', - ...(options?.token && { Authorization: `Bearer ${options?.token}` }), - }, - method: 'POST', - body: JSON.stringify({ entityRef }), - }, + const response = await this.apiClient.refreshEntity( + { body: { entityRef } }, + options, ); if (response.status !== 200) { @@ -331,14 +294,14 @@ export class CatalogClient implements CatalogApi { options?: CatalogRequestOptions, ): Promise { const { filter = [], facets } = request; - const params = this.getParams(filter); - - for (const facet of facets) { - params.push(`facet=${encodeURIComponent(facet)}`); - } - - const query = params.length ? `?${params.join('&')}` : ''; - return await this.requestOptional('GET', `/entity-facets${query}`, options); + return await this.requestOptional( + await this.apiClient.getEntityFacets( + { + query: { facet: facets, filter: this.getFilterValue(filter) }, + }, + options, + ), + ); } /** @@ -350,18 +313,12 @@ export class CatalogClient implements CatalogApi { ): Promise { const { type = 'url', target, dryRun } = request; - const response = await this.fetchApi.fetch( - `${await this.discoveryApi.getBaseUrl('catalog')}/locations${ - dryRun ? '?dryRun=true' : '' - }`, + const response = await this.apiClient.createLocation( { - headers: { - 'Content-Type': 'application/json', - ...(options?.token && { Authorization: `Bearer ${options?.token}` }), - }, - method: 'POST', - body: JSON.stringify({ type, target }), + body: { type, target }, + query: { dryRun: dryRun ? 'true' : undefined }, }, + options, ); if (response.status !== 201) { @@ -388,10 +345,8 @@ export class CatalogClient implements CatalogApi { locationRef: string, options?: CatalogRequestOptions, ): Promise { - const all: { data: Location }[] = await this.requestRequired( - 'GET', - '/locations', - options, + const all = await this.requestRequired( + await this.apiClient.getLocations({}, options), ); return all .map(r => r.data) @@ -406,9 +361,7 @@ export class CatalogClient implements CatalogApi { options?: CatalogRequestOptions, ): Promise { await this.requestIgnored( - 'DELETE', - `/locations/${encodeURIComponent(id)}`, - options, + await this.apiClient.deleteLocation({ path: { id } }, options), ); } @@ -420,9 +373,7 @@ export class CatalogClient implements CatalogApi { options?: CatalogRequestOptions, ): Promise { await this.requestIgnored( - 'DELETE', - `/entities/by-uid/${encodeURIComponent(uid)}`, - options, + await this.apiClient.deleteEntityByUid({ path: { uid } }, options), ); } @@ -434,16 +385,9 @@ export class CatalogClient implements CatalogApi { locationRef: string, options?: CatalogRequestOptions, ): Promise { - const response = await this.fetchApi.fetch( - `${await this.discoveryApi.getBaseUrl('catalog')}/validate-entity`, - { - headers: { - 'Content-Type': 'application/json', - ...(options?.token && { Authorization: `Bearer ${options?.token}` }), - }, - method: 'POST', - body: JSON.stringify({ entity, location: locationRef }), - }, + const response = await this.apiClient.validateEntity( + { body: { entity, location: locationRef } }, + options, ); if (response.ok) { @@ -456,7 +400,7 @@ export class CatalogClient implements CatalogApi { throw await ResponseError.fromResponse(response); } - const { errors = [] } = await response.json(); + const { errors = [] } = (await response.json()) as any; return { valid: false, @@ -468,33 +412,13 @@ export class CatalogClient implements CatalogApi { // Private methods // - private async requestIgnored( - method: string, - path: string, - options?: CatalogRequestOptions, - ): Promise { - const url = `${await this.discoveryApi.getBaseUrl('catalog')}${path}`; - const headers: Record = options?.token - ? { Authorization: `Bearer ${options.token}` } - : {}; - const response = await this.fetchApi.fetch(url, { method, headers }); - + private async requestIgnored(response: Response): Promise { if (!response.ok) { throw await ResponseError.fromResponse(response); } } - private async requestRequired( - method: string, - path: string, - options?: CatalogRequestOptions, - ): Promise { - const url = `${await this.discoveryApi.getBaseUrl('catalog')}${path}`; - const headers: Record = options?.token - ? { Authorization: `Bearer ${options.token}` } - : {}; - const response = await this.fetchApi.fetch(url, { method, headers }); - + private async requestRequired(response: TypedResponse): Promise { if (!response.ok) { throw await ResponseError.fromResponse(response); } @@ -502,17 +426,7 @@ export class CatalogClient implements CatalogApi { return response.json(); } - private async requestOptional( - method: string, - path: string, - options?: CatalogRequestOptions, - ): Promise { - const url = `${await this.discoveryApi.getBaseUrl('catalog')}${path}`; - const headers: Record = options?.token - ? { Authorization: `Bearer ${options.token}` } - : {}; - const response = await this.fetchApi.fetch(url, { method, headers }); - + private async requestOptional(response: Response): Promise { if (!response.ok) { if (response.status === 404) { return undefined; @@ -523,8 +437,8 @@ export class CatalogClient implements CatalogApi { return await response.json(); } - private getParams(filter: EntityFilterQuery = []) { - const params: string[] = []; + private getFilterValue(filter: EntityFilterQuery = []) { + const filters: string[] = []; // filter param can occur multiple times, for example // /api/catalog/entities?filter=metadata.name=wayback-search,kind=component&filter=metadata.name=www-artist,kind=component' // the "outer array" defined by `filter` occurrences corresponds to "anyOf" filters @@ -534,19 +448,17 @@ export class CatalogClient implements CatalogApi { for (const [key, value] of Object.entries(filterItem)) { for (const v of [value].flat()) { if (v === CATALOG_FILTER_EXISTS) { - filterParts.push(encodeURIComponent(key)); + filterParts.push(key); } else if (typeof v === 'string') { - filterParts.push( - `${encodeURIComponent(key)}=${encodeURIComponent(v)}`, - ); + filterParts.push(`${key}=${v}`); } } } if (filterParts.length) { - params.push(`filter=${filterParts.join(',')}`); + filters.push(filterParts.join(',')); } } - return params; + return filters; } } diff --git a/packages/catalog-client/src/generated/apis/DefaultApi.client.ts b/packages/catalog-client/src/generated/apis/DefaultApi.client.ts new file mode 100644 index 0000000000..65b8699370 --- /dev/null +++ b/packages/catalog-client/src/generated/apis/DefaultApi.client.ts @@ -0,0 +1,540 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { DiscoveryApi } from '../types/discovery'; +import { FetchApi } from '../types/fetch'; +import crossFetch from 'cross-fetch'; +import { pluginId } from '../pluginId'; +import * as parser from 'uri-template'; + +import { AnalyzeLocationRequest } from '../models/AnalyzeLocationRequest.model'; +import { AnalyzeLocationResponse } from '../models/AnalyzeLocationResponse.model'; +import { CreateLocation201Response } from '../models/CreateLocation201Response.model'; +import { CreateLocationRequest } from '../models/CreateLocationRequest.model'; +import { EntitiesBatchResponse } from '../models/EntitiesBatchResponse.model'; +import { EntitiesQueryResponse } from '../models/EntitiesQueryResponse.model'; +import { Entity } from '../models/Entity.model'; +import { EntityAncestryResponse } from '../models/EntityAncestryResponse.model'; +import { EntityFacetsResponse } from '../models/EntityFacetsResponse.model'; +import { GetEntitiesByRefsRequest } from '../models/GetEntitiesByRefsRequest.model'; +import { GetLocations200ResponseInner } from '../models/GetLocations200ResponseInner.model'; +import { Location } from '../models/Location.model'; +import { RefreshEntityRequest } from '../models/RefreshEntityRequest.model'; +import { ValidateEntityRequest } from '../models/ValidateEntityRequest.model'; + +/** + * Wraps the Response type to convey a type on the json call. + * + * @public + */ +export type TypedResponse = Omit & { + json: () => Promise; +}; + +/** + * Options you can pass into a request for additional information. + * + * @public + */ +export interface RequestOptions { + token?: string; +} + +/** + * no description + */ +export class DefaultApiClient { + private readonly discoveryApi: DiscoveryApi; + private readonly fetchApi: FetchApi; + + constructor(options: { + discoveryApi: { getBaseUrl(pluginId: string): Promise }; + fetchApi?: { fetch: typeof fetch }; + }) { + this.discoveryApi = options.discoveryApi; + this.fetchApi = options.fetchApi || { fetch: crossFetch }; + } + + /** + * Validate a given location. + * @param analyzeLocationRequest + */ + public async analyzeLocation( + // @ts-ignore + request: { + body: AnalyzeLocationRequest; + }, + options?: RequestOptions, + ): Promise> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/analyze-location`; + + const uri = parser.parse(uriTemplate).expand({}); + + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'POST', + body: JSON.stringify(request.body), + }); + } + + /** + * Create a location for a given target. + * @param createLocationRequest + * @param dryRun + */ + public async createLocation( + // @ts-ignore + request: { + body: CreateLocationRequest; + query: { + dryRun?: string; + }; + }, + options?: RequestOptions, + ): Promise> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/locations{?dryRun}`; + + const uri = parser.parse(uriTemplate).expand({ + ...request.query, + }); + + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'POST', + body: JSON.stringify(request.body), + }); + } + + /** + * Delete a single entity by UID. + * @param uid + */ + public async deleteEntityByUid( + // @ts-ignore + request: { + path: { + uid: string; + }; + }, + options?: RequestOptions, + ): Promise> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/entities/by-uid/{uid}`; + + const uri = parser.parse(uriTemplate).expand({ + uid: request.path.uid, + }); + + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'DELETE', + }); + } + + /** + * Delete a location by id. + * @param id + */ + public async deleteLocation( + // @ts-ignore + request: { + path: { + id: string; + }; + }, + options?: RequestOptions, + ): Promise> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/locations/{id}`; + + const uri = parser.parse(uriTemplate).expand({ + id: request.path.id, + }); + + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'DELETE', + }); + } + + /** + * Get all entities matching a given filter. + * @param fields Restrict to just these fields in the response. + * @param limit Number of records to return in the response. + * @param filter Filter for just the entities defined by this filter. + * @param offset Number of records to skip in the query page. + * @param after Pointer to the previous page of results. + * @param order + */ + public async getEntities( + // @ts-ignore + request: { + query: { + fields?: Array; + limit?: number; + filter?: Array; + offset?: number; + after?: string; + order?: Array; + }; + }, + options?: RequestOptions, + ): Promise>> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/entities{?fields,limit,filter*,offset,after,order*}`; + + const uri = parser.parse(uriTemplate).expand({ + ...request.query, + }); + + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'GET', + }); + } + + /** + * Search for entities by a given query. + * @param fields Restrict to just these fields in the response. + * @param limit Number of records to return in the response. + * @param orderField The fields to sort returned results by. + * @param cursor Cursor to a set page of results. + * @param filter Filter for just the entities defined by this filter. + * @param fullTextFilterTerm Text search term. + * @param fullTextFilterFields A comma separated list of fields to sort returned results by. + */ + public async getEntitiesByQuery( + // @ts-ignore + request: { + query: { + fields?: Array; + limit?: number; + orderField?: Array; + cursor?: string; + filter?: Array; + fullTextFilterTerm?: string; + fullTextFilterFields?: Array; + }; + }, + options?: RequestOptions, + ): Promise> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/entities/by-query{?fields,limit,orderField*,cursor,filter*,fullTextFilterTerm,fullTextFilterFields}`; + + const uri = parser.parse(uriTemplate).expand({ + ...request.query, + }); + + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'GET', + }); + } + + /** + * Get a batch set of entities given an array of entityRefs. + * @param getEntitiesByRefsRequest + */ + public async getEntitiesByRefs( + // @ts-ignore + request: { + body: GetEntitiesByRefsRequest; + }, + options?: RequestOptions, + ): Promise> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/entities/by-refs`; + + const uri = parser.parse(uriTemplate).expand({}); + + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'POST', + body: JSON.stringify(request.body), + }); + } + + /** + * Get an entity's ancestry by entity ref. + * @param kind + * @param namespace + * @param name + */ + public async getEntityAncestryByName( + // @ts-ignore + request: { + path: { + kind: string; + namespace: string; + name: string; + }; + }, + options?: RequestOptions, + ): Promise> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/entities/by-name/{kind}/{namespace}/{name}/ancestry`; + + const uri = parser.parse(uriTemplate).expand({ + kind: request.path.kind, + namespace: request.path.namespace, + name: request.path.name, + }); + + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'GET', + }); + } + + /** + * Get an entity by an entity ref. + * @param kind + * @param namespace + * @param name + */ + public async getEntityByName( + // @ts-ignore + request: { + path: { + kind: string; + namespace: string; + name: string; + }; + }, + options?: RequestOptions, + ): Promise> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/entities/by-name/{kind}/{namespace}/{name}`; + + const uri = parser.parse(uriTemplate).expand({ + kind: request.path.kind, + namespace: request.path.namespace, + name: request.path.name, + }); + + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'GET', + }); + } + + /** + * Get a single entity by the UID. + * @param uid + */ + public async getEntityByUid( + // @ts-ignore + request: { + path: { + uid: string; + }; + }, + options?: RequestOptions, + ): Promise> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/entities/by-uid/{uid}`; + + const uri = parser.parse(uriTemplate).expand({ + uid: request.path.uid, + }); + + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'GET', + }); + } + + /** + * Get all entity facets that match the given filters. + * @param facet + * @param filter Filter for just the entities defined by this filter. + */ + public async getEntityFacets( + // @ts-ignore + request: { + query: { + facet: Array; + filter?: Array; + }; + }, + options?: RequestOptions, + ): Promise> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/entity-facets{?facet*,filter*}`; + + const uri = parser.parse(uriTemplate).expand({ + ...request.query, + }); + + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'GET', + }); + } + + /** + * Get a location by id. + * @param id + */ + public async getLocation( + // @ts-ignore + request: { + path: { + id: string; + }; + }, + options?: RequestOptions, + ): Promise> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/locations/{id}`; + + const uri = parser.parse(uriTemplate).expand({ + id: request.path.id, + }); + + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'GET', + }); + } + + /** + * Get all locations + */ + public async getLocations( + // @ts-ignore + request: {}, + options?: RequestOptions, + ): Promise>> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/locations`; + + const uri = parser.parse(uriTemplate).expand({}); + + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'GET', + }); + } + + /** + * Refresh the entity related to entityRef. + * @param refreshEntityRequest + */ + public async refreshEntity( + // @ts-ignore + request: { + body: RefreshEntityRequest; + }, + options?: RequestOptions, + ): Promise> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/refresh`; + + const uri = parser.parse(uriTemplate).expand({}); + + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'POST', + body: JSON.stringify(request.body), + }); + } + + /** + * Validate that a passed in entity has no errors in schema. + * @param validateEntityRequest + */ + public async validateEntity( + // @ts-ignore + request: { + body: ValidateEntityRequest; + }, + options?: RequestOptions, + ): Promise> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/validate-entity`; + + const uri = parser.parse(uriTemplate).expand({}); + + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'POST', + body: JSON.stringify(request.body), + }); + } +} diff --git a/packages/catalog-client/src/generated/apis/index.ts b/packages/catalog-client/src/generated/apis/index.ts new file mode 100644 index 0000000000..ad2f72c5b2 --- /dev/null +++ b/packages/catalog-client/src/generated/apis/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './DefaultApi.client'; diff --git a/packages/catalog-client/src/generated/index.ts b/packages/catalog-client/src/generated/index.ts new file mode 100644 index 0000000000..0cf3e9cc49 --- /dev/null +++ b/packages/catalog-client/src/generated/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 * from './apis'; +export * from './models'; diff --git a/packages/catalog-client/src/generated/models/AnalyzeLocationEntityField.model.ts b/packages/catalog-client/src/generated/models/AnalyzeLocationEntityField.model.ts new file mode 100644 index 0000000000..a1c1e1f669 --- /dev/null +++ b/packages/catalog-client/src/generated/models/AnalyzeLocationEntityField.model.ts @@ -0,0 +1,36 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface AnalyzeLocationEntityField { + /** + * A text to show to the user to inform about the choices made. Like, it could say \"Found a CODEOWNERS file that covers this target, so we suggest leaving this field empty; which would currently make it owned by X\" where X is taken from the codeowners file. + */ + description: string; + value: string | null; + /** + * The outcome of the analysis for this particular field + */ + state: AnalyzeLocationEntityFieldStateEnum; + /** + * e.g. \"spec.owner\"? The frontend needs to know how to \"inject\" the field into the entity again if the user wants to change it + */ + field: string; +} + +export type AnalyzeLocationEntityFieldStateEnum = + | 'analysisSuggestedValue' + | 'analysisSuggestedNoValue' + | 'needsUserInput'; diff --git a/packages/catalog-client/src/generated/models/AnalyzeLocationExistingEntity.model.ts b/packages/catalog-client/src/generated/models/AnalyzeLocationExistingEntity.model.ts new file mode 100644 index 0000000000..5ede0fb60b --- /dev/null +++ b/packages/catalog-client/src/generated/models/AnalyzeLocationExistingEntity.model.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Entity } from '../models/Entity.model'; +import { LocationSpec } from '../models/LocationSpec.model'; + +/** + * If the folder pointed to already contained catalog info yaml files, they are read and emitted like this so that the frontend can inform the user that it located them and can make sure to register them as well if they weren't already + */ +export interface AnalyzeLocationExistingEntity { + entity: Entity; + isRegistered: boolean; + location: LocationSpec; +} diff --git a/packages/catalog-client/src/generated/models/AnalyzeLocationGenerateEntity.model.ts b/packages/catalog-client/src/generated/models/AnalyzeLocationGenerateEntity.model.ts new file mode 100644 index 0000000000..886aac05d9 --- /dev/null +++ b/packages/catalog-client/src/generated/models/AnalyzeLocationGenerateEntity.model.ts @@ -0,0 +1,26 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { AnalyzeLocationEntityField } from '../models/AnalyzeLocationEntityField.model'; +import { RecursivePartialEntity } from '../models/RecursivePartialEntity.model'; + +/** + * This is some form of representation of what the analyzer could deduce. We should probably have a chat about how this can best be conveyed to the frontend. It'll probably contain a (possibly incomplete) entity, plus enough info for the frontend to know what form data to show to the user for overriding/completing the info. + */ +export interface AnalyzeLocationGenerateEntity { + fields: Array; + entity: RecursivePartialEntity; +} diff --git a/packages/catalog-client/src/generated/models/AnalyzeLocationRequest.model.ts b/packages/catalog-client/src/generated/models/AnalyzeLocationRequest.model.ts new file mode 100644 index 0000000000..e8e9542f5a --- /dev/null +++ b/packages/catalog-client/src/generated/models/AnalyzeLocationRequest.model.ts @@ -0,0 +1,22 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { LocationInput } from '../models/LocationInput.model'; + +export interface AnalyzeLocationRequest { + catalogFileName?: string; + location: LocationInput; +} diff --git a/packages/catalog-client/src/generated/models/AnalyzeLocationResponse.model.ts b/packages/catalog-client/src/generated/models/AnalyzeLocationResponse.model.ts new file mode 100644 index 0000000000..bf60aa8018 --- /dev/null +++ b/packages/catalog-client/src/generated/models/AnalyzeLocationResponse.model.ts @@ -0,0 +1,23 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { AnalyzeLocationExistingEntity } from '../models/AnalyzeLocationExistingEntity.model'; +import { AnalyzeLocationGenerateEntity } from '../models/AnalyzeLocationGenerateEntity.model'; + +export interface AnalyzeLocationResponse { + generateEntities: Array; + existingEntityFiles: Array; +} diff --git a/packages/catalog-client/src/generated/models/CreateLocation201Response.model.ts b/packages/catalog-client/src/generated/models/CreateLocation201Response.model.ts new file mode 100644 index 0000000000..d090d80bf2 --- /dev/null +++ b/packages/catalog-client/src/generated/models/CreateLocation201Response.model.ts @@ -0,0 +1,24 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Entity } from '../models/Entity.model'; +import { Location } from '../models/Location.model'; + +export interface CreateLocation201Response { + exists?: boolean; + entities: Array; + location: Location; +} diff --git a/packages/catalog-client/src/generated/models/CreateLocationRequest.model.ts b/packages/catalog-client/src/generated/models/CreateLocationRequest.model.ts new file mode 100644 index 0000000000..6ef950072e --- /dev/null +++ b/packages/catalog-client/src/generated/models/CreateLocationRequest.model.ts @@ -0,0 +1,20 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface CreateLocationRequest { + target: string; + type: string; +} diff --git a/packages/catalog-client/src/generated/models/EntitiesBatchResponse.model.ts b/packages/catalog-client/src/generated/models/EntitiesBatchResponse.model.ts new file mode 100644 index 0000000000..d09b2cc086 --- /dev/null +++ b/packages/catalog-client/src/generated/models/EntitiesBatchResponse.model.ts @@ -0,0 +1,24 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { NullableEntity } from '../models/NullableEntity.model'; + +export interface EntitiesBatchResponse { + /** + * The list of entities, in the same order as the refs in the request. Entries that are null signify that no entity existed with that ref. + */ + items: Array; +} diff --git a/packages/catalog-client/src/generated/models/EntitiesQueryResponse.model.ts b/packages/catalog-client/src/generated/models/EntitiesQueryResponse.model.ts new file mode 100644 index 0000000000..10d4747caf --- /dev/null +++ b/packages/catalog-client/src/generated/models/EntitiesQueryResponse.model.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { EntitiesQueryResponsePageInfo } from '../models/EntitiesQueryResponsePageInfo.model'; +import { Entity } from '../models/Entity.model'; + +export interface EntitiesQueryResponse { + /** + * The list of entities paginated by a specific filter. + */ + items: Array; + totalItems: number; + pageInfo: EntitiesQueryResponsePageInfo; +} diff --git a/packages/catalog-client/src/generated/models/EntitiesQueryResponsePageInfo.model.ts b/packages/catalog-client/src/generated/models/EntitiesQueryResponsePageInfo.model.ts new file mode 100644 index 0000000000..8a7d5b39bb --- /dev/null +++ b/packages/catalog-client/src/generated/models/EntitiesQueryResponsePageInfo.model.ts @@ -0,0 +1,26 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface EntitiesQueryResponsePageInfo { + /** + * The cursor for the next batch of entities. + */ + nextCursor?: string; + /** + * The cursor for the previous batch of entities. + */ + prevCursor?: string; +} diff --git a/packages/catalog-client/src/generated/models/Entity.model.ts b/packages/catalog-client/src/generated/models/Entity.model.ts new file mode 100644 index 0000000000..59ef9bc741 --- /dev/null +++ b/packages/catalog-client/src/generated/models/Entity.model.ts @@ -0,0 +1,41 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { EntityMeta } from '../models/EntityMeta.model'; +import { EntityRelation } from '../models/EntityRelation.model'; + +/** + * The parts of the format that's common to all versions/kinds of entity. + */ +export interface Entity { + /** + * The relations that this entity has with other entities. + */ + relations?: Array; + /** + * A type representing all allowed JSON object values. + */ + spec?: { [key: string]: any }; + metadata: EntityMeta; + /** + * The high level entity type being described. + */ + kind: string; + /** + * The version of specification format for this particular entity that this is written against. + */ + apiVersion: string; +} diff --git a/packages/catalog-client/src/generated/models/EntityAncestryResponse.model.ts b/packages/catalog-client/src/generated/models/EntityAncestryResponse.model.ts new file mode 100644 index 0000000000..08076fcf36 --- /dev/null +++ b/packages/catalog-client/src/generated/models/EntityAncestryResponse.model.ts @@ -0,0 +1,22 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { EntityAncestryResponseItemsInner } from '../models/EntityAncestryResponseItemsInner.model'; + +export interface EntityAncestryResponse { + items: Array; + rootEntityRef: string; +} diff --git a/packages/catalog-client/src/generated/models/EntityAncestryResponseItemsInner.model.ts b/packages/catalog-client/src/generated/models/EntityAncestryResponseItemsInner.model.ts new file mode 100644 index 0000000000..7713c21295 --- /dev/null +++ b/packages/catalog-client/src/generated/models/EntityAncestryResponseItemsInner.model.ts @@ -0,0 +1,22 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Entity } from '../models/Entity.model'; + +export interface EntityAncestryResponseItemsInner { + parentEntityRefs: Array; + entity: Entity; +} diff --git a/packages/catalog-client/src/generated/models/EntityFacet.model.ts b/packages/catalog-client/src/generated/models/EntityFacet.model.ts new file mode 100644 index 0000000000..3872091d77 --- /dev/null +++ b/packages/catalog-client/src/generated/models/EntityFacet.model.ts @@ -0,0 +1,20 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface EntityFacet { + value: string; + count: number; +} diff --git a/packages/catalog-client/src/generated/models/EntityFacetsResponse.model.ts b/packages/catalog-client/src/generated/models/EntityFacetsResponse.model.ts new file mode 100644 index 0000000000..0ff37e4f2f --- /dev/null +++ b/packages/catalog-client/src/generated/models/EntityFacetsResponse.model.ts @@ -0,0 +1,21 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { EntityFacet } from '../models/EntityFacet.model'; + +export interface EntityFacetsResponse { + facets: { [key: string]: Array }; +} diff --git a/packages/catalog-client/src/generated/models/EntityLink.model.ts b/packages/catalog-client/src/generated/models/EntityLink.model.ts new file mode 100644 index 0000000000..f52f9f2df0 --- /dev/null +++ b/packages/catalog-client/src/generated/models/EntityLink.model.ts @@ -0,0 +1,37 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * A link to external information that is related to the entity. + */ +export interface EntityLink { + /** + * An optional value to categorize links into specific groups + */ + type?: string; + /** + * An optional semantic key that represents a visual icon. + */ + icon?: string; + /** + * An optional descriptive title for the link. + */ + title?: string; + /** + * The url to the external site, document, etc. + */ + url: string; +} diff --git a/packages/catalog-client/src/generated/models/EntityMeta.model.ts b/packages/catalog-client/src/generated/models/EntityMeta.model.ts new file mode 100644 index 0000000000..cb0fd28fdc --- /dev/null +++ b/packages/catalog-client/src/generated/models/EntityMeta.model.ts @@ -0,0 +1,64 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { EntityLink } from '../models/EntityLink.model'; + +/** + * Metadata fields common to all versions/kinds of entity. + */ +export interface EntityMeta { + [key: string]: any; + /** + * A list of external hyperlinks related to the entity. + */ + links?: Array; + /** + * A list of single-valued strings, to for example classify catalog entities in various ways. + */ + tags?: Array; + /** + * Construct a type with a set of properties K of type T + */ + annotations?: { [key: string]: string }; + /** + * Construct a type with a set of properties K of type T + */ + labels?: { [key: string]: string }; + /** + * A short (typically relatively few words, on one line) description of the entity. + */ + description?: string; + /** + * A display name of the entity, to be presented in user interfaces instead of the `name` property above, when available. This field is sometimes useful when the `name` is cumbersome or ends up being perceived as overly technical. The title generally does not have as stringent format requirements on it, so it may contain special characters and be more explanatory. Do keep it very short though, and avoid situations where a title can be confused with the name of another entity, or where two entities share a title. Note that this is only for display purposes, and may be ignored by some parts of the code. Entity references still always make use of the `name` property, not the title. + */ + title?: string; + /** + * The namespace that the entity belongs to. + */ + namespace?: string; + /** + * The name of the entity. Must be unique within the catalog at any given point in time, for any given namespace + kind pair. This value is part of the technical identifier of the entity, and as such it will appear in URLs, database tables, entity references, and similar. It is subject to restrictions regarding what characters are allowed. If you want to use a different, more human readable string with fewer restrictions on it in user interfaces, see the `title` field below. + */ + name: string; + /** + * An opaque string that changes for each update operation to any part of the entity, including metadata. This field can not be set by the user at creation time, and the server will reject an attempt to do so. The field will be populated in read operations. The field can (optionally) be specified when performing update or delete operations, and the server will then reject the operation if it does not match the current stored value. + */ + etag?: string; + /** + * A globally unique ID for the entity. This field can not be set by the user at creation time, and the server will reject an attempt to do so. The field will be populated in read operations. The field can (optionally) be specified when performing update or delete operations, but the server is free to reject requests that do so in such a way that it breaks semantics. + */ + uid?: string; +} diff --git a/packages/catalog-client/src/generated/models/EntityRelation.model.ts b/packages/catalog-client/src/generated/models/EntityRelation.model.ts new file mode 100644 index 0000000000..1107f7563c --- /dev/null +++ b/packages/catalog-client/src/generated/models/EntityRelation.model.ts @@ -0,0 +1,29 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * A relation of a specific type to another entity in the catalog. + */ +export interface EntityRelation { + /** + * The entity ref of the target of this relation. + */ + targetRef: string; + /** + * The type of the relation. + */ + type: string; +} diff --git a/packages/catalog-client/src/generated/models/ErrorError.model.ts b/packages/catalog-client/src/generated/models/ErrorError.model.ts new file mode 100644 index 0000000000..9dbfa22813 --- /dev/null +++ b/packages/catalog-client/src/generated/models/ErrorError.model.ts @@ -0,0 +1,22 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface ErrorError { + name: string; + message: string; + stack?: string; + code?: string; +} diff --git a/packages/catalog-client/src/generated/models/ErrorRequest.model.ts b/packages/catalog-client/src/generated/models/ErrorRequest.model.ts new file mode 100644 index 0000000000..e6306b87f5 --- /dev/null +++ b/packages/catalog-client/src/generated/models/ErrorRequest.model.ts @@ -0,0 +1,20 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface ErrorRequest { + method: string; + url: string; +} diff --git a/packages/catalog-client/src/generated/models/ErrorResponse.model.ts b/packages/catalog-client/src/generated/models/ErrorResponse.model.ts new file mode 100644 index 0000000000..1f55c34b4a --- /dev/null +++ b/packages/catalog-client/src/generated/models/ErrorResponse.model.ts @@ -0,0 +1,19 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface ErrorResponse { + statusCode: number; +} diff --git a/packages/catalog-client/src/generated/models/GetEntitiesByRefsRequest.model.ts b/packages/catalog-client/src/generated/models/GetEntitiesByRefsRequest.model.ts new file mode 100644 index 0000000000..bdda7c2fa6 --- /dev/null +++ b/packages/catalog-client/src/generated/models/GetEntitiesByRefsRequest.model.ts @@ -0,0 +1,20 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface GetEntitiesByRefsRequest { + entityRefs: Array; + fields?: Array; +} diff --git a/packages/catalog-client/src/generated/models/GetLocations200ResponseInner.model.ts b/packages/catalog-client/src/generated/models/GetLocations200ResponseInner.model.ts new file mode 100644 index 0000000000..134306cce7 --- /dev/null +++ b/packages/catalog-client/src/generated/models/GetLocations200ResponseInner.model.ts @@ -0,0 +1,21 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Location } from '../models/Location.model'; + +export interface GetLocations200ResponseInner { + data: Location; +} diff --git a/packages/catalog-client/src/generated/models/Location.model.ts b/packages/catalog-client/src/generated/models/Location.model.ts new file mode 100644 index 0000000000..27e47a5a25 --- /dev/null +++ b/packages/catalog-client/src/generated/models/Location.model.ts @@ -0,0 +1,24 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Entity location for a specific entity. + */ +export interface Location { + target: string; + type: string; + id: string; +} diff --git a/packages/catalog-client/src/generated/models/LocationInput.model.ts b/packages/catalog-client/src/generated/models/LocationInput.model.ts new file mode 100644 index 0000000000..8de7e3e6c9 --- /dev/null +++ b/packages/catalog-client/src/generated/models/LocationInput.model.ts @@ -0,0 +1,20 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface LocationInput { + type: string; + target: string; +} diff --git a/packages/catalog-client/src/generated/models/LocationSpec.model.ts b/packages/catalog-client/src/generated/models/LocationSpec.model.ts new file mode 100644 index 0000000000..80db2cadf2 --- /dev/null +++ b/packages/catalog-client/src/generated/models/LocationSpec.model.ts @@ -0,0 +1,23 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Holds the entity location information. + */ +export interface LocationSpec { + target: string; + type: string; +} diff --git a/packages/catalog-client/src/generated/models/ModelError.model.ts b/packages/catalog-client/src/generated/models/ModelError.model.ts new file mode 100644 index 0000000000..989e755c9a --- /dev/null +++ b/packages/catalog-client/src/generated/models/ModelError.model.ts @@ -0,0 +1,26 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ErrorError } from '../models/ErrorError.model'; +import { ErrorRequest } from '../models/ErrorRequest.model'; +import { ErrorResponse } from '../models/ErrorResponse.model'; + +export interface ModelError { + [key: string]: any; + error: ErrorError; + request?: ErrorRequest; + response: ErrorResponse; +} diff --git a/packages/catalog-client/src/generated/models/NullableEntity.model.ts b/packages/catalog-client/src/generated/models/NullableEntity.model.ts new file mode 100644 index 0000000000..36aff86ba8 --- /dev/null +++ b/packages/catalog-client/src/generated/models/NullableEntity.model.ts @@ -0,0 +1,41 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { EntityMeta } from '../models/EntityMeta.model'; +import { EntityRelation } from '../models/EntityRelation.model'; + +/** + * The parts of the format that's common to all versions/kinds of entity. + */ +export interface NullableEntity { + /** + * The relations that this entity has with other entities. + */ + relations?: Array; + /** + * A type representing all allowed JSON object values. + */ + spec?: { [key: string]: any }; + metadata: EntityMeta; + /** + * The high level entity type being described. + */ + kind: string; + /** + * The version of specification format for this particular entity that this is written against. + */ + apiVersion: string; +} diff --git a/packages/catalog-client/src/generated/models/RecursivePartialEntity.model.ts b/packages/catalog-client/src/generated/models/RecursivePartialEntity.model.ts new file mode 100644 index 0000000000..8de7824550 --- /dev/null +++ b/packages/catalog-client/src/generated/models/RecursivePartialEntity.model.ts @@ -0,0 +1,41 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { RecursivePartialEntityMeta } from '../models/RecursivePartialEntityMeta.model'; +import { RecursivePartialEntityRelation } from '../models/RecursivePartialEntityRelation.model'; + +/** + * Makes all keys of an entire hierarchy optional. + */ +export interface RecursivePartialEntity { + /** + * The version of specification format for this particular entity that this is written against. + */ + apiVersion?: string; + /** + * The high level entity type being described. + */ + kind?: string; + metadata?: RecursivePartialEntityMeta; + /** + * A type representing all allowed JSON object values. + */ + spec?: { [key: string]: any }; + /** + * The relations that this entity has with other entities. + */ + relations?: Array; +} diff --git a/packages/catalog-client/src/generated/models/RecursivePartialEntityMeta.model.ts b/packages/catalog-client/src/generated/models/RecursivePartialEntityMeta.model.ts new file mode 100644 index 0000000000..b21cc1bb21 --- /dev/null +++ b/packages/catalog-client/src/generated/models/RecursivePartialEntityMeta.model.ts @@ -0,0 +1,60 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { EntityLink } from '../models/EntityLink.model'; + +export interface RecursivePartialEntityMeta { + /** + * A list of external hyperlinks related to the entity. + */ + links?: Array; + /** + * A list of single-valued strings, to for example classify catalog entities in various ways. + */ + tags?: Array; + /** + * Construct a type with a set of properties K of type T + */ + annotations?: { [key: string]: string }; + /** + * Construct a type with a set of properties K of type T + */ + labels?: { [key: string]: string }; + /** + * A short (typically relatively few words, on one line) description of the entity. + */ + description?: string; + /** + * A display name of the entity, to be presented in user interfaces instead of the `name` property above, when available. This field is sometimes useful when the `name` is cumbersome or ends up being perceived as overly technical. The title generally does not have as stringent format requirements on it, so it may contain special characters and be more explanatory. Do keep it very short though, and avoid situations where a title can be confused with the name of another entity, or where two entities share a title. Note that this is only for display purposes, and may be ignored by some parts of the code. Entity references still always make use of the `name` property, not the title. + */ + title?: string; + /** + * The namespace that the entity belongs to. + */ + namespace?: string; + /** + * The name of the entity. Must be unique within the catalog at any given point in time, for any given namespace + kind pair. This value is part of the technical identifier of the entity, and as such it will appear in URLs, database tables, entity references, and similar. It is subject to restrictions regarding what characters are allowed. If you want to use a different, more human readable string with fewer restrictions on it in user interfaces, see the `title` field below. + */ + name?: string; + /** + * An opaque string that changes for each update operation to any part of the entity, including metadata. This field can not be set by the user at creation time, and the server will reject an attempt to do so. The field will be populated in read operations. The field can (optionally) be specified when performing update or delete operations, and the server will then reject the operation if it does not match the current stored value. + */ + etag?: string; + /** + * A globally unique ID for the entity. This field can not be set by the user at creation time, and the server will reject an attempt to do so. The field will be populated in read operations. The field can (optionally) be specified when performing update or delete operations, but the server is free to reject requests that do so in such a way that it breaks semantics. + */ + uid?: string; +} diff --git a/packages/catalog-client/src/generated/models/RecursivePartialEntityMetaAllOf.model.ts b/packages/catalog-client/src/generated/models/RecursivePartialEntityMetaAllOf.model.ts new file mode 100644 index 0000000000..5111cd7f9f --- /dev/null +++ b/packages/catalog-client/src/generated/models/RecursivePartialEntityMetaAllOf.model.ts @@ -0,0 +1,63 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { EntityLink } from '../models/EntityLink.model'; + +/** + * Metadata fields common to all versions/kinds of entity. + */ +export interface RecursivePartialEntityMetaAllOf { + /** + * A list of external hyperlinks related to the entity. + */ + links?: Array; + /** + * A list of single-valued strings, to for example classify catalog entities in various ways. + */ + tags?: Array; + /** + * Construct a type with a set of properties K of type T + */ + annotations?: { [key: string]: string }; + /** + * Construct a type with a set of properties K of type T + */ + labels?: { [key: string]: string }; + /** + * A short (typically relatively few words, on one line) description of the entity. + */ + description?: string; + /** + * A display name of the entity, to be presented in user interfaces instead of the `name` property above, when available. This field is sometimes useful when the `name` is cumbersome or ends up being perceived as overly technical. The title generally does not have as stringent format requirements on it, so it may contain special characters and be more explanatory. Do keep it very short though, and avoid situations where a title can be confused with the name of another entity, or where two entities share a title. Note that this is only for display purposes, and may be ignored by some parts of the code. Entity references still always make use of the `name` property, not the title. + */ + title?: string; + /** + * The namespace that the entity belongs to. + */ + namespace?: string; + /** + * The name of the entity. Must be unique within the catalog at any given point in time, for any given namespace + kind pair. This value is part of the technical identifier of the entity, and as such it will appear in URLs, database tables, entity references, and similar. It is subject to restrictions regarding what characters are allowed. If you want to use a different, more human readable string with fewer restrictions on it in user interfaces, see the `title` field below. + */ + name?: string; + /** + * An opaque string that changes for each update operation to any part of the entity, including metadata. This field can not be set by the user at creation time, and the server will reject an attempt to do so. The field will be populated in read operations. The field can (optionally) be specified when performing update or delete operations, and the server will then reject the operation if it does not match the current stored value. + */ + etag?: string; + /** + * A globally unique ID for the entity. This field can not be set by the user at creation time, and the server will reject an attempt to do so. The field will be populated in read operations. The field can (optionally) be specified when performing update or delete operations, but the server is free to reject requests that do so in such a way that it breaks semantics. + */ + uid?: string; +} diff --git a/packages/catalog-client/src/generated/models/RecursivePartialEntityRelation.model.ts b/packages/catalog-client/src/generated/models/RecursivePartialEntityRelation.model.ts new file mode 100644 index 0000000000..50635b69f4 --- /dev/null +++ b/packages/catalog-client/src/generated/models/RecursivePartialEntityRelation.model.ts @@ -0,0 +1,29 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * A relation of a specific type to another entity in the catalog. + */ +export interface RecursivePartialEntityRelation { + /** + * The entity ref of the target of this relation. + */ + targetRef?: string; + /** + * The type of the relation. + */ + type?: string; +} diff --git a/packages/catalog-client/src/generated/models/RefreshEntityRequest.model.ts b/packages/catalog-client/src/generated/models/RefreshEntityRequest.model.ts new file mode 100644 index 0000000000..573523385b --- /dev/null +++ b/packages/catalog-client/src/generated/models/RefreshEntityRequest.model.ts @@ -0,0 +1,26 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Options for requesting a refresh of entities in the catalog. + */ +export interface RefreshEntityRequest { + authorizationToken?: string; + /** + * The reference to a single entity that should be refreshed + */ + entityRef: string; +} diff --git a/packages/catalog-client/src/generated/models/ValidateEntity400Response.model.ts b/packages/catalog-client/src/generated/models/ValidateEntity400Response.model.ts new file mode 100644 index 0000000000..0031b2edc2 --- /dev/null +++ b/packages/catalog-client/src/generated/models/ValidateEntity400Response.model.ts @@ -0,0 +1,21 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ValidateEntity400ResponseErrorsInner } from '../models/ValidateEntity400ResponseErrorsInner.model'; + +export interface ValidateEntity400Response { + errors: Array; +} diff --git a/packages/catalog-client/src/generated/models/ValidateEntity400ResponseErrorsInner.model.ts b/packages/catalog-client/src/generated/models/ValidateEntity400ResponseErrorsInner.model.ts new file mode 100644 index 0000000000..6223df27af --- /dev/null +++ b/packages/catalog-client/src/generated/models/ValidateEntity400ResponseErrorsInner.model.ts @@ -0,0 +1,21 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface ValidateEntity400ResponseErrorsInner { + [key: string]: any; + name: string; + message: string; +} diff --git a/packages/catalog-client/src/generated/models/ValidateEntityRequest.model.ts b/packages/catalog-client/src/generated/models/ValidateEntityRequest.model.ts new file mode 100644 index 0000000000..d5ce1be5c9 --- /dev/null +++ b/packages/catalog-client/src/generated/models/ValidateEntityRequest.model.ts @@ -0,0 +1,20 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface ValidateEntityRequest { + location: string; + entity: { [key: string]: any }; +} diff --git a/packages/catalog-client/src/generated/models/index.ts b/packages/catalog-client/src/generated/models/index.ts new file mode 100644 index 0000000000..5a93dbb33a --- /dev/null +++ b/packages/catalog-client/src/generated/models/index.ts @@ -0,0 +1,52 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from '../models/AnalyzeLocationEntityField.model'; +export * from '../models/AnalyzeLocationExistingEntity.model'; +export * from '../models/AnalyzeLocationGenerateEntity.model'; +export * from '../models/AnalyzeLocationRequest.model'; +export * from '../models/AnalyzeLocationResponse.model'; +export * from '../models/CreateLocation201Response.model'; +export * from '../models/CreateLocationRequest.model'; +export * from '../models/EntitiesBatchResponse.model'; +export * from '../models/EntitiesQueryResponse.model'; +export * from '../models/EntitiesQueryResponsePageInfo.model'; +export * from '../models/Entity.model'; +export * from '../models/EntityAncestryResponse.model'; +export * from '../models/EntityAncestryResponseItemsInner.model'; +export * from '../models/EntityFacet.model'; +export * from '../models/EntityFacetsResponse.model'; +export * from '../models/EntityLink.model'; +export * from '../models/EntityMeta.model'; +export * from '../models/EntityRelation.model'; +export * from '../models/ErrorError.model'; +export * from '../models/ErrorRequest.model'; +export * from '../models/ErrorResponse.model'; +export * from '../models/GetEntitiesByRefsRequest.model'; +export * from '../models/GetLocations200ResponseInner.model'; +export * from '../models/Location.model'; +export * from '../models/LocationInput.model'; +export * from '../models/LocationSpec.model'; +export * from '../models/ModelError.model'; +export * from '../models/NullableEntity.model'; +export * from '../models/RecursivePartialEntity.model'; +export * from '../models/RecursivePartialEntityMeta.model'; +export * from '../models/RecursivePartialEntityMetaAllOf.model'; +export * from '../models/RecursivePartialEntityRelation.model'; +export * from '../models/RefreshEntityRequest.model'; +export * from '../models/ValidateEntity400Response.model'; +export * from '../models/ValidateEntity400ResponseErrorsInner.model'; +export * from '../models/ValidateEntityRequest.model'; diff --git a/packages/catalog-client/src/generated/pluginId.ts b/packages/catalog-client/src/generated/pluginId.ts new file mode 100644 index 0000000000..c8c8ce1ca3 --- /dev/null +++ b/packages/catalog-client/src/generated/pluginId.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export const pluginId = 'catalog'; diff --git a/packages/catalog-client/src/generated/types/discovery.ts b/packages/catalog-client/src/generated/types/discovery.ts new file mode 100644 index 0000000000..a7f87d3780 --- /dev/null +++ b/packages/catalog-client/src/generated/types/discovery.ts @@ -0,0 +1,22 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This is a copy of the DiscoveryApi, to avoid importing core-plugin-api. + */ +export type DiscoveryApi = { + getBaseUrl(pluginId: string): Promise; +}; diff --git a/packages/catalog-client/src/generated/types/fetch.ts b/packages/catalog-client/src/generated/types/fetch.ts new file mode 100644 index 0000000000..3de56c028e --- /dev/null +++ b/packages/catalog-client/src/generated/types/fetch.ts @@ -0,0 +1,22 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This is a copy of FetchApi, to avoid importing core-plugin-api. + */ +export type FetchApi = { + fetch: typeof fetch; +}; diff --git a/packages/catalog-model/alpha-api-report.md b/packages/catalog-model/api-report-alpha.md similarity index 100% rename from packages/catalog-model/alpha-api-report.md rename to packages/catalog-model/api-report-alpha.md diff --git a/packages/catalog-model/examples/acme/backstage-group.yaml b/packages/catalog-model/examples/acme/backstage-group.yaml index f83587532c..0372eedab7 100644 --- a/packages/catalog-model/examples/acme/backstage-group.yaml +++ b/packages/catalog-model/examples/acme/backstage-group.yaml @@ -8,6 +8,6 @@ spec: profile: displayName: Backstage email: backstage@example.com - picture: https://avatars.dicebear.com/api/identicon/backstage@example.com.svg?background=%23fff&margin=25 + picture: https://api.dicebear.com/7.x/identicon/svg?seed=Fluffy&backgroundColor=ffdfbf parent: infrastructure children: [team-a, team-b] diff --git a/packages/catalog-model/examples/acme/org.yaml b/packages/catalog-model/examples/acme/org.yaml index 9a0d690b57..96dd3a4e9e 100644 --- a/packages/catalog-model/examples/acme/org.yaml +++ b/packages/catalog-model/examples/acme/org.yaml @@ -13,7 +13,7 @@ spec: profile: displayName: ACME Corp email: info@example.com - picture: https://avatars.dicebear.com/api/identicon/info@example.com.svg?background=%23fff&margin=25 + picture: https://api.dicebear.com/7.x/identicon/svg?seed=Maggie&flip=true&backgroundColor=ffdfbf children: [infrastructure] --- apiVersion: backstage.io/v1alpha1 diff --git a/packages/catalog-model/examples/acme/team-a-group.yaml b/packages/catalog-model/examples/acme/team-a-group.yaml index e343209d5f..7fe0e7b3f3 100644 --- a/packages/catalog-model/examples/acme/team-a-group.yaml +++ b/packages/catalog-model/examples/acme/team-a-group.yaml @@ -8,7 +8,7 @@ spec: profile: # Intentional no displayName for testing email: team-a@example.com - picture: https://avatars.dicebear.com/api/identicon/team-a@example.com.svg?background=%23fff&margin=25 + picture: https://api.dicebear.com/7.x/identicon/svg?seed=Fluffy&backgroundType=solid,gradientLinear&backgroundColor=ffd5dc,b6e3f4 parent: backstage children: [] --- @@ -20,7 +20,7 @@ spec: profile: # Intentional no displayName for testing email: breanna-davison@example.com - picture: https://avatars.dicebear.com/api/avataaars/breanna-davison@example.com.svg?background=%23fff + picture: https://api.dicebear.com/7.x/avataaars/svg?seed=Luna&backgroundColor=transparent memberOf: [team-a] --- apiVersion: backstage.io/v1alpha1 @@ -31,7 +31,7 @@ spec: profile: displayName: Janelle Dawe email: janelle-dawe@example.com - picture: https://avatars.dicebear.com/api/avataaars/janelle-dawe@example.com.svg?background=%23fff + picture: https://api.dicebear.com/7.x/avataaars/svg?seed=Leo&backgroundColor=transparent memberOf: [team-a] --- apiVersion: backstage.io/v1alpha1 @@ -42,7 +42,7 @@ spec: profile: displayName: Nigel Manning email: nigel-manning@example.com - picture: https://avatars.dicebear.com/api/avataaars/nigel-manning@example.com.svg?background=%23fff + picture: https://api.dicebear.com/7.x/avataaars/svg?seed=Midnight&backgroundColor=transparent memberOf: [team-a] --- # This user is added as an example, to make it more easy for the "Guest" @@ -56,5 +56,4 @@ spec: profile: displayName: Guest User email: guest@example.com - picture: https://avatars.dicebear.com/api/avataaars/guest@example.com.svg?background=%23fff memberOf: [team-a] diff --git a/packages/catalog-model/examples/acme/team-b-group.yaml b/packages/catalog-model/examples/acme/team-b-group.yaml index 20ab8721ea..63dd000fb4 100644 --- a/packages/catalog-model/examples/acme/team-b-group.yaml +++ b/packages/catalog-model/examples/acme/team-b-group.yaml @@ -8,7 +8,7 @@ spec: profile: displayName: Team B email: team-b@example.com - picture: https://avatars.dicebear.com/api/identicon/team-b@example.com.svg?background=%23fff&margin=25 + picture: https://api.dicebear.com/7.x/identicon/svg?seed=Abby&backgroundType=solid,gradientLinear&backgroundColor=ffd5dc,b6e3f4 parent: backstage children: [] --- @@ -20,7 +20,7 @@ spec: profile: displayName: Amelia Park email: amelia-park@example.com - picture: https://avatars.dicebear.com/api/avataaars/amelia-park@example.com.svg?background=%23fff + picture: https://api.dicebear.com/7.x/avataaars/svg?seed=Gizmo&backgroundColor=transparent memberOf: [team-b] --- apiVersion: backstage.io/v1alpha1 @@ -31,7 +31,7 @@ spec: profile: displayName: Colette Brock email: colette-brock@example.com - picture: https://avatars.dicebear.com/api/avataaars/colette-brock@example.com.svg?background=%23fff + picture: https://api.dicebear.com/7.x/avataaars/svg?seed=Bailey&backgroundColor=transparent memberOf: [team-b] --- apiVersion: backstage.io/v1alpha1 @@ -42,7 +42,7 @@ spec: profile: displayName: Jenny Doe email: jenny-doe@example.com - picture: https://avatars.dicebear.com/api/avataaars/jenny-doe@example.com.svg?background=%23fff + picture: https://api.dicebear.com/7.x/avataaars/svg?seed=Mimi&backgroundColor=transparent memberOf: [team-b] --- apiVersion: backstage.io/v1alpha1 @@ -53,7 +53,7 @@ spec: profile: displayName: Jonathon Page email: jonathon-page@example.com - picture: https://avatars.dicebear.com/api/avataaars/jonathon-page@example.com.svg?background=%23fff + picture: https://api.dicebear.com/7.x/avataaars/svg?seed=Baby&backgroundColor=transparent memberOf: [team-b] --- apiVersion: backstage.io/v1alpha1 @@ -64,5 +64,5 @@ spec: profile: displayName: Justine Barrow email: justine-barrow@example.com - picture: https://avatars.dicebear.com/api/avataaars/justine-barrow@example.com.svg?background=%23fff + picture: https://api.dicebear.com/7.x/avataaars/svg?seed=Sassy&backgroundColor=transparent memberOf: [team-b] diff --git a/packages/catalog-model/examples/acme/team-c-group.yaml b/packages/catalog-model/examples/acme/team-c-group.yaml index 639b591d61..2daaa1daba 100644 --- a/packages/catalog-model/examples/acme/team-c-group.yaml +++ b/packages/catalog-model/examples/acme/team-c-group.yaml @@ -8,7 +8,7 @@ spec: profile: displayName: Team C email: team-c@example.com - picture: https://avatars.dicebear.com/api/identicon/team-c@example.com.svg?background=%23fff&margin=25 + picture: https://api.dicebear.com/7.x/identicon/svg?seed=Loki&backgroundType=gradientLinear&backgroundColor=b6e3f4,ffd5dc,ffdfbf,c0aede parent: boxoffice children: [] --- @@ -20,7 +20,7 @@ spec: profile: displayName: Calum Leavy email: calum-leavy@example.com - picture: https://avatars.dicebear.com/api/avataaars/calum-leavy@example.com.svg?background=%23fff + picture: https://api.dicebear.com/7.x/avataaars/svg?seed=Bear&backgroundColor=transparent memberOf: [team-c] --- apiVersion: backstage.io/v1alpha1 @@ -31,7 +31,7 @@ spec: profile: displayName: Frank Tiernan email: frank-tiernan@example.com - picture: https://avatars.dicebear.com/api/avataaars/frank-tiernan@example.com.svg?background=%23fff + picture: https://api.dicebear.com/7.x/avataaars/svg?seed=Bandit&backgroundColor=transparent memberOf: [team-c] --- apiVersion: backstage.io/v1alpha1 @@ -42,7 +42,7 @@ spec: profile: displayName: Peadar MacMahon email: peadar-macmahon@example.com - picture: https://avatars.dicebear.com/api/avataaars/peadar-macmahon@example.com.svg?background=%23fff + picture: https://api.dicebear.com/7.x/avataaars/svg?seed=Sophie memberOf: [team-c] --- apiVersion: backstage.io/v1alpha1 @@ -53,7 +53,7 @@ spec: profile: displayName: Sarah Gilroy email: sarah-gilroy@example.com - picture: https://avatars.dicebear.com/api/avataaars/sarah-gilroy@example.com.svg?background=%23fff + picture: https://api.dicebear.com/7.x/avataaars/svg?seed=Rascal memberOf: [team-c] --- apiVersion: backstage.io/v1alpha1 @@ -64,5 +64,5 @@ spec: profile: displayName: Tara MacGovern email: tara-macgovern@example.com - picture: https://avatars.dicebear.com/api/avataaars/tara-macgovern@example.com.svg?background=%23fff + picture: https://api.dicebear.com/7.x/avataaars/svg?seed=Jasmine memberOf: [team-c] diff --git a/packages/catalog-model/examples/acme/team-d-group.yaml b/packages/catalog-model/examples/acme/team-d-group.yaml index 898ed8be6c..ac6d70772e 100644 --- a/packages/catalog-model/examples/acme/team-d-group.yaml +++ b/packages/catalog-model/examples/acme/team-d-group.yaml @@ -8,7 +8,7 @@ spec: profile: displayName: Team D email: team-d@example.com - picture: https://avatars.dicebear.com/api/identicon/team-d@example.com.svg?background=%23fff&margin=25 + picture: https://api.dicebear.com/7.x/identicon/svg?seed=Bailey&backgroundType=gradientLinear&backgroundColor=b6e3f4,ffd5dc,ffdfbf,c0aede parent: boxoffice children: [] --- @@ -20,7 +20,7 @@ spec: profile: displayName: Eva MacDowell email: eva-macdowell@example.com - picture: https://avatars.dicebear.com/api/avataaars/eva-macdowell@example.com.svg?background=%23fff + picture: https://api.dicebear.com/7.x/avataaars/svg?seed=Cuddles memberOf: [team-d] --- apiVersion: backstage.io/v1alpha1 @@ -31,5 +31,5 @@ spec: profile: displayName: Lucy Sheehan email: lucy-sheehan@example.com - picture: https://avatars.dicebear.com/api/avataaars/lucy-sheehan@example.com.svg?background=%23fff + picture: https://api.dicebear.com/7.x/avataaars/svg?seed=Snickers memberOf: [team-d] diff --git a/packages/cli-node/CHANGELOG.md b/packages/cli-node/CHANGELOG.md index efe94c5ffa..176785b2db 100644 --- a/packages/cli-node/CHANGELOG.md +++ b/packages/cli-node/CHANGELOG.md @@ -1,5 +1,48 @@ # @backstage/cli-node +## 0.2.2 + +### Patch Changes + +- 7acbb5a: Removed `mock-fs` dev dependency. +- Updated dependencies + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.2.2-next.0 + +### Patch Changes + +- 7acbb5a: Removed `mock-fs` dev dependency. +- Updated dependencies + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.2.1 + +### Patch Changes + +- 0cbb03b: Fixing regular expression ReDoS with zod packages. Upgrading to latest. ref: https://security.snyk.io/vuln/SNYK-JS-ZOD-5925617 +- Updated dependencies + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.2.0 + +### Minor Changes + +- 8db5c3cd7a: Removed support for the `publishConfig.alphaTypes` and `.betaTypes` fields that were used together with `--experimental-type-build` to generate `/alpha` and `/beta` entry points. Use the `exports` field to achieve this instead. + +### Patch Changes + +- Updated dependencies + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + ## 0.2.0-next.0 ### Minor Changes diff --git a/packages/cli-node/package.json b/packages/cli-node/package.json index 74051dbd94..60ba687ddc 100644 --- a/packages/cli-node/package.json +++ b/packages/cli-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/cli-node", "description": "Node.js library for Backstage CLIs", - "version": "0.2.0-next.0", + "version": "0.2.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,11 +35,11 @@ "@yarnpkg/parsers": "^3.0.0-rc.4", "fs-extra": "10.1.0", "semver": "^7.5.3", - "zod": "^3.21.4" + "zod": "^3.22.4" }, "devDependencies": { - "@backstage/cli": "workspace:^", - "mock-fs": "^5.2.0" + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^" }, "files": [ "dist" diff --git a/packages/cli-node/src/monorepo/isMonorepo.test.ts b/packages/cli-node/src/monorepo/isMonorepo.test.ts index eb466a6ac8..de0dae0893 100644 --- a/packages/cli-node/src/monorepo/isMonorepo.test.ts +++ b/packages/cli-node/src/monorepo/isMonorepo.test.ts @@ -15,15 +15,17 @@ */ import { isMonoRepo } from './isMonoRepo'; -import mockFs from 'mock-fs'; +import { createMockDirectory } from '@backstage/backend-test-utils'; + +const mockDir = createMockDirectory(); + +jest.mock('../paths', () => ({ + paths: { resolveTargetRoot: (...args: string[]) => mockDir.resolve(...args) }, +})); describe('isMonoRepo', () => { - afterEach(() => { - mockFs.restore(); - }); - it('should detect a monorepo', async () => { - mockFs({ + mockDir.setContent({ 'package.json': JSON.stringify({ name: 'foo', workspaces: { @@ -35,7 +37,7 @@ describe('isMonoRepo', () => { }); it('should detect a non- monorepo', async () => { - mockFs({ + mockDir.setContent({ 'package.json': JSON.stringify({ name: 'foo', }), @@ -44,7 +46,7 @@ describe('isMonoRepo', () => { }); it('should return false if package.json is missing', async () => { - mockFs({}); + mockDir.setContent({}); await expect(isMonoRepo()).resolves.toBe(false); }); }); diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index c2f25872bf..0c686ea8c4 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,206 @@ # @backstage/cli +## 0.25.1 + +### Patch Changes + +- b6b15b2: Use sha256 instead of md5 in build script cache key calculation + + Makes it possible to build on FIPS nodejs. + +- Updated dependencies + - @backstage/config-loader@1.6.1 + - @backstage/cli-node@0.2.2 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/eslint-plugin@0.1.4 + - @backstage/integration@1.8.0 + - @backstage/release-manifests@0.0.11 + - @backstage/types@1.1.1 + +## 0.25.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.6.1-next.0 + - @backstage/cli-node@0.2.2-next.0 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/release-manifests@0.0.11 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + - @backstage/eslint-plugin@0.1.4 + - @backstage/types@1.1.1 + +## 0.25.1-next.0 + +### Patch Changes + +- b6b15b2: Use sha256 instead of md5 in build script cache key calculation + + Makes it possible to build on FIPS nodejs. + +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.1 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.6.0 + - @backstage/errors@1.2.3 + - @backstage/eslint-plugin@0.1.4 + - @backstage/integration@1.8.0 + - @backstage/release-manifests@0.0.11 + - @backstage/types@1.1.1 + +## 0.25.0 + +### Minor Changes + +- 3834067: Updates the ESLint config to ignore issues created by generated files in `**/src/generated/**`. + +### Patch Changes + +- 32018ff: Enable the `tsx` loader to work on Node 18.19 and up +- 0ffee55: Toned down the warning message when git is not found +- c6f3743: Added a warning when starting a standalone backend plugin that hasn't been updated to the new backend system. +- 3e358b0: Added deprecation warning for React Router v6 beta, please make sure you have migrated your apps to use React Router v6 stable as support for the beta version will be removed. See the [migration tutorial](https://backstage.io/docs/tutorials/react-router-stable-migration) for more information. +- 219d7f0: Updating template generation for scaffolder module +- 8cda3c7: Tweaked Node.js version check for when to use the new module register API with the new backend `package start` command. +- a3edc18: Updated dependency `vite-plugin-node-polyfills` to `^0.17.0`. +- 627554e: Updated dependency `@rollup/plugin-node-resolve` to `^15.0.0`. +- c07cee5: Updated dependency `@rollup/plugin-json` to `^6.0.0`. +- bd586a5: Updated dependency `bfj` to `^8.0.0`. +- 8056425: Updated dependency `@typescript-eslint/eslint-plugin` to `6.12.0`. +- 017c425: Updated dependency `@typescript-eslint/eslint-plugin` to `6.11.0`. +- 2565cc8: Updated dependency `@rollup/plugin-commonjs` to `^25.0.0`. +- 33e96e5: Switched the `@typescript-eslint/eslint-plugin` dependency back to using a `^` version range. +- 0cbb03b: Fixing regular expression ReDoS with zod packages. Upgrading to latest. ref: https://security.snyk.io/vuln/SNYK-JS-ZOD-5925617 +- Updated dependencies + - @backstage/eslint-plugin@0.1.4 + - @backstage/config-loader@1.6.0 + - @backstage/integration@1.8.0 + - @backstage/cli-node@0.2.1 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/release-manifests@0.0.11 + - @backstage/types@1.1.1 + +## 0.25.0-next.3 + +### Patch Changes + +- 219d7f0: Updating template generation for scaffolder module +- bd586a5: Updated dependency `bfj` to `^8.0.0`. +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.6.0-next.0 + - @backstage/errors@1.2.3 + - @backstage/eslint-plugin@0.1.4-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/release-manifests@0.0.11 + - @backstage/types@1.1.1 + +## 0.25.0-next.2 + +### Patch Changes + +- 32018ff: Enable the `tsx` loader to work on Node 18.19 and up +- a3edc18: Updated dependency `vite-plugin-node-polyfills` to `^0.17.0`. +- 627554e: Updated dependency `@rollup/plugin-node-resolve` to `^15.0.0`. +- c07cee5: Updated dependency `@rollup/plugin-json` to `^6.0.0`. +- 2565cc8: Updated dependency `@rollup/plugin-commonjs` to `^25.0.0`. +- Updated dependencies + - @backstage/config-loader@1.6.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/eslint-plugin@0.1.4-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/release-manifests@0.0.11 + - @backstage/types@1.1.1 + +## 0.25.0-next.1 + +### Minor Changes + +- 38340678c3: Updates the ESLint config to ignore issues created by generated files in `**/src/generated/**`. + +### Patch Changes + +- 0ffee55010: Toned down the warning message when git is not found +- c6f3743172: Added a warning when starting a standalone backend plugin that hasn't been updated to the new backend system. +- 3e358b0dff: Added deprecation warning for React Router v6 beta, please make sure you have migrated your apps to use React Router v6 stable as support for the beta version will be removed. See the [migration tutorial](https://backstage.io/docs/tutorials/react-router-stable-migration) for more information. +- 8056425e09: Updated dependency `@typescript-eslint/eslint-plugin` to `6.12.0`. +- 33e96e59e7: Switched the `@typescript-eslint/eslint-plugin` dependency back to using a `^` version range. +- Updated dependencies + - @backstage/eslint-plugin@0.1.4-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.5.3 + - @backstage/errors@1.2.3 + - @backstage/release-manifests@0.0.11 + - @backstage/types@1.1.1 + +## 0.24.1-next.0 + +### Patch Changes + +- 8cda3c72f2: Tweaked Node.js version check for when to use the new module register API with the new backend `package start` command. +- 017c425f93: Updated dependency `@typescript-eslint/eslint-plugin` to `6.11.0`. +- Updated dependencies + - @backstage/integration@1.8.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.5.3 + - @backstage/errors@1.2.3 + - @backstage/eslint-plugin@0.1.3 + - @backstage/release-manifests@0.0.11 + - @backstage/types@1.1.1 + +## 0.24.0 + +### Minor Changes + +- 8db5c3cd7a: Removed support for the `publishConfig.alphaTypes` and `.betaTypes` fields that were used together with `--experimental-type-build` to generate `/alpha` and `/beta` entry points. Use the `exports` field to achieve this instead. +- 4e36abef14: Remove support for the deprecated `--experimental-type-build` option for `package build`. + +### Patch Changes + +- 4ba4ac351f: Switch from using deprecated `@esbuild-kit/*` packages to using `tsx`. This also switches to using the new module loader `register` API when available, avoiding the experimental warning when starting backends. +- cd80ebb062: Updated dependency `vite-plugin-node-polyfills` to `^0.16.0`. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- 971dcba764: Updated dependency `@typescript-eslint/eslint-plugin` to `6.10.0`. +- 6bf7561d3c: The experimental package detection will now ignore packages that don't make `package.json` available. +- e14cbf563d: Added `EXPERIMENTAL_VITE` flag for using [vite](https://vitejs.dev) as dev server instead of Webpack +- 7cd34392f5: Ignore `stdin` when spawning backend child process for the `start` command. Fixing an issue where backend startup would hang. +- Updated dependencies + - @backstage/config-loader@1.5.3 + - @backstage/cli-node@0.2.0 + - @backstage/integration@1.7.2 + - @backstage/release-manifests@0.0.11 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/eslint-plugin@0.1.3 + - @backstage/types@1.1.1 + ## 0.24.0-next.1 ### Patch Changes diff --git a/packages/cli/config/eslint-factory.js b/packages/cli/config/eslint-factory.js index 58a9362051..3717943427 100644 --- a/packages/cli/config/eslint-factory.js +++ b/packages/cli/config/eslint-factory.js @@ -66,7 +66,7 @@ function createConfig(dir, extraConfig = {}) { ...(extraExtends ?? []), ], parser: '@typescript-eslint/parser', - plugins: ['import', ...(plugins ?? [])], + plugins: ['import', 'unused-imports', ...(plugins ?? [])], env: { jest: true, ...env, @@ -165,6 +165,23 @@ function createConfig(dir, extraConfig = {}) { ], }, }, + { + files: ['**/src/generated/**/*.ts'], + rules: { + ...tsRules, + 'no-unused-vars': 'off', + 'unused-imports/no-unused-imports': 'error', + 'unused-imports/no-unused-vars': [ + 'warn', + { + vars: 'all', + varsIgnorePattern: '^_', + args: 'none', + argsIgnorePattern: '^_', + }, + ], + }, + }, ...(overrides ?? []), ], }; diff --git a/packages/cli/config/jest.js b/packages/cli/config/jest.js index 4a8bf9694f..584a31c672 100644 --- a/packages/cli/config/jest.js +++ b/packages/cli/config/jest.js @@ -219,7 +219,7 @@ async function getProjectConfig(targetPath, extraConfig) { // If no explicit id was configured, generated one based on the configuration. if (!config.id) { const configHash = crypto - .createHash('md5') + .createHash('sha256') .update(version) .update(Buffer.alloc(1)) .update(JSON.stringify(config.transform)) diff --git a/packages/cli/config/jestSucraseTransform.js b/packages/cli/config/jestSucraseTransform.js index 64e7307cab..349b6a1d58 100644 --- a/packages/cli/config/jestSucraseTransform.js +++ b/packages/cli/config/jestSucraseTransform.js @@ -70,7 +70,7 @@ function createTransformer(config) { }; const getCacheKey = sourceText => { - return createHash('md5') + return createHash('sha256') .update(sourceText) .update(Buffer.alloc(1)) .update(sucrasePkg.version) diff --git a/packages/cli/config/jestYamlTransform.js b/packages/cli/config/jestYamlTransform.js index 1235f8a4b7..84d1d9838c 100644 --- a/packages/cli/config/jestYamlTransform.js +++ b/packages/cli/config/jestYamlTransform.js @@ -25,7 +25,7 @@ function createTransformer(config) { const getCacheKey = sourceText => { return crypto - .createHash('md5') + .createHash('sha256') .update(sourceText) .update(Buffer.alloc(1)) .update(JSON.stringify(config)) diff --git a/packages/cli/package.json b/packages/cli/package.json index 08652dc84c..a02e7474ff 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/cli", "description": "CLI for developing Backstage plugins and apps", - "version": "0.24.0-next.1", + "version": "0.25.1", "publishConfig": { "access": "public" }, @@ -46,9 +46,9 @@ "@octokit/oauth-app": "^4.2.0", "@octokit/request": "^6.0.0", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.7", - "@rollup/plugin-commonjs": "^23.0.0", - "@rollup/plugin-json": "^5.0.0", - "@rollup/plugin-node-resolve": "^13.0.6", + "@rollup/plugin-commonjs": "^25.0.0", + "@rollup/plugin-json": "^6.0.0", + "@rollup/plugin-node-resolve": "^15.0.0", "@rollup/plugin-yaml": "^4.0.0", "@spotify/eslint-config-base": "^14.0.0", "@spotify/eslint-config-react": "^14.0.0", @@ -64,11 +64,11 @@ "@swc/jest": "^0.2.22", "@types/jest": "^29.0.0", "@types/webpack-env": "^1.15.2", - "@typescript-eslint/eslint-plugin": "6.10.0", + "@typescript-eslint/eslint-plugin": "^6.12.0", "@typescript-eslint/parser": "^6.7.2", "@yarnpkg/lockfile": "^1.1.0", "@yarnpkg/parsers": "^3.0.0-rc.4", - "bfj": "^7.0.2", + "bfj": "^8.0.0", "buffer": "^6.0.3", "chalk": "^4.0.0", "chokidar": "^3.3.1", @@ -89,6 +89,7 @@ "eslint-plugin-jsx-a11y": "^6.5.1", "eslint-plugin-react": "^7.28.0", "eslint-plugin-react-hooks": "^4.3.0", + "eslint-plugin-unused-imports": "^3.0.0", "eslint-webpack-plugin": "^3.1.1", "express": "^4.17.1", "fork-ts-checker-webpack-plugin": "^7.0.0-alpha.8", @@ -129,7 +130,7 @@ "swc-loader": "^0.2.3", "tar": "^6.1.12", "terser-webpack-plugin": "^5.1.3", - "tsx": "^3.14.0", + "tsx": "^4.0.0", "util": "^0.12.3", "webpack": "^5.70.0", "webpack-dev-server": "^4.7.3", @@ -137,7 +138,7 @@ "yaml": "^2.0.0", "yml-loader": "^2.1.0", "yn": "^4.0.0", - "zod": "^3.21.4" + "zod": "^3.22.4" }, "devDependencies": { "@backstage/backend-common": "workspace:^", @@ -176,7 +177,7 @@ "@vitejs/plugin-react": "^4.0.4", "vite": "^4.4.9", "vite-plugin-html": "^3.2.0", - "vite-plugin-node-polyfills": "^0.16.0" + "vite-plugin-node-polyfills": "^0.17.0" }, "peerDependenciesMeta": { "@vitejs/plugin-react": { diff --git a/packages/cli/src/commands/start/command.ts b/packages/cli/src/commands/start/command.ts index 48122d5ac0..427f8b6efb 100644 --- a/packages/cli/src/commands/start/command.ts +++ b/packages/cli/src/commands/start/command.ts @@ -16,7 +16,7 @@ import { OptionValues } from 'commander'; import { findRoleFromCommand } from '../../lib/role'; -import { startBackend } from './startBackend'; +import { startBackend, startBackendPlugin } from './startBackend'; import { startFrontend } from './startFrontend'; export async function command(opts: OptionValues): Promise { @@ -31,10 +31,11 @@ export async function command(opts: OptionValues): Promise { switch (role) { case 'backend': + return startBackend(options); case 'backend-plugin': case 'backend-plugin-module': case 'node-library': - return startBackend(options); + return startBackendPlugin(options); case 'frontend': return startFrontend({ ...options, diff --git a/packages/cli/src/commands/start/startBackend.ts b/packages/cli/src/commands/start/startBackend.ts index 967a1108a0..25758a0939 100644 --- a/packages/cli/src/commands/start/startBackend.ts +++ b/packages/cli/src/commands/start/startBackend.ts @@ -26,17 +26,7 @@ interface StartBackendOptions { } export async function startBackend(options: StartBackendOptions) { - const hasDev = await fs.pathExists(paths.resolveTarget('dev')); - if (hasDev) { - const waitForExit = await startBackendExperimental({ - entry: 'dev/index', - checksEnabled: false, // not supported - inspectEnabled: options.inspectEnabled, - inspectBrkEnabled: options.inspectBrkEnabled, - }); - - await waitForExit(); - } else if (!process.env.LEGACY_BACKEND_START) { + if (!process.env.LEGACY_BACKEND_START) { const waitForExit = await startBackendExperimental({ entry: 'src/index', checksEnabled: false, // not supported @@ -46,12 +36,7 @@ export async function startBackend(options: StartBackendOptions) { await waitForExit(); } else { - // Cleaning dist/ before we start the dev process helps work around an issue - // where we end up with the entrypoint executing multiple times, causing - // a port bind conflict among other things. - await fs.remove(paths.resolveTarget('dist')); - - const waitForExit = await serveBackend({ + const waitForExit = await cleanDistAndServeBackend({ entry: 'src/index', checksEnabled: options.checksEnabled, inspectEnabled: options.inspectEnabled, @@ -61,3 +46,63 @@ export async function startBackend(options: StartBackendOptions) { await waitForExit(); } } + +export async function startBackendPlugin(options: StartBackendOptions) { + if (!process.env.LEGACY_BACKEND_START) { + const hasDevIndexEntry = await fs.pathExists( + paths.resolveTarget('dev', 'index.ts'), + ); + const hasSrcIndexEntry = await fs.pathExists( + paths.resolveTarget('src', 'run.ts'), + ); + + if (!hasDevIndexEntry && !hasSrcIndexEntry) { + console.warn( + hasSrcIndexEntry + ? `The 'dev' directory is missing. The plugin might not be updated for the new backend system. To run, use "LEGACY_BACKEND_START=1 yarn start".` + : `The 'dev' directory is missing. Please create a proper dev/index.ts in order to start the plugin.`, + ); + return; + } + + const waitForExit = await startBackendExperimental({ + entry: 'dev/index', + checksEnabled: false, // not supported + inspectEnabled: options.inspectEnabled, + inspectBrkEnabled: options.inspectBrkEnabled, + }); + + await waitForExit(); + } else { + const hasEntry = await fs.pathExists(paths.resolveTarget('src', 'run.ts')); + if (!hasEntry) { + console.warn( + `src/run.ts is missing. Please create the file or run the command without LEGACY_BACKEND_START`, + ); + return; + } + + const waitForExit = await cleanDistAndServeBackend({ + entry: 'src/run', + checksEnabled: options.checksEnabled, + inspectEnabled: options.inspectEnabled, + inspectBrkEnabled: options.inspectBrkEnabled, + }); + + await waitForExit(); + } +} + +async function cleanDistAndServeBackend(options: { + entry: string; + checksEnabled: boolean; + inspectEnabled: boolean; + inspectBrkEnabled: boolean; +}) { + // Cleaning dist/ before we start the dev process helps work around an issue + // where we end up with the entrypoint executing multiple times, causing + // a port bind conflict among other things. + await fs.remove(paths.resolveTarget('dist')); + + return serveBackend(options); +} diff --git a/packages/cli/src/lib/bundler/config.ts b/packages/cli/src/lib/bundler/config.ts index 542cc83ce9..a9d5c2aa67 100644 --- a/packages/cli/src/lib/bundler/config.ts +++ b/packages/cli/src/lib/bundler/config.ts @@ -55,18 +55,24 @@ export function resolveBaseUrl(config: Config): URL { async function readBuildInfo() { const timestamp = Date.now(); - let commit = 'unknown'; + let commit: string | undefined; try { commit = await runPlain('git', 'rev-parse', 'HEAD'); } catch (error) { - console.warn(`WARNING: Failed to read git commit, ${error}`); + // ignore, see below } - let gitVersion = 'unknown'; + let gitVersion: string | undefined; try { gitVersion = await runPlain('git', 'describe', '--always'); } catch (error) { - console.warn(`WARNING: Failed to describe git version, ${error}`); + // ignore, see below + } + + if (commit === undefined || gitVersion === undefined) { + console.info( + 'NOTE: Did not compute git version or commit hash, could not execute the git command line utility', + ); } const { version: packageVersion } = await fs.readJson( @@ -75,10 +81,10 @@ async function readBuildInfo() { return { cliVersion: version, - gitVersion, + gitVersion: gitVersion ?? 'unknown', packageVersion, timestamp, - commit, + commit: commit ?? 'unknown', }; } diff --git a/packages/cli/src/lib/bundler/server.ts b/packages/cli/src/lib/bundler/server.ts index bd70b2b074..2fd1385584 100644 --- a/packages/cli/src/lib/bundler/server.ts +++ b/packages/cli/src/lib/bundler/server.ts @@ -72,6 +72,20 @@ export async function serveBundle(options: ServeOptions) { ), ); } + + if ( + targetPkg.dependencies?.['react-router']?.includes('beta') || + targetPkg.dependencies?.['react-router-dom']?.includes('beta') + ) { + // eslint-disable-next-line no-console + console.warn( + chalk.yellow(` +DEPRECATION WARNING: React Router Beta is deprecated and support for it will be removed in a future release. + Please migrate to use React Router v6 stable. + See https://backstage.io/docs/tutorials/react-router-stable-migration +`), + ); + } } checkReactVersion(); diff --git a/packages/cli/src/lib/experimental/startBackendExperimental.ts b/packages/cli/src/lib/experimental/startBackendExperimental.ts index af6e33a1e4..0ca3b182b5 100644 --- a/packages/cli/src/lib/experimental/startBackendExperimental.ts +++ b/packages/cli/src/lib/experimental/startBackendExperimental.ts @@ -28,7 +28,10 @@ import { paths } from '../paths'; import spawn from 'cross-spawn'; const [nodeMajor, nodeMinor] = process.versions.node.split('.').map(Number); -const supportsModuleLoaderRegister = nodeMajor >= 20 && nodeMinor >= 6; +const supportsModuleLoaderRegister = + nodeMajor > 20 || + (nodeMajor === 20 && nodeMinor >= 6) || + (nodeMajor === 18 && nodeMinor >= 19); const loaderArgs = [ '--require', diff --git a/packages/cli/src/lib/version.ts b/packages/cli/src/lib/version.ts index 96b42fcfb7..9c19a3a8c4 100644 --- a/packages/cli/src/lib/version.ts +++ b/packages/cli/src/lib/version.ts @@ -44,8 +44,8 @@ import { version as coreComponents } from '../../../../packages/core-components/ import { version as corePluginApi } from '../../../../packages/core-plugin-api/package.json'; import { version as devUtils } from '../../../../packages/dev-utils/package.json'; import { version as testUtils } from '../../../../packages/test-utils/package.json'; +import { version as scaffolderNode } from '../../../../plugins/scaffolder-node/package.json'; import { version as theme } from '../../../../packages/theme/package.json'; -import { version as scaffolderBackend } from '../../../../plugins/scaffolder-backend/package.json'; export const packageVersions: Record = { '@backstage/backend-common': backendCommon, @@ -59,7 +59,7 @@ export const packageVersions: Record = { '@backstage/dev-utils': devUtils, '@backstage/test-utils': testUtils, '@backstage/theme': theme, - '@backstage/plugin-scaffolder-backend': scaffolderBackend, + '@backstage/plugin-scaffolder-node': scaffolderNode, }; export function findVersion() { diff --git a/packages/cli/templates/scaffolder-module/package.json.hbs b/packages/cli/templates/scaffolder-module/package.json.hbs index 618e953b74..0ebe5dd5f4 100644 --- a/packages/cli/templates/scaffolder-module/package.json.hbs +++ b/packages/cli/templates/scaffolder-module/package.json.hbs @@ -29,7 +29,7 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/plugin-scaffolder-backend": "{{versionQuery '@backstage/plugin-scaffolder-backend'}}" + "@backstage/plugin-scaffolder-node": "{{versionQuery '@backstage/plugin-scaffolder-node'}}" }, "devDependencies": { "@backstage/backend-common": "{{versionQuery '@backstage/backend-common'}}", diff --git a/packages/cli/templates/scaffolder-module/src/actions/example/example.ts b/packages/cli/templates/scaffolder-module/src/actions/example/example.ts index c04132e755..2b05c7fe38 100644 --- a/packages/cli/templates/scaffolder-module/src/actions/example/example.ts +++ b/packages/cli/templates/scaffolder-module/src/actions/example/example.ts @@ -1,4 +1,4 @@ -import { createTemplateAction } from '@backstage/plugin-scaffolder-backend'; +import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; /** * Creates an `acme:example` Scaffolder action. diff --git a/packages/config-loader/CHANGELOG.md b/packages/config-loader/CHANGELOG.md index 269c1b5c31..24f7a3addc 100644 --- a/packages/config-loader/CHANGELOG.md +++ b/packages/config-loader/CHANGELOG.md @@ -1,5 +1,67 @@ # @backstage/config-loader +## 1.6.1 + +### Patch Changes + +- 7acbb5a: Removed `mock-fs` dev dependency. +- Updated dependencies + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 1.6.1-next.0 + +### Patch Changes + +- 7acbb5a: Removed `mock-fs` dev dependency. +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 1.6.0 + +### Minor Changes + +- 24f5a85: Add "path" to `TransformFunc` context + +### Patch Changes + +- Updated dependencies + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 1.6.0-next.0 + +### Minor Changes + +- 24f5a85: Add "path" to `TransformFunc` context + +### Patch Changes + +- Updated dependencies + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 1.5.3 + +### Patch Changes + +- 22ca64f117: Correctly resolve config targets into absolute paths +- 087bab5b42: Updated dependency `typescript-json-schema` to `^0.62.0`. +- Updated dependencies + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + ## 1.5.2-next.0 ### Patch Changes diff --git a/packages/config-loader/api-report.md b/packages/config-loader/api-report.md index 9f55a27bf7..66572dd960 100644 --- a/packages/config-loader/api-report.md +++ b/packages/config-loader/api-report.md @@ -274,6 +274,7 @@ export type TransformFunc = ( value: T, context: { visibility: ConfigVisibility; + path: string; }, ) => T | undefined; ``` diff --git a/packages/config-loader/package.json b/packages/config-loader/package.json index 89d70825dd..e26a54559c 100644 --- a/packages/config-loader/package.json +++ b/packages/config-loader/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/config-loader", "description": "Config loading functionality used by Backstage backend, and CLI", - "version": "1.5.3-next.0", + "version": "1.6.1", "publishConfig": { "access": "public", "main": "dist/index.cjs.js", @@ -54,7 +54,6 @@ "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@types/json-schema-merge-allof": "^0.6.0", - "@types/mock-fs": "^4.10.0", "msw": "^1.0.0", "zen-observable": "^0.10.0" }, diff --git a/packages/config-loader/src/schema/filtering.ts b/packages/config-loader/src/schema/filtering.ts index 1b7bbf43c1..9c1c2fbda5 100644 --- a/packages/config-loader/src/schema/filtering.ts +++ b/packages/config-loader/src/schema/filtering.ts @@ -68,7 +68,7 @@ export function filterByVisibility( if (typeof jsonVal !== 'object') { if (isVisible) { if (transformFunc) { - return transformFunc(jsonVal, { visibility }); + return transformFunc(jsonVal, { visibility, path: filterPath }); } return jsonVal; } diff --git a/packages/config-loader/src/schema/types.ts b/packages/config-loader/src/schema/types.ts index dc8da64038..8f679c93fc 100644 --- a/packages/config-loader/src/schema/types.ts +++ b/packages/config-loader/src/schema/types.ts @@ -105,11 +105,22 @@ export type ValidationFunc = (configs: AppConfig[]) => ValidationResult; /** * A function used to transform primitive configuration values. * + * The "path" in the context is a JQ-style path to the current value from + * within the original object passed to filterByVisibility(). + * For example, "field.list[2]" would refer to: + * \{ + * field: [ + * "foo", + * "bar", + * "baz" -- this one + * ] + * \} + * * @public */ export type TransformFunc = ( value: T, - context: { visibility: ConfigVisibility }, + context: { visibility: ConfigVisibility; path: string }, ) => T | undefined; /** diff --git a/packages/core-app-api/CHANGELOG.md b/packages/core-app-api/CHANGELOG.md index 3ce35f99c0..9e32db5016 100644 --- a/packages/core-app-api/CHANGELOG.md +++ b/packages/core-app-api/CHANGELOG.md @@ -1,5 +1,71 @@ # @backstage/core-app-api +## 1.11.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## 1.11.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## 1.11.2 + +### Patch Changes + +- 3e358b0: Added deprecation warning for React Router v6 beta, please make sure you have migrated your apps to use React Router v6 stable as support for the beta version will be removed. See the [migration tutorial](https://backstage.io/docs/tutorials/react-router-stable-migration) for more information. +- 0cbb03b: Fixing regular expression ReDoS with zod packages. Upgrading to latest. ref: https://security.snyk.io/vuln/SNYK-JS-ZOD-5925617 +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## 1.11.2-next.1 + +### Patch Changes + +- 3e358b0dff: Added deprecation warning for React Router v6 beta, please make sure you have migrated your apps to use React Router v6 stable as support for the beta version will be removed. See the [migration tutorial](https://backstage.io/docs/tutorials/react-router-stable-migration) for more information. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## 1.11.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## 1.11.1 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 89d13e5618: Add current and default scopes when refreshing session +- 9ab0572217: Add component data `core.type` marker for `AppRouter` and `FlatRoutes`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.0 + - @backstage/version-bridge@1.0.7 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + ## 1.11.1-next.0 ### Patch Changes diff --git a/packages/core-app-api/package.json b/packages/core-app-api/package.json index 2a5a3cf0c8..f0654f7596 100644 --- a/packages/core-app-api/package.json +++ b/packages/core-app-api/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/core-app-api", "description": "Core app API used by Backstage apps", - "version": "1.11.1-next.0", + "version": "1.11.3", "publishConfig": { "access": "public" }, @@ -54,7 +54,7 @@ "prop-types": "^15.7.2", "react-use": "^17.2.4", "zen-observable": "^0.10.0", - "zod": "^3.21.4" + "zod": "^3.22.4" }, "peerDependencies": { "react": "^16.13.1 || ^17.0.0 || ^18.0.0", diff --git a/packages/core-app-api/src/app/AppManager.tsx b/packages/core-app-api/src/app/AppManager.tsx index 37407283b5..c8cdfd7c23 100644 --- a/packages/core-app-api/src/app/AppManager.tsx +++ b/packages/core-app-api/src/app/AppManager.tsx @@ -240,11 +240,21 @@ export class AppManager implements BackstageApp { ); const { routing, featureFlags, routeBindings } = useMemo(() => { + const usesReactRouterBeta = isReactRouterBeta(); + if (usesReactRouterBeta) { + // eslint-disable-next-line no-console + console.warn(` +DEPRECATION WARNING: React Router Beta is deprecated and support for it will be removed in a future release. + Please migrate to use React Router v6 stable. + See https://backstage.io/docs/tutorials/react-router-stable-migration +`); + } + const result = traverseElementTree({ root: children, discoverers: [childDiscoverer, routeElementDiscoverer], collectors: { - routing: isReactRouterBeta() + routing: usesReactRouterBeta ? routingV1Collector : routingV2Collector, collectedPlugins: pluginCollector, diff --git a/packages/core-compat-api/CHANGELOG.md b/packages/core-compat-api/CHANGELOG.md index 174d695533..21c7782627 100644 --- a/packages/core-compat-api/CHANGELOG.md +++ b/packages/core-compat-api/CHANGELOG.md @@ -1,5 +1,128 @@ # @backstage/core-compat-api +## 0.1.1 + +### Patch Changes + +- 4c1f50c: Make `convertLegacyApp` wrap discovered routes with `compatWrapper`. +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-plugin-api@1.8.2 + - @backstage/core-app-api@1.11.3 + - @backstage/version-bridge@1.0.7 + +## 0.1.1-next.2 + +### Patch Changes + +- 4c1f50c: Make `convertLegacyApp` wrap discovered routes with `compatWrapper`. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.1-next.2 + +## 0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-app-api@1.11.3-next.0 + - @backstage/frontend-plugin-api@0.4.1-next.1 + - @backstage/version-bridge@1.0.7 + +## 0.1.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.1-next.0 + - @backstage/core-app-api@1.11.2 + - @backstage/core-plugin-api@1.8.1 + - @backstage/version-bridge@1.0.7 + +## 0.1.0 + +### Minor Changes + +- cf5cc4c: Discover plugins and routes recursively beneath the root routes in `collectLecacyRoutes` +- af7bc3e: Switched all core extensions to instead use the namespace `'app'`. +- f63dd72: The `collectLegacyRoutes` has been removed and is replaced by `convertLegacyApp` now being able to convert a `FlatRoutes` element directly. + +### Patch Changes + +- 03d0b6d: Added `convertLegacyRouteRef` utility to convert existing route refs to be used with the new experimental packages. +- a379243: Leverage the new `FrontendFeature` type to simplify interfaces +- 8226442: Added `compatWrapper`, which can be used to wrap any React element to provide bi-directional interoperability between the `@backstage/core-*-api` and `@backstage/frontend-*-api` APIs. +- 8f5d6c1: Updates to match the new extension input wrapping. +- c219b16: Made package public so it can be published +- b7adf24: Delete alpha DI compatibility helper for components, migrating components should be simple without a helper. +- 046e443: Updates for compatibility with the new extension IDs. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/frontend-plugin-api@0.4.0 + - @backstage/core-app-api@1.11.2 + - @backstage/version-bridge@1.0.7 + +## 0.1.0-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/frontend-plugin-api@0.4.0-next.3 + - @backstage/version-bridge@1.0.7 + +## 0.1.0-next.2 + +### Minor Changes + +- cf5cc4c: Discover plugins and routes recursively beneath the root routes in `collectLecacyRoutes` + +### Patch Changes + +- 8226442: Added `compatWrapper`, which can be used to wrap any React element to provide bi-directional interoperability between the `@backstage/core-*-api` and `@backstage/frontend-*-api` APIs. +- 8f5d6c1: Updates to match the new extension input wrapping. +- b7adf24: Delete alpha DI compatibility helper for components, migrating components should be simple without a helper. +- 046e443: Updates for compatibility with the new extension IDs. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.2 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/version-bridge@1.0.7 + +## 0.0.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/core-app-api@1.11.2-next.1 + +## 0.0.1-next.0 + +### Patch Changes + +- c219b168aa: Made package public so it can be published + +## 0.0.2-next.0 + +### Patch Changes + +- 03d0b6dcdc: Added `convertLegacyRouteRef` utility to convert existing route refs to be used with the new experimental packages. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/frontend-plugin-api@0.3.1-next.0 + - @backstage/core-app-api@1.11.2-next.0 + +## 0.0.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.3.0 + - @backstage/core-plugin-api@1.8.0 + ## 0.0.1-next.2 ### Patch Changes diff --git a/packages/core-compat-api/api-report.md b/packages/core-compat-api/api-report.md index 3dd2eb6b22..494747be60 100644 --- a/packages/core-compat-api/api-report.md +++ b/packages/core-compat-api/api-report.md @@ -3,21 +3,42 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts -/// - -import { BackstagePlugin } from '@backstage/frontend-plugin-api'; -import { ExtensionOverrides } from '@backstage/frontend-plugin-api'; +import { AnyRouteRefParams } from '@backstage/core-plugin-api'; +import { ExternalRouteRef } from '@backstage/core-plugin-api'; +import { ExternalRouteRef as ExternalRouteRef_2 } from '@backstage/frontend-plugin-api'; +import { FrontendFeature } from '@backstage/frontend-plugin-api'; import { default as React_2 } from 'react'; +import { ReactNode } from 'react'; +import { RouteRef } from '@backstage/core-plugin-api'; +import { RouteRef as RouteRef_2 } from '@backstage/frontend-plugin-api'; +import { SubRouteRef } from '@backstage/core-plugin-api'; +import { SubRouteRef as SubRouteRef_2 } from '@backstage/frontend-plugin-api'; -// @public (undocumented) -export function collectLegacyRoutes( - flatRoutesElement: JSX.Element, -): BackstagePlugin[]; +// @public +export function compatWrapper(element: ReactNode): React_2.JSX.Element; // @public (undocumented) export function convertLegacyApp( rootElement: React_2.JSX.Element, -): (ExtensionOverrides | BackstagePlugin)[]; +): FrontendFeature[]; + +// @public +export function convertLegacyRouteRef( + ref: RouteRef, +): RouteRef_2; + +// @public +export function convertLegacyRouteRef( + ref: SubRouteRef, +): SubRouteRef_2; + +// @public +export function convertLegacyRouteRef< + TParams extends AnyRouteRefParams, + TOptional extends boolean, +>( + ref: ExternalRouteRef, +): ExternalRouteRef_2; // (No @packageDocumentation comment for this package) ``` diff --git a/packages/core-compat-api/package.json b/packages/core-compat-api/package.json index a9bdfe2ff9..99b705bfcf 100644 --- a/packages/core-compat-api/package.json +++ b/packages/core-compat-api/package.json @@ -1,10 +1,9 @@ { "name": "@backstage/core-compat-api", - "version": "0.0.1-next.2", + "version": "0.1.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", - "private": true, "publishConfig": { "access": "public", "main": "dist/index.esm.js", @@ -23,23 +22,29 @@ "prepack": "backstage-cli package prepack", "postpack": "backstage-cli package postpack" }, - "devDependencies": { - "@backstage/cli": "workspace:^", + "dependencies": { "@backstage/core-app-api": "workspace:^", - "@backstage/plugin-puppetdb": "workspace:^", - "@backstage/plugin-stackstorm": "workspace:^", - "@oriflame/backstage-plugin-score-card": "^0.7.0", - "@testing-library/jest-dom": "^6.0.0" + "@backstage/core-plugin-api": "workspace:^", + "@backstage/frontend-plugin-api": "workspace:^", + "@backstage/version-bridge": "workspace:^", + "@types/react": "^16.13.1 || ^17.0.0" }, - "files": [ - "dist" - ], "peerDependencies": { "react": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, - "dependencies": { - "@backstage/core-plugin-api": "workspace:^", - "@backstage/frontend-plugin-api": "workspace:^" - } + "devDependencies": { + "@backstage/cli": "workspace:^", + "@backstage/frontend-app-api": "workspace:^", + "@backstage/frontend-test-utils": "workspace:^", + "@backstage/plugin-catalog": "workspace:^", + "@backstage/plugin-puppetdb": "workspace:^", + "@backstage/plugin-stackstorm": "workspace:^", + "@oriflame/backstage-plugin-score-card": "^0.7.0", + "@testing-library/jest-dom": "^6.0.0", + "@testing-library/react": "^14.0.0" + }, + "files": [ + "dist" + ] } diff --git a/packages/core-compat-api/src/collectLegacyRoutes.test.tsx b/packages/core-compat-api/src/collectLegacyRoutes.test.tsx index 85fed83e8c..240aa33e2c 100644 --- a/packages/core-compat-api/src/collectLegacyRoutes.test.tsx +++ b/packages/core-compat-api/src/collectLegacyRoutes.test.tsx @@ -15,13 +15,31 @@ */ import { FlatRoutes } from '@backstage/core-app-api'; +import { + CatalogEntityPage, + CatalogIndexPage, + EntityAboutCard, + EntityLayout, + EntitySwitch, + isKind, +} from '@backstage/plugin-catalog'; import { PuppetDbPage } from '@backstage/plugin-puppetdb'; import { StackstormPage } from '@backstage/plugin-stackstorm'; import { ScoreBoardPage } from '@oriflame/backstage-plugin-score-card'; -import React from 'react'; -import { Route } from 'react-router-dom'; +import React, { Fragment } from 'react'; +import { Route, Routes } from 'react-router-dom'; import { collectLegacyRoutes } from './collectLegacyRoutes'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { toInternalBackstagePlugin } from '../../frontend-plugin-api/src/wiring/createPlugin'; +import { + createPlugin, + createRoutableExtension, + createRouteRef, + useApp, +} from '@backstage/core-plugin-api'; +import { createSpecializedApp } from '@backstage/frontend-app-api'; +import { render, screen } from '@testing-library/react'; describe('collectLegacyRoutes', () => { it('should collect legacy routes', () => { @@ -37,7 +55,7 @@ describe('collectLegacyRoutes', () => { expect( collected.map(p => ({ id: p.id, - extensions: p.extensions.map(e => ({ + extensions: toInternalBackstagePlugin(p).extensions.map(e => ({ id: e.id, attachTo: e.attachTo, disabled: e.disabled, @@ -49,14 +67,14 @@ describe('collectLegacyRoutes', () => { id: 'score-card', extensions: [ { - id: 'plugin.score-card.page', - attachTo: { id: 'core.routes', input: 'routes' }, + id: 'page:score-card', + attachTo: { id: 'app/routes', input: 'routes' }, disabled: false, defaultConfig: { path: 'score-board' }, }, { - id: 'apis.plugin.scoringdata.service', - attachTo: { id: 'core', input: 'apis' }, + id: 'api:plugin.scoringdata.service', + attachTo: { id: 'app', input: 'apis' }, disabled: false, }, ], @@ -65,14 +83,14 @@ describe('collectLegacyRoutes', () => { id: 'stackstorm', extensions: [ { - id: 'plugin.stackstorm.page', - attachTo: { id: 'core.routes', input: 'routes' }, + id: 'page:stackstorm', + attachTo: { id: 'app/routes', input: 'routes' }, disabled: false, defaultConfig: { path: 'stackstorm' }, }, { - id: 'apis.plugin.stackstorm.service', - attachTo: { id: 'core', input: 'apis' }, + id: 'api:plugin.stackstorm.service', + attachTo: { id: 'app', input: 'apis' }, disabled: false, }, ], @@ -81,24 +99,184 @@ describe('collectLegacyRoutes', () => { id: 'puppetDb', extensions: [ { - id: 'plugin.puppetDb.page', - attachTo: { id: 'core.routes', input: 'routes' }, + id: 'page:puppetDb', + attachTo: { id: 'app/routes', input: 'routes' }, disabled: false, defaultConfig: { path: 'puppetdb' }, }, { - id: 'plugin.puppetDb.page2', - attachTo: { id: 'core.routes', input: 'routes' }, + id: 'page:puppetDb/1', + attachTo: { id: 'app/routes', input: 'routes' }, disabled: false, defaultConfig: { path: 'puppetdb' }, }, { - id: 'apis.plugin.puppetdb.service', - attachTo: { id: 'core', input: 'apis' }, + id: 'api:plugin.puppetdb.service', + attachTo: { id: 'app', input: 'apis' }, disabled: false, }, ], }, ]); }); + + it('supports recursion into children, including passing through fragments', () => { + const collected = collectLegacyRoutes( + + } /> + } + > + + + + + } + /> + + + + + + + + + + + + + + + + , + ); + + expect( + collected.map(p => ({ + id: p.id, + extensions: toInternalBackstagePlugin(p).extensions.map(e => ({ + id: e.id, + attachTo: e.attachTo, + disabled: e.disabled, + defaultConfig: e.configSchema?.parse({}), + })), + })), + ).toEqual([ + { + id: 'catalog', + extensions: [ + { + id: 'page:catalog', + attachTo: { id: 'app/routes', input: 'routes' }, + disabled: false, + defaultConfig: { path: 'catalog' }, + }, + { + id: 'page:catalog/1', + attachTo: { id: 'app/routes', input: 'routes' }, + defaultConfig: { path: 'catalog/:namespace/:kind/:name' }, + disabled: false, + }, + { + id: 'routing-shim:catalog/2', + attachTo: { + id: 'page:catalog/1', + input: 'childRoutingShims', + }, + defaultConfig: undefined, + disabled: false, + }, + { + id: 'routing-shim:catalog/3', + attachTo: { + id: 'routing-shim:catalog/2', + input: 'childRoutingShims', + }, + defaultConfig: undefined, + disabled: false, + }, + { + id: 'routing-shim:catalog/4', + attachTo: { + id: 'routing-shim:catalog/3', + input: 'childRoutingShims', + }, + defaultConfig: undefined, + disabled: false, + }, + { + id: 'api:plugin.catalog.service', + attachTo: { + id: 'app', + input: 'apis', + }, + defaultConfig: undefined, + disabled: false, + }, + { + id: 'api:catalog-react.starred-entities', + attachTo: { + id: 'app', + input: 'apis', + }, + defaultConfig: undefined, + disabled: false, + }, + { + id: 'api:plugin.catalog.entity-presentation', + attachTo: { + id: 'app', + input: 'apis', + }, + defaultConfig: undefined, + disabled: false, + }, + ], + }, + { + id: 'score-card', + extensions: [ + { + id: 'api:plugin.scoringdata.service', + attachTo: { id: 'app', input: 'apis' }, + disabled: false, + }, + ], + }, + ]); + }); + + it('should make legacy APIs available', async () => { + const plugin = createPlugin({ + id: 'test', + }); + const routeRef = createRouteRef({ id: 'test' }); + const Page = plugin.provide( + createRoutableExtension({ + name: 'Test', + mountPoint: routeRef, + component: () => + Promise.resolve(() => { + const app = useApp(); + return
plugins: {app.getPlugins().map(p => p.getId())}
; + }), + }), + ); + + const features = collectLegacyRoutes( + + } /> + , + ); + + render(createSpecializedApp({ features }).createRoot()); + + await expect( + screen.findByText('plugins: test'), + ).resolves.toBeInTheDocument(); + }); }); diff --git a/packages/core-compat-api/src/collectLegacyRoutes.tsx b/packages/core-compat-api/src/collectLegacyRoutes.tsx index 8178de2876..4d560b81d5 100644 --- a/packages/core-compat-api/src/collectLegacyRoutes.tsx +++ b/packages/core-compat-api/src/collectLegacyRoutes.tsx @@ -14,21 +14,26 @@ * limitations under the License. */ -import React, { ReactNode } from 'react'; -import { - Extension, - createApiExtension, - createPageExtension, - createPlugin, - BackstagePlugin, -} from '@backstage/frontend-plugin-api'; -import { Route, Routes } from 'react-router-dom'; import { + AnyRouteRefParams, BackstagePlugin as LegacyBackstagePlugin, RouteRef, getComponentData, } from '@backstage/core-plugin-api'; -import { convertLegacyRouteRef } from '@backstage/core-plugin-api/alpha'; +import { + BackstagePlugin, + ExtensionDefinition, + coreExtensionData, + createApiExtension, + createExtension, + createExtensionInput, + createPageExtension, + createPlugin, +} from '@backstage/frontend-plugin-api'; +import React, { Children, ReactNode, isValidElement } from 'react'; +import { Route, Routes } from 'react-router-dom'; +import { convertLegacyRouteRef } from './convertLegacyRouteRef'; +import { compatWrapper } from './compatWrapper'; /* @@ -58,83 +63,185 @@ Existing tasks: */ -/** @public */ +// Creates a shim extension whose purpose is to build up the tree (anchored at +// the root page) of paths/routeRefs so that the app can bind them properly. +function makeRoutingShimExtension(options: { + name: string; + parentExtensionId: string; + routePath?: string; + routeRef?: RouteRef; +}) { + const { name, parentExtensionId, routePath, routeRef } = options; + return createExtension({ + kind: 'routing-shim', + name, + attachTo: { id: parentExtensionId, input: 'childRoutingShims' }, + inputs: { + childRoutingShims: createExtensionInput({ + routePath: coreExtensionData.routePath.optional(), + routeRef: coreExtensionData.routeRef.optional(), + }), + }, + output: { + routePath: coreExtensionData.routePath.optional(), + routeRef: coreExtensionData.routeRef.optional(), + }, + factory: () => ({ + routePath, + routeRef: routeRef ? convertLegacyRouteRef(routeRef) : undefined, + }), + }); +} + +function visitRouteChildren(options: { + children: ReactNode; + parentExtensionId: string; + context: { + pluginId: string; + extensions: ExtensionDefinition[]; + getUniqueName: () => string; + discoverPlugin: (plugin: LegacyBackstagePlugin) => void; + }; +}): void { + const { children, parentExtensionId, context } = options; + const { pluginId, extensions, getUniqueName, discoverPlugin } = context; + + Children.forEach(children, node => { + if (!isValidElement(node)) { + return; + } + + const plugin = getComponentData(node, 'core.plugin'); + const routeRef = getComponentData>( + node, + 'core.mountPoint', + ); + const routePath: string | undefined = node.props?.path; + + if (plugin) { + // We just mark the plugin as discovered, but don't change the context + discoverPlugin(plugin); + } + + let nextParentExtensionId = parentExtensionId; + if (routeRef || routePath) { + const nextParentExtensionName = getUniqueName(); + nextParentExtensionId = `routing-shim:${pluginId}/${nextParentExtensionName}`; + extensions.push( + makeRoutingShimExtension({ + name: nextParentExtensionName, + parentExtensionId, + routePath, + routeRef, + }), + ); + } + + visitRouteChildren({ + children: node.props.children, + parentExtensionId: nextParentExtensionId, + context, + }); + }); +} + +/** @internal */ export function collectLegacyRoutes( flatRoutesElement: JSX.Element, ): BackstagePlugin[] { - const createdPluginIds = new Map< + const pluginExtensions = new Map< LegacyBackstagePlugin, - Extension[] + ExtensionDefinition[] >(); + const getUniqueName = (() => { + let currentIndex = 1; + return () => String(currentIndex++); + })(); + + const getPluginExtensions = (plugin: LegacyBackstagePlugin) => { + let extensions = pluginExtensions.get(plugin); + if (!extensions) { + extensions = []; + pluginExtensions.set(plugin, extensions); + } + return extensions; + }; + React.Children.forEach( flatRoutesElement.props.children, (route: ReactNode) => { - if (!React.isValidElement(route)) { - return; - } - // TODO(freben): Handle feature flag and permissions framework wrapper elements - if (route.type !== Route) { + if (!React.isValidElement(route) || route.type !== Route) { return; } const routeElement = route.props.element; - - // TODO: to support deeper extension component, e.g. hidden within , use https://github.com/backstage/backstage/blob/518a34646b79ec2028cc0ed6bc67d4366c51c4d6/packages/core-app-api/src/routing/collectors.tsx#L69 + const path: string | undefined = route.props.path; const plugin = getComponentData( routeElement, 'core.plugin', ); - if (!plugin) { - return; - } - const routeRef = getComponentData( routeElement, 'core.mountPoint', ); + if (!plugin || !path) { + return; + } - const pluginId = plugin.getId(); + const extensions = getPluginExtensions(plugin); + const pageExtensionName = extensions.length ? getUniqueName() : undefined; + const pageExtensionId = `page:${plugin.getId()}${ + pageExtensionName ? `/${pageExtensionName}` : pageExtensionName + }`; - const detectedExtensions = - createdPluginIds.get(plugin) ?? new Array>(); - createdPluginIds.set(plugin, detectedExtensions); - - const path: string = route.props.path; - - detectedExtensions.push( + extensions.push( createPageExtension({ - id: `plugin.${pluginId}.page${ - detectedExtensions.length ? detectedExtensions.length + 1 : '' - }`, + name: pageExtensionName, defaultPath: path[0] === '/' ? path.slice(1) : path, routeRef: routeRef ? convertLegacyRouteRef(routeRef) : undefined, - + inputs: { + childRoutingShims: createExtensionInput({ + routePath: coreExtensionData.routePath.optional(), + routeRef: coreExtensionData.routeRef.optional(), + }), + }, loader: async () => - route.props.children ? ( - - - - - - ) : ( - routeElement + compatWrapper( + route.props.children ? ( + + + + + + ) : ( + routeElement + ), ), }), ); + + visitRouteChildren({ + children: route.props.children, + parentExtensionId: pageExtensionId, + context: { + pluginId: plugin.getId(), + extensions, + getUniqueName, + discoverPlugin: getPluginExtensions, + }, + }); }, ); - return Array.from(createdPluginIds).map(([plugin, extensions]) => + return Array.from(pluginExtensions).map(([plugin, extensions]) => createPlugin({ id: plugin.getId(), extensions: [ ...extensions, ...Array.from(plugin.getApis()).map(factory => - createApiExtension({ - factory, - }), + createApiExtension({ factory }), ), ], }), diff --git a/packages/core-compat-api/src/compatWrapper/BackwardsCompatProvider.tsx b/packages/core-compat-api/src/compatWrapper/BackwardsCompatProvider.tsx new file mode 100644 index 0000000000..099993a392 --- /dev/null +++ b/packages/core-compat-api/src/compatWrapper/BackwardsCompatProvider.tsx @@ -0,0 +1,129 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, { useMemo } from 'react'; +import { ReactNode } from 'react'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { AppContextProvider } from '../../../core-app-api/src/app/AppContext'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { + components as defaultComponents, + icons as defaultIcons, +} from '../../../app-defaults/src/defaults'; +import { + BackstagePlugin as NewBackstagePlugin, + appTreeApiRef, + useApi, +} from '@backstage/frontend-plugin-api'; +import { + AppComponents, + IconComponent, + BackstagePlugin as LegacyBackstagePlugin, +} from '@backstage/core-plugin-api'; +import { getOrCreateGlobalSingleton } from '@backstage/version-bridge'; + +// Make sure that we only convert each new plugin instance to its legacy equivalent once +const legacyPluginStore = getOrCreateGlobalSingleton( + 'legacy-plugin-compatibility-store', + () => new WeakMap(), +); + +function toLegacyPlugin(plugin: NewBackstagePlugin): LegacyBackstagePlugin { + let legacy = legacyPluginStore.get(plugin); + if (legacy) { + return legacy; + } + + const errorMsg = 'Not implemented in legacy plugin compatibility layer'; + const notImplemented = () => { + throw new Error(errorMsg); + }; + + legacy = { + getId(): string { + return plugin.id; + }, + get routes() { + return {}; + }, + get externalRoutes() { + return {}; + }, + getApis: notImplemented, + getFeatureFlags: notImplemented, + provide: notImplemented, + }; + + legacyPluginStore.set(plugin, legacy); + return legacy; +} + +// Recreates the old AppContext APIs using the various new APIs that replaced it +function LegacyAppContextProvider(props: { children: ReactNode }) { + const appTreeApi = useApi(appTreeApiRef); + + const appContext = useMemo(() => { + const { tree } = appTreeApi.getTree(); + + let gatheredPlugins: LegacyBackstagePlugin[] | undefined = undefined; + + return { + getPlugins(): LegacyBackstagePlugin[] { + if (gatheredPlugins) { + return gatheredPlugins; + } + + const pluginSet = new Set(); + for (const node of tree.nodes.values()) { + const plugin = node.spec.source; + if (plugin) { + pluginSet.add(toLegacyPlugin(plugin)); + } + } + gatheredPlugins = Array.from(pluginSet); + + return gatheredPlugins; + }, + + // TODO: Grab these from new API once it exists + getSystemIcon(key: string): IconComponent | undefined { + return key in defaultIcons + ? defaultIcons[key as keyof typeof defaultIcons] + : undefined; + }, + + // TODO: Grab these from new API once it exists + getSystemIcons(): Record { + return defaultIcons; + }, + + // TODO: Grab these from new API once it exists + getComponents(): AppComponents { + return defaultComponents; + }, + }; + }, [appTreeApi]); + + return ( + + {props.children} + + ); +} + +export function BackwardsCompatProvider(props: { children: ReactNode }) { + return {props.children}; +} diff --git a/packages/core-compat-api/src/compatWrapper/ForwardsCompatProvider.tsx b/packages/core-compat-api/src/compatWrapper/ForwardsCompatProvider.tsx new file mode 100644 index 0000000000..5544862aee --- /dev/null +++ b/packages/core-compat-api/src/compatWrapper/ForwardsCompatProvider.tsx @@ -0,0 +1,23 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { ReactNode } from 'react'; + +export function ForwardsCompatProvider(props: { children: ReactNode }) { + // TODO(Rugvip): Implement + return <>{props.children}; +} diff --git a/packages/core-compat-api/src/compatWrapper/compatWrapper.test.tsx b/packages/core-compat-api/src/compatWrapper/compatWrapper.test.tsx new file mode 100644 index 0000000000..b2ad7f3d0c --- /dev/null +++ b/packages/core-compat-api/src/compatWrapper/compatWrapper.test.tsx @@ -0,0 +1,67 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { + coreExtensionData, + createExtension, +} from '@backstage/frontend-plugin-api'; +import { createExtensionTester } from '@backstage/frontend-test-utils'; +import { screen } from '@testing-library/react'; +import { compatWrapper } from './compatWrapper'; +import { useApp } from '@backstage/core-plugin-api'; + +describe('BackwardsCompatProvider', () => { + it('should convert the app context', () => { + // TODO(Rugvip): Replace with the new renderInTestApp once it's available, and have some plugins + createExtensionTester( + createExtension({ + attachTo: { id: 'ignored', input: 'ignored' }, + output: { + element: coreExtensionData.reactElement, + }, + factory() { + function Component() { + const app = useApp(); + return ( +
+ plugins: + {app + .getPlugins() + .map(p => p.getId()) + .join(', ')} + {'\n'} + components: {Object.keys(app.getComponents()).join(', ')} + {'\n'} + icons: {Object.keys(app.getSystemIcons()).join(', ')} +
+ ); + } + + return { + element: compatWrapper(), + }; + }, + }), + ).render(); + + expect(screen.getByTestId('ctx').textContent).toMatchInlineSnapshot(` + "plugins: + components: Progress, Router, NotFoundErrorPage, BootErrorPage, ErrorBoundaryFallback + icons: brokenImage, catalog, scaffolder, techdocs, search, chat, dashboard, docs, email, github, group, help, kind:api, kind:component, kind:domain, kind:group, kind:location, kind:system, kind:user, kind:resource, kind:template, user, warning" + `); + }); +}); diff --git a/packages/core-compat-api/src/compatWrapper/compatWrapper.tsx b/packages/core-compat-api/src/compatWrapper/compatWrapper.tsx new file mode 100644 index 0000000000..cd7378a384 --- /dev/null +++ b/packages/core-compat-api/src/compatWrapper/compatWrapper.tsx @@ -0,0 +1,42 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { useVersionedContext } from '@backstage/version-bridge'; +import { ReactNode } from 'react'; +import { BackwardsCompatProvider } from './BackwardsCompatProvider'; +import { ForwardsCompatProvider } from './ForwardsCompatProvider'; + +function BidirectionalCompatProvider(props: { children: ReactNode }) { + const isInNewApp = !useVersionedContext<{ 1: unknown }>('app-context'); + + if (isInNewApp) { + return ; + } + + return ; +} + +/** + * Wraps a React element in a bidirectional compatibility provider, allow APIs + * from `@backstage/core-plugin-api` to be used in an app from `@backstage/frontend-app-api`, + * and APIs from `@backstage/frontend-plugin-api` to be used in an app from `@backstage/core-app-api`. + * + * @public + */ +export function compatWrapper(element: ReactNode) { + return {element}; +} diff --git a/packages/core-compat-api/src/compatWrapper/index.ts b/packages/core-compat-api/src/compatWrapper/index.ts new file mode 100644 index 0000000000..42a8ff6dd4 --- /dev/null +++ b/packages/core-compat-api/src/compatWrapper/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 { compatWrapper } from './compatWrapper'; diff --git a/packages/core-compat-api/src/convertLegacyApp.test.tsx b/packages/core-compat-api/src/convertLegacyApp.test.tsx index 0f1f6145c9..ef65603c85 100644 --- a/packages/core-compat-api/src/convertLegacyApp.test.tsx +++ b/packages/core-compat-api/src/convertLegacyApp.test.tsx @@ -59,14 +59,14 @@ describe('convertLegacyApp', () => { id: 'score-card', extensions: [ { - id: 'plugin.score-card.page', - attachTo: { id: 'core.routes', input: 'routes' }, + id: 'page:score-card', + attachTo: { id: 'app/routes', input: 'routes' }, disabled: false, defaultConfig: { path: 'score-board' }, }, { - id: 'apis.plugin.scoringdata.service', - attachTo: { id: 'core', input: 'apis' }, + id: 'api:plugin.scoringdata.service', + attachTo: { id: 'app', input: 'apis' }, disabled: false, }, ], @@ -75,14 +75,14 @@ describe('convertLegacyApp', () => { id: 'stackstorm', extensions: [ { - id: 'plugin.stackstorm.page', - attachTo: { id: 'core.routes', input: 'routes' }, + id: 'page:stackstorm', + attachTo: { id: 'app/routes', input: 'routes' }, disabled: false, defaultConfig: { path: 'stackstorm' }, }, { - id: 'apis.plugin.stackstorm.service', - attachTo: { id: 'core', input: 'apis' }, + id: 'api:plugin.stackstorm.service', + attachTo: { id: 'app', input: 'apis' }, disabled: false, }, ], @@ -91,20 +91,20 @@ describe('convertLegacyApp', () => { id: 'puppetDb', extensions: [ { - id: 'plugin.puppetDb.page', - attachTo: { id: 'core.routes', input: 'routes' }, + id: 'page:puppetDb', + attachTo: { id: 'app/routes', input: 'routes' }, disabled: false, defaultConfig: { path: 'puppetdb' }, }, { - id: 'plugin.puppetDb.page2', - attachTo: { id: 'core.routes', input: 'routes' }, + id: 'page:puppetDb/1', + attachTo: { id: 'app/routes', input: 'routes' }, disabled: false, defaultConfig: { path: 'puppetdb' }, }, { - id: 'apis.plugin.puppetdb.service', - attachTo: { id: 'core', input: 'apis' }, + id: 'api:plugin.puppetdb.service', + attachTo: { id: 'app', input: 'apis' }, disabled: false, }, ], @@ -113,17 +113,50 @@ describe('convertLegacyApp', () => { id: undefined, extensions: [ { - id: 'core.layout', - attachTo: { id: 'core', input: 'root' }, + id: 'app/layout', + attachTo: { id: 'app', input: 'root' }, disabled: false, }, { - id: 'core.nav', - attachTo: { id: 'core.layout', input: 'nav' }, + id: 'app/nav', + attachTo: { id: 'app/layout', input: 'nav' }, disabled: true, }, ], }, ]); }); + + it('should find and extract just routes', () => { + const collected = convertLegacyApp( + + } /> + } /> + } /> + } /> + , + ); + + expect( + collected.map((p: any /* TODO */) => ({ + id: p.id, + extensions: p.extensions.map((e: any) => ({ + id: e.id, + attachTo: e.attachTo, + disabled: e.disabled, + defaultConfig: e.configSchema?.parse({}), + })), + })), + ).toEqual([ + expect.objectContaining({ + id: 'score-card', + }), + expect.objectContaining({ + id: 'stackstorm', + }), + expect.objectContaining({ + id: 'puppetDb', + }), + ]); + }); }); diff --git a/packages/core-compat-api/src/convertLegacyApp.ts b/packages/core-compat-api/src/convertLegacyApp.ts index 93521b3955..72ce4b5e61 100644 --- a/packages/core-compat-api/src/convertLegacyApp.ts +++ b/packages/core-compat-api/src/convertLegacyApp.ts @@ -22,8 +22,7 @@ import React, { isValidElement, } from 'react'; import { - BackstagePlugin, - ExtensionOverrides, + FrontendFeature, coreExtensionData, createExtension, createExtensionInput, @@ -61,7 +60,11 @@ function selectChildren( /** @public */ export function convertLegacyApp( rootElement: React.JSX.Element, -): (ExtensionOverrides | BackstagePlugin)[] { +): FrontendFeature[] { + if (getComponentData(rootElement, 'core.type') === 'FlatRoutes') { + return collectLegacyRoutes(rootElement); + } + const appRouterEls = selectChildren( rootElement, el => getComponentData(el, 'core.type') === 'AppRouter', @@ -100,8 +103,9 @@ export function convertLegacyApp( const [routesEl] = routesEls; const CoreLayoutOverride = createExtension({ - id: 'core.layout', - attachTo: { id: 'core', input: 'root' }, + namespace: 'app', + name: 'layout', + attachTo: { id: 'app', input: 'root' }, inputs: { content: createExtensionInput( { @@ -116,13 +120,18 @@ export function convertLegacyApp( factory({ inputs }) { // Clone the root element, this replaces the FlatRoutes declared in the app with out content input return { - element: React.cloneElement(rootEl, undefined, inputs.content.element), + element: React.cloneElement( + rootEl, + undefined, + inputs.content.output.element, + ), }; }, }); const CoreNavOverride = createExtension({ - id: 'core.nav', - attachTo: { id: 'core.layout', input: 'nav' }, + namespace: 'app', + name: 'nav', + attachTo: { id: 'app/layout', input: 'nav' }, output: {}, factory: () => ({}), disabled: true, diff --git a/packages/core-plugin-api/src/routing/convertLegacyRouteRef.ts b/packages/core-compat-api/src/convertLegacyRouteRef.ts similarity index 75% rename from packages/core-plugin-api/src/routing/convertLegacyRouteRef.ts rename to packages/core-compat-api/src/convertLegacyRouteRef.ts index 940a4174a9..c5ee603722 100644 --- a/packages/core-plugin-api/src/routing/convertLegacyRouteRef.ts +++ b/packages/core-compat-api/src/convertLegacyRouteRef.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import { routeRefType } from './types'; import { RouteRef as LegacyRouteRef, SubRouteRef as LegacySubRouteRef, @@ -22,9 +21,9 @@ import { AnyRouteRefParams, } from '@backstage/core-plugin-api'; -// Relative imports to avoid dependency, at least for now - // eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { routeRefType } from '../../core-plugin-api/src/routing/types'; + import { RouteRef, SubRouteRef, @@ -32,29 +31,14 @@ import { createRouteRef, createSubRouteRef, createExternalRouteRef, -} from '../../../frontend-plugin-api/src/routing'; +} from '@backstage/frontend-plugin-api'; + // eslint-disable-next-line @backstage/no-relative-monorepo-imports -import { toInternalRouteRef } from '../../../frontend-plugin-api/src/routing/RouteRef'; +import { toInternalRouteRef } from '../../frontend-plugin-api/src/routing/RouteRef'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports -import { toInternalSubRouteRef } from '../../../frontend-plugin-api/src/routing/SubRouteRef'; +import { toInternalSubRouteRef } from '../../frontend-plugin-api/src/routing/SubRouteRef'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports -import { toInternalExternalRouteRef } from '../../../frontend-plugin-api/src/routing/ExternalRouteRef'; - -// TODO(Rugvip): Once this is moved to a compat package these aliases can be removed and imported from frontend- instead - -/** @ignore */ -type NewRouteRef = - RouteRef; - -/** @ignore */ -type NewSubRouteRef = - SubRouteRef; - -/** @ignore */ -type NewExternalRouteRef< - TParams extends AnyRouteRefParams = AnyRouteRefParams, - TOptional extends boolean = boolean, -> = ExternalRouteRef; +import { toInternalExternalRouteRef } from '../../frontend-plugin-api/src/routing/ExternalRouteRef'; /** * A temporary helper to convert a legacy route ref to the new system. @@ -66,7 +50,7 @@ type NewExternalRouteRef< */ export function convertLegacyRouteRef( ref: LegacyRouteRef, -): NewRouteRef; +): RouteRef; /** * A temporary helper to convert a legacy sub route ref to the new system. @@ -78,7 +62,7 @@ export function convertLegacyRouteRef( */ export function convertLegacyRouteRef( ref: LegacySubRouteRef, -): NewSubRouteRef; +): SubRouteRef; /** * A temporary helper to convert a legacy external route ref to the new system. @@ -93,20 +77,21 @@ export function convertLegacyRouteRef< TOptional extends boolean, >( ref: LegacyExternalRouteRef, -): NewExternalRouteRef; +): ExternalRouteRef; export function convertLegacyRouteRef( ref: LegacyRouteRef | LegacySubRouteRef | LegacyExternalRouteRef, -): NewRouteRef | NewSubRouteRef | NewExternalRouteRef { +): RouteRef | SubRouteRef | ExternalRouteRef { // Ref has already been converted if ('$$type' in ref) { - return ref as unknown as NewRouteRef | NewSubRouteRef | NewExternalRouteRef; + return ref as unknown as RouteRef | SubRouteRef | ExternalRouteRef; } const type = (ref as unknown as { [routeRefType]: unknown })[routeRefType]; if (type === 'absolute') { const legacyRef = ref as LegacyRouteRef; + const legacyRefStr = String(legacyRef); const newRef = toInternalRouteRef( createRouteRef<{ [key in string]: string }>({ params: legacyRef.params as string[], @@ -120,18 +105,19 @@ export function convertLegacyRouteRef( return newRef.getParams(); }, getDescription() { - return newRef.getDescription(); + return legacyRefStr; }, setId(id: string) { newRef.setId(id); }, toString() { - return newRef.toString(); + return legacyRefStr; }, }); } if (type === 'sub') { const legacyRef = ref as LegacySubRouteRef; + const legacyRefStr = String(legacyRef); const newRef = toInternalSubRouteRef( createSubRouteRef({ path: legacyRef.path, @@ -149,15 +135,16 @@ export function convertLegacyRouteRef( return newRef.getParent(); }, getDescription() { - return newRef.getDescription(); + return legacyRefStr; }, toString() { - return newRef.toString(); + return legacyRefStr; }, }); } if (type === 'external') { const legacyRef = ref as LegacyExternalRouteRef; + const legacyRefStr = String(legacyRef); const newRef = toInternalExternalRouteRef( createExternalRouteRef<{ [key in string]: string }>({ params: legacyRef.params as string[], @@ -173,13 +160,13 @@ export function convertLegacyRouteRef( return newRef.getParams(); }, getDescription() { - return newRef.getDescription(); + return legacyRefStr; }, setId(id: string) { newRef.setId(id); }, toString() { - return newRef.toString(); + return legacyRefStr; }, }); } diff --git a/packages/core-compat-api/src/index.ts b/packages/core-compat-api/src/index.ts index e5f61119a3..68e5d9cf19 100644 --- a/packages/core-compat-api/src/index.ts +++ b/packages/core-compat-api/src/index.ts @@ -13,5 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { collectLegacyRoutes } from './collectLegacyRoutes'; +export * from './compatWrapper'; + export { convertLegacyApp } from './convertLegacyApp'; +export { convertLegacyRouteRef } from './convertLegacyRouteRef'; diff --git a/packages/core-components/CHANGELOG.md b/packages/core-components/CHANGELOG.md index fd25c6bbc5..c6ffec5679 100644 --- a/packages/core-components/CHANGELOG.md +++ b/packages/core-components/CHANGELOG.md @@ -1,5 +1,144 @@ # @backstage/core-components +## 0.13.10 + +### Patch Changes + +- d625f66: Fixed bug in Link where it was possible to select and copy a hidden element into clipboard +- 6878b1d: Removed unnecessary `history` and `immer` dependencies. +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0 + - @backstage/version-bridge@1.0.7 + +## 0.13.10-next.1 + +### Patch Changes + +- 6878b1d: Removed unnecessary `history` and `immer` dependencies. +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0 + - @backstage/version-bridge@1.0.7 + +## 0.13.10-next.0 + +### Patch Changes + +- d625f66: Fixed bug in Link where it was possible to select and copy a hidden element into clipboard +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0 + - @backstage/version-bridge@1.0.7 + +## 0.13.9 + +### Patch Changes + +- e8f2ace: Added a new `/testUtils` sub-path that initially exports a `mockBreakpoint` helper. +- 381ed86: Add missing export for IconLinkVertical +- 5c8a3e3: Minor improvements to `Table` component. +- 752df93: Fixes a problem where the `LogViewer` was not able to handle very large logs +- 4d9e3b3: Register component overrides in the global `OverrideComponentNameToClassKeys` provided by `@backstage/theme`. This will in turn will provide component style override types for `createUnifiedTheme`. +- 07dfdf3: Updated dependency `linkifyjs` to `4.1.3`. +- a518c5a: Updated dependency `@react-hookz/web` to `^23.0.0`. +- f291757: Update `linkify-react` to version `4.1.3` +- 175d86b: Fixed an issue where the `onChange` prop within `HeaderTabs` was triggering twice upon tab-switching. +- 0cbb03b: Fixing regular expression ReDoS with zod packages. Upgrading to latest. ref: https://security.snyk.io/vuln/SNYK-JS-ZOD-5925617 +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/theme@0.5.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/version-bridge@1.0.7 + +## 0.13.9-next.3 + +### Patch Changes + +- 175d86b: Fixed an issue where the `onChange` prop within `HeaderTabs` was triggering twice upon tab-switching. +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/version-bridge@1.0.7 + +## 0.13.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/version-bridge@1.0.7 + +## 0.13.9-next.1 + +### Patch Changes + +- e8f2acef80: Added a new `/testUtils` sub-path that initially exports a `mockBreakpoint` helper. +- 07dfdf3702: Updated dependency `linkifyjs` to `4.1.3`. +- a518c5a25b: Updated dependency `@react-hookz/web` to `^23.0.0`. +- f291757e70: Update `linkify-react` to version `4.1.3` +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/version-bridge@1.0.7 + +## 0.13.9-next.0 + +### Patch Changes + +- 381ed86d5e: Add missing export for IconLinkVertical +- 5c8a3e3960: Minor improvements to `Table` component. +- 4d9e3b39e4: Register component overrides in the global `OverrideComponentNameToClassKeys` provided by `@backstage/theme`. This will in turn will provide component style override types for `createUnifiedTheme`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/version-bridge@1.0.7 + +## 0.13.8 + +### Patch Changes + +- 81c8db2088: Fix `RoutedTabs` so that it does not explode without tabs. +- eb817ee6d4: Fix spacing inconsistency with links and labels in headers +- f28c11743a: Add a possibility to use a formatter on a warning panel. Applied it for a scaffolder template +- 6c2b872153: Add official support for React 18. +- e07570a740: Fixed an issue causing the `Select` component to show empty chips when some of the selected values did not match any item +- 7bdc1b0a12: Fixed compatibility with Safari <16.3 by eliminating RegEx lookbehind in `extractInitials`. + + This PR also changed how initials are generated resulting in _John Jonathan Doe_ => _JD_ instead of _JJ_. + +- 66071b42c0: Make the `options.titleFormat` prop of `` apply to all keys including nested ones. Previously, this option would only apply to the root keys of the `metadata` prop. + + Document and improve the props of ``. Previously, the `options` prop was `any`. + +- 71c97e7d73: Fixed the type declaration of `DependencyGraphProps`, the `defs` prop now expects `JSX.Element`s. +- 0c5b78650c: Reverting the `MissingAnnotationEmptyState` component due to cyclical dependency. This component is now deprecated, please use the import from `@backstage/plugin-catalog-react` instead to use the new functionality +- 4b7d341746: Updated dependency `linkify-react` to `4.1.2`. +- 0ef24425c1: Updated dependency `linkifyjs` to `4.1.2`. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.0 + - @backstage/version-bridge@1.0.7 + - @backstage/theme@0.4.4 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + ## 0.13.8-next.2 ### Patch Changes diff --git a/packages/core-components/api-report-testUtils.md b/packages/core-components/api-report-testUtils.md new file mode 100644 index 0000000000..93a6bb2a07 --- /dev/null +++ b/packages/core-components/api-report-testUtils.md @@ -0,0 +1,10 @@ +## API Report File for "@backstage/core-components" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +// @public +export function mockBreakpoint(options: { matches: boolean }): void; + +// (No @packageDocumentation comment for this package) +``` diff --git a/packages/core-components/api-report.md b/packages/core-components/api-report.md index d03d51f4fd..cca7017089 100644 --- a/packages/core-components/api-report.md +++ b/packages/core-components/api-report.md @@ -8,7 +8,6 @@ import { ApiRef } from '@backstage/core-plugin-api'; import { BackstageIdentityApi } from '@backstage/core-plugin-api'; import { BackstagePalette } from '@backstage/theme'; -import { BackstageTheme } from '@backstage/theme'; import { BackstageUserIdentity } from '@backstage/core-plugin-api'; import { BottomNavigationActionProps } from '@material-ui/core/BottomNavigationAction'; import { ButtonProps as ButtonProps_2 } from '@material-ui/core/Button'; @@ -541,6 +540,17 @@ export type HorizontalScrollGridClassKey = | 'buttonLeft' | 'buttonRight'; +// @public (undocumented) +export function IconLinkVertical({ + color, + disabled, + href, + icon, + label, + onClick, + title, +}: IconLinkVerticalProps): React_2.JSX.Element; + // @public (undocumented) export type IconLinkVerticalClassKey = | 'link' diff --git a/packages/core-components/package.json b/packages/core-components/package.json index 734feb131c..70afda8983 100644 --- a/packages/core-components/package.json +++ b/packages/core-components/package.json @@ -1,11 +1,9 @@ { "name": "@backstage/core-components", "description": "Core components used by Backstage plugins and apps", - "version": "0.13.8-next.2", + "version": "0.13.10", "publishConfig": { - "access": "public", - "main": "dist/index.esm.js", - "types": "dist/index.d.ts" + "access": "public" }, "backstage": { "role": "web-library" @@ -22,6 +20,21 @@ "license": "Apache-2.0", "main": "src/index.ts", "types": "src/index.ts", + "exports": { + ".": "./src/index.ts", + "./testUtils": "./src/testUtils.ts", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "testUtils": [ + "src/testUtils.ts" + ], + "package.json": [ + "package.json" + ] + } + }, "sideEffects": false, "scripts": { "build": "backstage-cli package build", @@ -43,7 +56,7 @@ "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", - "@react-hookz/web": "^20.0.0", + "@react-hookz/web": "^23.0.0", "@types/react": "^16.13.1 || ^17.0.0", "@types/react-sparklines": "^1.7.0", "@types/react-text-truncate": "^0.14.0", @@ -53,10 +66,8 @@ "d3-shape": "^3.0.0", "d3-zoom": "^3.0.0", "dagre": "^0.8.5", - "history": "^5.0.0", - "immer": "^9.0.1", - "linkify-react": "4.1.2", - "linkifyjs": "4.1.2", + "linkify-react": "4.1.3", + "linkifyjs": "4.1.3", "lodash": "^4.17.21", "pluralize": "^8.0.0", "qs": "^6.9.4", @@ -73,7 +84,7 @@ "react-window": "^1.8.6", "remark-gfm": "^3.0.1", "zen-observable": "^0.10.0", - "zod": "^3.21.4" + "zod": "^3.22.4" }, "peerDependencies": { "react": "^16.13.1 || ^17.0.0 || ^18.0.0", @@ -101,6 +112,7 @@ "@types/react-window": "^1.8.5", "@types/zen-observable": "^0.8.0", "cross-fetch": "^4.0.0", + "history": "^5.0.0", "msw": "^1.0.0" }, "files": [ diff --git a/packages/core-components/src/components/CodeSnippet/CodeSnippet.tsx b/packages/core-components/src/components/CodeSnippet/CodeSnippet.tsx index 3270cac176..6eb274b015 100644 --- a/packages/core-components/src/components/CodeSnippet/CodeSnippet.tsx +++ b/packages/core-components/src/components/CodeSnippet/CodeSnippet.tsx @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { BackstageTheme } from '@backstage/theme'; + import Box from '@material-ui/core/Box'; import { useTheme } from '@material-ui/core/styles'; import React from 'react'; @@ -83,7 +83,7 @@ export function CodeSnippet(props: CodeSnippetProps) { customStyle, showCopyCodeButton = false, } = props; - const theme = useTheme(); + const theme = useTheme(); const mode = theme.palette.type === 'dark' ? dark : docco; const highlightColor = theme.palette.type === 'dark' ? '#256bf3' : '#e6ffed'; diff --git a/packages/core-components/src/components/CreateButton/CreateButton.tsx b/packages/core-components/src/components/CreateButton/CreateButton.tsx index d5d7080851..beca7e8c73 100644 --- a/packages/core-components/src/components/CreateButton/CreateButton.tsx +++ b/packages/core-components/src/components/CreateButton/CreateButton.tsx @@ -14,13 +14,13 @@ * limitations under the License. */ -import { BackstageTheme } from '@backstage/theme'; import Button from '@material-ui/core/Button'; import IconButton from '@material-ui/core/IconButton'; import useMediaQuery from '@material-ui/core/useMediaQuery'; import React from 'react'; import { Link as RouterLink, LinkProps } from 'react-router-dom'; import AddCircleOutline from '@material-ui/icons/AddCircleOutline'; +import { Theme } from '@material-ui/core/styles'; /** * Properties for {@link CreateButton} @@ -38,7 +38,7 @@ export type CreateButtonProps = { */ export function CreateButton(props: CreateButtonProps) { const { title, to } = props; - const isXSScreen = useMediaQuery(theme => + const isXSScreen = useMediaQuery(theme => theme.breakpoints.down('xs'), ); diff --git a/packages/core-components/src/components/DependencyGraph/DefaultLabel.tsx b/packages/core-components/src/components/DependencyGraph/DefaultLabel.tsx index 677782cf57..d4a91e50db 100644 --- a/packages/core-components/src/components/DependencyGraph/DefaultLabel.tsx +++ b/packages/core-components/src/components/DependencyGraph/DefaultLabel.tsx @@ -16,14 +16,13 @@ import React from 'react'; import makeStyles from '@material-ui/core/styles/makeStyles'; -import { BackstageTheme } from '@backstage/theme'; import { DependencyGraphTypes as Types } from './types'; /** @public */ export type DependencyGraphDefaultLabelClassKey = 'text'; const useStyles = makeStyles( - (theme: BackstageTheme) => ({ + theme => ({ text: { fill: theme.palette.textContrast, }, diff --git a/packages/core-components/src/components/DependencyGraph/DefaultNode.tsx b/packages/core-components/src/components/DependencyGraph/DefaultNode.tsx index 5c28375118..81a918c7b8 100644 --- a/packages/core-components/src/components/DependencyGraph/DefaultNode.tsx +++ b/packages/core-components/src/components/DependencyGraph/DefaultNode.tsx @@ -16,14 +16,13 @@ import React from 'react'; import { makeStyles } from '@material-ui/core/styles'; -import { BackstageTheme } from '@backstage/theme'; import { DependencyGraphTypes as Types } from './types'; /** @public */ export type DependencyGraphDefaultNodeClassKey = 'node' | 'text'; const useStyles = makeStyles( - (theme: BackstageTheme) => ({ + theme => ({ node: { fill: theme.palette.primary.light, stroke: theme.palette.primary.light, diff --git a/packages/core-components/src/components/DependencyGraph/DependencyGraph.tsx b/packages/core-components/src/components/DependencyGraph/DependencyGraph.tsx index 3dd1025b8f..d4907d2a18 100644 --- a/packages/core-components/src/components/DependencyGraph/DependencyGraph.tsx +++ b/packages/core-components/src/components/DependencyGraph/DependencyGraph.tsx @@ -20,7 +20,6 @@ import * as d3Selection from 'd3-selection'; import useTheme from '@material-ui/core/styles/useTheme'; import dagre from 'dagre'; import debounce from 'lodash/debounce'; -import { BackstageTheme } from '@backstage/theme'; import { DependencyGraphTypes as Types } from './types'; import { Node } from './Node'; import { Edge, GraphEdge } from './Edge'; @@ -205,7 +204,7 @@ export function DependencyGraph( fit = 'grow', ...svgProps } = props; - const theme: BackstageTheme = useTheme(); + const theme = useTheme(); const [containerWidth, setContainerWidth] = React.useState(100); const [containerHeight, setContainerHeight] = React.useState(100); diff --git a/packages/core-components/src/components/DependencyGraph/Edge.tsx b/packages/core-components/src/components/DependencyGraph/Edge.tsx index 4e3ba96e48..05e068eca4 100644 --- a/packages/core-components/src/components/DependencyGraph/Edge.tsx +++ b/packages/core-components/src/components/DependencyGraph/Edge.tsx @@ -18,7 +18,6 @@ import React from 'react'; import * as d3Shape from 'd3-shape'; import isFinite from 'lodash/isFinite'; import makeStyles from '@material-ui/core/styles/makeStyles'; -import { BackstageTheme } from '@backstage/theme'; import { DependencyGraphTypes as Types } from './types'; import { EDGE_TEST_ID, LABEL_TEST_ID } from './constants'; import { DefaultLabel } from './DefaultLabel'; @@ -42,7 +41,7 @@ export type GraphEdge = Types.DependencyEdge & export type DependencyGraphEdgeClassKey = 'path' | 'label'; const useStyles = makeStyles( - (theme: BackstageTheme) => ({ + theme => ({ path: { strokeWidth: 1, stroke: theme.palette.textSubtle, diff --git a/packages/core-components/src/components/DismissableBanner/DismissableBanner.tsx b/packages/core-components/src/components/DismissableBanner/DismissableBanner.tsx index 9b74b1e9b8..649043fc21 100644 --- a/packages/core-components/src/components/DismissableBanner/DismissableBanner.tsx +++ b/packages/core-components/src/components/DismissableBanner/DismissableBanner.tsx @@ -19,7 +19,6 @@ import { useApi, storageApiRef } from '@backstage/core-plugin-api'; import useObservable from 'react-use/lib/useObservable'; import classNames from 'classnames'; import { makeStyles } from '@material-ui/core/styles'; -import { BackstageTheme } from '@backstage/theme'; import Snackbar from '@material-ui/core/Snackbar'; import SnackbarContent from '@material-ui/core/SnackbarContent'; import IconButton from '@material-ui/core/IconButton'; @@ -42,7 +41,7 @@ export type DismissableBannerClassKey = export type DismissbleBannerClassKey = DismissableBannerClassKey; const useStyles = makeStyles( - (theme: BackstageTheme) => ({ + theme => ({ root: { padding: theme.spacing(0), marginBottom: theme.spacing(0), diff --git a/packages/core-components/src/components/EmptyState/MissingAnnotationEmptyState.tsx b/packages/core-components/src/components/EmptyState/MissingAnnotationEmptyState.tsx index efbfdb9999..81b4714531 100644 --- a/packages/core-components/src/components/EmptyState/MissingAnnotationEmptyState.tsx +++ b/packages/core-components/src/components/EmptyState/MissingAnnotationEmptyState.tsx @@ -14,7 +14,6 @@ * limitations under the License. */ -import { BackstageTheme } from '@backstage/theme'; import Box from '@material-ui/core/Box'; import Button from '@material-ui/core/Button'; import { makeStyles } from '@material-ui/core/styles'; @@ -54,7 +53,7 @@ type Props = { */ export type MissingAnnotationEmptyStateClassKey = 'code'; -const useStyles = makeStyles( +const useStyles = makeStyles( theme => ({ code: { borderRadius: 6, diff --git a/packages/core-components/src/components/HeaderIconLinkRow/index.ts b/packages/core-components/src/components/HeaderIconLinkRow/index.ts index f2207d32c5..84bb915945 100644 --- a/packages/core-components/src/components/HeaderIconLinkRow/index.ts +++ b/packages/core-components/src/components/HeaderIconLinkRow/index.ts @@ -15,6 +15,7 @@ */ export { HeaderIconLinkRow } from './HeaderIconLinkRow'; +export { IconLinkVertical } from './IconLinkVertical'; export type { HeaderIconLinkRowClassKey } from './HeaderIconLinkRow'; export type { IconLinkVerticalProps, diff --git a/packages/core-components/src/components/HorizontalScrollGrid/HorizontalScrollGrid.tsx b/packages/core-components/src/components/HorizontalScrollGrid/HorizontalScrollGrid.tsx index c4c9dadb78..e89b7896dd 100644 --- a/packages/core-components/src/components/HorizontalScrollGrid/HorizontalScrollGrid.tsx +++ b/packages/core-components/src/components/HorizontalScrollGrid/HorizontalScrollGrid.tsx @@ -16,7 +16,7 @@ import Box from '@material-ui/core/Box'; import Grid from '@material-ui/core/Grid'; import IconButton from '@material-ui/core/IconButton'; -import { makeStyles, Theme } from '@material-ui/core/styles'; +import { makeStyles } from '@material-ui/core/styles'; import ChevronLeftIcon from '@material-ui/icons/ChevronLeft'; import ChevronRightIcon from '@material-ui/icons/ChevronRight'; import classNames from 'classnames'; @@ -68,7 +68,7 @@ export type HorizontalScrollGridClassKey = | 'buttonLeft' | 'buttonRight'; -const useStyles = makeStyles( +const useStyles = makeStyles( theme => ({ root: { position: 'relative', diff --git a/packages/core-components/src/components/Link/Link.tsx b/packages/core-components/src/components/Link/Link.tsx index 4d58fdfa77..e957390da8 100644 --- a/packages/core-components/src/components/Link/Link.tsx +++ b/packages/core-components/src/components/Link/Link.tsx @@ -42,6 +42,7 @@ const useStyles = makeStyles( clipPath: 'inset(50%)', overflow: 'hidden', position: 'absolute', + userSelect: 'none', whiteSpace: 'nowrap', height: 1, width: 1, diff --git a/packages/core-components/src/components/LogViewer/AnsiProcessor.ts b/packages/core-components/src/components/LogViewer/AnsiProcessor.ts index d0f835a70e..bcd5af7ced 100644 --- a/packages/core-components/src/components/LogViewer/AnsiProcessor.ts +++ b/packages/core-components/src/components/LogViewer/AnsiProcessor.ts @@ -117,7 +117,7 @@ export class AnsiProcessor { return this.lines; } - if (text.startsWith(this.text)) { + if (this.text && text.startsWith(this.text)) { const lastLineIndex = this.lines.length > 0 ? this.lines.length - 1 : 0; const lastLine = this.lines[lastLineIndex] ?? new AnsiLine(); const lastChunk = lastLine.lastChunk(); @@ -130,7 +130,7 @@ export class AnsiProcessor { lastLine.replaceLastChunk(newLines[0]?.chunks); this.lines[lastLineIndex] = lastLine; - this.lines.push(...newLines.slice(1)); + this.lines = this.lines.concat(newLines.slice(1)); } else { this.lines = this.processLines(text); } diff --git a/packages/core-components/src/components/MarkdownContent/MarkdownContent.tsx b/packages/core-components/src/components/MarkdownContent/MarkdownContent.tsx index 425e723052..b422a62b6c 100644 --- a/packages/core-components/src/components/MarkdownContent/MarkdownContent.tsx +++ b/packages/core-components/src/components/MarkdownContent/MarkdownContent.tsx @@ -18,13 +18,12 @@ import { makeStyles } from '@material-ui/core/styles'; import ReactMarkdown, { Options } from 'react-markdown'; import gfm from 'remark-gfm'; import React from 'react'; -import { BackstageTheme } from '@backstage/theme'; import { CodeSnippet } from '../CodeSnippet'; import { HeadingProps } from 'react-markdown/lib/ast-to-react'; export type MarkdownContentClassKey = 'markdown'; -const useStyles = makeStyles( +const useStyles = makeStyles( theme => ({ markdown: { '& table': { diff --git a/packages/core-components/src/components/OAuthRequestDialog/LoginRequestListItem.tsx b/packages/core-components/src/components/OAuthRequestDialog/LoginRequestListItem.tsx index c7707c07d5..782624362d 100644 --- a/packages/core-components/src/components/OAuthRequestDialog/LoginRequestListItem.tsx +++ b/packages/core-components/src/components/OAuthRequestDialog/LoginRequestListItem.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { makeStyles, Theme } from '@material-ui/core/styles'; +import { makeStyles } from '@material-ui/core/styles'; import ListItem from '@material-ui/core/ListItem'; import ListItemAvatar from '@material-ui/core/ListItemAvatar'; import ListItemText from '@material-ui/core/ListItemText'; @@ -26,7 +26,7 @@ import { PendingOAuthRequest } from '@backstage/core-plugin-api'; export type LoginRequestListItemClassKey = 'root'; -const useItemStyles = makeStyles( +const useItemStyles = makeStyles( theme => ({ root: { paddingLeft: theme.spacing(3), diff --git a/packages/core-components/src/components/OAuthRequestDialog/OAuthRequestDialog.tsx b/packages/core-components/src/components/OAuthRequestDialog/OAuthRequestDialog.tsx index 8fdace3766..7c17e74e4a 100644 --- a/packages/core-components/src/components/OAuthRequestDialog/OAuthRequestDialog.tsx +++ b/packages/core-components/src/components/OAuthRequestDialog/OAuthRequestDialog.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { makeStyles, Theme } from '@material-ui/core/styles'; +import { makeStyles } from '@material-ui/core/styles'; import Dialog from '@material-ui/core/Dialog'; import DialogActions from '@material-ui/core/DialogActions'; import DialogContent from '@material-ui/core/DialogContent'; @@ -37,7 +37,7 @@ export type OAuthRequestDialogClassKey = | 'contentList' | 'actionButtons'; -const useStyles = makeStyles( +const useStyles = makeStyles( theme => ({ dialog: { paddingTop: theme.spacing(1), diff --git a/packages/core-components/src/components/Progress/Progress.tsx b/packages/core-components/src/components/Progress/Progress.tsx index eb17b9eb25..6d1281edd5 100644 --- a/packages/core-components/src/components/Progress/Progress.tsx +++ b/packages/core-components/src/components/Progress/Progress.tsx @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { BackstageTheme } from '@backstage/theme'; + import Box from '@material-ui/core/Box'; import LinearProgress, { LinearProgressProps, @@ -22,7 +22,7 @@ import { useTheme } from '@material-ui/core/styles'; import React, { PropsWithChildren, useEffect, useState } from 'react'; export function Progress(props: PropsWithChildren) { - const theme = useTheme(); + const theme = useTheme(); const [isVisible, setIsVisible] = useState(false); useEffect(() => { diff --git a/packages/core-components/src/components/ProgressBars/Gauge.tsx b/packages/core-components/src/components/ProgressBars/Gauge.tsx index ca84a5f480..088e369e62 100644 --- a/packages/core-components/src/components/ProgressBars/Gauge.tsx +++ b/packages/core-components/src/components/ProgressBars/Gauge.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { BackstagePalette, BackstageTheme } from '@backstage/theme'; +import { BackstagePalette } from '@backstage/theme'; import { makeStyles, useTheme } from '@material-ui/core/styles'; import { Circle } from 'rc-progress'; import React, { ReactNode, useEffect, useState } from 'react'; @@ -28,7 +28,7 @@ export type GaugeClassKey = | 'circle' | 'colorUnknown'; -const useStyles = makeStyles( +const useStyles = makeStyles( theme => ({ root: { position: 'relative', @@ -123,7 +123,7 @@ export function Gauge(props: GaugeProps) { const [hoverRef, setHoverRef] = useState(null); const { getColor = getProgressColor } = props; const classes = useStyles(props); - const { palette } = useTheme(); + const { palette } = useTheme(); const { value, fractional, inverse, unit, max, description } = { ...defaultGaugeProps, ...props, diff --git a/packages/core-components/src/components/ProgressBars/LinearGauge.tsx b/packages/core-components/src/components/ProgressBars/LinearGauge.tsx index 8d45b83571..a41b41f3dc 100644 --- a/packages/core-components/src/components/ProgressBars/LinearGauge.tsx +++ b/packages/core-components/src/components/ProgressBars/LinearGauge.tsx @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { BackstageTheme } from '@backstage/theme'; + import { useTheme } from '@material-ui/core/styles'; import Tooltip from '@material-ui/core/Tooltip'; import Typography from '@material-ui/core/Typography'; @@ -33,7 +33,7 @@ type Props = { export function LinearGauge(props: Props) { const { value, getColor = getProgressColor, width = 'thick' } = props; - const { palette } = useTheme(); + const { palette } = useTheme(); if (isNaN(value)) { return null; } diff --git a/packages/core-components/src/components/Select/Select.tsx b/packages/core-components/src/components/Select/Select.tsx index 918ce301fb..ec7f87eb94 100644 --- a/packages/core-components/src/components/Select/Select.tsx +++ b/packages/core-components/src/components/Select/Select.tsx @@ -218,15 +218,20 @@ export function SelectComponent(props: SelectProps) { renderValue={s => multiple && (value as any[]).length !== 0 ? ( - {(s as string[]).map(selectedValue => ( - el.value === selectedValue)?.value} - label={items.find(el => el.value === selectedValue)?.label} - clickable - onDelete={handleDelete(selectedValue)} - className={classes.chip} - /> - ))} + {(s as string[]).map(selectedValue => { + const item = items.find(el => el.value === selectedValue); + return item ? ( + + ) : ( + false + ); + })} ) : ( diff --git a/packages/core-components/src/components/Status/Status.tsx b/packages/core-components/src/components/Status/Status.tsx index 364193e383..615eed6aec 100644 --- a/packages/core-components/src/components/Status/Status.tsx +++ b/packages/core-components/src/components/Status/Status.tsx @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { BackstageTheme } from '@backstage/theme'; + import { makeStyles } from '@material-ui/core/styles'; import Typography from '@material-ui/core/Typography'; import classNames from 'classnames'; @@ -28,7 +28,7 @@ export type StatusClassKey = | 'running' | 'aborted'; -const useStyles = makeStyles( +const useStyles = makeStyles( theme => ({ status: { fontWeight: theme.typography.fontWeightMedium, diff --git a/packages/core-components/src/components/SupportButton/SupportButton.tsx b/packages/core-components/src/components/SupportButton/SupportButton.tsx index a07c03b7d2..726500c77e 100644 --- a/packages/core-components/src/components/SupportButton/SupportButton.tsx +++ b/packages/core-components/src/components/SupportButton/SupportButton.tsx @@ -13,8 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { useApp } from '@backstage/core-plugin-api'; -import { BackstageTheme } from '@backstage/theme'; import Box from '@material-ui/core/Box'; import Button from '@material-ui/core/Button'; import DialogActions from '@material-ui/core/DialogActions'; @@ -24,7 +24,7 @@ import ListItemText from '@material-ui/core/ListItemText'; import MenuItem from '@material-ui/core/MenuItem'; import MenuList from '@material-ui/core/MenuList'; import Popover from '@material-ui/core/Popover'; -import { makeStyles } from '@material-ui/core/styles'; +import { Theme, makeStyles } from '@material-ui/core/styles'; import Typography from '@material-ui/core/Typography'; import useMediaQuery from '@material-ui/core/useMediaQuery'; import React, { MouseEventHandler, useState } from 'react'; @@ -91,7 +91,7 @@ export function SupportButton(props: SupportButtonProps) { const [popoverOpen, setPopoverOpen] = useState(false); const [anchorEl, setAnchorEl] = useState(null); const classes = useStyles(); - const isSmallScreen = useMediaQuery(theme => + const isSmallScreen = useMediaQuery(theme => theme.breakpoints.down('sm'), ); diff --git a/packages/core-components/src/components/Table/Filters.tsx b/packages/core-components/src/components/Table/Filters.tsx index 24eaa98cb5..568b22b933 100644 --- a/packages/core-components/src/components/Table/Filters.tsx +++ b/packages/core-components/src/components/Table/Filters.tsx @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { BackstageTheme } from '@backstage/theme'; + import Box from '@material-ui/core/Box'; import Button from '@material-ui/core/Button'; import { makeStyles } from '@material-ui/core/styles'; @@ -24,7 +24,7 @@ import { SelectProps } from '../Select/Select'; export type TableFiltersClassKey = 'root' | 'value' | 'heder' | 'filters'; -const useFilterStyles = makeStyles( +const useFilterStyles = makeStyles( theme => ({ root: { height: '100%', diff --git a/packages/core-components/src/components/Table/SubvalueCell.tsx b/packages/core-components/src/components/Table/SubvalueCell.tsx index cc577b7456..8ccebbe65a 100644 --- a/packages/core-components/src/components/Table/SubvalueCell.tsx +++ b/packages/core-components/src/components/Table/SubvalueCell.tsx @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { BackstageTheme } from '@backstage/theme'; + import Box from '@material-ui/core/Box'; import { makeStyles } from '@material-ui/core/styles'; import React from 'react'; export type SubvalueCellClassKey = 'value' | 'subvalue'; -const useSubvalueCellStyles = makeStyles( +const useSubvalueCellStyles = makeStyles( theme => ({ value: { marginBottom: theme.spacing(0.75), diff --git a/packages/core-components/src/components/Table/Table.tsx b/packages/core-components/src/components/Table/Table.tsx index e4ee9b5995..4aba7445b3 100644 --- a/packages/core-components/src/components/Table/Table.tsx +++ b/packages/core-components/src/components/Table/Table.tsx @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { BackstageTheme } from '@backstage/theme'; + import MTable, { Column, Icons, @@ -25,7 +25,12 @@ import MTable, { } from '@material-table/core'; import Box from '@material-ui/core/Box'; import IconButton from '@material-ui/core/IconButton'; -import { makeStyles, useTheme, withStyles } from '@material-ui/core/styles'; +import { + makeStyles, + Theme, + useTheme, + withStyles, +} from '@material-ui/core/styles'; import Typography from '@material-ui/core/Typography'; import AddBox from '@material-ui/icons/AddBox'; import ArrowUpward from '@material-ui/icons/ArrowUpward'; @@ -48,12 +53,13 @@ import React, { ReactNode, useCallback, useEffect, + useMemo, useState, } from 'react'; import { SelectProps } from '../Select/Select'; import { Filter, Filters, SelectedFilters, Without } from './Filters'; -import CircularProgress from '@material-ui/core/CircularProgress'; +import { TableLoadingBody } from './TableLoadingBody'; // Material-table is not using the standard icons available in in material-ui. https://github.com/mbrn/material-table/issues/51 const tableIcons: Icons = { @@ -136,7 +142,7 @@ const StyledMTableToolbar = withStyles( /** @public */ export type FiltersContainerClassKey = 'root' | 'title'; -const useFilterStyles = makeStyles( +const useFilterStyles = makeStyles( theme => ({ root: { display: 'flex', @@ -154,7 +160,7 @@ const useFilterStyles = makeStyles( export type TableClassKey = 'root'; -const useTableStyles = makeStyles( +const useTableStyles = makeStyles( () => ({ root: { display: 'flex', @@ -166,7 +172,7 @@ const useTableStyles = makeStyles( function convertColumns( columns: TableColumn[], - theme: BackstageTheme, + theme: Theme, ): TableColumn[] { return columns.map(column => { const headerStyle: React.CSSProperties = column.headerStyle ?? {}; @@ -303,20 +309,21 @@ export function Table(props: TableProps) { const { data, columns, + emptyContent, options, title, subtitle, + localization, filters, initialState, - emptyContent, onStateChange, components, - isLoading: isLoading, + isLoading: loading, ...restProps } = props; const tableClasses = useTableStyles(); - const theme = useTheme(); + const theme = useTheme(); const calculatedInitialState = { ...defaultInitialState, ...initialState }; @@ -327,14 +334,11 @@ export function Table(props: TableProps) { () => setFiltersOpen(v => !v), [setFiltersOpen], ); - const [selectedFiltersLength, setSelectedFiltersLength] = useState(0); - const [tableData, setTableData] = useState(data as any[]); + const [selectedFilters, setSelectedFilters] = useState( calculatedInitialState.filters, ); - const MTColumns = convertColumns(columns, theme); - const [search, setSearch] = useState(calculatedInitialState.search); useEffect(() => { @@ -352,25 +356,15 @@ export function Table(props: TableProps) { } }, [search, filtersOpen, selectedFilters, onStateChange]); - const defaultOptions: Options = { - headerStyle: { - textTransform: 'uppercase', - }, - }; - const getFieldByTitle = useCallback( (titleValue: string | keyof T) => columns.find(el => el.title === titleValue)?.field, [columns], ); - useEffect(() => { - if (typeof data === 'function') { - return; - } - if (!selectedFilters) { - setTableData(data as any[]); - return; + const tableData = useMemo(() => { + if (typeof data === 'function' || !selectedFilters) { + return data; } const selectedFiltersArray = Object.values(selectedFilters); @@ -396,62 +390,12 @@ export function Table(props: TableProps) { return fieldValue === filterValue; }), ); - setTableData(newData); - } else { - setTableData(data as any[]); + return newData; } - setSelectedFiltersLength(selectedFiltersArray.flat().length); + return data; }, [data, selectedFilters, getFieldByTitle]); - const constructFilters = ( - filterConfig: TableFilter[], - dataValue: any[] | undefined, - ): Filter[] => { - const extractDistinctValues = (field: string | keyof T): Set => { - const distinctValues = new Set(); - const addValue = (value: any) => { - if (value !== undefined && value !== null) { - distinctValues.add(value); - } - }; - - if (dataValue) { - dataValue.forEach(el => { - const value = extractValueByField( - el, - getFieldByTitle(field) as string, - ); - - if (Array.isArray(value)) { - (value as []).forEach(addValue); - } else { - addValue(value); - } - }); - } - - return distinctValues; - }; - - const constructSelect = ( - filter: TableFilter, - ): Without => { - return { - placeholder: 'All results', - label: filter.column, - multiple: filter.type === 'multiple-select', - items: [...extractDistinctValues(filter.column)].sort().map(value => ({ - label: value, - value, - })), - }; - }; - - return filterConfig.map(filter => ({ - type: filter.type, - element: constructSelect(filter), - })); - }; + const selectedFiltersLength = Object.values(selectedFilters).flat().length; const hasFilters = !!filters?.length; const Toolbar = useCallback( @@ -471,50 +415,16 @@ export function Table(props: TableProps) { const hasNoRows = typeof data !== 'function' && data.length === 0; const columnCount = columns.length; - const Body = useCallback( - (bodyProps: any /* no type for this in material-table */) => { - if (isLoading) { - return ( - - - - - - - - - - ); - } - - if (emptyContent && hasNoRows) { - return ( - - - {emptyContent} - - - ); - } - - return ; - }, - [hasNoRows, emptyContent, columnCount, isLoading], + const Body = useMemo( + () => makeBody({ hasNoRows, emptyContent, columnCount, loading }), + [hasNoRows, emptyContent, columnCount, loading], ); return ( {filtersOpen && data && typeof data !== 'function' && filters?.length && ( @@ -522,12 +432,12 @@ export function Table(props: TableProps) { components={{ Header: StyledMTableHeader, - Toolbar, Body, + Toolbar, ...components, }} - options={{ ...defaultOptions, ...options }} - columns={MTColumns} + options={{ headerStyle: { textTransform: 'uppercase' }, ...options }} + columns={convertColumns(columns, theme)} icons={tableIcons} title={ <> @@ -541,10 +451,11 @@ export function Table(props: TableProps) { )} } - data={typeof data === 'function' ? data : tableData} + data={tableData} style={{ width: '100%' }} localization={{ toolbar: { searchPlaceholder: 'Filter', searchTooltip: 'Filter' }, + ...localization, }} {...restProps} /> @@ -553,3 +464,84 @@ export function Table(props: TableProps) { } Table.icons = Object.freeze(tableIcons); + +function makeBody({ + columnCount, + emptyContent, + hasNoRows, + loading, +}: { + hasNoRows: boolean; + emptyContent: ReactNode; + columnCount: number; + loading?: boolean; +}) { + return (bodyProps: any /* no type for this in material-table */) => { + if (loading) { + return ; + } + + if (emptyContent && hasNoRows) { + return ( + + + {emptyContent} + + + ); + } + + return ; + }; +} + +function constructFilters( + filterConfig: TableFilter[], + dataValue: any[] | undefined, + columns: TableColumn[], +): Filter[] { + const extractDistinctValues = (field: string | keyof T): Set => { + const distinctValues = new Set(); + const addValue = (value: any) => { + if (value !== undefined && value !== null) { + distinctValues.add(value); + } + }; + + if (dataValue) { + dataValue.forEach(el => { + const value = extractValueByField( + el, + columns.find(c => c.title === field)?.field as string, + ); + + if (Array.isArray(value)) { + (value as []).forEach(addValue); + } else { + addValue(value); + } + }); + } + + return distinctValues; + }; + + const constructSelect = ( + filter: TableFilter, + ): Without => { + return { + placeholder: 'All results', + label: filter.column, + multiple: filter.type === 'multiple-select', + items: [...extractDistinctValues(filter.column)].sort().map(value => ({ + label: value, + value, + })), + }; + }; + + return filterConfig.map(filter => ({ + type: filter.type, + element: constructSelect(filter), + })); +} diff --git a/packages/core-components/src/components/Table/TableLoadingBody.tsx b/packages/core-components/src/components/Table/TableLoadingBody.tsx new file mode 100644 index 0000000000..3671bf1c51 --- /dev/null +++ b/packages/core-components/src/components/Table/TableLoadingBody.tsx @@ -0,0 +1,44 @@ +/* + * 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 Box from '@material-ui/core/Box'; +import CircularProgress from '@material-ui/core/CircularProgress'; +import React from 'react'; + +/** + * @internal + */ +export function TableLoadingBody(props: { colSpan?: number }) { + return ( + + + + + + + + + + ); +} diff --git a/packages/core-components/src/components/TrendLine/TrendLine.tsx b/packages/core-components/src/components/TrendLine/TrendLine.tsx index b59d748c2c..25d1045e09 100644 --- a/packages/core-components/src/components/TrendLine/TrendLine.tsx +++ b/packages/core-components/src/components/TrendLine/TrendLine.tsx @@ -21,10 +21,9 @@ import { SparklinesLineProps, SparklinesProps, } from 'react-sparklines'; -import { useTheme } from '@material-ui/core/styles'; -import { BackstageTheme } from '@backstage/theme'; +import { Theme, useTheme } from '@material-ui/core/styles'; -function color(data: number[], theme: BackstageTheme): string | undefined { +function color(data: number[], theme: Theme): string | undefined { const lastNum = data[data.length - 1]; if (!lastNum) return undefined; if (lastNum >= 0.9) return theme.palette.status.ok; @@ -36,7 +35,7 @@ export function TrendLine( props: SparklinesProps & Pick & { title?: string }, ) { - const theme = useTheme(); + const theme = useTheme(); if (!props.data) return null; return ( diff --git a/packages/core-components/src/components/WarningPanel/WarningPanel.tsx b/packages/core-components/src/components/WarningPanel/WarningPanel.tsx index 1ed356024c..634b8f7b09 100644 --- a/packages/core-components/src/components/WarningPanel/WarningPanel.tsx +++ b/packages/core-components/src/components/WarningPanel/WarningPanel.tsx @@ -13,8 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { BackstageTheme } from '@backstage/theme'; -import { makeStyles, darken, lighten } from '@material-ui/core/styles'; + +import { makeStyles, darken, lighten, Theme } from '@material-ui/core/styles'; import Accordion from '@material-ui/core/Accordion'; import AccordionSummary from '@material-ui/core/AccordionSummary'; import AccordionDetails from '@material-ui/core/AccordionDetails'; @@ -27,7 +27,7 @@ import { MarkdownContent } from '../MarkdownContent'; const getWarningTextColor = ( severity: NonNullable, - theme: BackstageTheme, + theme: Theme, ) => { const getColor = theme.palette.type === 'light' ? darken : lighten; return getColor(theme.palette[severity].light, 0.6); @@ -35,13 +35,13 @@ const getWarningTextColor = ( const getWarningBackgroundColor = ( severity: NonNullable, - theme: BackstageTheme, + theme: Theme, ) => { const getBackgroundColor = theme.palette.type === 'light' ? lighten : darken; return getBackgroundColor(theme.palette[severity].light, 0.9); }; -const useErrorOutlineStyles = makeStyles(theme => ({ +const useErrorOutlineStyles = makeStyles(theme => ({ root: { marginRight: theme.spacing(1), fill: ({ severity }: WarningProps) => @@ -68,7 +68,7 @@ export type WarningPanelClassKey = | 'message' | 'details'; -const useStyles = makeStyles( +const useStyles = makeStyles( theme => ({ panel: { backgroundColor: ({ severity }: WarningProps) => diff --git a/packages/core-components/src/layout/BottomLink/BottomLink.tsx b/packages/core-components/src/layout/BottomLink/BottomLink.tsx index f385d9ce11..ea706002a4 100644 --- a/packages/core-components/src/layout/BottomLink/BottomLink.tsx +++ b/packages/core-components/src/layout/BottomLink/BottomLink.tsx @@ -14,7 +14,6 @@ * limitations under the License. */ -import { BackstageTheme } from '@backstage/theme'; import Box from '@material-ui/core/Box'; import Divider from '@material-ui/core/Divider'; import { makeStyles } from '@material-ui/core/styles'; @@ -26,7 +25,7 @@ import { Link } from '../../components/Link'; /** @public */ export type BottomLinkClassKey = 'root' | 'boxTitle' | 'arrow'; -const useStyles = makeStyles( +const useStyles = makeStyles( theme => ({ root: { maxWidth: 'fit-content', diff --git a/packages/core-components/src/layout/ErrorPage/ErrorPage.tsx b/packages/core-components/src/layout/ErrorPage/ErrorPage.tsx index 9cfaac363e..73acf1f650 100644 --- a/packages/core-components/src/layout/ErrorPage/ErrorPage.tsx +++ b/packages/core-components/src/layout/ErrorPage/ErrorPage.tsx @@ -14,7 +14,6 @@ * limitations under the License. */ -import { BackstageTheme } from '@backstage/theme'; import Grid from '@material-ui/core/Grid'; import { makeStyles } from '@material-ui/core/styles'; import Typography from '@material-ui/core/Typography'; @@ -34,7 +33,7 @@ interface IErrorPageProps { /** @public */ export type ErrorPageClassKey = 'container' | 'title' | 'subtitle'; -const useStyles = makeStyles( +const useStyles = makeStyles( theme => ({ container: { padding: theme.spacing(8), diff --git a/packages/core-components/src/layout/Header/Header.tsx b/packages/core-components/src/layout/Header/Header.tsx index cd2f281d65..c6ceda1070 100644 --- a/packages/core-components/src/layout/Header/Header.tsx +++ b/packages/core-components/src/layout/Header/Header.tsx @@ -15,7 +15,6 @@ */ import { configApiRef, useApi } from '@backstage/core-plugin-api'; -import { BackstageTheme } from '@backstage/theme'; import Box from '@material-ui/core/Box'; import Grid from '@material-ui/core/Grid'; import { makeStyles } from '@material-ui/core/styles'; @@ -39,7 +38,7 @@ export type HeaderClassKey = | 'breadcrumbType' | 'breadcrumbTitle'; -const useStyles = makeStyles( +const useStyles = makeStyles( theme => ({ header: { gridArea: 'pageHeader', diff --git a/packages/core-components/src/layout/HeaderLabel/HeaderLabel.tsx b/packages/core-components/src/layout/HeaderLabel/HeaderLabel.tsx index fdd48a5d81..6a41d6aedc 100644 --- a/packages/core-components/src/layout/HeaderLabel/HeaderLabel.tsx +++ b/packages/core-components/src/layout/HeaderLabel/HeaderLabel.tsx @@ -14,7 +14,6 @@ * limitations under the License. */ -import { BackstageTheme } from '@backstage/theme'; import Grid from '@material-ui/core/Grid'; import { alpha, makeStyles } from '@material-ui/core/styles'; import Typography from '@material-ui/core/Typography'; @@ -24,7 +23,7 @@ import { Link } from '../../components/Link'; /** @public */ export type HeaderLabelClassKey = 'root' | 'label' | 'value'; -const useStyles = makeStyles( +const useStyles = makeStyles( theme => ({ root: { textAlign: 'left', diff --git a/packages/core-components/src/layout/HeaderTabs/HeaderTabs.test.tsx b/packages/core-components/src/layout/HeaderTabs/HeaderTabs.test.tsx index f656696f8a..5aec83bc2b 100644 --- a/packages/core-components/src/layout/HeaderTabs/HeaderTabs.test.tsx +++ b/packages/core-components/src/layout/HeaderTabs/HeaderTabs.test.tsx @@ -83,4 +83,16 @@ describe('', () => { expect(rendered.getByText('Alarms')).toBeInTheDocument(); expect(rendered.getByText('three new alarms')).toBeInTheDocument(); }); + + it('should trigger onChange only once', async () => { + const mockOnChange = jest.fn(); + const user = userEvent.setup(); + + const rendered = await renderInTestApp( + , + ); + + await user.click(rendered.getByText('Docs')); + expect(mockOnChange).toHaveBeenCalledTimes(1); + }); }); diff --git a/packages/core-components/src/layout/HeaderTabs/HeaderTabs.tsx b/packages/core-components/src/layout/HeaderTabs/HeaderTabs.tsx index 704df67374..799eab1eb5 100644 --- a/packages/core-components/src/layout/HeaderTabs/HeaderTabs.tsx +++ b/packages/core-components/src/layout/HeaderTabs/HeaderTabs.tsx @@ -99,7 +99,6 @@ export function HeaderTabs(props: HeaderTabsProps) { return ( +const styles = (theme: Theme) => createStyles({ root: { color: theme.palette.common.white, diff --git a/packages/core-components/src/layout/Page/Page.tsx b/packages/core-components/src/layout/Page/Page.tsx index e388e0366a..28194b2889 100644 --- a/packages/core-components/src/layout/Page/Page.tsx +++ b/packages/core-components/src/layout/Page/Page.tsx @@ -15,12 +15,11 @@ */ import React from 'react'; -import { BackstageTheme } from '@backstage/theme'; -import { makeStyles, ThemeProvider } from '@material-ui/core/styles'; +import { makeStyles, Theme, ThemeProvider } from '@material-ui/core/styles'; export type PageClassKey = 'root'; -const useStyles = makeStyles( +const useStyles = makeStyles( theme => ({ root: { display: 'grid', @@ -53,7 +52,7 @@ export function Page(props: Props) { const classes = useStyles(); return ( ({ + theme={(baseTheme: Theme) => ({ ...baseTheme, page: baseTheme.getPageTheme({ themeId }), })} diff --git a/packages/core-components/src/layout/Sidebar/Bar.tsx b/packages/core-components/src/layout/Sidebar/Bar.tsx index 8cb43ba007..550c614522 100644 --- a/packages/core-components/src/layout/Sidebar/Bar.tsx +++ b/packages/core-components/src/layout/Sidebar/Bar.tsx @@ -14,10 +14,9 @@ * limitations under the License. */ -import { BackstageTheme } from '@backstage/theme'; import Box from '@material-ui/core/Box'; import Button from '@material-ui/core/Button'; -import { makeStyles } from '@material-ui/core/styles'; +import { makeStyles, Theme } from '@material-ui/core/styles'; import useMediaQuery from '@material-ui/core/useMediaQuery'; import classnames from 'classnames'; import React, { useContext, useRef, useState } from 'react'; @@ -38,7 +37,7 @@ import { useSidebarPinState } from './SidebarPinStateContext'; /** @public */ export type SidebarClassKey = 'drawer' | 'drawerOpen'; -const useStyles = makeStyles( +const useStyles = makeStyles( theme => ({ drawer: { display: 'flex', @@ -133,7 +132,7 @@ const DesktopSidebar = (props: DesktopSidebarProps) => { } = props; const classes = useStyles({ sidebarConfig }); - const isSmallScreen = useMediaQuery( + const isSmallScreen = useMediaQuery( theme => theme.breakpoints.down('md'), { noSsr: true }, ); diff --git a/packages/core-components/src/layout/Sidebar/Intro.tsx b/packages/core-components/src/layout/Sidebar/Intro.tsx index 824e9e42fd..6f75f096fb 100644 --- a/packages/core-components/src/layout/Sidebar/Intro.tsx +++ b/packages/core-components/src/layout/Sidebar/Intro.tsx @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { BackstageTheme } from '@backstage/theme'; + import Box from '@material-ui/core/Box'; import Collapse from '@material-ui/core/Collapse'; import IconButton from '@material-ui/core/IconButton'; -import { makeStyles } from '@material-ui/core/styles'; +import { makeStyles, Theme } from '@material-ui/core/styles'; import Typography from '@material-ui/core/Typography'; import CloseIcon from '@material-ui/icons/Close'; import { useLocalStorageValue } from '@react-hookz/web'; @@ -39,7 +39,7 @@ export type SidebarIntroClassKey = | 'introDismissText' | 'introDismissIcon'; -const useStyles = makeStyles( +const useStyles = makeStyles( theme => ({ introCard: props => ({ color: '#b5b5b5', diff --git a/packages/core-components/src/layout/Sidebar/Items.tsx b/packages/core-components/src/layout/Sidebar/Items.tsx index aba4c79181..b2449075cc 100644 --- a/packages/core-components/src/layout/Sidebar/Items.tsx +++ b/packages/core-components/src/layout/Sidebar/Items.tsx @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { IconComponent, useAnalytics, useElementFilter, } from '@backstage/core-plugin-api'; -import { BackstageTheme } from '@backstage/theme'; import Badge from '@material-ui/core/Badge'; import Box from '@material-ui/core/Box'; import { makeStyles, styled, Theme } from '@material-ui/core/styles'; @@ -34,7 +34,7 @@ import ArrowDropUp from '@material-ui/icons/ArrowDropUp'; import ArrowRightIcon from '@material-ui/icons/ArrowRight'; import SearchIcon from '@material-ui/icons/Search'; import classnames from 'classnames'; -import { Location } from 'history'; +import type { Location } from 'history'; import React, { ComponentProps, ComponentType, @@ -90,7 +90,7 @@ export type SidebarItemClassKey = | 'selected'; const makeSidebarStyles = (sidebarConfig: SidebarConfig) => - makeStyles( + makeStyles( theme => ({ root: { color: theme.palette.navigation.color, @@ -501,7 +501,7 @@ const SidebarItemWithSubmenu = ({ const [isHoveredOn, setIsHoveredOn] = useState(false); const location = useLocation(); const isActive = useLocationMatch(children, location); - const isSmallScreen = useMediaQuery((theme: BackstageTheme) => + const isSmallScreen = useMediaQuery((theme: Theme) => theme.breakpoints.down('sm'), ); @@ -726,7 +726,7 @@ export const SidebarExpandButton = () => { const { sidebarConfig } = useContext(SidebarConfigContext); const classes = useMemoStyles(sidebarConfig); const { isOpen, setOpen } = useSidebarOpenState(); - const isSmallScreen = useMediaQuery( + const isSmallScreen = useMediaQuery( theme => theme.breakpoints.down('md'), { noSsr: true }, ); diff --git a/packages/core-components/src/layout/Sidebar/MobileSidebar.test.tsx b/packages/core-components/src/layout/Sidebar/MobileSidebar.test.tsx index 7012afabf1..c29276a6cf 100644 --- a/packages/core-components/src/layout/Sidebar/MobileSidebar.test.tsx +++ b/packages/core-components/src/layout/Sidebar/MobileSidebar.test.tsx @@ -14,7 +14,8 @@ * limitations under the License. */ -import { mockBreakpoint, renderInTestApp } from '@backstage/test-utils'; +import { renderInTestApp } from '@backstage/test-utils'; +import { mockBreakpoint } from '@backstage/core-components/testUtils'; import CreateComponentIcon from '@material-ui/icons/AddCircleOutline'; import HomeIcon from '@material-ui/icons/Home'; import LayersIcon from '@material-ui/icons/Layers'; diff --git a/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx b/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx index 88d653cea5..bc38f5510c 100644 --- a/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx +++ b/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx @@ -15,11 +15,10 @@ */ import { useElementFilter } from '@backstage/core-plugin-api'; -import { BackstageTheme } from '@backstage/theme'; import BottomNavigation from '@material-ui/core/BottomNavigation'; import Box from '@material-ui/core/Box'; import IconButton from '@material-ui/core/IconButton'; -import { makeStyles } from '@material-ui/core/styles'; +import { Theme, makeStyles } from '@material-ui/core/styles'; import Drawer from '@material-ui/core/Drawer'; import Typography from '@material-ui/core/Typography'; import CloseIcon from '@material-ui/icons/Close'; @@ -51,7 +50,7 @@ type OverlayMenuProps = { children?: React.ReactNode; }; -const useStyles = makeStyles( +const useStyles = makeStyles( theme => ({ root: { position: 'fixed', diff --git a/packages/core-components/src/layout/Sidebar/Page.tsx b/packages/core-components/src/layout/Sidebar/Page.tsx index c0107256e1..09d5bd910c 100644 --- a/packages/core-components/src/layout/Sidebar/Page.tsx +++ b/packages/core-components/src/layout/Sidebar/Page.tsx @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { BackstageTheme } from '@backstage/theme'; + import Box from '@material-ui/core/Box'; -import { makeStyles } from '@material-ui/core/styles'; +import { makeStyles, Theme } from '@material-ui/core/styles'; import useMediaQuery from '@material-ui/core/useMediaQuery'; import React, { createContext, @@ -34,7 +34,7 @@ import { SidebarPinStateProvider } from './SidebarPinStateContext'; export type SidebarPageClassKey = 'root'; const useStyles = makeStyles< - BackstageTheme, + Theme, { sidebarConfig: SidebarConfig; isPinned: boolean } >( theme => ({ @@ -107,10 +107,9 @@ export function SidebarPage(props: SidebarPageProps) { LocalStorage.setSidebarPinState(isPinned); }, [isPinned]); - const isMobile = useMediaQuery( - theme => theme.breakpoints.down('xs'), - { noSsr: true }, - ); + const isMobile = useMediaQuery(theme => theme.breakpoints.down('xs'), { + noSsr: true, + }); const toggleSidebarPinState = () => setIsPinned(!isPinned); diff --git a/packages/core-components/src/layout/Sidebar/SidebarGroup.test.tsx b/packages/core-components/src/layout/Sidebar/SidebarGroup.test.tsx index 687140277a..b59395efab 100644 --- a/packages/core-components/src/layout/Sidebar/SidebarGroup.test.tsx +++ b/packages/core-components/src/layout/Sidebar/SidebarGroup.test.tsx @@ -14,7 +14,8 @@ * limitations under the License. */ -import { mockBreakpoint, renderInTestApp } from '@backstage/test-utils'; +import { mockBreakpoint } from '@backstage/core-components/testUtils'; +import { renderInTestApp } from '@backstage/test-utils'; import HomeIcon from '@material-ui/icons/Home'; import LayersIcon from '@material-ui/icons/Layers'; import LibraryBooks from '@material-ui/icons/LibraryBooks'; diff --git a/packages/core-components/src/layout/Sidebar/SidebarGroup.tsx b/packages/core-components/src/layout/Sidebar/SidebarGroup.tsx index 2ce68cd51a..7944728af6 100644 --- a/packages/core-components/src/layout/Sidebar/SidebarGroup.tsx +++ b/packages/core-components/src/layout/Sidebar/SidebarGroup.tsx @@ -15,11 +15,10 @@ * limitations under the License. */ -import { BackstageTheme } from '@backstage/theme'; import BottomNavigationAction, { BottomNavigationActionProps, } from '@material-ui/core/BottomNavigationAction'; -import { makeStyles } from '@material-ui/core/styles'; +import { Theme, makeStyles } from '@material-ui/core/styles'; import React, { useContext } from 'react'; import { useLocation } from 'react-router-dom'; import { Link } from '../../components/Link/Link'; @@ -48,7 +47,7 @@ export interface SidebarGroupProps extends BottomNavigationActionProps { children?: React.ReactNode; } -const useStyles = makeStyles( +const useStyles = makeStyles( theme => ({ root: { flexGrow: 0, diff --git a/packages/core-components/src/layout/Sidebar/SidebarSubmenu.tsx b/packages/core-components/src/layout/Sidebar/SidebarSubmenu.tsx index 85ba923672..6b6951d023 100644 --- a/packages/core-components/src/layout/Sidebar/SidebarSubmenu.tsx +++ b/packages/core-components/src/layout/Sidebar/SidebarSubmenu.tsx @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { BackstageTheme } from '@backstage/theme'; + import Box from '@material-ui/core/Box'; -import { makeStyles } from '@material-ui/core/styles'; +import { makeStyles, Theme } from '@material-ui/core/styles'; import Typography from '@material-ui/core/Typography'; import classnames from 'classnames'; import React, { ReactNode, useContext, useEffect, useState } from 'react'; @@ -28,7 +28,7 @@ import { import { useSidebarOpenState } from './SidebarOpenStateContext'; const useStyles = makeStyles< - BackstageTheme, + Theme, { submenuConfig: SubmenuConfig; left: number } >( theme => ({ diff --git a/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx b/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx index d1925036bb..0503f58f1c 100644 --- a/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx +++ b/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import React, { useContext, useState } from 'react'; import { resolvePath, useLocation, useResolvedPath } from 'react-router-dom'; import { makeStyles } from '@material-ui/core/styles'; @@ -21,7 +22,6 @@ import Typography from '@material-ui/core/Typography'; import { Link } from '../../components/Link'; import { IconComponent } from '@backstage/core-plugin-api'; import classnames from 'classnames'; -import { BackstageTheme } from '@backstage/theme'; import ArrowDropDownIcon from '@material-ui/icons/ArrowDropDown'; import ArrowDropUpIcon from '@material-ui/icons/ArrowDropUp'; import { SidebarItemWithSubmenuContext } from './config'; @@ -29,7 +29,7 @@ import { isLocationMatch } from './utils'; import Box from '@material-ui/core/Box'; import Button from '@material-ui/core/Button'; -const useStyles = makeStyles( +const useStyles = makeStyles( theme => ({ item: { height: 48, diff --git a/packages/core-components/src/layout/Sidebar/utils.test.ts b/packages/core-components/src/layout/Sidebar/utils.test.ts index 976108a63d..19fe3e5671 100644 --- a/packages/core-components/src/layout/Sidebar/utils.test.ts +++ b/packages/core-components/src/layout/Sidebar/utils.test.ts @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { Location, Path } from 'history'; +import type { Location, Path } from 'history'; import { isLocationMatch } from './utils'; describe('isLocationMatching', () => { diff --git a/packages/core-components/src/layout/Sidebar/utils.ts b/packages/core-components/src/layout/Sidebar/utils.ts index 5dba73f4cd..bf5f77a26f 100644 --- a/packages/core-components/src/layout/Sidebar/utils.ts +++ b/packages/core-components/src/layout/Sidebar/utils.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { Location, Path } from 'history'; +import type { Location, Path } from 'history'; import { isEqual, isMatch } from 'lodash'; import qs from 'qs'; diff --git a/packages/core-components/src/layout/TabbedCard/TabbedCard.test.tsx b/packages/core-components/src/layout/TabbedCard/TabbedCard.test.tsx index 1b7c3329a2..707d528867 100644 --- a/packages/core-components/src/layout/TabbedCard/TabbedCard.test.tsx +++ b/packages/core-components/src/layout/TabbedCard/TabbedCard.test.tsx @@ -18,6 +18,7 @@ import { renderInTestApp, wrapInTestApp } from '@backstage/test-utils'; import { fireEvent, render, screen } from '@testing-library/react'; import React from 'react'; import { CardTab, TabbedCard } from './TabbedCard'; +import userEvent from '@testing-library/user-event'; const minProps = { title: 'Some title', @@ -96,4 +97,25 @@ describe('', () => { ); expect(screen.getByText('Test Content 2')).toBeInTheDocument(); }); + + it('should trigger onChange only once', async () => { + const mockOnChange = jest.fn(); + const user = userEvent.setup(); + + const rendered = render( + wrapInTestApp( + + + Test Content 1 + + + Test Content 2 + + , + ), + ); + + await user.click(rendered.getByText('Test 2')); + expect(mockOnChange).toHaveBeenCalledTimes(1); + }); }); diff --git a/packages/core-components/src/layout/TabbedCard/TabbedCard.tsx b/packages/core-components/src/layout/TabbedCard/TabbedCard.tsx index 4e75878a7d..088e54c1f3 100644 --- a/packages/core-components/src/layout/TabbedCard/TabbedCard.tsx +++ b/packages/core-components/src/layout/TabbedCard/TabbedCard.tsx @@ -114,7 +114,6 @@ export function TabbedCard(props: PropsWithChildren) { {title && } >; }; + +declare module '@backstage/theme' { + interface OverrideComponentNameToClassKeys + extends BackstageComponentsNameToClassKey {} +} diff --git a/packages/core-components/src/testUtils.ts b/packages/core-components/src/testUtils.ts new file mode 100644 index 0000000000..17bb0db63b --- /dev/null +++ b/packages/core-components/src/testUtils.ts @@ -0,0 +1,43 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This is a mocking method suggested in the Jest docs, as it is not implemented in JSDOM yet. + * It can be used to mock values for the Material UI `useMediaQuery` hook if it is used in a tested component. + * + * For issues checkout the documentation: + * https://jestjs.io/docs/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom + * + * If there are any updates from Material UI React on testing `useMediaQuery` this mock should be replaced + * https://mui.com/material-ui/react-use-media-query/#testing + * + * @public + */ +export function mockBreakpoint(options: { matches: boolean }) { + Object.defineProperty(window, 'matchMedia', { + writable: true, + value: jest.fn().mockImplementation(query => ({ + matches: options.matches ?? false, + media: query, + onchange: null, + addListener: jest.fn(), // deprecated + removeListener: jest.fn(), // deprecated + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn(), + })), + }); +} diff --git a/packages/core-plugin-api/CHANGELOG.md b/packages/core-plugin-api/CHANGELOG.md index 23dbfc0968..4cb681e4aa 100644 --- a/packages/core-plugin-api/CHANGELOG.md +++ b/packages/core-plugin-api/CHANGELOG.md @@ -1,5 +1,73 @@ # @backstage/core-plugin-api +## 1.8.2 + +### Patch Changes + +- 6878b1d: Removed unnecessary `i18next` dependency. +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## 1.8.2-next.0 + +### Patch Changes + +- 6878b1d: Removed unnecessary `i18next` dependency. +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## 1.8.1 + +### Patch Changes + +- 03d0b6d: Removed the alpha `convertLegacyRouteRef` utility, which as been moved to `@backstage/core-compat-api` +- 0c93dc3: The `createTranslationRef` function from the `/alpha` subpath can now also accept a nested object structure of default translation messages, which will be flatted using `.` separators. +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## 1.8.1-next.1 + +### Patch Changes + +- 0c93dc37b2: The `createTranslationRef` function from the `/alpha` subpath can now also accept a nested object structure of default translation messages, which will be flatted using `.` separators. +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## 1.8.1-next.0 + +### Patch Changes + +- 03d0b6dcdc: Removed the alpha `convertLegacyRouteRef` utility, which as been moved to `@backstage/core-compat-api` +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## 1.8.0 + +### Minor Changes + +- 1e5b7d993a: `IconComponent` can now have a `fontSize` of `inherit`, which is useful for in-line icons. +- cb6db75bc2: Introduced `AnyRouteRefParams` as a replacement for `AnyParams`, which is now deprecated. + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- cb6db75bc2: Deprecated several types related to the routing system that are scheduled to be removed, as well as several fields on the route ref types themselves. +- 68fc9dc60e: Added a new `/alpha` export `convertLegacyRouteRef`, which is a temporary utility to allow existing route refs to be used with the new experimental packages. +- Updated dependencies + - @backstage/version-bridge@1.0.7 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + ## 1.8.0-next.0 ### Minor Changes diff --git a/packages/core-plugin-api/alpha-api-report.md b/packages/core-plugin-api/api-report-alpha.md similarity index 82% rename from packages/core-plugin-api/alpha-api-report.md rename to packages/core-plugin-api/api-report-alpha.md index 0284d691a9..c0f0d02535 100644 --- a/packages/core-plugin-api/alpha-api-report.md +++ b/packages/core-plugin-api/api-report-alpha.md @@ -3,12 +3,8 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts -import { AnyRouteRefParams } from '@backstage/core-plugin-api'; import { ApiRef } from '@backstage/core-plugin-api'; -import { ExternalRouteRef } from '@backstage/core-plugin-api'; import { Observable } from '@backstage/types'; -import { RouteRef } from '@backstage/core-plugin-api'; -import { SubRouteRef } from '@backstage/core-plugin-api'; import { TranslationMessages as TranslationMessages_2 } from '@backstage/core-plugin-api/alpha'; import { TranslationRef as TranslationRef_2 } from '@backstage/core-plugin-api/alpha'; @@ -29,24 +25,6 @@ export type AppLanguageApi = { // @alpha (undocumented) export const appLanguageApiRef: ApiRef; -// @public -export function convertLegacyRouteRef( - ref: RouteRef, -): NewRouteRef; - -// @public -export function convertLegacyRouteRef( - ref: SubRouteRef, -): NewSubRouteRef; - -// @public -export function convertLegacyRouteRef< - TParams extends AnyRouteRefParams, - TOptional extends boolean, ->( - ref: ExternalRouteRef, -): NewExternalRouteRef; - // @alpha export function createTranslationMessages< TId extends string, @@ -61,19 +39,17 @@ export function createTranslationMessages< // @alpha (undocumented) export function createTranslationRef< TId extends string, - const TMessages extends { - [key in string]: string; - }, + const TNestedMessages extends AnyNestedMessages, TTranslations extends { [language in string]: () => Promise<{ default: { - [key in keyof TMessages]: string | null; + [key in keyof FlattenedMessages]: string | null; }; }>; }, >( - config: TranslationRefOptions, -): TranslationRef; + config: TranslationRefOptions, +): TranslationRef>; // @alpha (undocumented) export function createTranslationResource< @@ -191,13 +167,11 @@ export interface TranslationRef< // @alpha (undocumented) export interface TranslationRefOptions< TId extends string, - TMessages extends { - [key in string]: string; - }, + TNestedMessages extends AnyNestedMessages, TTranslations extends { [language in string]: () => Promise<{ default: { - [key in keyof TMessages]: string | null; + [key in keyof FlattenedMessages]: string | null; }; }>; }, @@ -205,7 +179,7 @@ export interface TranslationRefOptions< // (undocumented) id: TId; // (undocumented) - messages: TMessages; + messages: TNestedMessages; // (undocumented) translations?: TTranslations; } diff --git a/packages/core-plugin-api/package.json b/packages/core-plugin-api/package.json index 5aac6b3fb7..d676260227 100644 --- a/packages/core-plugin-api/package.json +++ b/packages/core-plugin-api/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/core-plugin-api", "description": "Core API used by Backstage plugins", - "version": "1.8.0-next.0", + "version": "1.8.2", "publishConfig": { "access": "public" }, @@ -50,8 +50,7 @@ "@backstage/types": "workspace:^", "@backstage/version-bridge": "workspace:^", "@types/react": "^16.13.1 || ^17.0.0", - "history": "^5.0.0", - "i18next": "^22.4.15" + "history": "^5.0.0" }, "peerDependencies": { "react": "^16.13.1 || ^17.0.0 || ^18.0.0", diff --git a/packages/core-plugin-api/src/alpha.ts b/packages/core-plugin-api/src/alpha.ts index 540b4ed22a..ebcbcf34c0 100644 --- a/packages/core-plugin-api/src/alpha.ts +++ b/packages/core-plugin-api/src/alpha.ts @@ -16,4 +16,3 @@ export * from './translation'; export * from './apis/alpha'; -export { convertLegacyRouteRef } from './routing/convertLegacyRouteRef'; diff --git a/packages/core-plugin-api/src/translation/TranslationRef.test.ts b/packages/core-plugin-api/src/translation/TranslationRef.test.ts index b73b521774..d1fde0810f 100644 --- a/packages/core-plugin-api/src/translation/TranslationRef.test.ts +++ b/packages/core-plugin-api/src/translation/TranslationRef.test.ts @@ -34,6 +34,40 @@ describe('TranslationRefImpl', () => { expect(internalRef.getDefaultMessages()).toEqual({ key: 'value' }); }); + it('should create a TranslationRef instance with nested messages', () => { + const ref = createTranslationRef({ + id: 'test', + messages: { + key: 'value', + 'nested.conflict1': 'outer conflict1', + nested: { + key: 'nested value', + key2: 'nested value2', + conflict1: 'inner conflict1', + conflict2: 'inner conflict2', + inner: { + key: 'inner value', + }, + }, + 'nested.conflict2': 'outer conflict2', + }, + }); + + const internalRef = toInternalTranslationRef(ref); + + expect(internalRef.$$type).toBe('@backstage/TranslationRef'); + expect(internalRef.version).toBe('v1'); + expect(internalRef.id).toBe('test'); + expect(internalRef.getDefaultMessages()).toEqual({ + key: 'value', + 'nested.key': 'nested value', + 'nested.key2': 'nested value2', + 'nested.conflict1': 'inner conflict1', + 'nested.inner.key': 'inner value', + 'nested.conflict2': 'outer conflict2', + }); + }); + it('should be created with lazy translations', async () => { const ref = createTranslationRef({ id: 'test', diff --git a/packages/core-plugin-api/src/translation/TranslationRef.ts b/packages/core-plugin-api/src/translation/TranslationRef.ts index 345a9c3f65..c2ac7a5ce3 100644 --- a/packages/core-plugin-api/src/translation/TranslationRef.ts +++ b/packages/core-plugin-api/src/translation/TranslationRef.ts @@ -34,6 +34,43 @@ export interface TranslationRef< /** @internal */ type AnyMessages = { [key in string]: string }; +/** @ignore */ +type AnyNestedMessages = { [key in string]: AnyNestedMessages | string }; + +/** + * Flattens a nested message declaration into a flat object with dot-separated keys. + * + * @ignore + */ +type FlattenedMessages = + // Flatten out object keys into a union structure of objects, e.g. { a: 'a', b: 'b' } -> { a: 'a' } | { b: 'b' } + // Any nested object will be flattened into the individual unions, e.g. { a: 'a', b: { x: 'x', y: 'y' } } -> { a: 'a' } | { 'b.x': 'x', 'b.y': 'y' } + // We create this structure by first nesting the desired union types into the original object, and + // then extract them by indexing with `keyof TMessages` to form the union. + // Throughout this the objects are wrapped up in a function parameter, which allows us to have the + // final step of flipping this unions around to an intersection by inferring the function parameter. + { + [TKey in keyof TMessages]: ( + _: TMessages[TKey] extends infer TValue // "local variable" for the value + ? TValue extends AnyNestedMessages + ? FlattenedMessages extends infer TNested // Recurse into nested messages, "local variable" for the result + ? { + [TNestedKey in keyof TNested as `${TKey & string}.${TNestedKey & + string}`]: TNested[TNestedKey]; + } + : never + : { [_ in TKey]: TValue } // Primitive object values are passed through with the same key + : never, + ) => void; + // The `[keyof TMessages]` extracts the object values union from our flattened structure, still wrapped up in function parameters. + // The `extends (_: infer TIntersection) => void` flips the union to an intersection, at which point we have the correct type. + }[keyof TMessages] extends (_: infer TIntersection) => void + ? // This object mapping just expands similar to the Expand<> utility type, providing nicer type hints + { + readonly [TExpandKey in keyof TIntersection]: TIntersection[TExpandKey]; + } + : never; + /** @internal */ export interface InternalTranslationRef< TId extends string = string, @@ -49,31 +86,53 @@ export interface InternalTranslationRef< /** @alpha */ export interface TranslationRefOptions< TId extends string, - TMessages extends { [key in string]: string }, + TNestedMessages extends AnyNestedMessages, TTranslations extends { [language in string]: () => Promise<{ - default: { [key in keyof TMessages]: string | null }; + default: { + [key in keyof FlattenedMessages]: string | null; + }; }>; }, > { id: TId; - messages: TMessages; + messages: TNestedMessages; translations?: TTranslations; } +function flattenMessages(nested: AnyNestedMessages): AnyMessages { + const entries = new Array<[string, string]>(); + + function visit(obj: AnyNestedMessages, prefix: string): void { + for (const [key, value] of Object.entries(obj)) { + if (typeof value === 'string') { + entries.push([prefix + key, value]); + } else { + visit(value, `${prefix}${key}.`); + } + } + } + + visit(nested, ''); + + return Object.fromEntries(entries); +} + /** @internal */ class TranslationRefImpl< TId extends string, - TMessages extends { [key in string]: string }, -> implements InternalTranslationRef + TNestedMessages extends AnyNestedMessages, +> implements InternalTranslationRef> { #id: TId; - #messages: TMessages; + #messages: FlattenedMessages; #resources: TranslationResource | undefined; - constructor(options: TranslationRefOptions) { + constructor(options: TranslationRefOptions) { this.#id = options.id; - this.#messages = options.messages; + this.#messages = flattenMessages( + options.messages, + ) as FlattenedMessages; } $$type = '@backstage/TranslationRef' as const; @@ -108,15 +167,17 @@ class TranslationRefImpl< /** @alpha */ export function createTranslationRef< TId extends string, - const TMessages extends { [key in string]: string }, + const TNestedMessages extends AnyNestedMessages, TTranslations extends { [language in string]: () => Promise<{ - default: { [key in keyof TMessages]: string | null }; + default: { + [key in keyof FlattenedMessages]: string | null; + }; }>; }, >( - config: TranslationRefOptions, -): TranslationRef { + config: TranslationRefOptions, +): TranslationRef> { const ref = new TranslationRefImpl(config); if (config.translations) { ref.setDefaultResource( @@ -132,7 +193,7 @@ export function createTranslationRef< /** @internal */ export function toInternalTranslationRef< TId extends string, - TMessages extends { [key in string]: string }, + TMessages extends AnyMessages, >(ref: TranslationRef): InternalTranslationRef { const r = ref as InternalTranslationRef; if (r.$$type !== '@backstage/TranslationRef') { diff --git a/packages/create-app/CHANGELOG.md b/packages/create-app/CHANGELOG.md index 1260ed1e4a..3008a3a03d 100644 --- a/packages/create-app/CHANGELOG.md +++ b/packages/create-app/CHANGELOG.md @@ -1,5 +1,113 @@ # @backstage/create-app +## 0.5.9 + +### Patch Changes + +- c9f71fb: Bumped create-app version. +- ac277f3: Bumped create-app version. +- 7acbb5a: Removed `mock-fs` dev dependency. +- Updated dependencies + - @backstage/cli-common@0.1.13 + +## 0.5.9-next.2 + +### Patch Changes + +- Bumped create-app version. + +## 0.5.9-next.1 + +### Patch Changes + +- 7acbb5a: Removed `mock-fs` dev dependency. +- Updated dependencies + - @backstage/cli-common@0.1.13 + +## 0.5.9-next.0 + +### Patch Changes + +- Bumped create-app version. +- Updated dependencies + - @backstage/cli-common@0.1.13 + +## 0.5.8 + +### Patch Changes + +- 8ece804: Bumped create-app version. +- 0351e09: Bumped create-app version. +- 3f1192f: Bumped create-app version. +- a96c2d4: Include the `` for group entities by default +- 375b6f7: CircelCI plugin moved permanently +- Updated dependencies + - @backstage/cli-common@0.1.13 + +## 0.5.8-next.4 + +### Patch Changes + +- Bumped create-app version. +- Updated dependencies + - @backstage/cli-common@0.1.13 + +## 0.5.8-next.3 + +### Patch Changes + +- a96c2d4: Include the `` for group entities by default +- Updated dependencies + - @backstage/cli-common@0.1.13 + +## 0.5.8-next.2 + +### Patch Changes + +- 375b6f7d68: CircelCI plugin moved permanently +- Updated dependencies + - @backstage/cli-common@0.1.13 + +## 0.5.8-next.1 + +### Patch Changes + +- Bumped create-app version. + +## 0.5.8-next.0 + +### Patch Changes + +- Bumped create-app version. +- Updated dependencies + - @backstage/cli-common@0.1.13 + +## 0.5.7 + +### Patch Changes + +- 770763487a: Cleaned up cases where deprecated code was being used but had a new location they should be imported from +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. + + You can do the same in your own Backstage repository to ensure that you get future node 18+ relevant updates, by having the following lines in your `packages/backend/package.json`: + + ``` + "dependencies": { + // ... + "knex": "^3.0.0" + }, + "devDependencies": { + // ... + "better-sqlite3": "^9.0.0", + ``` + +- f577e1176f: Bumped create-app version. +- 6c2b872153: Add official support for React 18. +- ae1602e54d: If create app installs dependencies, don't suggest to user that they also need to do it. +- e6b7ab8d2b: Added missing node-gyp dependency to fix Docker image build +- Updated dependencies + - @backstage/cli-common@0.1.13 + ## 0.5.7-next.2 ### Patch Changes diff --git a/packages/create-app/package.json b/packages/create-app/package.json index f1ae787ca8..e9f73d6e1f 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.7-next.2", + "version": "0.5.9", "publishConfig": { "access": "public" }, @@ -49,7 +49,6 @@ "@types/inquirer": "^8.1.3", "@types/node": "^18.17.8", "@types/recursive-readdir": "^2.2.0", - "mock-fs": "^5.2.0", "nodemon": "^3.0.1", "ts-node": "^10.0.0" }, diff --git a/packages/create-app/src/lib/versions.ts b/packages/create-app/src/lib/versions.ts index 81bae3c0b8..03ef32d921 100644 --- a/packages/create-app/src/lib/versions.ts +++ b/packages/create-app/src/lib/versions.ts @@ -58,7 +58,6 @@ import { version as pluginCatalogBackend } from '../../../../plugins/catalog-bac import { version as pluginCatalogBackendModuleScaffolderEntityModel } from '../../../../plugins/catalog-backend-module-scaffolder-entity-model/package.json'; import { version as pluginCatalogGraph } from '../../../../plugins/catalog-graph/package.json'; import { version as pluginCatalogImport } from '../../../../plugins/catalog-import/package.json'; -import { version as pluginCircleci } from '../../../../plugins/circleci/package.json'; import { version as pluginExplore } from '../../../../plugins/explore/package.json'; import { version as pluginGithubActions } from '../../../../plugins/github-actions/package.json'; import { version as pluginLighthouse } from '../../../../plugins/lighthouse/package.json'; @@ -111,7 +110,6 @@ export const packageVersions = { pluginCatalogBackendModuleScaffolderEntityModel, '@backstage/plugin-catalog-graph': pluginCatalogGraph, '@backstage/plugin-catalog-import': pluginCatalogImport, - '@backstage/plugin-circleci': pluginCircleci, '@backstage/plugin-explore': pluginExplore, '@backstage/plugin-github-actions': pluginGithubActions, '@backstage/plugin-lighthouse': pluginLighthouse, diff --git a/packages/create-app/templates/default-app/packages/app/src/components/catalog/EntityPage.tsx b/packages/create-app/templates/default-app/packages/app/src/components/catalog/EntityPage.tsx index 6722ea2d03..7c6a71e070 100644 --- a/packages/create-app/templates/default-app/packages/app/src/components/catalog/EntityPage.tsx +++ b/packages/create-app/templates/default-app/packages/app/src/components/catalog/EntityPage.tsx @@ -300,9 +300,12 @@ const groupPage = ( - + + + + diff --git a/packages/dev-utils/CHANGELOG.md b/packages/dev-utils/CHANGELOG.md index 4cc9fc7b4c..602f2b563e 100644 --- a/packages/dev-utils/CHANGELOG.md +++ b/packages/dev-utils/CHANGELOG.md @@ -1,5 +1,141 @@ # @backstage/dev-utils +## 1.0.26 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/app-defaults@1.4.7 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/core-app-api@1.11.3 + - @backstage/theme@0.5.0 + +## 1.0.26-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + - @backstage/integration-react@1.1.23-next.0 + +## 1.0.26-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/app-defaults@1.4.7-next.1 + - @backstage/core-app-api@1.11.3-next.0 + - @backstage/integration-react@1.1.23-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0 + +## 1.0.26-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/app-defaults@1.4.7-next.0 + - @backstage/integration-react@1.1.22 + - @backstage/catalog-model@1.4.3 + - @backstage/core-app-api@1.11.2 + - @backstage/core-plugin-api@1.8.1 + - @backstage/theme@0.5.0 + +## 1.0.25 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/core-app-api@1.11.2 + - @backstage/app-defaults@1.4.6 + - @backstage/integration-react@1.1.22 + - @backstage/catalog-model@1.4.3 + +## 1.0.25-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/app-defaults@1.4.6-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## 1.0.25-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/app-defaults@1.4.6-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/integration-react@1.1.22-next.1 + +## 1.0.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/app-defaults@1.4.6-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## 1.0.25-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/app-defaults@1.4.6-next.0 + - @backstage/core-app-api@1.11.2-next.0 + - @backstage/integration-react@1.1.22-next.0 + - @backstage/catalog-model@1.4.3 + +## 1.0.23 + +### Patch Changes + +- 67cc85bb14: Switched the conditional `react-dom/client` import to use `import(...)` rather than `require(...)`. +- 38cda52746: Added support for React 18. The new `createRoot` API from `react-dom/client` will now be used if present. +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/integration-react@1.1.21 + - @backstage/core-plugin-api@1.8.0 + - @backstage/app-defaults@1.4.5 + - @backstage/core-app-api@1.11.1 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + ## 1.0.23-next.2 ### Patch Changes diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index a4fce127b3..40537c1a98 100644 --- a/packages/dev-utils/package.json +++ b/packages/dev-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/dev-utils", "description": "Utilities for developing Backstage plugins.", - "version": "1.0.23-next.2", + "version": "1.0.26", "publishConfig": { "access": "public", "main": "dist/index.esm.js", diff --git a/packages/dev-utils/src/components/EntityGridItem/EntityGridItem.tsx b/packages/dev-utils/src/components/EntityGridItem/EntityGridItem.tsx index a66550a4d2..55bac24a34 100644 --- a/packages/dev-utils/src/components/EntityGridItem/EntityGridItem.tsx +++ b/packages/dev-utils/src/components/EntityGridItem/EntityGridItem.tsx @@ -16,11 +16,10 @@ import { Entity } from '@backstage/catalog-model'; import { EntityProvider } from '@backstage/plugin-catalog-react'; -import { BackstageTheme } from '@backstage/theme'; -import { Grid, GridProps, makeStyles } from '@material-ui/core'; +import { Grid, GridProps, Theme, makeStyles } from '@material-ui/core'; import React from 'react'; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles(theme => ({ root: ({ entity }) => ({ position: 'relative', diff --git a/packages/e2e-test-utils/playwright-api-report.md b/packages/e2e-test-utils/api-report-playwright.md similarity index 100% rename from packages/e2e-test-utils/playwright-api-report.md rename to packages/e2e-test-utils/api-report-playwright.md diff --git a/packages/e2e-test/CHANGELOG.md b/packages/e2e-test/CHANGELOG.md index 20a0576918..f130de43d4 100644 --- a/packages/e2e-test/CHANGELOG.md +++ b/packages/e2e-test/CHANGELOG.md @@ -1,5 +1,100 @@ # e2e-test +## 0.2.11 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.9 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + +## 0.2.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.9-next.2 + +## 0.2.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.9-next.1 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + +## 0.2.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.9-next.0 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + +## 0.2.10 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.8 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + +## 0.2.10-next.4 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.8-next.4 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + +## 0.2.10-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.8-next.3 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + +## 0.2.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.8-next.2 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + +## 0.2.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.8-next.1 + +## 0.2.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.8-next.0 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + +## 0.2.9 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.7 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + ## 0.2.9-next.2 ### Patch Changes diff --git a/packages/e2e-test/package.json b/packages/e2e-test/package.json index 4e01ad4c77..40699588e2 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.9-next.2", + "version": "0.2.11", "private": true, "backstage": { "role": "cli" diff --git a/packages/eslint-plugin/CHANGELOG.md b/packages/eslint-plugin/CHANGELOG.md index 56ed54388a..dd931378ef 100644 --- a/packages/eslint-plugin/CHANGELOG.md +++ b/packages/eslint-plugin/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/eslint-plugin +## 0.1.4 + +### Patch Changes + +- 107dc46: The `no-undeclared-imports` rule will now prefer using version queries that already exist en the repo for the same dependency type when installing new packages. + +## 0.1.4-next.0 + +### Patch Changes + +- 107dc46ab1: The `no-undeclared-imports` rule will now prefer using version queries that already exist en the repo for the same dependency type when installing new packages. + ## 0.1.3 ### Patch Changes diff --git a/packages/eslint-plugin/README.md b/packages/eslint-plugin/README.md index c311670603..600b3268e1 100644 --- a/packages/eslint-plugin/README.md +++ b/packages/eslint-plugin/README.md @@ -35,8 +35,9 @@ rules: { The following rules are provided by this plugin: -| Rule | Description | -| --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | -| [@backstage/no-forbidden-package-imports](./docs/rules/no-forbidden-package-imports.md) | Disallow internal monorepo imports from package subpaths that are not exported. | -| [@backstage/no-relative-monorepo-imports](./docs/rules/no-relative-monorepo-imports.md) | Forbid relative imports that reach outside of the package in a monorepo. | -| [@backstage/no-undeclared-imports](./docs/rules/no-undeclared-imports.md) | Forbid imports of external packages that have not been declared in the appropriate dependencies field in `package.json`. | +| Rule | Description | +| --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | +| [@backstage/no-forbidden-package-imports](./docs/rules/no-forbidden-package-imports.md) | Disallow internal monorepo imports from package subpaths that are not exported. | +| [@backstage/no-relative-monorepo-imports](./docs/rules/no-relative-monorepo-imports.md) | Forbid relative imports that reach outside of the package in a monorepo. | +| [@backstage/no-undeclared-imports](./docs/rules/no-undeclared-imports.md) | Forbid imports of external packages that have not been declared in the appropriate dependencies field in `package.json`. | +| [@backstage/no-top-level-material-ui-4-imports](./docs/rules/no-top-level-material-ui-4-imports.md) | Forbid top level import from Material UI v4 packages. | 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 new file mode 100644 index 0000000000..a105014abc --- /dev/null +++ b/packages/eslint-plugin/docs/rules/no-top-level-material-ui-4-imports.md @@ -0,0 +1,43 @@ +# @backstage/no-top-level-material-ui-4-imports + +Forbid top level import from Material UI v4 packages. + +## Usage + +Add the rules as follows, it has no options: + +```js +'@backstage/no-top-level-material-ui-4-imports': 'error' +``` + +## Rule Details + +Automatically fixes imports from named to default imports. This will help you comply with [Material UI recommendations](https://mui.com/material-ui/guides/minimizing-bundle-size/) and make migrating to Material UI v5 easier. + +### Fail + +```tsx +import { Box, Typography } from '@material-ui/core'; +``` + +```tsx +import Box from '@material-ui/core'; +``` + +```tsx +import { + Box, + DialogActions, + DialogContent, + DialogTitle, + Grid, + makeStyles, +} from '@material-ui/core'; +``` + +### Pass + +```tsx +import Typography from '@material-ui/core/Typography'; +import Box from '@material-ui/core/Box'; +``` diff --git a/packages/eslint-plugin/index.js b/packages/eslint-plugin/index.js index 20a0ff2d18..af1a8891c3 100644 --- a/packages/eslint-plugin/index.js +++ b/packages/eslint-plugin/index.js @@ -29,5 +29,6 @@ module.exports = { 'no-forbidden-package-imports': require('./rules/no-forbidden-package-imports'), 'no-relative-monorepo-imports': require('./rules/no-relative-monorepo-imports'), 'no-undeclared-imports': require('./rules/no-undeclared-imports'), + 'no-top-level-material-ui-4-imports': require('./rules/no-top-level-material-ui-4-imports'), }, }; diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index 34a8205868..a0825c8816 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/eslint-plugin", "description": "Backstage ESLint plugin", - "version": "0.1.3", + "version": "0.1.4", "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 new file mode 100644 index 0000000000..6a726545fc --- /dev/null +++ b/packages/eslint-plugin/rules/no-top-level-material-ui-4-imports.js @@ -0,0 +1,156 @@ +/* + * 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. + */ + +// @ts-check + +const KNOWN_STYLES = [ + 'makeStyles', + 'withStyles', + 'createStyles', + 'styled', + 'useTheme', + 'Theme', +]; + +/** @type {import('eslint').Rule.RuleModule} */ +module.exports = { + meta: { + type: 'problem', + fixable: 'code', + messages: { + topLevelImport: 'Top level imports for Material UI are not allowed', + }, + docs: { + description: 'Forbid top level import from Material UI v4 packages.', + url: 'https://github.com/backstage/backstage/blob/master/packages/eslint-plugin/docs/rules/no-top-level-material-ui-4-imports.md', + }, + }, + create: context => ({ + ImportDeclaration: node => { + // Anatomy of a Node + // Example: import SvgIcon, { SvgIconProps } from '@material-ui/core/SvgIcon'; + // Specifiers are the part between the `import` and `from`, in the example that would be `SvgIcon, { SvgIconProps }` + // Source is the part after the `from`, in the example that would be `'@material-ui/core/SvgIcon'` + // Source value gets you `@material-ui/core/SvgIcon` without the quotes, where as Source raw gets it as is + + // Return if empty import + if (node.specifiers.length === 0) return; + // Return if empty source value + if (!node.source.value) return; + // Return if source value not a string + if (typeof node.source.value !== 'string') return; + // Return if import does not start with '@material-ui/' + if (!node.source.value.startsWith('@material-ui/')) return; + // Return if import is from '@material-ui/core/styles', as it's valid already + if (node.source.value === '@material-ui/core/styles') return; + // Return if proper import eg. `import Box from '@material-ui/core/Box'` + // Or if third level or deeper imports + if (node.source.value?.split('/').length >= 3) return; + + // Report all other imports + context.report({ + node, + messageId: 'topLevelImport', + fix: fixer => { + const replacements = []; + const styles = []; + + const specifiers = node.specifiers.filter( + s => s.type === 'ImportSpecifier', + ); + + const specifiersMap = specifiers.map(s => { + const propsMatch = /^([A-Z]\w+)Props$/.exec(s.local.name); + + return { + emitComponent: !(propsMatch !== null), + emitProp: propsMatch !== null, + value: s.local.name, + propValue: propsMatch ? propsMatch[1] : undefined, + }; + }); + + // We have 3 cases: + // 1 - Just Prop: import { TabProps } from '@material-ui/core'; + // 2 - Just Component: import { Box } from '@material-ui/core'; + // 3 - Component and Prop: import { SvgIcon, SvgIconProps } from '@material-ui/core'; + + const components = specifiersMap + .filter(f => { + return f.emitComponent; + }) + .map(m => m.value); + const props = specifiersMap + .filter(f => { + return f.emitProp; + }) + .map(m => m.value); + + if ( + specifiersMap.some(s => s.emitProp) && + !specifiersMap.some(s => s.emitComponent) + ) { + // 1 - Just Prop + const propValue = specifiersMap + .filter(f => { + return f.emitProp; + }) + .map(m => m.propValue); + replacements.push( + `import { ${props.join(', ')} } from '@material-ui/core/${ + propValue[0] + }';`, + ); + } else if ( + !specifiersMap.some(s => s.emitProp) && + specifiersMap.some(s => s.emitComponent) + ) { + // 2 - Just Component + for (const specifier of specifiers) { + if (KNOWN_STYLES.includes(specifier.local.name)) { + styles.push(specifier.local.name); + } else { + const replacement = `import ${specifier.local.name} from '${node.source.value}/${specifier.local.name}';`; + replacements.push(replacement); + } + } + } else if ( + specifiersMap.some(s => s.emitProp) && + specifiersMap.some(s => s.emitComponent) + ) { + // 3 - Component and Prop + replacements.push( + `import ${components[0]}, { ${props.join( + ', ', + )} } from '@material-ui/core/${components[0]}';`, + ); + } + + if (styles.length > 0) { + const stylesReplacement = `import { ${styles.join( + ', ', + )} } from '@material-ui/core/styles';`; + replacements.push(stylesReplacement); + } + + const result = fixer.replaceText(node, replacements.join('\n')); + + return result; + }, + }); + }, + }), +}; diff --git a/packages/eslint-plugin/rules/no-undeclared-imports.js b/packages/eslint-plugin/rules/no-undeclared-imports.js index c986b52c65..d2c92ccb8a 100644 --- a/packages/eslint-plugin/rules/no-undeclared-imports.js +++ b/packages/eslint-plugin/rules/no-undeclared-imports.js @@ -121,6 +121,39 @@ function getAddFlagForDepsField(depsField) { } } +/** + * Looks up the most common version range for a dependency if it already exists in the repo. + * + * @param {string} name + * @param {string} flag + * @param {getPackageMap.PackageMap} packages + * @returns {string} + */ +function addVersionQuery(name, flag, packages) { + const rangeCounts = new Map(); + + for (const pkg of packages.list) { + const deps = + flag === '--dev' + ? pkg.packageJson.devDependencies + : flag === '--peer' + ? pkg.packageJson.peerDependencies + : pkg.packageJson.dependencies; + const range = deps?.[name]; + if (range) { + rangeCounts.set(range, (rangeCounts.get(range) ?? 0) + 1); + } + } + + const mostCommonRange = [...rangeCounts.entries()].sort( + (a, b) => b[1] - a[1], + )[0]?.[0]; + if (!mostCommonRange) { + return name; + } + return `${name}@${mostCommonRange}`; +} + /** @type {import('eslint').Rule.RuleModule} */ module.exports = { meta: { @@ -177,13 +210,22 @@ module.exports = { } for (const [flag, names] of Object.entries(byFlag)) { + // Look up existing version queries in the repo for the same dependency + const namesWithQuery = [...names].map(name => + addVersionQuery(name, flag, packages), + ); + // The security implication of this is a bit interesting, as crafted add-import // directives could be used to install malicious packages. However, the same is true - // for adding malicious packages to package.json, so there's significant difference. - execFileSync('yarn', ['add', ...(flag ? [flag] : []), ...names], { - cwd: localPkg.dir, - stdio: 'inherit', - }); + // for adding malicious packages to package.json, so there's no significant difference. + execFileSync( + 'yarn', + ['add', ...(flag ? [flag] : []), ...namesWithQuery], + { + cwd: localPkg.dir, + stdio: 'inherit', + }, + ); } // This switches all import directives back to the original import. 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 new file mode 100644 index 0000000000..568bdb8cc8 --- /dev/null +++ b/packages/eslint-plugin/src/no-top-level-material-ui-4-imports.test.ts @@ -0,0 +1,107 @@ +/* + * 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 { RuleTester } from 'eslint'; +import rule from '../rules/no-top-level-material-ui-4-imports'; + +const ruleTester = new RuleTester({ + parserOptions: { + sourceType: 'module', + ecmaVersion: 2021, + }, +}); + +ruleTester.run('path-imports-rule', rule, { + valid: [ + { + code: `import Typography from '@material-ui/core/Typography';`, + }, + { + code: `import Box from '@material-ui/core/Box'`, + }, + { + code: `import { styled, withStyles } from '@material-ui/core/styles';`, + }, + { + code: `import SvgIcon, { SvgIconProps } from '@material-ui/core/SvgIcon';`, + }, + { + code: `import { StyleRules } from '@material-ui/core/styles/withStyles';`, + }, + { + code: `import { CreateCSSProperties, StyledComponentProps } from '@material-ui/core/styles/withStyles';`, + }, + ], + invalid: [ + { + code: `import { Box, Typography } from '@material-ui/core';`, + errors: [{ messageId: 'topLevelImport' }], + output: `import Box from '@material-ui/core/Box'; +import Typography from '@material-ui/core/Typography';`, + }, + { + code: `import { Box } from '@material-ui/core';`, + errors: [{ messageId: 'topLevelImport' }], + output: `import Box from '@material-ui/core/Box';`, + }, + { + code: `import { + Box, + DialogActions, + DialogContent, + DialogTitle, + Grid, + makeStyles, + } from '@material-ui/core';`, + errors: [{ messageId: 'topLevelImport' }], + output: `import Box from '@material-ui/core/Box'; +import DialogActions from '@material-ui/core/DialogActions'; +import DialogContent from '@material-ui/core/DialogContent'; +import DialogTitle from '@material-ui/core/DialogTitle'; +import Grid from '@material-ui/core/Grid'; +import { makeStyles } from '@material-ui/core/styles';`, + }, + { + code: `import { Box, Button, makeStyles } from '@material-ui/core';`, + errors: [{ messageId: 'topLevelImport' }], + output: `import Box from '@material-ui/core/Box'; +import Button from '@material-ui/core/Button'; +import { makeStyles } from '@material-ui/core/styles';`, + }, + { + code: `import { Paper, Typography, styled, withStyles } 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';`, + }, + { + code: `import { styled } from '@material-ui/core';`, + errors: [{ messageId: 'topLevelImport' }], + output: `import { styled } from '@material-ui/core/styles';`, + }, + { + code: `import { SvgIcon, SvgIconProps } from '@material-ui/core';`, + errors: [{ messageId: 'topLevelImport' }], + output: `import SvgIcon, { SvgIconProps } from '@material-ui/core/SvgIcon';`, + }, + { + code: `import { TabProps } from '@material-ui/core';`, + errors: [{ messageId: 'topLevelImport' }], + output: `import { TabProps } from '@material-ui/core/Tab';`, + }, + ], +}); diff --git a/packages/frontend-app-api/CHANGELOG.md b/packages/frontend-app-api/CHANGELOG.md index b65d797397..d7c7816449 100644 --- a/packages/frontend-app-api/CHANGELOG.md +++ b/packages/frontend-app-api/CHANGELOG.md @@ -1,5 +1,215 @@ # @backstage/frontend-app-api +## 0.5.0 + +### Minor Changes + +- d4149bf: **BREAKING**: Renamed the `app/router` extension to `app/root`. +- 074dfe3: Attaching extensions to an input that does not exist is now a warning rather than an error. + +### Patch Changes + +- 7d63b32: Accepts sub route refs on the new `createPlugin` routes map. +- 516fd3e: Updated README to reflect release status +- c97fa1c: Added `elements`, `wrappers`, and `router` inputs to `app/root`, that let you add things to the root of the React tree above the layout. You can use the `createAppRootElementExtension`, `createAppRootWrapperExtension`, and `createRouterExtension` extension creator, respectively, to conveniently create such extensions. These are all optional, and if you do not supply a router a default one will be used (`BrowserRouter` in regular runs, `MemoryRouter` in tests/CI). +- 5fe6600: add oauth dialog and alert display to the root elements +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## 0.4.1-next.2 + +### Patch Changes + +- 516fd3e: Updated README to reflect release status +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.1-next.2 + +## 0.4.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/core-app-api@1.11.3-next.0 + - @backstage/frontend-plugin-api@0.4.1-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## 0.4.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/frontend-plugin-api@0.4.1-next.0 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.2 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## 0.4.0 + +### Minor Changes + +- e539735: Updated core extension structure to make space for the sign-in page by adding `core.router`. +- 44735df: Removed `featureLoader` from `createApp`, `features` instead accepts both `FrontendFeature` and `CreateAppFeatureLoader` +- af7bc3e: Switched all core extensions to instead use the namespace `'app'`. +- ea06590: The app no longer provides the `AppContext` from `@backstage/core-plugin-api`. Components that require this context to be available should use the `compatWrapper` helper from `@backstage/core-compat-api`. + +### Patch Changes + +- 5eb6b8a: Added the nav logo extension for customization of sidebar logo +- aeb8008: Add support for translation extensions. +- 1f12fb7: Create a core components extension that allows adopters to override core app components such as `Progress`, `BootErrorPage`, `NotFoundErrorPage` and `ErrorBoundaryFallback`. +- a379243: Leverage the new `FrontendFeature` type to simplify interfaces +- 60d6eb5: Removed `@backstage/plugin-graphiql` dependency. +- b7adf24: Use the new plugin type for error boundary components. +- 5970928: Collect and register feature flags from plugins and extension overrides. +- 9ad4039: Bringing over apis from core-plugin-api +- 8f5d6c1: Updates to match the new extension input wrapping. +- c35036b: A `configLoader` passed to `createApp` now returns an object, to make room for future expansion +- f27ee7d: Migrate analytics route tracker component. +- b8cb780: Added `createSpecializedApp`, which is a synchronous version of `createApp` where config and features already need to be loaded. +- c36e0b9: Renamed `AppRouteBinder` to `CreateAppRouteBinder` +- cb4197a: Forward ` node`` instead of `extensionId` to resolved extension inputs. +- 8837a96: Updates to match the introduction of `ExtensionDefinition` and new extension ID naming patterns. +- a5a0473: Updates to provide `node` to extension factories instead of `id` and `source`. +- 5cdf2b3: Updated usage of `Extension` and `ExtensionDefinition` as they are now opaque. +- f9ef632: Updates to match the new `coreExtensionData` structure. +- f1183b7: Renamed the `component` option of `createComponentExtension` to `loader`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/frontend-plugin-api@0.4.0 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/core-app-api@1.11.2 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## 0.4.0-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/frontend-plugin-api@0.4.0-next.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## 0.4.0-next.2 + +### Minor Changes + +- ea06590: The app no longer provides the `AppContext` from `@backstage/core-plugin-api`. Components that require this context to be available should use the `compatWrapper` helper from `@backstage/core-compat-api`. + +### Patch Changes + +- aeb8008: Add support for translation extensions. +- b7adf24: Use the new plugin type for error boundary components. +- 8f5d6c1: Updates to match the new extension input wrapping. +- cb4197a: Forward ` node`` instead of `extensionId` to resolved extension inputs. +- 8837a96: Updates to match the introduction of `ExtensionDefinition` and new extension ID naming patterns. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.2 + - @backstage/theme@0.5.0-next.1 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## 0.4.0-next.1 + +### Minor Changes + +- e539735435: Updated core extension structure to make space for the sign-in page by adding `core.router`. + +### Patch Changes + +- 5eb6b8a7bc: Added the nav logo extension for customization of sidebar logo +- 1f12fb762c: Create a core components extension that allows adopters to override core app components such as `Progress`, `BootErrorPage`, `NotFoundErrorPage` and `ErrorBoundaryFallback`. +- 59709286b3: Collect and register feature flags from plugins and extension overrides. +- f27ee7d937: Migrate analytics route tracker component. +- a5a04739e1: Updates to provide `node` to extension factories instead of `id` and `source`. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## 0.3.1-next.0 + +### Patch Changes + +- 60d6eb544e: Removed `@backstage/plugin-graphiql` dependency. +- 9ad4039efa: Bringing over apis from core-plugin-api +- b8cb7804c8: Added `createSpecializedApp`, which is a synchronous version of `createApp` where config and features already need to be loaded. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/frontend-plugin-api@0.3.1-next.0 + - @backstage/core-app-api@1.11.2-next.0 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## 0.3.0 + +### Minor Changes + +- 68fc9dc60e: Added the ability to configure bound routes through `app.routes.bindings`. The routing system used by `createApp` has been replaced by one that only supports route refs of the new format from `@backstage/frontend-plugin-api`. The requirement for route refs to have the same ID as their associated extension has been removed. + +### Patch Changes + +- e28d379e32: Refactor internal extension instance system into an app graph. +- fdc348d5d3: The options parameter of `createApp` is now optional. +- 6c2b872153: Add official support for React 18. +- dc613f9bcf: Updated `app.extensions` configuration schema. +- 733bd95746: Implement new `AppTreeApi` +- 685a4c8901: Installed features are now deduplicated both by reference and ID when available. Features passed to `createApp` now override both discovered and loaded features. +- fa28d4e6df: No longer throw error on invalid input if the child is disabled. +- bb98953cb9: Register default implementation for the `Translation API` on the new `createApp`. +- fe6d09953d: Fix for app node output IDs not being serialized correctly. +- 77f009b35d: Internal updates to match changes in the experimental `@backstage/frontend-plugin-api`. +- 4d6fa921db: Internal refactor to rename the app graph to app tree +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/frontend-plugin-api@0.3.0 + - @backstage/plugin-graphiql@0.3.0 + - @backstage/core-plugin-api@1.8.0 + - @backstage/version-bridge@1.0.7 + - @backstage/core-app-api@1.11.1 + - @backstage/theme@0.4.4 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + ## 0.3.0-next.2 ### Patch Changes diff --git a/packages/frontend-app-api/README.md b/packages/frontend-app-api/README.md index 8b2fe5dc23..256ae99462 100644 --- a/packages/frontend-app-api/README.md +++ b/packages/frontend-app-api/README.md @@ -1,8 +1,8 @@ # @backstage/frontend-app-api -**This package is EXPERIMENTAL, we recommend against using it for production deployments** +**The [new frontend system](https://backstage.io/docs/frontend-system/) that this package is part of is in alpha, and we do not yet recommend using it for production deployments** -This package provides the core API used by Backstage frontend apps. It implements the design outlined in [RFC: Frontend System Evolution](https://github.com/backstage/backstage/issues/18372). +This package provides the framework API used by Backstage frontend apps. It implements the design outlined in [RFC: Frontend System Evolution](https://github.com/backstage/backstage/issues/18372). ## Documentation diff --git a/packages/frontend-app-api/api-report.md b/packages/frontend-app-api/api-report.md index 3d6d936018..e7dd584734 100644 --- a/packages/frontend-app-api/api-report.md +++ b/packages/frontend-app-api/api-report.md @@ -3,18 +3,36 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts -import { BackstagePlugin } from '@backstage/frontend-plugin-api'; import { Config } from '@backstage/config'; import { ConfigApi } from '@backstage/core-plugin-api'; import { ExtensionDataRef } from '@backstage/frontend-plugin-api'; -import { ExtensionOverrides } from '@backstage/frontend-plugin-api'; import { ExternalRouteRef } from '@backstage/frontend-plugin-api'; +import { FrontendFeature } from '@backstage/frontend-plugin-api'; import { JSX as JSX_2 } from 'react'; import { RouteRef } from '@backstage/frontend-plugin-api'; import { SubRouteRef } from '@backstage/frontend-plugin-api'; +// @public (undocumented) +export function createApp(options?: { + features?: (FrontendFeature | CreateAppFeatureLoader)[]; + configLoader?: () => Promise<{ + config: ConfigApi; + }>; + bindRoutes?(context: { bind: CreateAppRouteBinder }): void; +}): { + createRoot(): JSX_2.Element; +}; + // @public -export type AppRouteBinder = < +export interface CreateAppFeatureLoader { + getLoaderName(): string; + load(options: { config: ConfigApi }): Promise<{ + features: FrontendFeature[]; + }>; +} + +// @public +export type CreateAppRouteBinder = < TExternalRoutes extends { [name: string]: ExternalRouteRef; }, @@ -27,20 +45,17 @@ export type AppRouteBinder = < ) => void; // @public (undocumented) -export function createApp(options?: { - features?: (BackstagePlugin | ExtensionOverrides)[]; - configLoader?: () => Promise; - bindRoutes?(context: { bind: AppRouteBinder }): void; - featureLoader?: (ctx: { - config: ConfigApi; - }) => Promise<(BackstagePlugin | ExtensionOverrides)[]>; +export function createExtensionTree(options: { config: Config }): ExtensionTree; + +// @public +export function createSpecializedApp(options?: { + features?: FrontendFeature[]; + config?: ConfigApi; + bindRoutes?(context: { bind: CreateAppRouteBinder }): void; }): { createRoot(): JSX_2.Element; }; -// @public (undocumented) -export function createExtensionTree(options: { config: Config }): ExtensionTree; - // @public (undocumented) export interface ExtensionTree { // (undocumented) diff --git a/packages/frontend-app-api/package.json b/packages/frontend-app-api/package.json index d8b51a0776..440f0cdb3f 100644 --- a/packages/frontend-app-api/package.json +++ b/packages/frontend-app-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/frontend-app-api", - "version": "0.3.0-next.2", + "version": "0.5.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -38,8 +38,8 @@ "@backstage/core-app-api": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", + "@backstage/errors": "workspace:^", "@backstage/frontend-plugin-api": "workspace:^", - "@backstage/plugin-graphiql": "workspace:^", "@backstage/theme": "workspace:^", "@backstage/types": "workspace:^", "@backstage/version-bridge": "workspace:^", diff --git a/packages/frontend-app-api/src/apis/implementations/ComponentsApi/ComponentsApi.ts b/packages/frontend-app-api/src/apis/implementations/ComponentsApi/ComponentsApi.ts new file mode 100644 index 0000000000..4d8bc47e24 --- /dev/null +++ b/packages/frontend-app-api/src/apis/implementations/ComponentsApi/ComponentsApi.ts @@ -0,0 +1,39 @@ +/* + * 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 { ComponentType } from 'react'; +import { ComponentRef, ComponentsApi } from '@backstage/frontend-plugin-api'; + +/** + * Implementation for the {@linkComponentApi} + * + * @internal + */ +export class DefaultComponentsApi implements ComponentsApi { + #components: Map, ComponentType>; + + constructor(components: Map, any>) { + this.#components = components; + } + + getComponent(ref: ComponentRef): ComponentType { + const impl = this.#components.get(ref); + if (!impl) { + throw new Error(`No implementation found for component ref ${ref}`); + } + return impl; + } +} diff --git a/packages/frontend-app-api/src/apis/implementations/ComponentsApi/index.ts b/packages/frontend-app-api/src/apis/implementations/ComponentsApi/index.ts new file mode 100644 index 0000000000..f04059c54f --- /dev/null +++ b/packages/frontend-app-api/src/apis/implementations/ComponentsApi/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { DefaultComponentsApi } from './ComponentsApi'; diff --git a/packages/frontend-app-api/src/extensions/Core.tsx b/packages/frontend-app-api/src/extensions/App.tsx similarity index 68% rename from packages/frontend-app-api/src/extensions/Core.tsx rename to packages/frontend-app-api/src/extensions/App.tsx index 60772d435c..751a255fa7 100644 --- a/packages/frontend-app-api/src/extensions/Core.tsx +++ b/packages/frontend-app-api/src/extensions/App.tsx @@ -16,19 +16,29 @@ import { coreExtensionData, + createApiExtension, + createComponentExtension, createExtension, createExtensionInput, + createThemeExtension, + createTranslationExtension, } from '@backstage/frontend-plugin-api'; -export const Core = createExtension({ - id: 'core', +export const App = createExtension({ + namespace: 'app', attachTo: { id: 'root', input: 'default' }, // ignored inputs: { apis: createExtensionInput({ - api: coreExtensionData.apiFactory, + api: createApiExtension.factoryDataRef, }), themes: createExtensionInput({ - theme: coreExtensionData.theme, + theme: createThemeExtension.themeDataRef, + }), + components: createExtensionInput({ + component: createComponentExtension.componentDataRef, + }), + translations: createExtensionInput({ + translation: createTranslationExtension.translationDataRef, }), root: createExtensionInput( { @@ -42,7 +52,7 @@ export const Core = createExtension({ }, factory({ inputs }) { return { - root: inputs.root.element, + root: inputs.root.output.element, }; }, }); diff --git a/packages/frontend-app-api/src/extensions/CoreLayout.tsx b/packages/frontend-app-api/src/extensions/AppLayout.tsx similarity index 85% rename from packages/frontend-app-api/src/extensions/CoreLayout.tsx rename to packages/frontend-app-api/src/extensions/AppLayout.tsx index 97f49acac9..7be0029c25 100644 --- a/packages/frontend-app-api/src/extensions/CoreLayout.tsx +++ b/packages/frontend-app-api/src/extensions/AppLayout.tsx @@ -22,9 +22,10 @@ import { } from '@backstage/frontend-plugin-api'; import { SidebarPage } from '@backstage/core-components'; -export const CoreLayout = createExtension({ - id: 'core.layout', - attachTo: { id: 'core', input: 'root' }, +export const AppLayout = createExtension({ + namespace: 'app', + name: 'layout', + attachTo: { id: 'app/root', input: 'children' }, inputs: { nav: createExtensionInput( { @@ -46,8 +47,8 @@ export const CoreLayout = createExtension({ return { element: ( - {inputs.nav.element} - {inputs.content.element} + {inputs.nav.output.element} + {inputs.content.output.element} ), }; diff --git a/packages/frontend-app-api/src/extensions/CoreNav.tsx b/packages/frontend-app-api/src/extensions/AppNav.tsx similarity index 73% rename from packages/frontend-app-api/src/extensions/CoreNav.tsx rename to packages/frontend-app-api/src/extensions/AppNav.tsx index 37ce50276b..c5bf028ef8 100644 --- a/packages/frontend-app-api/src/extensions/CoreNav.tsx +++ b/packages/frontend-app-api/src/extensions/AppNav.tsx @@ -19,8 +19,9 @@ import { createExtension, coreExtensionData, createExtensionInput, - NavTarget, useRouteRef, + createNavItemExtension, + createNavLogoExtension, } from '@backstage/frontend-plugin-api'; import { makeStyles } from '@material-ui/core'; import { @@ -51,33 +52,49 @@ const useSidebarLogoStyles = makeStyles({ }, }); -const SidebarLogo = () => { +const SidebarLogo = ( + props: (typeof createNavLogoExtension.logoElementsDataRef)['T'], +) => { const classes = useSidebarLogoStyles(); const { isOpen } = useSidebarOpenState(); return (
- {isOpen ? : } + {isOpen + ? props?.logoFull ?? + : props?.logoIcon ?? }
); }; -const SidebarNavItem = (props: NavTarget) => { +const SidebarNavItem = ( + props: (typeof createNavItemExtension.targetDataRef)['T'], +) => { const { icon: Icon, title, routeRef } = props; const to = useRouteRef(routeRef)(); // TODO: Support opening modal, for example, the search one return ; }; -export const CoreNav = createExtension({ - id: 'core.nav', - attachTo: { id: 'core.layout', input: 'nav' }, +export const AppNav = createExtension({ + namespace: 'app', + name: 'nav', + attachTo: { id: 'app/layout', input: 'nav' }, inputs: { items: createExtensionInput({ - target: coreExtensionData.navTarget, + target: createNavItemExtension.targetDataRef, }), + logos: createExtensionInput( + { + elements: createNavLogoExtension.logoElementsDataRef, + }, + { + singleton: true, + optional: true, + }, + ), }, output: { element: coreExtensionData.reactElement, @@ -86,10 +103,10 @@ export const CoreNav = createExtension({ return { element: ( - + {inputs.items.map((item, index) => ( - + ))} ), diff --git a/packages/frontend-app-api/src/extensions/AppRoot.tsx b/packages/frontend-app-api/src/extensions/AppRoot.tsx new file mode 100644 index 0000000000..2b709f4e42 --- /dev/null +++ b/packages/frontend-app-api/src/extensions/AppRoot.tsx @@ -0,0 +1,223 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, { + ComponentType, + Fragment, + PropsWithChildren, + ReactNode, + useContext, + useState, +} from 'react'; +import { + coreExtensionData, + createAppRootWrapperExtension, + createExtension, + createExtensionInput, + createRouterExtension, + createSignInPageExtension, +} from '@backstage/frontend-plugin-api'; +import { + ConfigApi, + IdentityApi, + SignInPageProps, + configApiRef, + useApi, +} from '@backstage/core-plugin-api'; +import { InternalAppContext } from '../wiring/InternalAppContext'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { AppIdentityProxy } from '../../../core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy'; +import { BrowserRouter } from 'react-router-dom'; +import { RouteTracker } from '../routing/RouteTracker'; + +export const AppRoot = createExtension({ + namespace: 'app', + name: 'root', + attachTo: { id: 'app', input: 'root' }, + inputs: { + router: createExtensionInput( + { component: createRouterExtension.componentDataRef }, + { singleton: true, optional: true }, + ), + signInPage: createExtensionInput( + { component: createSignInPageExtension.componentDataRef }, + { singleton: true, optional: true }, + ), + children: createExtensionInput( + { element: coreExtensionData.reactElement }, + { singleton: true }, + ), + elements: createExtensionInput({ + element: coreExtensionData.reactElement, + }), + wrappers: createExtensionInput({ + component: createAppRootWrapperExtension.componentDataRef, + }), + }, + output: { + element: coreExtensionData.reactElement, + }, + factory({ inputs }) { + let content: React.ReactNode = ( + <> + {inputs.elements.map(el => ( + {el.output.element} + ))} + {inputs.children.output.element} + + ); + + for (const wrapper of inputs.wrappers) { + content = {content}; + } + + return { + element: ( + + {content} + + ), + }; + }, +}); + +/** + * Read the configured base path. + * + * The returned path does not have a trailing slash. + */ +function getBasePath(configApi: ConfigApi) { + let { pathname } = new URL( + configApi.getOptionalString('app.baseUrl') ?? '/', + 'http://sample.dev', // baseUrl can be specified as just a path + ); + pathname = pathname.replace(/\/*$/, ''); + return pathname; +} + +// This wraps the sign-in page and waits for sign-in to be completed before rendering the app +function SignInPageWrapper({ + component: Component, + appIdentityProxy, + children, +}: { + component: ComponentType; + appIdentityProxy: AppIdentityProxy; + children: ReactNode; +}) { + const [identityApi, setIdentityApi] = useState(); + const configApi = useApi(configApiRef); + const basePath = getBasePath(configApi); + + if (!identityApi) { + return ; + } + + appIdentityProxy.setTarget(identityApi, { + signOutTargetUrl: basePath || '/', + }); + return <>{children}; +} + +/** + * Props for the {@link AppRouter} component. + * @public + */ +export interface AppRouterProps { + children?: ReactNode; + SignInPageComponent?: ComponentType; + RouterComponent?: ComponentType>; +} + +function DefaultRouter(props: PropsWithChildren<{}>) { + const configApi = useApi(configApiRef); + const basePath = getBasePath(configApi); + return {props.children}; +} + +/** + * App router and sign-in page wrapper. + * + * @remarks + * + * The AppRouter provides the routing context and renders the sign-in page. + * Until the user has successfully signed in, this component will render + * the sign-in page. Once the user has signed-in, it will instead render + * the app, while providing routing and route tracking for the app. + */ +export function AppRouter(props: AppRouterProps) { + const { + children, + SignInPageComponent, + RouterComponent = DefaultRouter, + } = props; + + const configApi = useApi(configApiRef); + const basePath = getBasePath(configApi); + const internalAppContext = useContext(InternalAppContext); + if (!internalAppContext) { + throw new Error('AppRouter must be rendered within the AppProvider'); + } + const { routeObjects, appIdentityProxy } = internalAppContext; + + // If the app hasn't configured a sign-in page, we just continue as guest. + if (!SignInPageComponent) { + appIdentityProxy.setTarget( + { + getUserId: () => 'guest', + getIdToken: async () => undefined, + getProfile: () => ({ + email: 'guest@example.com', + displayName: 'Guest', + }), + getProfileInfo: async () => ({ + email: 'guest@example.com', + displayName: 'Guest', + }), + getBackstageIdentity: async () => ({ + type: 'user', + userEntityRef: 'user:default/guest', + ownershipEntityRefs: ['user:default/guest'], + }), + getCredentials: async () => ({}), + signOut: async () => {}, + }, + { signOutTargetUrl: basePath || '/' }, + ); + + return ( + + + {children} + + ); + } + + return ( + + + + {children} + + + ); +} diff --git a/packages/frontend-app-api/src/extensions/CoreRoutes.tsx b/packages/frontend-app-api/src/extensions/AppRoutes.tsx similarity index 69% rename from packages/frontend-app-api/src/extensions/CoreRoutes.tsx rename to packages/frontend-app-api/src/extensions/AppRoutes.tsx index 985fd07be9..38a9291755 100644 --- a/packages/frontend-app-api/src/extensions/CoreRoutes.tsx +++ b/packages/frontend-app-api/src/extensions/AppRoutes.tsx @@ -19,12 +19,15 @@ import { createExtension, coreExtensionData, createExtensionInput, + coreComponentRefs, + useComponentRef, } from '@backstage/frontend-plugin-api'; import { useRoutes } from 'react-router-dom'; -export const CoreRoutes = createExtension({ - id: 'core.routes', - attachTo: { id: 'core.layout', input: 'content' }, +export const AppRoutes = createExtension({ + namespace: 'app', + name: 'routes', + attachTo: { id: 'app/layout', input: 'content' }, inputs: { routes: createExtensionInput({ path: coreExtensionData.routePath, @@ -37,15 +40,24 @@ export const CoreRoutes = createExtension({ }, factory({ inputs }) { const Routes = () => { - const element = useRoutes( - inputs.routes.map(route => ({ - path: `${route.path}/*`, - element: route.element, - })), + const NotFoundErrorPage = useComponentRef( + coreComponentRefs.notFoundErrorPage, ); + const element = useRoutes([ + ...inputs.routes.map(route => ({ + path: `${route.output.path}/*`, + element: route.output.element, + })), + { + path: '*', + element: , + }, + ]); + return element; }; + return { element: , }; diff --git a/packages/frontend-app-api/src/extensions/components.tsx b/packages/frontend-app-api/src/extensions/components.tsx new file mode 100644 index 0000000000..3064737e21 --- /dev/null +++ b/packages/frontend-app-api/src/extensions/components.tsx @@ -0,0 +1,56 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +// TODO: Dependency on MUI should be removed from core packages +import { Button } from '@material-ui/core'; + +import { + createComponentExtension, + coreComponentRefs, +} from '@backstage/frontend-plugin-api'; +import { ErrorPanel } from '@backstage/core-components'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { components as defaultComponents } from '../../../app-defaults/src/defaults'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports + +export const DefaultProgressComponent = createComponentExtension({ + ref: coreComponentRefs.progress, + loader: { sync: () => defaultComponents.Progress }, +}); + +export const DefaultNotFoundErrorPageComponent = createComponentExtension({ + ref: coreComponentRefs.notFoundErrorPage, + loader: { sync: () => defaultComponents.NotFoundErrorPage }, +}); + +export const DefaultErrorBoundaryComponent = createComponentExtension({ + ref: coreComponentRefs.errorBoundaryFallback, + loader: { + sync: () => props => { + const { plugin, error, resetError } = props; + const title = `Error in ${plugin?.id}`; + + return ( + + + + ); + }, + }, +}); diff --git a/packages/frontend-app-api/src/extensions/elements.tsx b/packages/frontend-app-api/src/extensions/elements.tsx new file mode 100644 index 0000000000..0a764583bb --- /dev/null +++ b/packages/frontend-app-api/src/extensions/elements.tsx @@ -0,0 +1,45 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { AlertDisplay, OAuthRequestDialog } from '@backstage/core-components'; +import { + createAppRootElementExtension, + createSchemaFromZod, +} from '@backstage/frontend-plugin-api'; +import React from 'react'; + +export const oauthRequestDialogAppRootElement = createAppRootElementExtension({ + namespace: 'app', + name: 'oauth-request-dialog', + element: , +}); + +export const alertDisplayAppRootElement = createAppRootElementExtension({ + namespace: 'app', + name: 'alert-display', + configSchema: createSchemaFromZod(z => + z.object({ + transientTimeoutMs: z.number().default(5000), + anchorOrigin: z + .object({ + vertical: z.enum(['top', 'bottom']).default('top'), + horizontal: z.enum(['left', 'center', 'right']).default('center'), + }) + .default({}), + }), + ), + element: ({ config }) => , +}); diff --git a/packages/frontend-app-api/src/routing/RouteTracker.test.tsx b/packages/frontend-app-api/src/routing/RouteTracker.test.tsx new file mode 100644 index 0000000000..0e66d0e50d --- /dev/null +++ b/packages/frontend-app-api/src/routing/RouteTracker.test.tsx @@ -0,0 +1,254 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { TestApiProvider } from '@backstage/test-utils'; +import React, { useEffect } from 'react'; +import { BackstageRouteObject } from './types'; +import { fireEvent, render } from '@testing-library/react'; +import { RouteTracker } from './RouteTracker'; +import { Link, MemoryRouter, Route, Routes } from 'react-router-dom'; +import { createPlugin } from '@backstage/core-plugin-api'; +import { + createRouteRef, + AnalyticsApi, + analyticsApiRef, + AppNode, + useAnalytics, +} from '@backstage/frontend-plugin-api'; +import { MATCH_ALL_ROUTE } from './extractRouteInfoFromAppNode'; + +describe('RouteTracker', () => { + const routeRef0 = createRouteRef(); + const routeRef1 = createRouteRef(); + const routeRef2 = createRouteRef(); + const plugin0 = createPlugin({ id: 'home' }); + const plugin1 = createPlugin({ id: 'plugin1' }); + const plugin2 = createPlugin({ id: 'plugin2' }); + + const routeObjects: BackstageRouteObject[] = [ + { + path: '', + element:
home page
, + routeRefs: new Set([routeRef0]), + plugins: new Set([plugin0]), + caseSensitive: false, + children: [MATCH_ALL_ROUTE], + appNode: { + spec: { extension: { id: 'home.page.index' }, source: { id: 'home' } }, + } as AppNode, + }, + { + path: '/path/:p1/:p2', + element: go, + routeRefs: new Set([routeRef1]), + plugins: new Set([plugin1]), + caseSensitive: false, + children: [MATCH_ALL_ROUTE], + appNode: { + spec: { + extension: { id: 'plugin1.page.index' }, + source: { id: 'plugin1' }, + }, + } as AppNode, + }, + { + path: '/path2/:param', + element:
hi there
, + routeRefs: new Set([routeRef2]), + plugins: new Set([plugin2]), + caseSensitive: false, + children: [MATCH_ALL_ROUTE], + appNode: { + spec: { + extension: { id: 'plugin2.page.index' }, + source: { id: 'plugin2' }, + }, + } as AppNode, + }, + ]; + + const mockedAnalytics: jest.Mocked = { + captureEvent: jest.fn(), + }; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should capture the navigate event on load', async () => { + render( + + + + + , + ); + + expect(mockedAnalytics.captureEvent).toHaveBeenCalledWith({ + action: 'navigate', + attributes: { + p1: 'foo', + p2: 'bar', + }, + context: { + extensionId: 'plugin1.page.index', + pluginId: 'plugin1', + }, + subject: '/path/foo/bar', + value: undefined, + }); + }); + + it('should capture the navigate event on route change', async () => { + const { getByText } = render( + + + + + + {routeObjects.map(({ path, element }) => ( + + ))} + + + , + ); + + fireEvent.click(getByText('go')); + + expect(mockedAnalytics.captureEvent).toHaveBeenCalledWith({ + action: 'navigate', + attributes: { + param: 'hello', + }, + context: { + extensionId: 'plugin2.page.index', + pluginId: 'plugin2', + }, + subject: '/path2/hello', + value: undefined, + }); + }); + + it('should capture path query and hash', async () => { + render( + + + + + , + ); + + expect(mockedAnalytics.captureEvent).toHaveBeenCalledWith({ + action: 'navigate', + attributes: { + p1: 'foo', + p2: 'bar', + }, + context: { + extensionId: 'plugin1.page.index', + pluginId: 'plugin1', + }, + subject: '/path/foo/bar?q=1#header-1', + value: undefined, + }); + }); + + it('should match the root path and send relevant context', async () => { + render( + + + + + , + ); + + expect(mockedAnalytics.captureEvent).toHaveBeenCalledWith({ + action: 'navigate', + attributes: {}, + context: { + extensionId: 'home.page.index', + pluginId: 'home', + }, + subject: '/', + value: undefined, + }); + }); + + it('should return default context when it would have otherwise matched on the root path', async () => { + const Dummy = () => { + const analytics = useAnalytics(); + useEffect(() => { + analytics.captureEvent('click', 'test', {}); + }, [analytics]); + return
dummy
; + }; + + render( + + + + + } /> + + + , + ); + + expect(mockedAnalytics.captureEvent).toHaveBeenNthCalledWith(1, { + action: 'navigate', + attributes: {}, + context: { + extensionId: 'App', + pluginId: 'root', + }, + subject: '/not-routable-extension', + value: undefined, + }); + expect(mockedAnalytics.captureEvent).toHaveBeenNthCalledWith(2, { + action: 'click', + attributes: undefined, + context: { + extensionId: 'App', + pluginId: 'root', + }, + subject: 'test', + value: undefined, + }); + }); + + it('should return parent route context on navigating to a sub-route', async () => { + render( + + + + + , + ); + + expect(mockedAnalytics.captureEvent).toHaveBeenCalledWith({ + action: 'navigate', + attributes: { + param: 'param-value', + }, + context: { + extensionId: 'plugin2.page.index', + pluginId: 'plugin2', + }, + subject: '/path2/param-value/sub-route', + value: undefined, + }); + }); +}); diff --git a/packages/frontend-app-api/src/routing/RouteTracker.tsx b/packages/frontend-app-api/src/routing/RouteTracker.tsx new file mode 100644 index 0000000000..8cddca5c68 --- /dev/null +++ b/packages/frontend-app-api/src/routing/RouteTracker.tsx @@ -0,0 +1,129 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, { useEffect } from 'react'; +import { matchRoutes, useLocation } from 'react-router-dom'; +import { + useAnalytics, + AnalyticsContext, + AnalyticsEventAttributes, +} from '@backstage/frontend-plugin-api'; +import { BackstageRouteObject } from './types'; + +/** + * Returns an extension context given the current pathname and a list of + * Backstage route objects. + */ +const getExtensionContext = ( + pathname: string, + routes: BackstageRouteObject[], +) => { + try { + // Find matching routes for the given path name. + const matches = matchRoutes(routes, { pathname }); + + // Of the matching routes, get the last (e.g. most specific) instance of + // the BackstageRouteObject that contains a routeRef. Filtering by routeRef + // ensures subRouteRefs are aligned to their parent routes' context. + const routeMatch = matches + ?.filter(match => match?.route.routeRefs?.size > 0) + .pop(); + const routeObject = routeMatch?.route; + + // If there is no route object, then allow inheritance of default context. + if (!routeObject) { + return undefined; + } + + // If the matched route is the root route (no path), and the pathname is + // not the path of the homepage, then inherit from the default context. + if (routeObject.path === '' && pathname !== '/') { + return undefined; + } + + const params = Object.entries( + routeMatch?.params || {}, + ).reduce((acc, [key, value]) => { + if (value !== undefined && key !== '*') { + acc[key] = value; + } + return acc; + }, {}); + + const plugin = routeObject.appNode?.spec.source; + const extension = routeObject.appNode?.spec.extension; + + return { + params, + pluginId: plugin?.id || 'root', + extensionId: extension?.id || 'App', + }; + } catch { + return undefined; + } +}; + +/** + * Performs the actual event capture on render. + */ +const TrackNavigation = ({ + pathname, + search, + hash, + attributes, +}: { + pathname: string; + search: string; + hash: string; + attributes?: AnalyticsEventAttributes; +}) => { + const analytics = useAnalytics(); + useEffect(() => { + analytics.captureEvent('navigate', `${pathname}${search}${hash}`, { + attributes, + }); + }, [analytics, pathname, search, hash, attributes]); + + return null; +}; + +/** + * Logs a "navigate" event with appropriate plugin-level analytics context + * attributes each time the user navigates to a page. + */ +export const RouteTracker = ({ + routeObjects, +}: { + routeObjects: BackstageRouteObject[]; +}) => { + const { pathname, search, hash } = useLocation(); + + const { params, ...attributes } = getExtensionContext( + pathname, + routeObjects, + ) || { params: {} }; + + return ( + + + + ); +}; diff --git a/packages/frontend-app-api/src/routing/collectRouteIds.ts b/packages/frontend-app-api/src/routing/collectRouteIds.ts index 7e2a4cad2e..2fbb8b6791 100644 --- a/packages/frontend-app-api/src/routing/collectRouteIds.ts +++ b/packages/frontend-app-api/src/routing/collectRouteIds.ts @@ -15,16 +15,20 @@ */ import { - BackstagePlugin, - ExtensionOverrides, RouteRef, SubRouteRef, ExternalRouteRef, + FrontendFeature, } from '@backstage/frontend-plugin-api'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports -import { toInternalRouteRef } from '../../../frontend-plugin-api/src/routing/RouteRef'; +import { + isRouteRef, + toInternalRouteRef, +} from '../../../frontend-plugin-api/src/routing/RouteRef'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports import { toInternalExternalRouteRef } from '../../../frontend-plugin-api/src/routing/ExternalRouteRef'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { toInternalSubRouteRef } from '../../../frontend-plugin-api/src/routing/SubRouteRef'; /** @internal */ export interface RouteRefsById { @@ -33,9 +37,7 @@ export interface RouteRefsById { } /** @internal */ -export function collectRouteIds( - features: (BackstagePlugin | ExtensionOverrides)[], -): RouteRefsById { +export function collectRouteIds(features: FrontendFeature[]): RouteRefsById { const routesById = new Map(); const externalRoutesById = new Map(); @@ -50,9 +52,14 @@ export function collectRouteIds( throw new Error(`Unexpected duplicate route '${refId}'`); } - const internalRef = toInternalRouteRef(ref); - internalRef.setId(refId); - routesById.set(refId, ref); + if (isRouteRef(ref)) { + const internalRef = toInternalRouteRef(ref); + internalRef.setId(refId); + routesById.set(refId, ref); + } else { + const internalRef = toInternalSubRouteRef(ref); + routesById.set(refId, internalRef); + } } for (const [name, ref] of Object.entries(feature.externalRoutes)) { const refId = `plugin.${feature.id}.externalRoutes.${name}`; diff --git a/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.test.ts b/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.test.ts index c44c10180a..1c332b331f 100644 --- a/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.test.ts +++ b/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.test.ts @@ -19,7 +19,8 @@ import { BackstagePlugin } from '@backstage/core-plugin-api'; import { extractRouteInfoFromAppNode } from './extractRouteInfoFromAppNode'; import { AnyRouteRefParams, - Extension, + AppNode, + ExtensionDefinition, RouteRef, coreExtensionData, createExtension, @@ -29,10 +30,7 @@ import { } from '@backstage/frontend-plugin-api'; import { MockConfigApi } from '@backstage/test-utils'; import { createAppTree } from '../tree'; -import { Core } from '../extensions/Core'; -import { CoreRoutes } from '../extensions/CoreRoutes'; -import { CoreNav } from '../extensions/CoreNav'; -import { CoreLayout } from '../extensions/CoreLayout'; +import { builtinExtensions } from '../wiring/createApp'; const ref1 = createRouteRef(); const ref2 = createRouteRef(); @@ -42,16 +40,16 @@ const ref5 = createRouteRef(); const refOrder: RouteRef[] = [ref1, ref2, ref3, ref4, ref5]; function createTestExtension(options: { - id: string; + name: string; parent?: string; path?: string; routeRef?: RouteRef; }) { return createExtension({ - id: options.id, + name: options.name, attachTo: options.parent - ? { id: options.parent, input: 'children' } - : { id: 'core.routes', input: 'routes' }, + ? { id: `test/${options.parent}`, input: 'children' } + : { id: 'app/routes', input: 'routes' }, output: { element: coreExtensionData.reactElement, path: coreExtensionData.routePath.optional(), @@ -72,14 +70,14 @@ function createTestExtension(options: { }); } -function routeInfoFromExtensions(extensions: Extension[]) { +function routeInfoFromExtensions(extensions: ExtensionDefinition[]) { const plugin = createPlugin({ id: 'test', extensions, }); const tree = createAppTree({ config: new MockConfigApi({}), - builtinExtensions: [Core, CoreRoutes, CoreNav, CoreLayout], + builtinExtensions, features: [plugin], }); @@ -98,8 +96,10 @@ function routeObj( children: any[] = [], type: 'mounted' | 'gathered' = 'mounted', backstagePlugin?: BackstagePlugin, + appNode?: AppNode, ) { return { + appNode, path: path, caseSensitive: false, element: type, @@ -122,33 +122,33 @@ describe('discovery', () => { it('should collect routes', () => { const info = routeInfoFromExtensions([ createTestExtension({ - id: 'nothing', + name: 'nothing', path: 'nothing', }), createTestExtension({ - id: 'page1', + name: 'page1', path: 'foo', routeRef: ref1, }), createTestExtension({ - id: 'page2', + name: 'page2', parent: 'page1', path: 'bar/:id', routeRef: ref2, }), createTestExtension({ - id: 'page3', + name: 'page3', parent: 'page2', path: 'baz', routeRef: ref3, }), createTestExtension({ - id: 'page4', + name: 'page4', path: 'divsoup', routeRef: ref4, }), createTestExtension({ - id: 'page5', + name: 'page5', parent: 'page1', path: 'blop', routeRef: ref5, @@ -170,7 +170,14 @@ describe('discovery', () => { [ref5, ref1], ]); expect(info.routeObjects).toEqual([ - routeObj('nothing', []), + routeObj( + 'nothing', + [], + undefined, + undefined, + undefined, + expect.any(Object), + ), routeObj( 'foo', [ref1], @@ -178,45 +185,70 @@ describe('discovery', () => { routeObj( 'bar/:id', [ref2], - [routeObj('baz', [ref3], undefined, undefined, expect.any(Object))], + [ + routeObj( + 'baz', + [ref3], + undefined, + undefined, + expect.any(Object), + expect.any(Object), + ), + ], undefined, expect.any(Object), + expect.any(Object), + ), + routeObj( + 'blop', + [ref5], + undefined, + undefined, + expect.any(Object), + expect.any(Object), ), - routeObj('blop', [ref5], undefined, undefined, expect.any(Object)), ], undefined, expect.any(Object), + expect.any(Object), + ), + routeObj( + 'divsoup', + [ref4], + undefined, + undefined, + expect.any(Object), + expect.any(Object), ), - routeObj('divsoup', [ref4], undefined, undefined, expect.any(Object)), ]); }); it('should handle all react router Route patterns', () => { const info = routeInfoFromExtensions([ createTestExtension({ - id: 'page1', + name: 'page1', path: 'foo', routeRef: ref1, }), createTestExtension({ - id: 'page2', + name: 'page2', parent: 'page1', path: 'bar/:id', routeRef: ref2, }), createTestExtension({ - id: 'page3', + name: 'page3', path: 'baz', routeRef: ref3, }), createTestExtension({ - id: 'page4', + name: 'page4', parent: 'page3', path: 'divsoup', routeRef: ref4, }), createTestExtension({ - id: 'page5', + name: 'page5', parent: 'page3', path: 'blop', routeRef: ref5, @@ -242,29 +274,29 @@ describe('discovery', () => { it('should strip leading slashes in route paths', () => { const info = routeInfoFromExtensions([ createTestExtension({ - id: 'page1', + name: 'page1', path: '/foo', routeRef: ref1, }), createTestExtension({ - id: 'page2', + name: 'page2', parent: 'page1', path: '/bar/:id', routeRef: ref2, }), createTestExtension({ - id: 'page3', + name: 'page3', path: '/baz', routeRef: ref3, }), createTestExtension({ - id: 'page4', + name: 'page4', parent: 'page3', path: '/divsoup', routeRef: ref4, }), createTestExtension({ - id: 'page5', + name: 'page5', parent: 'page3', path: '/blop', routeRef: ref5, @@ -290,44 +322,44 @@ describe('discovery', () => { it('should use the route aggregator key to bind child routes to the same path', () => { const info = routeInfoFromExtensions([ createTestExtension({ - id: 'foo', + name: 'foo', path: 'foo', }), createTestExtension({ - id: 'page1', + name: 'page1', parent: 'foo', routeRef: ref1, }), createTestExtension({ - id: 'fooChild', + name: 'fooChild', parent: 'foo', }), createTestExtension({ - id: 'page2', + name: 'page2', parent: 'fooChild', routeRef: ref2, }), createTestExtension({ - id: 'fooEmpty', + name: 'fooEmpty', parent: 'foo', }), createTestExtension({ - id: 'page3', + name: 'page3', path: 'bar', routeRef: ref3, }), createTestExtension({ - id: 'page3Child', + name: 'page3Child', parent: 'page3', path: '', }), createTestExtension({ - id: 'page4', + name: 'page4', parent: 'page3Child', routeRef: ref4, }), createTestExtension({ - id: 'page5', + name: 'page5', parent: 'page4', routeRef: ref5, }), @@ -348,13 +380,30 @@ describe('discovery', () => { [ref5, ref3], ]); expect(info.routeObjects).toEqual([ - routeObj('foo', [ref1, ref2], [], 'mounted', expect.any(Object)), + routeObj( + 'foo', + [ref1, ref2], + [], + 'mounted', + expect.any(Object), + expect.any(Object), + ), routeObj( 'bar', [ref3], - [routeObj('', [ref4, ref5], [], 'mounted', expect.any(Object))], + [ + routeObj( + '', + [ref4, ref5], + [], + 'mounted', + expect.any(Object), + expect.any(Object), + ), + ], 'mounted', expect.any(Object), + expect.any(Object), ), ]); }); @@ -362,34 +411,34 @@ describe('discovery', () => { it('should use the route aggregator but stop when encountering explicit path', () => { const info = routeInfoFromExtensions([ createTestExtension({ - id: 'page1', + name: 'page1', path: 'foo', routeRef: ref1, }), createTestExtension({ - id: 'page1Child', + name: 'page1Child', parent: 'page1', path: 'bar', }), createTestExtension({ - id: 'page2', + name: 'page2', parent: 'page1Child', routeRef: ref2, }), createTestExtension({ - id: 'page3', + name: 'page3', parent: 'page2', path: 'baz', routeRef: ref3, }), createTestExtension({ - id: 'page4', + name: 'page4', parent: 'page3', path: '/blop', routeRef: ref4, }), createTestExtension({ - id: 'page5', + name: 'page5', parent: 'page2', routeRef: ref5, }), @@ -428,18 +477,22 @@ describe('discovery', () => { undefined, undefined, expect.any(Object), + expect.any(Object), ), ], undefined, expect.any(Object), + expect.any(Object), ), ], 'mounted', expect.any(Object), + expect.any(Object), ), ], undefined, expect.any(Object), + expect.any(Object), ), ]); }); @@ -447,34 +500,34 @@ describe('discovery', () => { it('should account for loose route paths', () => { const info = routeInfoFromExtensions([ createTestExtension({ - id: 'r', + name: 'r', path: 'r', }), createTestExtension({ - id: 'page1', + name: 'page1', parent: 'r', path: 'x', routeRef: ref1, }), createTestExtension({ - id: 'y', + name: 'y', path: 'y', parent: 'r', }), createTestExtension({ - id: 'page2', + name: 'page2', parent: 'y', path: '1', routeRef: ref2, }), createTestExtension({ - id: 'page3', + name: 'page3', parent: 'page2', path: 'a', routeRef: ref3, }), createTestExtension({ - id: 'page4', + name: 'page4', parent: 'page2', path: 'b', routeRef: ref4, @@ -498,7 +551,14 @@ describe('discovery', () => { 'r', [], [ - routeObj('x', [ref1], [], 'mounted', expect.any(Object)), + routeObj( + 'x', + [ref1], + [], + 'mounted', + expect.any(Object), + expect.any(Object), + ), routeObj( 'y', [], @@ -513,6 +573,7 @@ describe('discovery', () => { undefined, 'mounted', expect.any(Object), + expect.any(Object), ), routeObj( 'b', @@ -520,15 +581,22 @@ describe('discovery', () => { undefined, 'mounted', expect.any(Object), + expect.any(Object), ), ], 'mounted', expect.any(Object), + expect.any(Object), ), ], 'mounted', + undefined, + expect.any(Object), ), ], + undefined, + undefined, + expect.any(Object), ), ]); }); diff --git a/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.ts b/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.ts index 43955328a8..17afbeb4c9 100644 --- a/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.ts +++ b/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.ts @@ -15,10 +15,9 @@ */ import { RouteRef, coreExtensionData } from '@backstage/frontend-plugin-api'; -// eslint-disable-next-line @backstage/no-relative-monorepo-imports -import { toLegacyPlugin } from '../wiring/createApp'; import { BackstageRouteObject } from './types'; import { AppNode } from '@backstage/frontend-plugin-api'; +import { toLegacyPlugin } from './toLegacyPlugin'; // We always add a child that matches all subroutes but without any route refs. This makes // sure that we're always able to match each route no matter how deep the navigation goes. @@ -85,6 +84,7 @@ export function extractRouteInfoFromAppNode(node: AppNode): { caseSensitive: false, children: [MATCH_ALL_ROUTE], plugins: new Set(), + appNode: current, }; parentChildren.push(currentObj); diff --git a/packages/frontend-app-api/src/routing/index.ts b/packages/frontend-app-api/src/routing/index.ts index 8c26a732d3..fedbad0261 100644 --- a/packages/frontend-app-api/src/routing/index.ts +++ b/packages/frontend-app-api/src/routing/index.ts @@ -14,4 +14,4 @@ * limitations under the License. */ -export { type AppRouteBinder } from './resolveRouteBindings'; +export { type CreateAppRouteBinder } from './resolveRouteBindings'; diff --git a/packages/frontend-app-api/src/routing/resolveRouteBindings.ts b/packages/frontend-app-api/src/routing/resolveRouteBindings.ts index f5a2e5bd94..18ea9f9bd8 100644 --- a/packages/frontend-app-api/src/routing/resolveRouteBindings.ts +++ b/packages/frontend-app-api/src/routing/resolveRouteBindings.ts @@ -64,7 +64,7 @@ type TargetRouteMap< * * @public */ -export type AppRouteBinder = < +export type CreateAppRouteBinder = < TExternalRoutes extends { [name: string]: ExternalRouteRef }, >( externalRoutes: TExternalRoutes, @@ -76,14 +76,14 @@ export type AppRouteBinder = < /** @internal */ export function resolveRouteBindings( - bindRoutes: ((context: { bind: AppRouteBinder }) => void) | undefined, + bindRoutes: ((context: { bind: CreateAppRouteBinder }) => void) | undefined, config: Config, routesById: RouteRefsById, ): Map { const result = new Map(); if (bindRoutes) { - const bind: AppRouteBinder = ( + const bind: CreateAppRouteBinder = ( externalRoutes, targetRoutes: { [name: string]: RouteRef | SubRouteRef }, ) => { diff --git a/packages/frontend-app-api/src/routing/toLegacyPlugin.ts b/packages/frontend-app-api/src/routing/toLegacyPlugin.ts new file mode 100644 index 0000000000..2d04d04dda --- /dev/null +++ b/packages/frontend-app-api/src/routing/toLegacyPlugin.ts @@ -0,0 +1,55 @@ +/* + * 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 { BackstagePlugin } from '@backstage/frontend-plugin-api'; +import { BackstagePlugin as LegacyBackstagePlugin } from '@backstage/core-plugin-api'; +import { getOrCreateGlobalSingleton } from '@backstage/version-bridge'; + +// Make sure that we only convert each new plugin instance to its legacy equivalent once +const legacyPluginStore = getOrCreateGlobalSingleton( + 'legacy-plugin-compatibility-store', + () => new WeakMap(), +); + +export function toLegacyPlugin(plugin: BackstagePlugin): LegacyBackstagePlugin { + let legacy = legacyPluginStore.get(plugin); + if (legacy) { + return legacy; + } + + const errorMsg = 'Not implemented in legacy plugin compatibility layer'; + const notImplemented = () => { + throw new Error(errorMsg); + }; + + legacy = { + getId(): string { + return plugin.id; + }, + get routes() { + return {}; + }, + get externalRoutes() { + return {}; + }, + getApis: notImplemented, + getFeatureFlags: notImplemented, + provide: notImplemented, + }; + + legacyPluginStore.set(plugin, legacy); + return legacy; +} diff --git a/packages/frontend-app-api/src/routing/types.ts b/packages/frontend-app-api/src/routing/types.ts index 5f1ed9be84..05ea73dff8 100644 --- a/packages/frontend-app-api/src/routing/types.ts +++ b/packages/frontend-app-api/src/routing/types.ts @@ -15,6 +15,7 @@ */ import { + AppNode, ExternalRouteRef, RouteRef, SubRouteRef, @@ -35,4 +36,5 @@ export interface BackstageRouteObject { path: string; routeRefs: Set; plugins: Set; + appNode?: AppNode; } diff --git a/packages/frontend-app-api/src/tree/createAppTree.test.ts b/packages/frontend-app-api/src/tree/createAppTree.test.ts index 667e3a6fc3..9ee58fe2d2 100644 --- a/packages/frontend-app-api/src/tree/createAppTree.test.ts +++ b/packages/frontend-app-api/src/tree/createAppTree.test.ts @@ -24,18 +24,18 @@ import { createAppTree } from './createAppTree'; const extBase = { id: 'test', - attachTo: { id: 'core', input: 'root' }, + attachTo: { id: 'app', input: 'root' }, output: {}, factory: () => ({}), }; describe('createAppTree', () => { - it('throws an error when a core extension is parametrized', () => { + it('throws an error when a app extension is parametrized', () => { const config = new MockConfigApi({ app: { extensions: [ { - core: {}, + app: {}, }, ], }, @@ -48,18 +48,17 @@ describe('createAppTree', () => { ]; expect(() => createAppTree({ features, config, builtinExtensions: [] }), - ).toThrow("Configuration of the 'core' extension is forbidden"); + ).toThrow("Configuration of the 'app' extension is forbidden"); }); - it('throws an error when a core extension is overridden', () => { + it('throws an error when a app extension is overridden', () => { const config = new MockConfigApi({}); const features = [ - createPlugin({ - id: 'plugin', + createExtensionOverrides({ extensions: [ createExtension({ - id: 'core', - attachTo: { id: 'core.routes', input: 'route' }, + name: 'app', + attachTo: { id: 'app/routes', input: 'route' }, inputs: {}, output: {}, factory: () => ({}), @@ -70,33 +69,7 @@ describe('createAppTree', () => { expect(() => createAppTree({ features, config, builtinExtensions: [] }), ).toThrow( - "It is forbidden to override the following extension(s): 'core', which is done by the following plugin(s): 'plugin'", - ); - }); - - it('throws an error when duplicated extensions are detected', () => { - const config = new MockConfigApi({}); - - const ExtensionA = createExtension({ ...extBase, id: 'A' }); - - const ExtensionB = createExtension({ ...extBase, id: 'B' }); - - const PluginA = createPlugin({ - id: 'A', - extensions: [ExtensionA, ExtensionA], - }); - - const PluginB = createPlugin({ - id: 'B', - extensions: [ExtensionA, ExtensionB, ExtensionB], - }); - - const features = [PluginA, PluginB]; - - expect(() => - createAppTree({ features, config, builtinExtensions: [] }), - ).toThrow( - "The following extensions are duplicated: The extension 'A' was provided 2 time(s) by the plugin 'A' and 1 time(s) by the plugin 'B', The extension 'B' was provided 2 time(s) by the plugin 'B'", + "It is forbidden to override the following extension(s): 'app', which is done by one or more extension overrides", ); }); @@ -106,13 +79,13 @@ describe('createAppTree', () => { features: [ createExtensionOverrides({ extensions: [ - createExtension({ ...extBase, id: 'a' }), - createExtension({ ...extBase, id: 'a' }), - createExtension({ ...extBase, id: 'b' }), + createExtension({ ...extBase, name: 'a' }), + createExtension({ ...extBase, name: 'a' }), + createExtension({ ...extBase, name: 'b' }), ], }), createExtensionOverrides({ - extensions: [createExtension({ ...extBase, id: 'b' })], + extensions: [createExtension({ ...extBase, name: 'b' })], }), ], config: new MockConfigApi({}), diff --git a/packages/frontend-app-api/src/tree/createAppTree.ts b/packages/frontend-app-api/src/tree/createAppTree.ts index 950669febd..12c7f7fc3a 100644 --- a/packages/frontend-app-api/src/tree/createAppTree.ts +++ b/packages/frontend-app-api/src/tree/createAppTree.ts @@ -14,11 +14,7 @@ * limitations under the License. */ -import { - BackstagePlugin, - Extension, - ExtensionOverrides, -} from '@backstage/frontend-plugin-api'; +import { Extension, FrontendFeature } from '@backstage/frontend-plugin-api'; import { readAppExtensionsConfig } from './readAppExtensionsConfig'; import { resolveAppTree } from './resolveAppTree'; import { resolveAppNodeSpecs } from './resolveAppNodeSpecs'; @@ -28,7 +24,7 @@ import { instantiateAppNodeTree } from './instantiateAppNodeTree'; /** @internal */ export interface CreateAppTreeOptions { - features: (BackstagePlugin | ExtensionOverrides)[]; + features: FrontendFeature[]; builtinExtensions: Extension[]; config: Config; } @@ -36,12 +32,12 @@ export interface CreateAppTreeOptions { /** @internal */ export function createAppTree(options: CreateAppTreeOptions): AppTree { const tree = resolveAppTree( - 'core', + 'app', resolveAppNodeSpecs({ features: options.features, builtinExtensions: options.builtinExtensions, parameters: readAppExtensionsConfig(options.config), - forbidden: new Set(['core']), + forbidden: new Set(['app']), }), ); instantiateAppNodeTree(tree.root); diff --git a/packages/frontend-app-api/src/tree/instantiateAppNodeTree.test.ts b/packages/frontend-app-api/src/tree/instantiateAppNodeTree.test.ts index 68a95fa1fe..766cb4804e 100644 --- a/packages/frontend-app-api/src/tree/instantiateAppNodeTree.test.ts +++ b/packages/frontend-app-api/src/tree/instantiateAppNodeTree.test.ts @@ -15,6 +15,7 @@ */ import { + AppNode, Extension, createExtension, createExtensionDataRef, @@ -25,53 +26,72 @@ import { createAppNodeInstance, instantiateAppNodeTree, } from './instantiateAppNodeTree'; -import { AppNodeInstance, AppNodeSpec } from '@backstage/frontend-plugin-api'; +import { AppNodeSpec } from '@backstage/frontend-plugin-api'; import { resolveAppTree } from './resolveAppTree'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { resolveExtensionDefinition } from '../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition'; +import { withLogCollector } from '@backstage/test-utils'; const testDataRef = createExtensionDataRef('test'); const otherDataRef = createExtensionDataRef('other'); const inputMirrorDataRef = createExtensionDataRef('mirror'); -const simpleExtension = createExtension({ - id: 'core.test', - attachTo: { id: 'ignored', input: 'ignored' }, - output: { - test: testDataRef, - other: otherDataRef.optional(), - }, - configSchema: createSchemaFromZod(z => - z.object({ - output: z.string().default('test'), - other: z.number().optional(), - }), - ), - factory({ config }) { - return { test: config.output, other: config.other }; - }, -}); +const simpleExtension = resolveExtensionDefinition( + createExtension({ + namespace: 'app', + name: 'test', + attachTo: { id: 'ignored', input: 'ignored' }, + output: { + test: testDataRef, + other: otherDataRef.optional(), + }, + configSchema: createSchemaFromZod(z => + z.object({ + output: z.string().default('test'), + other: z.number().optional(), + }), + ), + factory({ config }) { + return { test: config.output, other: config.other }; + }, + }), +); function makeSpec( extension: Extension, - config?: TConfig, + spec?: Partial, ): AppNodeSpec { return { id: extension.id, attachTo: extension.attachTo, disabled: extension.disabled, extension, - config, source: undefined, + ...spec, + }; +} + +function makeNode( + extension: Extension, + spec?: Partial, +): AppNode { + return { + spec: makeSpec(extension, spec), + edges: { + attachments: new Map(), + }, }; } function makeInstanceWithId( extension: Extension, config?: TConfig, -): { id: string; instance: AppNodeInstance } { +): AppNode { + const node = makeNode(extension, { config }); return { - id: extension.id, + ...node, instance: createAppNodeInstance({ - spec: makeSpec(extension, config), + node, attachments: new Map(), }), }; @@ -80,7 +100,7 @@ function makeInstanceWithId( describe('instantiateAppNodeTree', () => { it('should instantiate a single node', () => { const tree = resolveAppTree('root-node', [ - { ...makeSpec(simpleExtension), id: 'root-node' }, + makeSpec(simpleExtension, { id: 'root-node' }), ]); expect(tree.root.instance).not.toBeDefined(); instantiateAppNodeTree(tree.root); @@ -94,7 +114,7 @@ describe('instantiateAppNodeTree', () => { it('should not instantiate disabled nodes', () => { const tree = resolveAppTree('root-node', [ - { ...makeSpec(simpleExtension), id: 'root-node', disabled: true }, + makeSpec(simpleExtension, { id: 'root-node', disabled: true }), ]); expect(tree.root.instance).not.toBeDefined(); instantiateAppNodeTree(tree.root); @@ -103,10 +123,10 @@ describe('instantiateAppNodeTree', () => { it('should instantiate a node with attachments', () => { const tree = resolveAppTree('root-node', [ - { - ...makeSpec( + makeSpec( + resolveExtensionDefinition( createExtension({ - id: 'root-node', + namespace: 'root-node', attachTo: { id: 'ignored', input: 'ignored' }, inputs: { test: createExtensionInput({ test: testDataRef }), @@ -119,12 +139,11 @@ describe('instantiateAppNodeTree', () => { }, }), ), - }, - { - ...makeSpec(simpleExtension), + ), + makeSpec(simpleExtension, { id: 'child-node', attachTo: { id: 'root-node', input: 'test' }, - }, + }), ]); const childNode = tree.nodes.get('child-node'); @@ -135,8 +154,10 @@ describe('instantiateAppNodeTree', () => { instantiateAppNodeTree(tree.root); expect(tree.root.instance).toBeDefined(); expect(childNode?.instance).toBeDefined(); - expect(tree.root.instance?.getData(inputMirrorDataRef)).toEqual({ - test: [{ test: 'test' }], + expect(tree.root.instance?.getData(inputMirrorDataRef)).toMatchObject({ + test: [ + { node: { spec: { id: 'child-node' } }, output: { test: 'test' } }, + ], }); // Multiple calls should have no effect @@ -149,19 +170,21 @@ describe('instantiateAppNodeTree', () => { const tree = resolveAppTree('root-node', [ { ...makeSpec( - createExtension({ - id: 'root-node', - attachTo: { id: 'ignored', input: 'ignored' }, - inputs: { - test: createExtensionInput({ test: testDataRef }), - }, - output: { - inputMirror: inputMirrorDataRef, - }, - factory({ inputs }) { - return { inputMirror: inputs }; - }, - }), + resolveExtensionDefinition( + createExtension({ + namespace: 'root-node', + attachTo: { id: 'ignored', input: 'ignored' }, + inputs: { + test: createExtensionInput({ test: testDataRef }), + }, + output: { + inputMirror: inputMirrorDataRef, + }, + factory({ inputs }) { + return { inputMirror: inputs }; + }, + }), + ), ), }, { @@ -191,7 +214,7 @@ describe('createAppNodeInstance', () => { it('should create a simple extension instance', () => { const attachments = new Map(); const instance = createAppNodeInstance({ - spec: makeSpec(simpleExtension), + node: makeNode(simpleExtension), attachments, }); @@ -231,164 +254,188 @@ describe('createAppNodeInstance', () => { ]); const instance = createAppNodeInstance({ attachments, - spec: makeSpec( - createExtension({ - id: 'core.test', - attachTo: { id: 'ignored', input: 'ignored' }, - inputs: { - optionalSingletonPresent: createExtensionInput( - { + node: makeNode( + resolveExtensionDefinition( + createExtension({ + namespace: 'app', + name: 'test', + attachTo: { id: 'ignored', input: 'ignored' }, + inputs: { + optionalSingletonPresent: createExtensionInput( + { + test: testDataRef, + other: otherDataRef.optional(), + }, + { singleton: true, optional: true }, + ), + optionalSingletonMissing: createExtensionInput( + { + test: testDataRef, + other: otherDataRef.optional(), + }, + { singleton: true, optional: true }, + ), + singleton: createExtensionInput( + { + test: testDataRef, + other: otherDataRef.optional(), + }, + { singleton: true }, + ), + many: createExtensionInput({ test: testDataRef, other: otherDataRef.optional(), - }, - { singleton: true, optional: true }, - ), - optionalSingletonMissing: createExtensionInput( - { - test: testDataRef, - other: otherDataRef.optional(), - }, - { singleton: true, optional: true }, - ), - singleton: createExtensionInput( - { - test: testDataRef, - other: otherDataRef.optional(), - }, - { singleton: true }, - ), - many: createExtensionInput({ - test: testDataRef, - other: otherDataRef.optional(), - }), - }, - output: { - inputMirror: inputMirrorDataRef, - }, - factory({ inputs }) { - return { inputMirror: inputs }; - }, - }), + }), + }, + output: { + inputMirror: inputMirrorDataRef, + }, + factory({ inputs }) { + return { inputMirror: inputs }; + }, + }), + ), ), }); expect(Array.from(instance.getDataRefs())).toEqual([inputMirrorDataRef]); - expect(instance.getData(inputMirrorDataRef)).toEqual({ - optionalSingletonPresent: { test: 'optionalSingletonPresent' }, - singleton: { test: 'singleton', other: 2 }, - many: [{ test: 'many1' }, { test: 'many2', other: 3 }], + expect(instance.getData(inputMirrorDataRef)).toMatchObject({ + optionalSingletonPresent: { + node: { spec: { id: 'app/test' } }, + output: { test: 'optionalSingletonPresent' }, + }, + singleton: { + node: { spec: { id: 'app/test' } }, + output: { test: 'singleton', other: 2 }, + }, + many: [ + { node: { spec: { id: 'app/test' } }, output: { test: 'many1' } }, + { + node: { spec: { id: 'app/test' } }, + output: { test: 'many2', other: 3 }, + }, + ], }); }); it('should refuse to create an extension with invalid config', () => { expect(() => createAppNodeInstance({ - spec: { - ...makeSpec(simpleExtension), - config: { other: 'not-a-number' }, - }, + node: makeNode(simpleExtension, { config: { other: 'not-a-number' } }), attachments: new Map(), }), ).toThrow( - "Invalid configuration for extension 'core.test'; caused by Error: Expected number, received string at 'other'", + "Invalid configuration for extension 'app/test'; caused by Error: Expected number, received string at 'other'", ); }); it('should forward extension factory errors', () => { expect(() => createAppNodeInstance({ - spec: makeSpec( - createExtension({ - id: 'core.test', - attachTo: { id: 'ignored', input: 'ignored' }, - output: {}, - factory() { - const error = new Error('NOPE'); - error.name = 'NopeError'; - throw error; - }, - }), + node: makeNode( + resolveExtensionDefinition( + createExtension({ + namespace: 'app', + name: 'test', + attachTo: { id: 'ignored', input: 'ignored' }, + output: {}, + factory() { + const error = new Error('NOPE'); + error.name = 'NopeError'; + throw error; + }, + }), + ), ), attachments: new Map(), }), ).toThrow( - "Failed to instantiate extension 'core.test'; caused by NopeError: NOPE", + "Failed to instantiate extension 'app/test'; caused by NopeError: NOPE", ); }); it('should refuse to create an instance with duplicate output', () => { expect(() => createAppNodeInstance({ - spec: makeSpec( - createExtension({ - id: 'core.test', - attachTo: { id: 'ignored', input: 'ignored' }, - output: { - test1: testDataRef, - test2: testDataRef, - }, - factory({}) { - return { test1: 'test', test2: 'test2' }; - }, - }), + node: makeNode( + resolveExtensionDefinition( + createExtension({ + namespace: 'app', + name: 'test', + attachTo: { id: 'ignored', input: 'ignored' }, + output: { + test1: testDataRef, + test2: testDataRef, + }, + factory({}) { + return { test1: 'test', test2: 'test2' }; + }, + }), + ), ), attachments: new Map(), }), ).toThrow( - "Failed to instantiate extension 'core.test', duplicate extension data 'test' received via output 'test2'", + "Failed to instantiate extension 'app/test', duplicate extension data 'test' received via output 'test2'", ); }); it('should refuse to create an instance with disconnected output data', () => { expect(() => createAppNodeInstance({ - spec: makeSpec( - createExtension({ - id: 'core.test', - attachTo: { id: 'ignored', input: 'ignored' }, - output: { - test: testDataRef, - }, - factory({}) { - return { nonexistent: 'test' } as any; - }, - }), + node: makeNode( + resolveExtensionDefinition( + createExtension({ + namespace: 'app', + name: 'test', + attachTo: { id: 'ignored', input: 'ignored' }, + output: { + test: testDataRef, + }, + factory({}) { + return { nonexistent: 'test' } as any; + }, + }), + ), ), attachments: new Map(), }), ).toThrow( - "Failed to instantiate extension 'core.test', unknown output provided via 'nonexistent'", + "Failed to instantiate extension 'app/test', unknown output provided via 'nonexistent'", ); }); it('should refuse to create an instance with missing required input', () => { expect(() => createAppNodeInstance({ - spec: makeSpec( - createExtension({ - id: 'core.test', - attachTo: { id: 'ignored', input: 'ignored' }, - inputs: { - singleton: createExtensionInput( - { - test: testDataRef, - }, - { singleton: true }, - ), - }, - output: {}, - factory: () => ({}), - }), + node: makeNode( + resolveExtensionDefinition( + createExtension({ + namespace: 'app', + name: 'test', + attachTo: { id: 'ignored', input: 'ignored' }, + inputs: { + singleton: createExtensionInput( + { + test: testDataRef, + }, + { singleton: true }, + ), + }, + output: {}, + factory: () => ({}), + }), + ), ), attachments: new Map(), }), ).toThrow( - "Failed to instantiate extension 'core.test', input 'singleton' is required but was not received", + "Failed to instantiate extension 'app/test', input 'singleton' is required but was not received", ); }); - it('should refuse to create an instance with undeclared inputs', () => { - expect(() => + it('should warn when creating an instance with undeclared inputs', () => { + const { warn } = withLogCollector(['warn'], () => createAppNodeInstance({ attachments: new Map([ [ @@ -408,27 +455,32 @@ describe('createAppNodeInstance', () => { ], ], ]), - spec: makeSpec( - createExtension({ - id: 'core.test', - attachTo: { id: 'ignored', input: 'ignored' }, - inputs: { - declared: createExtensionInput({ - test: testDataRef, - }), - }, - output: {}, - factory: () => ({}), - }), + node: makeNode( + resolveExtensionDefinition( + createExtension({ + namespace: 'app', + name: 'parent', + attachTo: { id: 'ignored', input: 'ignored' }, + inputs: { + declared: createExtensionInput({ + test: testDataRef, + }), + }, + output: {}, + factory: () => ({}), + }), + ), ), }), - ).toThrow( - "Failed to instantiate extension 'core.test', received undeclared input 'undeclared' from extension 'core.test'", ); + + expect(warn).toEqual([ + "The extension 'app/test' is attached to the input 'undeclared' of the extension 'app/parent', but it has no such input (candidates are 'declared')", + ]); }); it('should refuse to create an instance with multiple undeclared inputs', () => { - expect(() => + const { warn } = withLogCollector(['warn'], () => createAppNodeInstance({ attachments: new Map([ [ @@ -443,18 +495,24 @@ describe('createAppNodeInstance', () => { ], ], ]), - spec: makeSpec( - createExtension({ - id: 'core.test', - attachTo: { id: 'ignored', input: 'ignored' }, - output: {}, - factory: () => ({}), - }), + node: makeNode( + resolveExtensionDefinition( + createExtension({ + namespace: 'app', + name: 'parent', + attachTo: { id: 'ignored', input: 'ignored' }, + output: {}, + factory: () => ({}), + }), + ), ), }), - ).toThrow( - "Failed to instantiate extension 'core.test', received undeclared inputs 'undeclared1' from extension 'core.test' and 'undeclared2' from extensions 'core.test', 'core.test'", ); + + expect(warn).toEqual([ + "The extension 'app/test' is attached to the input 'undeclared1' of the extension 'app/parent', but it has no inputs", + "The extensions 'app/test', 'app/test' are attached to the input 'undeclared2' of the extension 'app/parent', but it has no inputs", + ]); }); it('should refuse to create an instance with multiple inputs for required singleton', () => { @@ -469,25 +527,28 @@ describe('createAppNodeInstance', () => { ], ], ]), - spec: makeSpec( - createExtension({ - id: 'core.test', - attachTo: { id: 'ignored', input: 'ignored' }, - inputs: { - singleton: createExtensionInput( - { - test: testDataRef, - }, - { singleton: true }, - ), - }, - output: {}, - factory: () => ({}), - }), + node: makeNode( + resolveExtensionDefinition( + createExtension({ + namespace: 'app', + name: 'test', + attachTo: { id: 'ignored', input: 'ignored' }, + inputs: { + singleton: createExtensionInput( + { + test: testDataRef, + }, + { singleton: true }, + ), + }, + output: {}, + factory: () => ({}), + }), + ), ), }), ).toThrow( - "Failed to instantiate extension 'core.test', expected exactly one 'singleton' input but received multiple: 'core.test', 'core.test'", + "Failed to instantiate extension 'app/test', expected exactly one 'singleton' input but received multiple: 'app/test', 'app/test'", ); }); @@ -503,25 +564,28 @@ describe('createAppNodeInstance', () => { ], ], ]), - spec: makeSpec( - createExtension({ - id: 'core.test', - attachTo: { id: 'ignored', input: 'ignored' }, - inputs: { - singleton: createExtensionInput( - { - test: testDataRef, - }, - { singleton: true, optional: true }, - ), - }, - output: {}, - factory: () => ({}), - }), + node: makeNode( + resolveExtensionDefinition( + createExtension({ + namespace: 'app', + name: 'test', + attachTo: { id: 'ignored', input: 'ignored' }, + inputs: { + singleton: createExtensionInput( + { + test: testDataRef, + }, + { singleton: true, optional: true }, + ), + }, + output: {}, + factory: () => ({}), + }), + ), ), }), ).toThrow( - "Failed to instantiate extension 'core.test', expected at most one 'singleton' input but received multiple: 'core.test', 'core.test'", + "Failed to instantiate extension 'app/test', expected at most one 'singleton' input but received multiple: 'app/test', 'app/test'", ); }); @@ -531,25 +595,28 @@ describe('createAppNodeInstance', () => { attachments: new Map([ ['singleton', [makeInstanceWithId(simpleExtension, undefined)]], ]), - spec: makeSpec( - createExtension({ - id: 'core.test', - attachTo: { id: 'ignored', input: 'ignored' }, - inputs: { - singleton: createExtensionInput( - { - other: otherDataRef, - }, - { singleton: true }, - ), - }, - output: {}, - factory: () => ({}), - }), + node: makeNode( + resolveExtensionDefinition( + createExtension({ + namespace: 'app', + name: 'test', + attachTo: { id: 'ignored', input: 'ignored' }, + inputs: { + singleton: createExtensionInput( + { + other: otherDataRef, + }, + { singleton: true }, + ), + }, + output: {}, + factory: () => ({}), + }), + ), ), }), ).toThrow( - "Failed to instantiate extension 'core.test', input 'singleton' did not receive required extension data 'other' from extension 'core.test'", + "Failed to instantiate extension 'app/test', input 'singleton' did not receive required extension data 'other' from extension 'app/test'", ); }); }); diff --git a/packages/frontend-app-api/src/tree/instantiateAppNodeTree.ts b/packages/frontend-app-api/src/tree/instantiateAppNodeTree.ts index 003abbb97e..90a256fea6 100644 --- a/packages/frontend-app-api/src/tree/instantiateAppNodeTree.ts +++ b/packages/frontend-app-api/src/tree/instantiateAppNodeTree.ts @@ -18,13 +18,12 @@ import { AnyExtensionDataMap, AnyExtensionInputMap, ExtensionDataRef, + ResolvedExtensionInputs, } from '@backstage/frontend-plugin-api'; import mapValues from 'lodash/mapValues'; -import { - AppNode, - AppNodeInstance, - AppNodeSpec, -} from '@backstage/frontend-plugin-api'; +import { AppNode, AppNodeInstance } from '@backstage/frontend-plugin-api'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { toInternalExtension } from '../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition'; type Mutable = { -readonly [P in keyof T]: T[P]; @@ -32,14 +31,14 @@ type Mutable = { function resolveInputData( dataMap: AnyExtensionDataMap, - attachment: { id: string; instance: AppNodeInstance }, + attachment: AppNode, inputName: string, ) { return mapValues(dataMap, ref => { - const value = attachment.instance.getData(ref); + const value = attachment.instance?.getData(ref); if (value === undefined && !ref.config.optional) { throw new Error( - `input '${inputName}' did not receive required extension data '${ref.id}' from extension '${attachment.id}'`, + `input '${inputName}' did not receive required extension data '${ref.id}' from extension '${attachment.spec.id}'`, ); } return value; @@ -47,26 +46,32 @@ function resolveInputData( } function resolveInputs( + id: string, inputMap: AnyExtensionInputMap, - attachments: ReadonlyMap, -) { + attachments: ReadonlyMap, +): ResolvedExtensionInputs { const undeclaredAttachments = Array.from(attachments.entries()).filter( ([inputName]) => inputMap[inputName] === undefined, ); - // TODO: Make this a warning rather than an error - if (undeclaredAttachments.length > 0) { - throw new Error( - `received undeclared input${ - undeclaredAttachments.length > 1 ? 's' : '' - } ${undeclaredAttachments - .map( - ([k, exts]) => - `'${k}' from extension${exts.length > 1 ? 's' : ''} '${exts - .map(e => e.id) - .join("', '")}'`, - ) - .join(' and ')}`, - ); + + if (process.env.NODE_ENV !== 'production') { + const inputNames = Object.keys(inputMap); + + for (const [name, nodes] of undeclaredAttachments) { + const pl = nodes.length > 1; + // eslint-disable-next-line no-console + console.warn( + [ + `The extension${pl ? 's' : ''} '${nodes + .map(n => n.spec.id) + .join("', '")}' ${pl ? 'are' : 'is'}`, + `attached to the input '${name}' of the extension '${id}', but it`, + inputNames.length === 0 + ? 'has no inputs' + : `has no such input (candidates are '${inputNames.join("', '")}')`, + ].join(' '), + ); + } } return mapValues(inputMap, (input, inputName) => { @@ -74,7 +79,7 @@ function resolveInputs( if (input.config.singleton) { if (attachedNodes.length > 1) { - const attachedNodeIds = attachedNodes.map(e => e.id); + const attachedNodeIds = attachedNodes.map(e => e.spec.id); throw Error( `expected ${ input.config.optional ? 'at most' : 'exactly' @@ -88,22 +93,30 @@ function resolveInputs( } throw Error(`input '${inputName}' is required but was not received`); } - return resolveInputData(input.extensionData, attachedNodes[0], inputName); + return { + node: attachedNodes[0], + output: resolveInputData( + input.extensionData, + attachedNodes[0], + inputName, + ), + }; } - return attachedNodes.map(attachment => - resolveInputData(input.extensionData, attachment, inputName), - ); - }); + return attachedNodes.map(attachment => ({ + node: attachment, + output: resolveInputData(input.extensionData, attachment, inputName), + })); + }) as ResolvedExtensionInputs; } /** @internal */ export function createAppNodeInstance(options: { - spec: AppNodeSpec; - attachments: ReadonlyMap; + node: AppNode; + attachments: ReadonlyMap; }): AppNodeInstance { - const { spec, attachments } = options; - const { id, extension, config, source } = spec; + const { node, attachments } = options; + const { id, extension, config } = node.spec; const extensionData = new Map(); const extensionDataRefs = new Set>(); @@ -117,14 +130,16 @@ export function createAppNodeInstance(options: { } try { - const namedOutputs = extension.factory({ - source, + const internalExtension = toInternalExtension(extension); + + const namedOutputs = internalExtension.factory({ + node, config: parsedConfig, - inputs: resolveInputs(extension.inputs, attachments), + inputs: resolveInputs(id, internalExtension.inputs, attachments), }); for (const [name, output] of Object.entries(namedOutputs)) { - const ref = extension.output[name]; + const ref = internalExtension.output[name]; if (!ref) { throw new Error(`unknown output provided via '${name}'`); } @@ -139,7 +154,7 @@ export function createAppNodeInstance(options: { } catch (e) { throw new Error( `Failed to instantiate extension '${id}'${ - e.name === 'Error' ? `, ${e.message}` : `; caused by ${e}` + e.name === 'Error' ? `, ${e.message}` : `; caused by ${e.stack}` }`, ); } @@ -167,10 +182,7 @@ export function instantiateAppNodeTree(rootNode: AppNode): void { return undefined; } - const instantiatedAttachments = new Map< - string, - { id: string; instance: AppNodeInstance }[] - >(); + const instantiatedAttachments = new Map(); for (const [input, children] of node.edges.attachments) { const instantiatedChildren = children.flatMap(child => { @@ -178,7 +190,7 @@ export function instantiateAppNodeTree(rootNode: AppNode): void { if (!childInstance) { return []; } - return [{ id: child.spec.id, instance: childInstance }]; + return [child]; }); if (instantiatedChildren.length > 0) { instantiatedAttachments.set(input, instantiatedChildren); @@ -186,7 +198,7 @@ export function instantiateAppNodeTree(rootNode: AppNode): void { } (node as Mutable).instance = createAppNodeInstance({ - spec: node.spec, + node, attachments: instantiatedAttachments, }); diff --git a/packages/frontend-app-api/src/tree/readAppExtensionsConfig.test.ts b/packages/frontend-app-api/src/tree/readAppExtensionsConfig.test.ts index 91f6992f29..440407549e 100644 --- a/packages/frontend-app-api/src/tree/readAppExtensionsConfig.test.ts +++ b/packages/frontend-app-api/src/tree/readAppExtensionsConfig.test.ts @@ -25,18 +25,18 @@ describe('readAppExtensionsConfig', () => { it('should disable extension with shorthand notation', () => { expect( readAppExtensionsConfig( - new ConfigReader({ app: { extensions: [{ 'core.router': false }] } }), + new ConfigReader({ app: { extensions: [{ 'app/root': false }] } }), ), ).toEqual([ { - id: 'core.router', + id: 'app/root', disabled: true, }, ]); expect( readAppExtensionsConfig( new ConfigReader({ - app: { extensions: [{ 'core.router': { disabled: true } }] }, + app: { extensions: [{ 'app/root': { disabled: true } }] }, }), ), ).toEqual([ @@ -44,7 +44,7 @@ describe('readAppExtensionsConfig', () => { at: undefined, config: undefined, disabled: true, - id: 'core.router', + id: 'app/root', }, ]); }); @@ -52,33 +52,33 @@ describe('readAppExtensionsConfig', () => { it('should enable extension with shorthand notation', () => { expect( readAppExtensionsConfig( - new ConfigReader({ app: { extensions: ['core.router'] } }), + new ConfigReader({ app: { extensions: ['app/root'] } }), ), ).toEqual([ { - id: 'core.router', + id: 'app/root', disabled: false, }, ]); expect( readAppExtensionsConfig( - new ConfigReader({ app: { extensions: [{ 'core.router': true }] } }), + new ConfigReader({ app: { extensions: [{ 'app/root': true }] } }), ), ).toEqual([ { - id: 'core.router', + id: 'app/root', disabled: false, }, ]); expect( readAppExtensionsConfig( new ConfigReader({ - app: { extensions: [{ 'core.router': { disabled: false } }] }, + app: { extensions: [{ 'app/root': { disabled: false } }] }, }), ), ).toEqual([ { - id: 'core.router', + id: 'app/root', disabled: false, }, ]); @@ -89,12 +89,12 @@ describe('readAppExtensionsConfig', () => { readAppExtensionsConfig( new ConfigReader({ app: { - extensions: [{ 'core.router': 'some-string' }], + extensions: [{ 'app/root': 'some-string' }], }, }), ), ).toThrow( - 'Invalid extension configuration at app.extensions[0][core.router], value must be a boolean or object', + 'Invalid extension configuration at app.extensions[0][app/root], value must be a boolean or object', ); }); @@ -105,7 +105,7 @@ describe('readAppExtensionsConfig', () => { app: { extensions: [ { - 'core.router/routes': { + '': { extension: 'example-package#MyPage', config: { foo: 'bar' }, }, @@ -115,7 +115,7 @@ describe('readAppExtensionsConfig', () => { }), ), ).toThrowErrorMatchingInlineSnapshot( - `"Invalid extension configuration at app.extensions[0], extension ID must not contain slashes; got 'core.router/routes', did you mean 'core.router'?"`, + `"Invalid extension configuration at app.extensions[0], extension ID must not be empty or contain whitespace"`, ); }); }); @@ -156,8 +156,8 @@ describe('expandShorthandExtensionParameters', () => { }); it('supports string key', () => { - expect(run('core.router')).toEqual({ - id: 'core.router', + expect(run('app/root')).toEqual({ + id: 'app/root', disabled: false, }); expect(() => run('')).toThrowErrorMatchingInlineSnapshot( @@ -166,103 +166,100 @@ describe('expandShorthandExtensionParameters', () => { expect(() => run(' a')).toThrowErrorMatchingInlineSnapshot( `"Invalid extension configuration at app.extensions[1], extension ID must not be empty or contain whitespace"`, ); - expect(() => run('core.router/routes')).toThrowErrorMatchingInlineSnapshot( - `"Invalid extension configuration at app.extensions[1], extension ID must not contain slashes; got 'core.router/routes', did you mean 'core.router'?"`, - ); }); it('supports null value', () => { // this is the result of typing: - // - core.router: + // - app/root: // The missing value is interpreted as null by the yaml parser so we deal with that - expect(run({ 'core.router': null })).toEqual({ - id: 'core.router', + expect(run({ 'app/root': null })).toEqual({ + id: 'app/root', disabled: false, }); }); it('supports boolean value', () => { - expect(run({ 'core.router': true })).toEqual({ - id: 'core.router', + expect(run({ 'app/root': true })).toEqual({ + id: 'app/root', disabled: false, }); - expect(run({ 'core.router': false })).toEqual({ - id: 'core.router', + expect(run({ 'app/root': false })).toEqual({ + id: 'app/root', disabled: true, }); }); it('should not support string values', () => { expect(() => - run({ 'core.router': 'example-package#MyRouter' }), + run({ 'app/root': 'example-package#MyRouter' }), ).toThrowErrorMatchingInlineSnapshot( - `"Invalid extension configuration at app.extensions[1][core.router], value must be a boolean or object"`, + `"Invalid extension configuration at app.extensions[1][app/root], value must be a boolean or object"`, ); }); it('supports object id only in the key', () => { expect(() => - run({ 'core.router': { id: 'some.id' } }), + run({ 'app/root': { id: 'some.id' } }), ).toThrowErrorMatchingInlineSnapshot( - `"Invalid extension configuration at app.extensions[1][core.router].id, unknown parameter; expected one of 'attachTo', 'disabled', 'config'"`, + `"Invalid extension configuration at app.extensions[1][app/root].id, unknown parameter; expected one of 'attachTo', 'disabled', 'config'"`, ); }); it('supports object attachTo', () => { expect( run({ - 'core.router': { attachTo: { id: 'other.root', input: 'inputs' } }, + 'app/root': { attachTo: { id: 'other.root', input: 'inputs' } }, }), ).toEqual({ - id: 'core.router', + id: 'app/root', attachTo: { id: 'other.root', input: 'inputs' }, }); expect(() => run({ - 'core.router': { + 'app/root': { id: 'other-id', }, }), ).toThrowErrorMatchingInlineSnapshot( - `"Invalid extension configuration at app.extensions[1][core.router].id, unknown parameter; expected one of 'attachTo', 'disabled', 'config'"`, + `"Invalid extension configuration at app.extensions[1][app/root].id, unknown parameter; expected one of 'attachTo', 'disabled', 'config'"`, ); }); it('supports object disabled', () => { - expect(run({ 'core.router': { disabled: true } })).toEqual({ - id: 'core.router', + expect(run({ 'app/root': { disabled: true } })).toEqual({ + id: 'app/root', disabled: true, }); - expect(run({ 'core.router': { disabled: false } })).toEqual({ - id: 'core.router', + expect(run({ 'app/root': { disabled: false } })).toEqual({ + id: 'app/root', disabled: false, }); expect(() => - run({ 'core.router': { disabled: 0 } }), + run({ 'app/root': { disabled: 0 } }), ).toThrowErrorMatchingInlineSnapshot( - `"Invalid extension configuration at app.extensions[1][core.router].disabled, must be a boolean"`, + `"Invalid extension configuration at app.extensions[1][app/root].disabled, must be a boolean"`, ); }); it('supports object config', () => { - expect( - run({ 'core.router': { config: { disableRedirects: true } } }), - ).toEqual({ - id: 'core.router', - config: { disableRedirects: true }, - }); + expect(run({ 'app/root': { config: { disableRedirects: true } } })).toEqual( + { + id: 'app/root', + config: { disableRedirects: true }, + }, + ); expect(() => - run({ 'core.router': { config: 0 } }), + run({ 'app/root': { config: 0 } }), ).toThrowErrorMatchingInlineSnapshot( - `"Invalid extension configuration at app.extensions[1][core.router].config, must be an object"`, + `"Invalid extension configuration at app.extensions[1][app/root].config, must be an object"`, ); }); it('rejects unknown object keys', () => { expect(() => - run({ 'core.router': { foo: { settings: true } } }), + run({ 'app/root': { foo: { settings: true } } }), ).toThrowErrorMatchingInlineSnapshot( - `"Invalid extension configuration at app.extensions[1][core.router].foo, unknown parameter; expected one of 'attachTo', 'disabled', 'config'"`, + `"Invalid extension configuration at app.extensions[1][app/root].foo, unknown parameter; expected one of 'attachTo', 'disabled', 'config'"`, ); }); }); diff --git a/packages/frontend-app-api/src/tree/readAppExtensionsConfig.ts b/packages/frontend-app-api/src/tree/readAppExtensionsConfig.ts index 2b5b51ce92..cca7064add 100644 --- a/packages/frontend-app-api/src/tree/readAppExtensionsConfig.ts +++ b/packages/frontend-app-api/src/tree/readAppExtensionsConfig.ts @@ -70,15 +70,6 @@ export function expandShorthandExtensionParameters( errorMsg('extension ID must not be empty or contain whitespace'), ); } - - if (id.includes('/')) { - let message = `extension ID must not contain slashes; got '${id}'`; - const good = id.split('/')[0]; - if (good) { - message += `, did you mean '${good}'?`; - } - throw new Error(errorMsg(message)); - } } // Example YAML: diff --git a/packages/frontend-app-api/src/tree/resolveAppNodeSpecs.test.ts b/packages/frontend-app-api/src/tree/resolveAppNodeSpecs.test.ts index 39eceaaf28..82f274b960 100644 --- a/packages/frontend-app-api/src/tree/resolveAppNodeSpecs.test.ts +++ b/packages/frontend-app-api/src/tree/resolveAppNodeSpecs.test.ts @@ -18,6 +18,7 @@ import { createExtensionOverrides, createPlugin, Extension, + ExtensionDefinition, } from '@backstage/frontend-plugin-api'; import { resolveAppNodeSpecs } from './resolveAppNodeSpecs'; @@ -27,12 +28,29 @@ function makeExt( attachId: string = 'root', ) { return { + $$type: '@backstage/Extension', + version: 'v1', id, attachTo: { id: attachId, input: 'default' }, disabled: status === 'disabled', + toString: expect.any(Function), } as Extension; } +function makeExtDef( + name: string, + status: 'disabled' | 'enabled' = 'enabled', + attachId: string = 'root', +) { + return { + $$type: '@backstage/ExtensionDefinition', + version: 'v1', + name, + attachTo: { id: attachId, input: 'default' }, + disabled: status === 'disabled', + } as ExtensionDefinition; +} + describe('resolveAppNodeSpecs', () => { it('should not filter out disabled extension instances', () => { const a = makeExt('a', 'disabled'); @@ -78,9 +96,8 @@ describe('resolveAppNodeSpecs', () => { }); it('should override attachment points', () => { - const a = makeExt('a'); const b = makeExt('b'); - const pluginA = createPlugin({ id: 'test', extensions: [a] }); + const pluginA = createPlugin({ id: 'test', extensions: [makeExtDef('a')] }); expect( resolveAppNodeSpecs({ features: [pluginA], @@ -94,8 +111,8 @@ describe('resolveAppNodeSpecs', () => { }), ).toEqual([ { - id: 'a', - extension: a, + id: 'test/a', + extension: makeExt('test/a'), attachTo: { id: 'root', input: 'default' }, source: pluginA, disabled: false, @@ -110,31 +127,34 @@ describe('resolveAppNodeSpecs', () => { }); it('should fully override configuration and duplicate', () => { - const a = makeExt('a'); - const b = makeExt('b'); - const plugin = createPlugin({ id: 'test', extensions: [a, b] }); + const a = makeExt('test/a'); + const b = makeExt('test/b'); + const plugin = createPlugin({ + id: 'test', + extensions: [makeExtDef('a'), makeExtDef('b')], + }); expect( resolveAppNodeSpecs({ features: [plugin], builtinExtensions: [], parameters: [ { - id: 'a', + id: 'test/a', config: { foo: { bar: 1 } }, }, { - id: 'b', + id: 'test/b', config: { foo: { bar: 2 } }, }, { - id: 'b', + id: 'test/b', config: { foo: { qux: 3 } }, }, ], }), ).toEqual([ { - id: 'a', + id: 'test/a', extension: a, attachTo: { id: 'root', input: 'default' }, source: plugin, @@ -142,7 +162,7 @@ describe('resolveAppNodeSpecs', () => { disabled: false, }, { - id: 'b', + id: 'test/b', extension: b, attachTo: { id: 'root', input: 'default' }, source: plugin, @@ -187,11 +207,12 @@ describe('resolveAppNodeSpecs', () => { }); it('should apply extension overrides', () => { - const a = makeExt('a'); - const b = makeExt('b'); - const plugin = createPlugin({ id: 'test', extensions: [a, b] }); - const aOverride = makeExt('a', 'enabled', 'other'); - const bOverride = makeExt('b', 'disabled', 'other'); + const plugin = createPlugin({ + id: 'test', + extensions: [makeExtDef('a'), makeExtDef('b')], + }); + const aOverride = makeExt('test/a', 'enabled', 'other'); + const bOverride = makeExt('test/b', 'disabled', 'other'); const cOverride = makeExt('c'); expect( @@ -199,7 +220,11 @@ describe('resolveAppNodeSpecs', () => { features: [ plugin, createExtensionOverrides({ - extensions: [aOverride, bOverride, cOverride], + extensions: [ + makeExtDef('test/a', 'enabled', 'other'), + makeExtDef('test/b', 'disabled', 'other'), + makeExtDef('c'), + ], }), ], builtinExtensions: [], @@ -207,14 +232,14 @@ describe('resolveAppNodeSpecs', () => { }), ).toEqual([ { - id: 'a', + id: 'test/a', extension: aOverride, attachTo: { id: 'other', input: 'default' }, source: plugin, disabled: false, }, { - id: 'b', + id: 'test/b', extension: bOverride, attachTo: { id: 'other', input: 'default' }, source: plugin, @@ -231,39 +256,50 @@ describe('resolveAppNodeSpecs', () => { }); it('should use order from configuration when rather than overrides', () => { - const a = makeExt('a', 'disabled'); - const b = makeExt('b', 'disabled'); - const c = makeExt('c', 'disabled'); - const aOverride = makeExt('c', 'disabled'); - const bOverride = makeExt('b', 'disabled'); - const cOverride = makeExt('a', 'disabled'); - const result = resolveAppNodeSpecs({ features: [ - createPlugin({ id: 'test', extensions: [a, b, c] }), + createPlugin({ + id: 'test', + extensions: [ + makeExtDef('a', 'disabled'), + makeExtDef('b', 'disabled'), + makeExtDef('c', 'disabled'), + ], + }), createExtensionOverrides({ - extensions: [cOverride, bOverride, aOverride], + extensions: [ + makeExtDef('test/c', 'disabled'), + makeExtDef('test/b', 'disabled'), + makeExtDef('test/a', 'disabled'), + ], }), ], builtinExtensions: [], - parameters: ['b', 'c', 'a'].map(id => ({ id, disabled: false })), + parameters: ['test/b', 'test/c', 'test/a'].map(id => ({ + id, + disabled: false, + })), }); - expect(result.map(r => r.extension.id)).toEqual(['b', 'c', 'a']); + expect(result.map(r => r.extension.id)).toEqual([ + 'test/b', + 'test/c', + 'test/a', + ]); }); it('throws an error when a forbidden extension is overridden by a plugin', () => { expect(() => resolveAppNodeSpecs({ features: [ - createPlugin({ id: 'test', extensions: [makeExt('forbidden')] }), + createPlugin({ id: 'test', extensions: [makeExtDef('forbidden')] }), ], builtinExtensions: [], parameters: [], - forbidden: new Set(['forbidden']), + forbidden: new Set(['test/forbidden']), }), ).toThrow( - "It is forbidden to override the following extension(s): 'forbidden', which is done by the following plugin(s): 'test'", + "It is forbidden to override the following extension(s): 'test/forbidden', which is done by the following plugin(s): 'test'", ); }); @@ -271,7 +307,7 @@ describe('resolveAppNodeSpecs', () => { expect(() => resolveAppNodeSpecs({ features: [ - createExtensionOverrides({ extensions: [makeExt('forbidden')] }), + createExtensionOverrides({ extensions: [makeExtDef('forbidden')] }), ], builtinExtensions: [], parameters: [], diff --git a/packages/frontend-app-api/src/tree/resolveAppNodeSpecs.ts b/packages/frontend-app-api/src/tree/resolveAppNodeSpecs.ts index 0a024c0a3f..8fd9d44638 100644 --- a/packages/frontend-app-api/src/tree/resolveAppNodeSpecs.ts +++ b/packages/frontend-app-api/src/tree/resolveAppNodeSpecs.ts @@ -18,15 +18,20 @@ import { BackstagePlugin, Extension, ExtensionOverrides, + FrontendFeature, } from '@backstage/frontend-plugin-api'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports import { toInternalExtensionOverrides } from '../../../frontend-plugin-api/src/wiring/createExtensionOverrides'; import { ExtensionParameters } from './readAppExtensionsConfig'; import { AppNodeSpec } from '@backstage/frontend-plugin-api'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { toInternalBackstagePlugin } from '../../../frontend-plugin-api/src/wiring/createPlugin'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { toInternalExtension } from '../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition'; /** @internal */ export function resolveAppNodeSpecs(options: { - features: (BackstagePlugin | ExtensionOverrides)[]; + features: FrontendFeature[]; builtinExtensions: Extension[]; parameters: Array; forbidden?: Set; @@ -42,7 +47,10 @@ export function resolveAppNodeSpecs(options: { ); const pluginExtensions = plugins.flatMap(source => { - return source.extensions.map(extension => ({ ...extension, source })); + return toInternalBackstagePlugin(source).extensions.map(extension => ({ + ...extension, + source, + })); }); const overrideExtensions = overrides.flatMap( override => toInternalExtensionOverrides(override).extensions, @@ -83,45 +91,53 @@ export function resolveAppNodeSpecs(options: { } const configuredExtensions = [ - ...pluginExtensions.map(({ source, ...extension }) => ({ - extension, - params: { - source, - attachTo: extension.attachTo, - disabled: extension.disabled, - config: undefined as unknown, - }, - })), - ...builtinExtensions.map(extension => ({ - extension, - params: { - source: undefined, - attachTo: extension.attachTo, - disabled: extension.disabled, - config: undefined as unknown, - }, - })), + ...pluginExtensions.map(({ source, ...extension }) => { + const internalExtension = toInternalExtension(extension); + return { + extension: internalExtension, + params: { + source, + attachTo: internalExtension.attachTo, + disabled: internalExtension.disabled, + config: undefined as unknown, + }, + }; + }), + ...builtinExtensions.map(extension => { + const internalExtension = toInternalExtension(extension); + return { + extension: internalExtension, + params: { + source: undefined, + attachTo: internalExtension.attachTo, + disabled: internalExtension.disabled, + config: undefined as unknown, + }, + }; + }), ]; // Install all extension overrides for (const extension of overrideExtensions) { + const internalExtension = toInternalExtension(extension); + // Check if our override is overriding an extension that already exists const index = configuredExtensions.findIndex( e => e.extension.id === extension.id, ); if (index !== -1) { // Only implementation, attachment point and default disabled status are overridden, the source is kept - configuredExtensions[index].extension = extension; - configuredExtensions[index].params.attachTo = extension.attachTo; - configuredExtensions[index].params.disabled = extension.disabled; + configuredExtensions[index].extension = internalExtension; + configuredExtensions[index].params.attachTo = internalExtension.attachTo; + configuredExtensions[index].params.disabled = internalExtension.disabled; } else { // Add the extension as a new one when not overriding an existing one configuredExtensions.push({ - extension, + extension: internalExtension, params: { source: undefined, - attachTo: extension.attachTo, - disabled: extension.disabled, + attachTo: internalExtension.attachTo, + disabled: internalExtension.disabled, config: undefined, }, }); diff --git a/packages/frontend-app-api/src/tree/resolveAppTree.test.ts b/packages/frontend-app-api/src/tree/resolveAppTree.test.ts index d84064b26a..f964fceb50 100644 --- a/packages/frontend-app-api/src/tree/resolveAppTree.test.ts +++ b/packages/frontend-app-api/src/tree/resolveAppTree.test.ts @@ -16,15 +16,17 @@ import { createExtension } from '@backstage/frontend-plugin-api'; import { resolveAppTree } from './resolveAppTree'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { resolveExtensionDefinition } from '../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition'; -const extBaseConfig = { - id: 'test', - attachTo: { id: 'nonexistent', input: 'nonexistent' }, - output: {}, - factory: () => ({}), -}; - -const extension = createExtension(extBaseConfig); +const extension = resolveExtensionDefinition( + createExtension({ + name: 'test', + attachTo: { id: 'nonexistent', input: 'nonexistent' }, + output: {}, + factory: () => ({}), + }), +); const baseSpec = { extension, @@ -34,19 +36,19 @@ const baseSpec = { describe('buildAppTree', () => { it('should fail to create an empty tree', () => { - expect(() => resolveAppTree('core', [])).toThrow( - "No root node with id 'core' found in app tree", + expect(() => resolveAppTree('app', [])).toThrow( + "No root node with id 'app' found in app tree", ); }); it('should create a tree with only one node', () => { - const tree = resolveAppTree('core', [{ ...baseSpec, id: 'core' }]); + const tree = resolveAppTree('app', [{ ...baseSpec, id: 'app' }]); expect(tree.root).toEqual({ - spec: { ...baseSpec, id: 'core' }, + spec: { ...baseSpec, id: 'app' }, edges: { attachments: new Map() }, }); expect(Array.from(tree.orphans)).toEqual([]); - expect(Array.from(tree.nodes.keys())).toEqual(['core']); + expect(Array.from(tree.nodes.keys())).toEqual(['app']); }); it('should create a tree', () => { @@ -157,7 +159,7 @@ describe('buildAppTree', () => { it('throws an error when duplicated extensions are detected', () => { expect(() => - resolveAppTree('core', [ + resolveAppTree('app', [ { ...baseSpec, id: 'a' }, { ...baseSpec, id: 'a' }, ]), diff --git a/packages/frontend-app-api/src/wiring/InternalAppContext.ts b/packages/frontend-app-api/src/wiring/InternalAppContext.ts new file mode 100644 index 0000000000..81264bd81b --- /dev/null +++ b/packages/frontend-app-api/src/wiring/InternalAppContext.ts @@ -0,0 +1,28 @@ +/* + * 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 { createContext } from 'react'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { AppIdentityProxy } from '../../../core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy'; +import { BackstageRouteObject } from '../routing/types'; + +export const InternalAppContext = createContext< + | undefined + | { + appIdentityProxy: AppIdentityProxy; + routeObjects: BackstageRouteObject[]; + } +>(undefined); diff --git a/packages/frontend-app-api/src/wiring/createApp.test.tsx b/packages/frontend-app-api/src/wiring/createApp.test.tsx index 80d9f846f0..43bb4499b1 100644 --- a/packages/frontend-app-api/src/wiring/createApp.test.tsx +++ b/packages/frontend-app-api/src/wiring/createApp.test.tsx @@ -17,25 +17,32 @@ import { AppTreeApi, appTreeApiRef, + coreExtensionData, + createExtension, + createExtensionOverrides, createPageExtension, createPlugin, createThemeExtension, } from '@backstage/frontend-plugin-api'; import { screen, waitFor } from '@testing-library/react'; -import { createApp } from './createApp'; +import { CreateAppFeatureLoader, createApp } from './createApp'; import { MockConfigApi, renderWithEffects } from '@backstage/test-utils'; import React from 'react'; -import { useApi } from '@backstage/core-plugin-api'; +import { featureFlagsApiRef, useApi } from '@backstage/core-plugin-api'; describe('createApp', () => { it('should allow themes to be installed', async () => { const app = createApp({ - configLoader: async () => - new MockConfigApi({ + configLoader: async () => ({ + config: new MockConfigApi({ app: { - extensions: [{ 'themes.light': false }, { 'themes.dark': false }], + extensions: [ + { 'theme:app/light': false }, + { 'theme:app/dark': false }, + ], }, }), + }), features: [ createPlugin({ id: 'test', @@ -59,13 +66,12 @@ describe('createApp', () => { it('should deduplicate features keeping the last received one', async () => { const duplicatedFeatureId = 'test'; const app = createApp({ - configLoader: async () => new MockConfigApi({}), + configLoader: async () => ({ config: new MockConfigApi({}) }), features: [ createPlugin({ id: duplicatedFeatureId, extensions: [ createPageExtension({ - id: 'test.page.first', defaultPath: '/', loader: async () =>
First Page
, }), @@ -75,7 +81,6 @@ describe('createApp', () => { id: duplicatedFeatureId, extensions: [ createPageExtension({ - id: 'test.page.last', defaultPath: '/', loader: async () =>
Last Page
, }), @@ -94,17 +99,129 @@ describe('createApp', () => { ); }); + it('should support feature loaders', async () => { + const loader: CreateAppFeatureLoader = { + getLoaderName() { + return 'test-loader'; + }, + async load({ config }) { + return { + features: [ + createPlugin({ + id: 'test', + extensions: [ + createPageExtension({ + defaultPath: '/', + loader: async () =>
{config.getString('key')}
, + }), + ], + }), + ], + }; + }, + }; + + const app = createApp({ + configLoader: async () => ({ + config: new MockConfigApi({ key: 'config-value' }), + }), + features: [loader], + }); + + await renderWithEffects(app.createRoot()); + + await expect( + screen.findByText('config-value'), + ).resolves.toBeInTheDocument(); + }); + + it('should propagate errors thrown by feature loaders', async () => { + const loader: CreateAppFeatureLoader = { + getLoaderName() { + return 'test-loader'; + }, + async load() { + throw new TypeError('boom'); + }, + }; + + const app = createApp({ + configLoader: async () => ({ + config: new MockConfigApi({}), + }), + features: [loader], + }); + + await expect( + renderWithEffects(app.createRoot()), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Failed to read frontend features from loader 'test-loader', TypeError: boom"`, + ); + }); + + it('should register feature flags', async () => { + const app = createApp({ + configLoader: async () => ({ config: new MockConfigApi({}) }), + features: [ + createPlugin({ + id: 'test', + featureFlags: [{ name: 'test-1' }], + extensions: [ + createExtension({ + name: 'first', + attachTo: { id: 'app', input: 'root' }, + output: { element: coreExtensionData.reactElement }, + factory() { + const Component = () => { + const flagsApi = useApi(featureFlagsApiRef); + return ( +
+ Flags:{' '} + {flagsApi + .getRegisteredFlags() + .map(flag => `${flag.name} from '${flag.pluginId}'`) + .join(', ')} +
+ ); + }; + return { element: }; + }, + }), + ], + }), + createExtensionOverrides({ + featureFlags: [{ name: 'test-2' }], + extensions: [ + createExtension({ + namespace: 'app', + name: 'root', + attachTo: { id: 'app', input: 'root' }, + disabled: true, + output: {}, + factory: () => ({}), + }), + ], + }), + ], + }); + + await renderWithEffects(app.createRoot()); + + await expect( + screen.findByText("Flags: test-1 from 'test', test-2 from ''"), + ).resolves.toBeInTheDocument(); + }); + it('should make the app structure available through the AppTreeApi', async () => { let appTreeApi: AppTreeApi | undefined = undefined; const app = createApp({ - configLoader: async () => new MockConfigApi({}), + configLoader: async () => ({ config: new MockConfigApi({}) }), features: [ createPlugin({ id: 'my-plugin', extensions: [ createPageExtension({ - id: 'plugin.my-plugin.page', defaultPath: '/', loader: async () => { const Component = () => { @@ -125,26 +242,58 @@ describe('createApp', () => { const { tree } = appTreeApi!.getTree(); expect(String(tree.root)).toMatchInlineSnapshot(` - " + " root [ - - content [ - - routes [ - + + children [ + + content [ + + routes [ + + ] + ] - + nav [ + + ] + ] - nav [ - + elements [ + + ] - + + ] + components [ + + + ] themes [ - - + + ] - " + apis [ + + + + + + + + + + + + + + + + + + ] + " `); }); }); diff --git a/packages/frontend-app-api/src/wiring/createApp.tsx b/packages/frontend-app-api/src/wiring/createApp.tsx index ca0e1d60d1..7b2f17193e 100644 --- a/packages/frontend-app-api/src/wiring/createApp.tsx +++ b/packages/frontend-app-api/src/wiring/createApp.tsx @@ -19,27 +19,30 @@ import { ConfigReader, Config } from '@backstage/config'; import { AppTree, appTreeApiRef, - BackstagePlugin, + ComponentRef, + componentsApiRef, coreExtensionData, + createApiExtension, + createComponentExtension, + createNavItemExtension, + createThemeExtension, + createTranslationExtension, ExtensionDataRef, - ExtensionOverrides, + FrontendFeature, RouteRef, useRouteRef, } from '@backstage/frontend-plugin-api'; -import { Core } from '../extensions/Core'; -import { CoreRoutes } from '../extensions/CoreRoutes'; -import { CoreLayout } from '../extensions/CoreLayout'; -import { CoreNav } from '../extensions/CoreNav'; +import { App } from '../extensions/App'; +import { AppRoutes } from '../extensions/AppRoutes'; +import { AppLayout } from '../extensions/AppLayout'; +import { AppNav } from '../extensions/AppNav'; import { AnyApiFactory, ApiHolder, - AppComponents, - AppContext, appThemeApiRef, ConfigApi, configApiRef, IconComponent, - BackstagePlugin as LegacyBackstagePlugin, featureFlagsApiRef, attachComponentData, identityApiRef, @@ -59,8 +62,6 @@ import { AppThemeProvider } from '../../../core-app-api/src/app/AppThemeProvider // eslint-disable-next-line @backstage/no-relative-monorepo-imports import { AppIdentityProxy } from '../../../core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports -import { AppContextProvider } from '../../../core-app-api/src/app/AppContext'; -// eslint-disable-next-line @backstage/no-relative-monorepo-imports import { LocalStorageFeatureFlags } from '../../../core-app-api/src/apis/implementations/FeatureFlagsApi/LocalStorageFeatureFlags'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports import { defaultConfigLoaderSync } from '../../../core-app-api/src/app/defaultConfigLoader'; @@ -71,35 +72,58 @@ import { AppLanguageSelector } from '../../../core-app-api/src/apis/implementati // eslint-disable-next-line @backstage/no-relative-monorepo-imports import { I18nextTranslationApi } from '../../../core-app-api/src/apis/implementations/TranslationApi/I18nextTranslationApi'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports -import { - apis as defaultApis, - components as defaultComponents, - icons as defaultIcons, -} from '../../../app-defaults/src/defaults'; -import { BrowserRouter, Route } from 'react-router-dom'; +import { resolveExtensionDefinition } from '../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { apis as defaultApis } from '../../../app-defaults/src/defaults'; +import { Route } from 'react-router-dom'; import { SidebarItem } from '@backstage/core-components'; import { DarkTheme, LightTheme } from '../extensions/themes'; +import { + oauthRequestDialogAppRootElement, + alertDisplayAppRootElement, +} from '../extensions/elements'; import { extractRouteInfoFromAppNode } from '../routing/extractRouteInfoFromAppNode'; -import { getOrCreateGlobalSingleton } from '@backstage/version-bridge'; import { appLanguageApiRef, translationApiRef, } from '@backstage/core-plugin-api/alpha'; -import { AppRouteBinder } from '../routing'; +import { CreateAppRouteBinder } from '../routing'; import { RoutingProvider } from '../routing/RoutingProvider'; import { resolveRouteBindings } from '../routing/resolveRouteBindings'; import { collectRouteIds } from '../routing/collectRouteIds'; import { createAppTree } from '../tree'; +import { + DefaultProgressComponent, + DefaultErrorBoundaryComponent, + DefaultNotFoundErrorPageComponent, +} from '../extensions/components'; import { AppNode } from '@backstage/frontend-plugin-api'; +import { InternalAppContext } from './InternalAppContext'; +import { AppRoot } from '../extensions/AppRoot'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { toInternalBackstagePlugin } from '../../../frontend-plugin-api/src/wiring/createPlugin'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { toInternalExtensionOverrides } from '../../../frontend-plugin-api/src/wiring/createExtensionOverrides'; +import { DefaultComponentsApi } from '../apis/implementations/ComponentsApi'; +import { stringifyError } from '@backstage/errors'; -const builtinExtensions = [ - Core, - CoreRoutes, - CoreNav, - CoreLayout, +const DefaultApis = defaultApis.map(factory => createApiExtension({ factory })); + +export const builtinExtensions = [ + App, + AppRoot, + AppRoutes, + AppNav, + AppLayout, + DefaultProgressComponent, + DefaultErrorBoundaryComponent, + DefaultNotFoundErrorPageComponent, LightTheme, DarkTheme, -]; + oauthRequestDialogAppRootElement, + alertDisplayAppRootElement, + ...DefaultApis, +].map(def => resolveExtensionDefinition(def)); /** @public */ export interface ExtensionTreeNode { @@ -154,7 +178,7 @@ export function createExtensionTree(options: { ); }, getRootRoutes(): JSX.Element[] { - return this.getExtensionAttachments('core.routes', 'routes').map(node => { + return this.getExtensionAttachments('app/routes', 'routes').map(node => { const path = node.getData(coreExtensionData.routePath); const element = node.getData(coreExtensionData.reactElement); const routeRef = node.getData(coreExtensionData.routeRef); @@ -181,9 +205,9 @@ export function createExtensionTree(options: { ); }; - return this.getExtensionAttachments('core.nav', 'items') + return this.getExtensionAttachments('app/nav', 'items') .map((node, index) => { - const target = node.getData(coreExtensionData.navTarget); + const target = node.getData(createNavItemExtension.targetDataRef); if (!target) { return null; } @@ -202,8 +226,8 @@ export function createExtensionTree(options: { } function deduplicateFeatures( - allFeatures: (BackstagePlugin | ExtensionOverrides)[], -): (BackstagePlugin | ExtensionOverrides)[] { + allFeatures: FrontendFeature[], +): FrontendFeature[] { // Start by removing duplicates by reference const features = Array.from(new Set(allFeatures)); @@ -224,69 +248,67 @@ function deduplicateFeatures( .reverse(); } +/** + * A source of dynamically loaded frontend features. + * + * @public + */ +export interface CreateAppFeatureLoader { + /** + * Returns name of this loader. suitable for showing to users. + */ + getLoaderName(): string; + + /** + * Loads a number of features dynamically. + */ + load(options: { config: ConfigApi }): Promise<{ + features: FrontendFeature[]; + }>; +} + /** @public */ export function createApp(options?: { - features?: (BackstagePlugin | ExtensionOverrides)[]; - configLoader?: () => Promise; - bindRoutes?(context: { bind: AppRouteBinder }): void; - featureLoader?: (ctx: { - config: ConfigApi; - }) => Promise<(BackstagePlugin | ExtensionOverrides)[]>; + features?: (FrontendFeature | CreateAppFeatureLoader)[]; + configLoader?: () => Promise<{ config: ConfigApi }>; + bindRoutes?(context: { bind: CreateAppRouteBinder }): void; }): { createRoot(): JSX.Element; } { async function appLoader() { const config = - (await options?.configLoader?.()) ?? + (await options?.configLoader?.().then(c => c.config)) ?? ConfigReader.fromConfigs( overrideBaseUrlConfigs(defaultConfigLoaderSync()), ); const discoveredFeatures = getAvailableFeatures(config); - const loadedFeatures = (await options?.featureLoader?.({ config })) ?? []; - const allFeatures = deduplicateFeatures([ - ...discoveredFeatures, - ...loadedFeatures, - ...(options?.features ?? []), - ]); - const tree = createAppTree({ - features: allFeatures, - builtinExtensions, + const providedFeatures: FrontendFeature[] = []; + for (const entry of options?.features ?? []) { + if ('load' in entry) { + try { + const result = await entry.load({ config }); + providedFeatures.push(...result.features); + } catch (e) { + throw new Error( + `Failed to read frontend features from loader '${entry.getLoaderName()}', ${stringifyError( + e, + )}`, + ); + } + } else { + providedFeatures.push(entry); + } + } + + const app = createSpecializedApp({ config, - }); + features: [...discoveredFeatures, ...providedFeatures], + bindRoutes: options?.bindRoutes, + }).createRoot(); - const appContext = createLegacyAppContext( - allFeatures.filter( - (f): f is BackstagePlugin => f.$$type === '@backstage/BackstagePlugin', - ), - ); - - const routeIds = collectRouteIds(allFeatures); - - const App = () => ( - - - - - {/* TODO: set base path using the logic from AppRouter */} - - {tree.root.instance!.getData(coreExtensionData.reactElement)} - - - - - - ); - - return { default: App }; + return { default: () => app }; } return { @@ -301,80 +323,111 @@ export function createApp(options?: { }; } -// Make sure that we only convert each new plugin instance to its legacy equivalent once -const legacyPluginStore = getOrCreateGlobalSingleton( - 'legacy-plugin-compatibility-store', - () => new WeakMap(), -); +/** + * Synchronous version of {@link createApp}, expecting all features and + * config to have been loaded already. + * + * @public + */ +export function createSpecializedApp(options?: { + features?: FrontendFeature[]; + config?: ConfigApi; + bindRoutes?(context: { bind: CreateAppRouteBinder }): void; +}): { createRoot(): JSX.Element } { + const { + features: duplicatedFeatures = [], + config = new ConfigReader({}, 'empty-config'), + } = options ?? {}; -export function toLegacyPlugin(plugin: BackstagePlugin): LegacyBackstagePlugin { - let legacy = legacyPluginStore.get(plugin); - if (legacy) { - return legacy; + const features = deduplicateFeatures(duplicatedFeatures); + + const tree = createAppTree({ + features, + builtinExtensions, + config, + }); + + const appIdentityProxy = new AppIdentityProxy(); + const apiHolder = createApiHolder(tree, config, appIdentityProxy); + + const featureFlagApi = apiHolder.get(featureFlagsApiRef); + if (featureFlagApi) { + for (const feature of features) { + if (feature.$$type === '@backstage/BackstagePlugin') { + toInternalBackstagePlugin(feature).featureFlags.forEach(flag => + featureFlagApi.registerFlag({ + name: flag.name, + pluginId: feature.id, + }), + ); + } + if (feature.$$type === '@backstage/ExtensionOverrides') { + toInternalExtensionOverrides(feature).featureFlags.forEach(flag => + featureFlagApi.registerFlag({ name: flag.name, pluginId: '' }), + ); + } + } } - const errorMsg = 'Not implemented in legacy plugin compatibility layer'; - const notImplemented = () => { - throw new Error(errorMsg); - }; + const routeInfo = extractRouteInfoFromAppNode(tree.root); + const routeBindings = resolveRouteBindings( + options?.bindRoutes, + config, + collectRouteIds(features), + ); + const rootEl = tree.root.instance!.getData(coreExtensionData.reactElement); - legacy = { - getId(): string { - return plugin.id; - }, - get routes() { - return {}; - }, - get externalRoutes() { - return {}; - }, - getApis: notImplemented, - getFeatureFlags: notImplemented, - provide: notImplemented, - }; + const AppComponent = () => ( + + + + + {rootEl} + + + + + ); - legacyPluginStore.set(plugin, legacy); - return legacy; -} - -function createLegacyAppContext(plugins: BackstagePlugin[]): AppContext { return { - getPlugins(): LegacyBackstagePlugin[] { - return plugins.map(toLegacyPlugin); - }, - - getSystemIcon(key: string): IconComponent | undefined { - return key in defaultIcons - ? defaultIcons[key as keyof typeof defaultIcons] - : undefined; - }, - - getSystemIcons(): Record { - return defaultIcons; - }, - - getComponents(): AppComponents { - return defaultComponents; + createRoot() { + return ; }, }; } -function createApiHolder(tree: AppTree, configApi: ConfigApi): ApiHolder { +function createApiHolder( + tree: AppTree, + configApi: ConfigApi, + appIdentityProxy: AppIdentityProxy, +): ApiHolder { const factoryRegistry = new ApiFactoryRegistry(); const pluginApis = tree.root.edges.attachments .get('apis') - ?.map(e => e.instance?.getData(coreExtensionData.apiFactory)) + ?.map(e => e.instance?.getData(createApiExtension.factoryDataRef)) .filter((x): x is AnyApiFactory => !!x) ?? []; const themeExtensions = tree.root.edges.attachments .get('themes') - ?.map(e => e.instance?.getData(coreExtensionData.theme)) + ?.map(e => e.instance?.getData(createThemeExtension.themeDataRef)) .filter((x): x is AppTheme => !!x) ?? []; - for (const factory of [...defaultApis, ...pluginApis]) { + const translationResources = + tree.root.edges.attachments + .get('translations') + ?.map(e => + e.instance?.getData(createTranslationExtension.translationDataRef), + ) + .filter( + (x): x is typeof createTranslationExtension.translationDataRef.T => !!x, + ) ?? []; + + for (const factory of pluginApis) { factoryRegistry.register('default', factory); } @@ -388,33 +441,7 @@ function createApiHolder(tree: AppTree, configApi: ConfigApi): ApiHolder { factoryRegistry.register('static', { api: identityApiRef, deps: {}, - factory: () => { - const appIdentityProxy = new AppIdentityProxy(); - // TODO: Remove this when sign-in page is migrated - appIdentityProxy.setTarget( - { - getUserId: () => 'guest', - getIdToken: async () => undefined, - getProfile: () => ({ - email: 'guest@example.com', - displayName: 'Guest', - }), - getProfileInfo: async () => ({ - email: 'guest@example.com', - displayName: 'Guest', - }), - getBackstageIdentity: async () => ({ - type: 'user', - userEntityRef: 'user:default/guest', - ownershipEntityRefs: ['user:default/guest'], - }), - getCredentials: async () => ({}), - signOut: async () => {}, - }, - { signOutTargetUrl: '/' }, - ); - return appIdentityProxy; - }, + factory: () => appIdentityProxy, }); factoryRegistry.register('static', { @@ -425,6 +452,24 @@ function createApiHolder(tree: AppTree, configApi: ConfigApi): ApiHolder { }), }); + const componentsExtensions = + tree.root.edges.attachments + .get('components') + ?.map(e => e.instance?.getData(createComponentExtension.componentDataRef)) + .filter(x => !!x) ?? []; + + const componentsMap = componentsExtensions.reduce( + (components, component) => + component ? components.set(component.ref, component?.impl) : components, + new Map, any>(), + ); + + factoryRegistry.register('static', { + api: componentsApiRef, + deps: {}, + factory: () => new DefaultComponentsApi(componentsMap), + }); + factoryRegistry.register('static', { api: appThemeApiRef, deps: {}, @@ -438,15 +483,6 @@ function createApiHolder(tree: AppTree, configApi: ConfigApi): ApiHolder { factory: () => AppLanguageSelector.createWithStorage(), }); - factoryRegistry.register('default', { - api: translationApiRef, - deps: { languageApi: appLanguageApiRef }, - factory: ({ languageApi }) => - I18nextTranslationApi.create({ - languageApi, - }), - }); - factoryRegistry.register('static', { api: configApiRef, deps: {}, @@ -459,24 +495,16 @@ function createApiHolder(tree: AppTree, configApi: ConfigApi): ApiHolder { factory: () => AppLanguageSelector.createWithStorage(), }); - factoryRegistry.register('default', { + factoryRegistry.register('static', { api: translationApiRef, deps: { languageApi: appLanguageApiRef }, factory: ({ languageApi }) => I18nextTranslationApi.create({ languageApi, + resources: translationResources, }), }); - // TODO: ship these as default extensions instead - for (const factory of defaultApis as AnyApiFactory[]) { - if (!factoryRegistry.register('app', factory)) { - throw new Error( - `Duplicate or forbidden API factory for ${factory.api} in app`, - ); - } - } - ApiResolver.validateFactories(factoryRegistry, factoryRegistry.getAllApis()); return new ApiResolver(factoryRegistry); diff --git a/packages/frontend-app-api/src/wiring/discovery.ts b/packages/frontend-app-api/src/wiring/discovery.ts index 1181992d53..4e50290350 100644 --- a/packages/frontend-app-api/src/wiring/discovery.ts +++ b/packages/frontend-app-api/src/wiring/discovery.ts @@ -15,10 +15,7 @@ */ import { Config, ConfigReader } from '@backstage/config'; -import { - BackstagePlugin, - ExtensionOverrides, -} from '@backstage/frontend-plugin-api'; +import { FrontendFeature } from '@backstage/frontend-plugin-api'; interface DiscoveryGlobal { modules: Array<{ name: string; export?: string; default: unknown }>; @@ -58,9 +55,7 @@ function readPackageDetectionConfig(config: Config) { /** * @public */ -export function getAvailableFeatures( - config: Config, -): (BackstagePlugin | ExtensionOverrides)[] { +export function getAvailableFeatures(config: Config): FrontendFeature[] { const discovered = ( window as { '__@backstage/discovered__'?: DiscoveryGlobal } )['__@backstage/discovered__']; @@ -86,9 +81,7 @@ export function getAvailableFeatures( ); } -function isBackstageFeature( - obj: unknown, -): obj is BackstagePlugin | ExtensionOverrides { +function isBackstageFeature(obj: unknown): obj is FrontendFeature { if (obj !== null && typeof obj === 'object' && '$$type' in obj) { return ( obj.$$type === '@backstage/BackstagePlugin' || diff --git a/packages/frontend-app-api/src/wiring/index.ts b/packages/frontend-app-api/src/wiring/index.ts index dc1ba3bc13..00c6458bd5 100644 --- a/packages/frontend-app-api/src/wiring/index.ts +++ b/packages/frontend-app-api/src/wiring/index.ts @@ -16,7 +16,9 @@ export { createApp, + createSpecializedApp, createExtensionTree, + type CreateAppFeatureLoader, type ExtensionTreeNode, type ExtensionTree, } from './createApp'; diff --git a/packages/frontend-plugin-api/CHANGELOG.md b/packages/frontend-plugin-api/CHANGELOG.md index 00defc21c8..c6ae8056ec 100644 --- a/packages/frontend-plugin-api/CHANGELOG.md +++ b/packages/frontend-plugin-api/CHANGELOG.md @@ -1,5 +1,166 @@ # @backstage/frontend-plugin-api +## 0.5.0 + +### Minor Changes + +- d4149bf: **BREAKING**: Renamed the `app/router` extension to `app/root`. + +### Patch Changes + +- b2d370e: Exposed `createComponentRef`, and ensured that produced refs and feature bits have a `toString` for easier debugging +- 7d63b32: Accepts sub route refs on the new `createPlugin` routes map. +- 516fd3e: Updated README to reflect release status +- 4016f21: Remove some unused dependencies +- c97fa1c: Added `elements`, `wrappers`, and `router` inputs to `app/root`, that let you add things to the root of the React tree above the layout. You can use the `createAppRootElementExtension`, `createAppRootWrapperExtension`, and `createRouterExtension` extension creator, respectively, to conveniently create such extensions. These are all optional, and if you do not supply a router a default one will be used (`BrowserRouter` in regular runs, `MemoryRouter` in tests/CI). +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## 0.4.1-next.2 + +### Patch Changes + +- 516fd3e: Updated README to reflect release status + +## 0.4.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## 0.4.1-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## 0.4.0 + +### Minor Changes + +- af7bc3e: Switched all core extensions to instead use the namespace `'app'`. +- 5cdf2b3: Changed `Extension` and `ExtensionDefinition` to use opaque types. +- 8f5d6c1: Extension inputs are now wrapped into an additional object when passed to the extension factory, with the previous values being available at the `output` property. The `ExtensionInputValues` type has also been replaced by `ResolvedExtensionInputs`. +- 8837a96: **BREAKING**: This version changes how extensions are created and how their IDs are determined. The `createExtension` function now accepts `kind`, `namespace` and `name` instead of `id`. All of the new options are optional, and are used to construct the final extension ID. By convention extension creators should set the `kind` to match their own name, for example `createNavItemExtension` sets the kind `nav-item`. + + The `createExtension` function as well as all extension creators now also return an `ExtensionDefinition` rather than an `Extension`, which in turn needs to be passed to `createPlugin` or `createExtensionOverrides` to be used. + +- f9ef632: Moved several extension data references from `coreExtensionData` to their respective extension creators. +- a5a0473: The extension `factory` function now longer receives `id` or `source`, but instead now provides the extension's `AppNode` as `node`. The `ExtensionBoundary` component has also been updated to receive a `node` prop rather than `id` and `source`. + +### Patch Changes + +- a379243: Add the `FrontendFeature` type, which is the union of `BackstagePlugin` and `ExtensionOverrides` +- b7adf24: Update alpha component ref type to be more specific than any, delete boot page component and use new plugin type for error boundary component extensions. +- 5eb6b8a: Added the nav logo extension for customization of sidebar logo +- 1f12fb7: Create factories for overriding default core components extensions. +- 5970928: Add feature flags to plugins and extension overrides. +- e539735: Added `createSignInPageExtension`. +- 73246ec: Added translation APIs as well as `createTranslationExtension`. +- cb4197a: Forward ` node`` instead of `extensionId` to resolved extension inputs. +- f27ee7d: Migrate analytics api and context files. +- 0cbb03b: Fixing regular expression ReDoS with zod packages. Upgrading to latest. ref: https://security.snyk.io/vuln/SNYK-JS-ZOD-5925617 +- f1183b7: Renamed the `component` option of `createComponentExtension` to `loader`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## 0.4.0-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## 0.4.0-next.2 + +### Minor Changes + +- 8f5d6c1: Extension inputs are now wrapped into an additional object when passed to the extension factory, with the previous values being available at the `output` property. The `ExtensionInputValues` type has also been replaced by `ResolvedExtensionInputs`. +- 8837a96: **BREAKING**: This version changes how extensions are created and how their IDs are determined. The `createExtension` function now accepts `kind`, `namespace` and `name` instead of `id`. All of the new options are optional, and are used to construct the final extension ID. By convention extension creators should set the `kind` to match their own name, for example `createNavItemExtension` sets the kind `nav-item`. + + The `createExtension` function as well as all extension creators now also return an `ExtensionDefinition` rather than an `Extension`, which in turn needs to be passed to `createPlugin` or `createExtensionOverrides` to be used. + +### Patch Changes + +- b7adf24: Update alpha component ref type to be more specific than any, delete boot page component and use new plugin type for error boundary component extensions. +- 73246ec: Added translation APIs as well as `createTranslationExtension`. +- cb4197a: Forward ` node`` instead of `extensionId` to resolved extension inputs. +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## 0.4.0-next.1 + +### Minor Changes + +- a5a04739e1: The extension `factory` function now longer receives `id` or `source`, but instead now provides the extension's `AppNode` as `node`. The `ExtensionBoundary` component has also been updated to receive a `node` prop rather than `id` and `source`. + +### Patch Changes + +- 5eb6b8a7bc: Added the nav logo extension for customization of sidebar logo +- 1f12fb762c: Create factories for overriding default core components extensions. +- 59709286b3: Add feature flags to plugins and extension overrides. +- e539735435: Added `createSignInPageExtension`. +- f27ee7d937: Migrate analytics api and context files. +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## 0.3.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## 0.3.0 + +### Minor Changes + +- 68fc9dc60e: Added `RouteRef`, `SubRouteRef`, `ExternalRouteRef`, and related types. All exports from this package that previously relied on the types with the same name from `@backstage/core-plugin-api` now use the new types instead. To convert and existing legacy route ref to be compatible with the APIs from this package, use the `convertLegacyRouteRef` utility from `@backstage/core-plugin-api/alpha`. +- 77f009b35d: Extensions now return their output from the factory function rather than calling `bind(...)`. + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 733bd95746: Add new `AppTreeApi`. +- 6af88a05ff: Improve the extension boundary component and create a default extension suspense component. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/version-bridge@1.0.7 + - @backstage/types@1.1.1 + ## 0.3.0-next.2 ### Patch Changes diff --git a/packages/frontend-plugin-api/README.md b/packages/frontend-plugin-api/README.md index 1fd3da79d8..aedf740840 100644 --- a/packages/frontend-plugin-api/README.md +++ b/packages/frontend-plugin-api/README.md @@ -1,8 +1,8 @@ # @backstage/frontend-plugin-api -**This package is EXPERIMENTAL, we recommend against using it for production deployments** +**The [new frontend system](https://backstage.io/docs/frontend-system/) that this package is part of is in alpha, and we do not yet recommend using it for production deployments** -This package provides the core API used by Backstage frontend plugins. It implements the design outlined in [RFC: Frontend System Evolution](https://github.com/backstage/backstage/issues/18372). +This package provides the framework API used by Backstage frontend plugins. It implements the design outlined in [RFC: Frontend System Evolution](https://github.com/backstage/backstage/issues/18372). ## Documentation diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index 794da9617b..1d42d8bab8 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -5,19 +5,147 @@ ```ts /// +import { AlertApi } from '@backstage/core-plugin-api'; +import { alertApiRef } from '@backstage/core-plugin-api'; +import { AlertMessage } from '@backstage/core-plugin-api'; import { AnyApiFactory } from '@backstage/core-plugin-api'; import { AnyApiRef } from '@backstage/core-plugin-api'; +import { ApiFactory } from '@backstage/core-plugin-api'; +import { ApiHolder } from '@backstage/core-plugin-api'; import { ApiRef } from '@backstage/core-plugin-api'; +import { ApiRefConfig } from '@backstage/core-plugin-api'; import { AppTheme } from '@backstage/core-plugin-api'; -import { IconComponent } from '@backstage/core-plugin-api'; +import { AppThemeApi } from '@backstage/core-plugin-api'; +import { appThemeApiRef } from '@backstage/core-plugin-api'; +import { atlassianAuthApiRef } from '@backstage/core-plugin-api'; +import { AuthProviderInfo } from '@backstage/core-plugin-api'; +import { AuthRequestOptions } from '@backstage/core-plugin-api'; +import { BackstageIdentityApi } from '@backstage/core-plugin-api'; +import { BackstageIdentityResponse } from '@backstage/core-plugin-api'; +import { BackstageUserIdentity } from '@backstage/core-plugin-api'; +import { bitbucketAuthApiRef } from '@backstage/core-plugin-api'; +import { bitbucketServerAuthApiRef } from '@backstage/core-plugin-api'; +import { ComponentType } from 'react'; +import { ConfigApi } from '@backstage/core-plugin-api'; +import { configApiRef } from '@backstage/core-plugin-api'; +import { createApiFactory } from '@backstage/core-plugin-api'; +import { createApiRef } from '@backstage/core-plugin-api'; +import { createTranslationMessages } from '@backstage/core-plugin-api/alpha'; +import { createTranslationRef } from '@backstage/core-plugin-api/alpha'; +import { createTranslationResource } from '@backstage/core-plugin-api/alpha'; +import { DiscoveryApi } from '@backstage/core-plugin-api'; +import { discoveryApiRef } from '@backstage/core-plugin-api'; +import { ErrorApi } from '@backstage/core-plugin-api'; +import { ErrorApiError } from '@backstage/core-plugin-api'; +import { ErrorApiErrorContext } from '@backstage/core-plugin-api'; +import { errorApiRef } from '@backstage/core-plugin-api'; +import { FeatureFlag } from '@backstage/core-plugin-api'; +import { FeatureFlagsApi } from '@backstage/core-plugin-api'; +import { featureFlagsApiRef } from '@backstage/core-plugin-api'; +import { FeatureFlagsSaveOptions } from '@backstage/core-plugin-api'; +import { FeatureFlagState } from '@backstage/core-plugin-api'; +import { FetchApi } from '@backstage/core-plugin-api'; +import { fetchApiRef } from '@backstage/core-plugin-api'; +import { githubAuthApiRef } from '@backstage/core-plugin-api'; +import { gitlabAuthApiRef } from '@backstage/core-plugin-api'; +import { googleAuthApiRef } from '@backstage/core-plugin-api'; +import { IconComponent as IconComponent_2 } from '@backstage/core-plugin-api'; +import { IdentityApi } from '@backstage/core-plugin-api'; +import { identityApiRef } from '@backstage/core-plugin-api'; import { JsonObject } from '@backstage/types'; import { JSX as JSX_2 } from 'react'; +import { microsoftAuthApiRef } from '@backstage/core-plugin-api'; +import { OAuthApi } from '@backstage/core-plugin-api'; +import { OAuthRequestApi } from '@backstage/core-plugin-api'; +import { oauthRequestApiRef } from '@backstage/core-plugin-api'; +import { OAuthRequester } from '@backstage/core-plugin-api'; +import { OAuthRequesterOptions } from '@backstage/core-plugin-api'; +import { OAuthScope } from '@backstage/core-plugin-api'; +import { oktaAuthApiRef } from '@backstage/core-plugin-api'; +import { oneloginAuthApiRef } from '@backstage/core-plugin-api'; +import { OpenIdConnectApi } from '@backstage/core-plugin-api'; +import { PendingOAuthRequest } from '@backstage/core-plugin-api'; +import { ProfileInfo } from '@backstage/core-plugin-api'; +import { ProfileInfoApi } from '@backstage/core-plugin-api'; +import { PropsWithChildren } from 'react'; import { default as React_2 } from 'react'; import { ReactNode } from 'react'; +import { SessionApi } from '@backstage/core-plugin-api'; +import { SessionState } from '@backstage/core-plugin-api'; +import { SignInPageProps } from '@backstage/core-plugin-api'; +import { StorageApi } from '@backstage/core-plugin-api'; +import { storageApiRef } from '@backstage/core-plugin-api'; +import { StorageValueSnapshot } from '@backstage/core-plugin-api'; +import { TranslationMessages } from '@backstage/core-plugin-api/alpha'; +import { TranslationMessagesOptions } from '@backstage/core-plugin-api/alpha'; +import { TranslationRef } from '@backstage/core-plugin-api/alpha'; +import { TranslationRefOptions } from '@backstage/core-plugin-api/alpha'; +import { TranslationResource } from '@backstage/core-plugin-api/alpha'; +import { TranslationResourceOptions } from '@backstage/core-plugin-api/alpha'; +import { TypesToApiRefs } from '@backstage/core-plugin-api'; +import { useApi } from '@backstage/core-plugin-api'; +import { useApiHolder } from '@backstage/core-plugin-api'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; +import { withApis } from '@backstage/core-plugin-api'; import { z } from 'zod'; import { ZodSchema } from 'zod'; import { ZodTypeDef } from 'zod'; +export { AlertApi }; + +export { alertApiRef }; + +export { AlertMessage }; + +// @public +export type AnalyticsApi = { + captureEvent(event: AnalyticsEvent): void; +}; + +// @public +export const analyticsApiRef: ApiRef; + +// @public +export const AnalyticsContext: (options: { + attributes: Partial; + children: ReactNode; +}) => React_2.JSX.Element; + +// @public +export type AnalyticsContextValue = CommonAnalyticsContext & { + [param in string]: string | boolean | number | undefined; +}; + +// @public +export type AnalyticsEvent = { + action: string; + subject: string; + value?: number; + attributes?: AnalyticsEventAttributes; + context: AnalyticsContextValue; +}; + +// @public +export type AnalyticsEventAttributes = { + [attribute in string]: string | boolean | number; +}; + +// @public +export type AnalyticsTracker = { + captureEvent: ( + action: string, + subject: string, + options?: { + value?: number; + attributes?: AnalyticsEventAttributes; + }, + ) => void; +}; + +export { AnyApiFactory }; + +export { AnyApiRef }; + // @public (undocumented) export type AnyExtensionDataMap = { [name in string]: ExtensionDataRef< @@ -53,9 +181,17 @@ export type AnyRouteRefParams = // @public (undocumented) export type AnyRoutes = { - [name in string]: RouteRef; + [name in string]: RouteRef | SubRouteRef; }; +export { ApiFactory }; + +export { ApiHolder }; + +export { ApiRef }; + +export { ApiRefConfig }; + // @public export interface AppNode { readonly edges: AppNodeEdges; @@ -99,6 +235,12 @@ export interface AppNodeSpec { readonly source?: BackstagePlugin; } +export { AppTheme }; + +export { AppThemeApi }; + +export { appThemeApiRef }; + // @public export interface AppTree { readonly nodes: ReadonlyMap; @@ -116,23 +258,62 @@ export interface AppTreeApi { // @public export const appTreeApiRef: ApiRef; +export { atlassianAuthApiRef }; + +export { AuthProviderInfo }; + +export { AuthRequestOptions }; + +export { BackstageIdentityApi }; + +export { BackstageIdentityResponse }; + // @public (undocumented) export interface BackstagePlugin< Routes extends AnyRoutes = AnyRoutes, ExternalRoutes extends AnyExternalRoutes = AnyExternalRoutes, > { // (undocumented) - $$type: '@backstage/BackstagePlugin'; + readonly $$type: '@backstage/BackstagePlugin'; // (undocumented) - extensions: Extension[]; + readonly externalRoutes: ExternalRoutes; // (undocumented) - externalRoutes: ExternalRoutes; + readonly id: string; // (undocumented) - id: string; - // (undocumented) - routes: Routes; + readonly routes: Routes; } +export { BackstageUserIdentity }; + +export { bitbucketAuthApiRef }; + +export { bitbucketServerAuthApiRef }; + +// @public +export type CommonAnalyticsContext = { + pluginId: string; + extensionId: string; +}; + +// @public (undocumented) +export type ComponentRef = { + id: string; + T: T; +}; + +// @public +export interface ComponentsApi { + // (undocumented) + getComponent(ref: ComponentRef): ComponentType; +} + +// @public +export const componentsApiRef: ApiRef; + +export { ConfigApi }; + +export { configApiRef }; + // @public (undocumented) export interface ConfigurableExtensionDataRef< TData, @@ -149,16 +330,35 @@ export interface ConfigurableExtensionDataRef< >; } +// @public (undocumented) +export const coreComponentRefs: { + progress: ComponentRef; + notFoundErrorPage: ComponentRef; + errorBoundaryFallback: ComponentRef; +}; + +// @public (undocumented) +export type CoreErrorBoundaryFallbackProps = { + plugin?: BackstagePlugin; + error: Error; + resetError: () => void; +}; + // @public (undocumented) export const coreExtensionData: { reactElement: ConfigurableExtensionDataRef; routePath: ConfigurableExtensionDataRef; - apiFactory: ConfigurableExtensionDataRef; routeRef: ConfigurableExtensionDataRef, {}>; - navTarget: ConfigurableExtensionDataRef; - theme: ConfigurableExtensionDataRef; }; +// @public (undocumented) +export type CoreNotFoundErrorPageProps = { + children?: ReactNode; +}; + +// @public (undocumented) +export type CoreProgressProps = {}; + // @public (undocumented) export function createApiExtension< TConfig extends {}, @@ -169,7 +369,7 @@ export function createApiExtension< api: AnyApiRef; factory: (options: { config: TConfig; - inputs: Expand>; + inputs: Expand>; }) => AnyApiFactory; } | { @@ -179,7 +379,115 @@ export function createApiExtension< configSchema?: PortableSchema; inputs?: TInputs; }, -): Extension; +): ExtensionDefinition; + +// @public (undocumented) +export namespace createApiExtension { + const // (undocumented) + factoryDataRef: ConfigurableExtensionDataRef; +} + +export { createApiFactory }; + +export { createApiRef }; + +// @public +export function createAppRootElementExtension< + TConfig extends {}, + TInputs extends AnyExtensionInputMap, +>(options: { + namespace?: string; + name?: string; + attachTo?: { + id: string; + input: string; + }; + configSchema?: PortableSchema; + disabled?: boolean; + inputs?: TInputs; + element: + | JSX_2.Element + | ((options: { + inputs: Expand>; + config: TConfig; + }) => JSX_2.Element); +}): ExtensionDefinition; + +// @public +export function createAppRootWrapperExtension< + TConfig extends {}, + TInputs extends AnyExtensionInputMap, +>(options: { + namespace?: string; + name?: string; + attachTo?: { + id: string; + input: string; + }; + configSchema?: PortableSchema; + disabled?: boolean; + inputs?: TInputs; + Component: ComponentType< + PropsWithChildren<{ + inputs: Expand>; + config: TConfig; + }> + >; +}): ExtensionDefinition; + +// @public (undocumented) +export namespace createAppRootWrapperExtension { + const // (undocumented) + componentDataRef: ConfigurableExtensionDataRef< + React_2.ComponentType<{ + children?: React_2.ReactNode; + }>, + {} + >; +} + +// @public (undocumented) +export function createComponentExtension< + TProps extends {}, + TConfig extends {}, + TInputs extends AnyExtensionInputMap, +>(options: { + ref: ComponentRef; + name?: string; + disabled?: boolean; + inputs?: TInputs; + configSchema?: PortableSchema; + loader: + | { + lazy: (values: { + config: TConfig; + inputs: Expand>; + }) => Promise>; + } + | { + sync: (values: { + config: TConfig; + inputs: Expand>; + }) => ComponentType; + }; +}): ExtensionDefinition; + +// @public (undocumented) +export namespace createComponentExtension { + const // (undocumented) + componentDataRef: ConfigurableExtensionDataRef< + { + ref: ComponentRef; + impl: ComponentType; + }, + {} + >; +} + +// @public (undocumented) +export function createComponentRef(options: { + id: string; +}): ComponentRef; // @public (undocumented) export function createExtension< @@ -188,7 +496,7 @@ export function createExtension< TConfig = never, >( options: CreateExtensionOptions, -): Extension; +): ExtensionDefinition; // @public (undocumented) export function createExtensionDataRef( @@ -230,15 +538,19 @@ export interface CreateExtensionOptions< disabled?: boolean; // (undocumented) factory(options: { - source?: BackstagePlugin; + node: AppNode; config: TConfig; - inputs: Expand>; + inputs: Expand>; }): Expand>; // (undocumented) - id: string; - // (undocumented) inputs?: TInputs; // (undocumented) + kind?: string; + // (undocumented) + name?: string; + // (undocumented) + namespace?: string; + // (undocumented) output: TOutput; } @@ -274,14 +586,48 @@ export function createExternalRouteRef< // @public export function createNavItemExtension(options: { - id: string; + namespace?: string; + name?: string; routeRef: RouteRef; title: string; - icon: IconComponent; -}): Extension<{ + icon: IconComponent_2; +}): ExtensionDefinition<{ title: string; }>; +// @public (undocumented) +export namespace createNavItemExtension { + const // (undocumented) + targetDataRef: ConfigurableExtensionDataRef< + { + title: string; + icon: IconComponent_2; + routeRef: RouteRef; + }, + {} + >; +} + +// @public +export function createNavLogoExtension(options: { + name?: string; + namespace?: string; + logoIcon: JSX.Element; + logoFull: JSX.Element; +}): ExtensionDefinition; + +// @public (undocumented) +export namespace createNavLogoExtension { + const // (undocumented) + logoElementsDataRef: ConfigurableExtensionDataRef< + { + logoIcon?: JSX.Element | undefined; + logoFull?: JSX.Element | undefined; + }, + {} + >; +} + // @public export function createPageExtension< TConfig extends { @@ -297,7 +643,8 @@ export function createPageExtension< configSchema: PortableSchema; } ) & { - id: string; + namespace?: string; + name?: string; attachTo?: { id: string; input: string; @@ -307,10 +654,10 @@ export function createPageExtension< routeRef?: RouteRef; loader: (options: { config: TConfig; - inputs: Expand>; + inputs: Expand>; }) => Promise; }, -): Extension; +): ExtensionDefinition; // @public (undocumented) export function createPlugin< @@ -340,11 +687,73 @@ export function createRouteRef< } >; +// @public +export function createRouterExtension< + TConfig extends {}, + TInputs extends AnyExtensionInputMap, +>(options: { + namespace?: string; + name?: string; + attachTo?: { + id: string; + input: string; + }; + configSchema?: PortableSchema; + disabled?: boolean; + inputs?: TInputs; + Component: ComponentType< + PropsWithChildren<{ + inputs: Expand>; + config: TConfig; + }> + >; +}): ExtensionDefinition; + +// @public (undocumented) +export namespace createRouterExtension { + const // (undocumented) + componentDataRef: ConfigurableExtensionDataRef< + React_2.ComponentType<{ + children?: React_2.ReactNode; + }>, + {} + >; +} + // @public (undocumented) export function createSchemaFromZod( schemaCreator: (zImpl: typeof z) => ZodSchema, ): PortableSchema; +// @public (undocumented) +export function createSignInPageExtension< + TConfig extends {}, + TInputs extends AnyExtensionInputMap, +>(options: { + namespace?: string; + name?: string; + attachTo?: { + id: string; + input: string; + }; + configSchema?: PortableSchema; + disabled?: boolean; + inputs?: TInputs; + loader: (options: { + config: TConfig; + inputs: Expand>; + }) => Promise>; +}): ExtensionDefinition; + +// @public (undocumented) +export namespace createSignInPageExtension { + const // (undocumented) + componentDataRef: ConfigurableExtensionDataRef< + React_2.ComponentType, + {} + >; +} + // @public export function createSubRouteRef< Path extends string, @@ -355,36 +764,71 @@ export function createSubRouteRef< }): MakeSubRouteRef, ParentParams>; // @public (undocumented) -export function createThemeExtension(theme: AppTheme): Extension; +export function createThemeExtension( + theme: AppTheme, +): ExtensionDefinition; + +// @public (undocumented) +export namespace createThemeExtension { + const // (undocumented) + themeDataRef: ConfigurableExtensionDataRef; +} + +// @public (undocumented) +export function createTranslationExtension(options: { + name?: string; + resource: TranslationResource | TranslationMessages; +}): ExtensionDefinition; + +// @public (undocumented) +export namespace createTranslationExtension { + const // (undocumented) + translationDataRef: ConfigurableExtensionDataRef< + | TranslationResource + | TranslationMessages< + string, + { + [x: string]: string; + }, + boolean + >, + {} + >; +} + +export { createTranslationMessages }; + +export { createTranslationRef }; + +export { createTranslationResource }; + +export { DiscoveryApi }; + +export { discoveryApiRef }; + +export { ErrorApi }; + +export { ErrorApiError }; + +export { ErrorApiErrorContext }; + +export { errorApiRef }; // @public (undocumented) export interface Extension { // (undocumented) $$type: '@backstage/Extension'; // (undocumented) - attachTo: { + readonly attachTo: { id: string; input: string; }; // (undocumented) - configSchema?: PortableSchema; + readonly configSchema?: PortableSchema; // (undocumented) - disabled: boolean; + readonly disabled: boolean; // (undocumented) - factory(options: { - source?: BackstagePlugin; - config: TConfig; - inputs: Record< - string, - undefined | Record | Array> - >; - }): ExtensionDataValues; - // (undocumented) - id: string; - // (undocumented) - inputs: AnyExtensionInputMap; - // (undocumented) - output: AnyExtensionDataMap; + readonly id: string; } // @public (undocumented) @@ -397,11 +841,9 @@ export interface ExtensionBoundaryProps { // (undocumented) children: ReactNode; // (undocumented) - id: string; + node: AppNode; // (undocumented) routable?: boolean; - // (undocumented) - source?: BackstagePlugin; } // @public (undocumented) @@ -432,6 +874,27 @@ export type ExtensionDataValues = { : never]?: TExtensionData[DataName]['T']; }; +// @public (undocumented) +export interface ExtensionDefinition { + // (undocumented) + $$type: '@backstage/ExtensionDefinition'; + // (undocumented) + readonly attachTo: { + id: string; + input: string; + }; + // (undocumented) + readonly configSchema?: PortableSchema; + // (undocumented) + readonly disabled: boolean; + // (undocumented) + readonly kind?: string; + // (undocumented) + readonly name?: string; + // (undocumented) + readonly namespace?: string; +} + // @public (undocumented) export interface ExtensionInput< TExtensionData extends AnyExtensionDataMap, @@ -448,31 +911,18 @@ export interface ExtensionInput< extensionData: TExtensionData; } -// @public -export type ExtensionInputValues< - TInputs extends { - [name in string]: ExtensionInput; - }, -> = { - [InputName in keyof TInputs]: false extends TInputs[InputName]['config']['singleton'] - ? Array>> - : false extends TInputs[InputName]['config']['optional'] - ? Expand> - : Expand< - ExtensionDataValues | undefined - >; -}; - // @public (undocumented) export interface ExtensionOverrides { // (undocumented) - $$type: '@backstage/ExtensionOverrides'; + readonly $$type: '@backstage/ExtensionOverrides'; } // @public (undocumented) export interface ExtensionOverridesOptions { // (undocumented) - extensions: Extension[]; + extensions: ExtensionDefinition[]; + // (undocumented) + featureFlags?: FeatureFlagConfig[]; } // @public @@ -488,23 +938,82 @@ export interface ExternalRouteRef< readonly T: TParams; } -// @public (undocumented) -export type NavTarget = { - title: string; - icon: IconComponent; - routeRef: RouteRef; +export { FeatureFlag }; + +// @public +export type FeatureFlagConfig = { + name: string; }; +export { FeatureFlagsApi }; + +export { featureFlagsApiRef }; + +export { FeatureFlagsSaveOptions }; + +export { FeatureFlagState }; + +export { FetchApi }; + +export { fetchApiRef }; + +// @public (undocumented) +export type FrontendFeature = BackstagePlugin | ExtensionOverrides; + +export { githubAuthApiRef }; + +export { gitlabAuthApiRef }; + +export { googleAuthApiRef }; + +// @public +export type IconComponent = ComponentType< + | { + fontSize?: 'large' | 'small' | 'default' | 'inherit'; + } + | { + fontSize?: 'medium' | 'large' | 'small' | 'inherit'; + } +>; + +export { IdentityApi }; + +export { identityApiRef }; + +export { microsoftAuthApiRef }; + +export { OAuthApi }; + +export { OAuthRequestApi }; + +export { oauthRequestApiRef }; + +export { OAuthRequester }; + +export { OAuthRequesterOptions }; + +export { OAuthScope }; + +export { oktaAuthApiRef }; + +export { oneloginAuthApiRef }; + +export { OpenIdConnectApi }; + +export { PendingOAuthRequest }; + // @public (undocumented) export interface PluginOptions< Routes extends AnyRoutes, ExternalRoutes extends AnyExternalRoutes, > { // (undocumented) - extensions?: Extension[]; + extensions?: ExtensionDefinition[]; // (undocumented) externalRoutes?: ExternalRoutes; // (undocumented) + featureFlags?: FeatureFlagConfig[]; + // (undocumented) id: string; // (undocumented) routes?: Routes; @@ -516,6 +1025,32 @@ export type PortableSchema = { schema: JsonObject; }; +export { ProfileInfo }; + +export { ProfileInfoApi }; + +// @public +export type ResolvedExtensionInput = + { + node: AppNode; + output: ExtensionDataValues; + }; + +// @public +export type ResolvedExtensionInputs< + TInputs extends { + [name in string]: ExtensionInput; + }, +> = { + [InputName in keyof TInputs]: false extends TInputs[InputName]['config']['singleton'] + ? Array>> + : false extends TInputs[InputName]['config']['optional'] + ? Expand> + : Expand< + ResolvedExtensionInput | undefined + >; +}; + // @public export type RouteFunc = ( ...[params]: TParams extends undefined @@ -533,6 +1068,16 @@ export interface RouteRef< readonly T: TParams; } +export { SessionApi }; + +export { SessionState }; + +export { StorageApi }; + +export { storageApiRef }; + +export { StorageValueSnapshot }; + // @public export interface SubRouteRef< TParams extends AnyRouteRefParams = AnyRouteRefParams, @@ -545,6 +1090,32 @@ export interface SubRouteRef< readonly T: TParams; } +export { TranslationMessages }; + +export { TranslationMessagesOptions }; + +export { TranslationRef }; + +export { TranslationRefOptions }; + +export { TranslationResource }; + +export { TranslationResourceOptions }; + +export { TypesToApiRefs }; + +// @public +export function useAnalytics(): AnalyticsTracker; + +export { useApi }; + +export { useApiHolder }; + +// @public +export function useComponentRef( + ref: ComponentRef, +): ComponentType; + // @public export function useRouteRef< TOptional extends boolean, @@ -562,4 +1133,8 @@ export function useRouteRef( export function useRouteRefParams( _routeRef: RouteRef | SubRouteRef, ): Params; + +export { useTranslationRef }; + +export { withApis }; ``` diff --git a/packages/frontend-plugin-api/package.json b/packages/frontend-plugin-api/package.json index 86714f2713..bc92f6f632 100644 --- a/packages/frontend-plugin-api/package.json +++ b/packages/frontend-plugin-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/frontend-plugin-api", - "version": "0.3.0-next.2", + "version": "0.5.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,21 +22,6 @@ "prepack": "backstage-cli package prepack", "postpack": "backstage-cli package postpack" }, - "devDependencies": { - "@backstage/cli": "workspace:^", - "@backstage/frontend-app-api": "workspace:^", - "@backstage/test-utils": "workspace:^", - "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^14.0.0", - "history": "^5.3.0" - }, - "files": [ - "dist" - ], - "peerDependencies": { - "react": "^16.13.1 || ^17.0.0 || ^18.0.0", - "react-router-dom": "6.0.0-beta.0 || ^6.3.0" - }, "dependencies": { "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", @@ -45,7 +30,23 @@ "@material-ui/core": "^4.12.4", "@types/react": "^16.13.1 || ^17.0.0", "lodash": "^4.17.21", - "zod": "^3.21.4", + "zod": "^3.22.4", "zod-to-json-schema": "^3.21.4" - } + }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-router-dom": "6.0.0-beta.0 || ^6.3.0" + }, + "devDependencies": { + "@backstage/cli": "workspace:^", + "@backstage/frontend-app-api": "workspace:^", + "@backstage/frontend-test-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", + "@testing-library/jest-dom": "^6.0.0", + "@testing-library/react": "^14.0.0", + "history": "^5.3.0" + }, + "files": [ + "dist" + ] } diff --git a/packages/frontend-plugin-api/src/analytics/AnalyticsContext.test.tsx b/packages/frontend-plugin-api/src/analytics/AnalyticsContext.test.tsx new file mode 100644 index 0000000000..8e78bdc8c4 --- /dev/null +++ b/packages/frontend-plugin-api/src/analytics/AnalyticsContext.test.tsx @@ -0,0 +1,82 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { render } from '@testing-library/react'; +import { renderHook } from '@testing-library/react'; +import { AnalyticsContext, useAnalyticsContext } from './AnalyticsContext'; + +const AnalyticsSpy = () => { + const context = useAnalyticsContext(); + return ( + <> +
{context.pluginId}
+
{context.extensionId}
+
{context.custom}
+ + ); +}; + +describe('AnalyticsContext', () => { + describe('useAnalyticsContext', () => { + it('returns default values', () => { + const { result } = renderHook(() => useAnalyticsContext()); + expect(result.current).toEqual({ + extensionId: 'App', + pluginId: 'root', + }); + }); + }); + + describe('AnalyticsContext', () => { + it('uses default analytics context', () => { + const result = render( + + + , + ); + + expect(result.getByTestId('extension-id')).toHaveTextContent('App'); + expect(result.getByTestId('plugin-id')).toHaveTextContent('root'); + }); + + it('uses provided analytics context', () => { + const result = render( + + + , + ); + + expect(result.getByTestId('extension-id')).toHaveTextContent('App'); + expect(result.getByTestId('plugin-id')).toHaveTextContent('custom'); + }); + + it('uses nested analytics context', () => { + const result = render( + + + + + , + ); + + expect(result.getByTestId('extension-id')).toHaveTextContent( + 'AnalyticsSpy', + ); + expect(result.getByTestId('plugin-id')).toHaveTextContent('custom'); + }); + }); +}); diff --git a/packages/frontend-plugin-api/src/analytics/AnalyticsContext.tsx b/packages/frontend-plugin-api/src/analytics/AnalyticsContext.tsx new file mode 100644 index 0000000000..10ef475803 --- /dev/null +++ b/packages/frontend-plugin-api/src/analytics/AnalyticsContext.tsx @@ -0,0 +1,108 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + createVersionedContext, + createVersionedValueMap, +} from '@backstage/version-bridge'; +import React, { ReactNode, useContext } from 'react'; +import { AnalyticsContextValue } from './types'; + +const AnalyticsReactContext = createVersionedContext<{ + 1: AnalyticsContextValue; +}>('analytics-context'); + +/** + * A "private" (to this package) hook that enables context inheritance and a + * way to read Analytics Context values at event capture-time. + * + * @internal + */ +export const useAnalyticsContext = (): AnalyticsContextValue => { + const theContext = useContext(AnalyticsReactContext); + + // Provide a default value if no value exists. + if (theContext === undefined) { + return { + pluginId: 'root', + extensionId: 'App', + }; + } + + // This should probably never happen, but check for it. + const theValue = theContext.atVersion(1); + if (theValue === undefined) { + throw new Error('No context found for version 1.'); + } + + return theValue; +}; + +/** + * Provides components in the child react tree an Analytics Context, ensuring + * all analytics events captured within the context have relevant attributes. + * + * @remarks + * + * Analytics contexts are additive, meaning the context ultimately emitted with + * an event is the combination of all contexts in the parent tree. + * + * @public + */ +export const AnalyticsContext = (options: { + attributes: Partial; + children: ReactNode; +}) => { + const { attributes, children } = options; + + const parentValues = useAnalyticsContext(); + const combinedValue = { + ...parentValues, + ...attributes, + }; + + const versionedCombinedValue = createVersionedValueMap({ 1: combinedValue }); + return ( + + {children} + + ); +}; + +/** + * Returns an HOC wrapping the provided component in an Analytics context with + * the given values. + * + * @param Component - Component to be wrapped with analytics context attributes + * @param values - Analytics context key/value pairs. + * @internal + */ +export function withAnalyticsContext( + Component: React.ComponentType, + values: AnalyticsContextValue, +) { + const ComponentWithAnalyticsContext = (props: TProps) => { + return ( + + + + ); + }; + ComponentWithAnalyticsContext.displayName = `WithAnalyticsContext(${ + Component.displayName || Component.name || 'Component' + })`; + return ComponentWithAnalyticsContext; +} diff --git a/packages/frontend-plugin-api/src/analytics/Tracker.test.ts b/packages/frontend-plugin-api/src/analytics/Tracker.test.ts new file mode 100644 index 0000000000..f1670cf9c4 --- /dev/null +++ b/packages/frontend-plugin-api/src/analytics/Tracker.test.ts @@ -0,0 +1,285 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { getOrCreateGlobalSingleton } from '@backstage/version-bridge'; +import { Tracker, routableExtensionRenderedEvent } from './Tracker'; + +describe('Tracker', () => { + const defaultContext = { + pluginId: 'root', + extensionId: 'App', + }; + const globalEvents = getOrCreateGlobalSingleton( + 'core-plugin-api:analytics-tracker-events', + () => ({}), + ); + const analyticsApiSpy = { + captureEvent: jest.fn(), + }; + let trackerUnderTest: Tracker; + + beforeEach(() => { + // Reset mocks and global state + jest.resetAllMocks(); + globalEvents.mostRecentGatheredNavigation = undefined; + globalEvents.mostRecentRoutableExtensionRender = undefined; + + // Set up a new tracker to test. + trackerUnderTest = new Tracker(analyticsApiSpy); + }); + + it('captures simple event with default context', () => { + trackerUnderTest.captureEvent('click', 'test 1'); + + expect(analyticsApiSpy.captureEvent).toHaveBeenCalledWith( + expect.objectContaining({ + action: 'click', + subject: 'test 1', + context: defaultContext, + }), + ); + }); + + it('captures simple event with set context', () => { + trackerUnderTest.setContext({ + pluginId: 'catalog', + extensionId: 'App', + }); + trackerUnderTest.captureEvent('click', 'test 2', { + value: 2, + attributes: { to: '/page-2' }, + }); + + expect(analyticsApiSpy.captureEvent).toHaveBeenCalledWith( + expect.objectContaining({ + action: 'click', + subject: 'test 2', + value: 2, + attributes: { to: '/page-2' }, + context: { + pluginId: 'catalog', + extensionId: 'App', + }, + }), + ); + }); + + describe('accurate navigate events', () => { + it('never captures _routeNodeType context key on navigate event', () => { + trackerUnderTest.setContext({ + pluginId: 'catalog', + extensionId: 'App', + }); + trackerUnderTest.captureEvent('navigate', '/page-3'); + + const receivedContext = + analyticsApiSpy.captureEvent.mock.calls[0][0].context; + expect(receivedContext.pluginId).toBe('catalog'); + expect(receivedContext._routeNodeType).toBe(undefined); + }); + + it('never immediately captures navigate event with _routeNodeType "gathered"', () => { + trackerUnderTest.setContext({ + ...defaultContext, + }); + trackerUnderTest.captureEvent('navigate', '/page-4'); + + expect(analyticsApiSpy.captureEvent).not.toHaveBeenCalled(); + }); + + it('never captures "routable-extension-rendered" events', () => { + trackerUnderTest.captureEvent(routableExtensionRenderedEvent, ''); + + expect(analyticsApiSpy.captureEvent).not.toHaveBeenCalled(); + }); + + it('captures deferred navigate event with expected context', () => { + // User navigates to a gathered mountpoint with multiple plugins + trackerUnderTest.setContext({ + ...defaultContext, + }); + trackerUnderTest.captureEvent('navigate', '/page-5'); + + // A routable extension is rendered with specific plugin context + trackerUnderTest.setContext({ + pluginId: 'some-plugin', + extensionId: 'App', + }); + trackerUnderTest.captureEvent(routableExtensionRenderedEvent, ''); + + // A non-navigate event + trackerUnderTest.captureEvent('click', 'test 5'); + + expect(analyticsApiSpy.captureEvent).toHaveBeenCalledTimes(2); + expect(analyticsApiSpy.captureEvent).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + action: 'navigate', + subject: '/page-5', + context: { + pluginId: 'some-plugin', + extensionId: 'App', + }, + }), + ); + expect(analyticsApiSpy.captureEvent).toHaveBeenNthCalledWith( + 2, + expect.objectContaining({ + action: 'click', + subject: 'test 5', + context: { + pluginId: 'some-plugin', + extensionId: 'App', + }, + }), + ); + }); + + it('captures deferred navigate event with expected context when second event is also deferrable', () => { + // User navigates to a gathered mountpoint with multiple plugins + trackerUnderTest.setContext({ + ...defaultContext, + }); + trackerUnderTest.captureEvent('navigate', '/page-6'); + + // A routable extension is rendered with specific plugin context + trackerUnderTest.setContext({ + pluginId: 'another-plugin', + extensionId: 'App', + }); + trackerUnderTest.captureEvent(routableExtensionRenderedEvent, ''); + + // User navigates to another gathered mountpoint with multiple plugins + trackerUnderTest.setContext({ + ...defaultContext, + }); + trackerUnderTest.captureEvent('navigate', '/page-6-2'); + + expect(analyticsApiSpy.captureEvent).toHaveBeenCalledTimes(1); + expect(analyticsApiSpy.captureEvent).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + action: 'navigate', + subject: '/page-6', + context: { + pluginId: 'another-plugin', + extensionId: 'App', + }, + }), + ); + }); + + it('captures deferred navigate event with default context when no extension is rendered in between', () => { + // User navigates to a gathered mountpoint with multiple plugins + trackerUnderTest.setContext({ + ...defaultContext, + }); + trackerUnderTest.captureEvent('navigate', '/page-7'); + + // A non-navigate event with no routable extension render in between + trackerUnderTest.captureEvent('click', 'test 7'); + + expect(analyticsApiSpy.captureEvent).toHaveBeenCalledTimes(2); + expect(analyticsApiSpy.captureEvent).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + action: 'navigate', + subject: '/page-7', + context: defaultContext, + }), + ); + expect(analyticsApiSpy.captureEvent).toHaveBeenNthCalledWith( + 2, + expect.objectContaining({ + action: 'click', + subject: 'test 7', + context: defaultContext, + }), + ); + }); + + it('captures deferred navigate event with expected context across separate trackers', () => { + // User navigates to a gathered mountpoint with multiple plugins + trackerUnderTest.setContext({ + ...defaultContext, + }); + trackerUnderTest.captureEvent('navigate', '/page-8'); + + // A routable extension is rendered with specific plugin context and + // captured via a separate tracker instance. + const anotherTracker = new Tracker(analyticsApiSpy, { + pluginId: 'the-plugin', + extensionId: 'App', + }); + anotherTracker.captureEvent(routableExtensionRenderedEvent, ''); + + // A non-navigate event is captured + const aThirdTracker = new Tracker(analyticsApiSpy); + aThirdTracker.captureEvent('click', 'test 8'); + + expect(analyticsApiSpy.captureEvent).toHaveBeenCalledTimes(2); + expect(analyticsApiSpy.captureEvent).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + action: 'navigate', + subject: '/page-8', + context: { + pluginId: 'the-plugin', + extensionId: 'App', + }, + }), + ); + expect(analyticsApiSpy.captureEvent).toHaveBeenNthCalledWith( + 2, + expect.objectContaining({ + action: 'click', + subject: 'test 8', + }), + ); + }); + + it('replaces extension context with "App" when capturing deferred events', () => { + // User navigates to a gathered mountpoint with multiple plugins + trackerUnderTest.setContext({ + ...defaultContext, + }); + trackerUnderTest.captureEvent('navigate', '/page-9'); + + // A routable extension is rendered with specific plugin context + trackerUnderTest.setContext({ + pluginId: 'very-plugin', + extensionId: 'ShouldBeReplaced', + }); + trackerUnderTest.captureEvent(routableExtensionRenderedEvent, ''); + + // A non-navigate event + trackerUnderTest.captureEvent('click', 'test 9'); + + // Extension context should have been replaced with just "App" + expect(analyticsApiSpy.captureEvent).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + action: 'navigate', + subject: '/page-9', + context: { + pluginId: 'very-plugin', + extensionId: 'App', + }, + }), + ); + }); + }); +}); diff --git a/packages/frontend-plugin-api/src/analytics/Tracker.ts b/packages/frontend-plugin-api/src/analytics/Tracker.ts new file mode 100644 index 0000000000..dd0d770354 --- /dev/null +++ b/packages/frontend-plugin-api/src/analytics/Tracker.ts @@ -0,0 +1,175 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { getOrCreateGlobalSingleton } from '@backstage/version-bridge'; +import { + AnalyticsApi, + AnalyticsEventAttributes, + AnalyticsTracker, +} from '../apis'; +import { AnalyticsContextValue } from './'; + +type TempGlobalEvents = { + /** + * Stores the most recent "gathered" mountpoint navigation. + */ + mostRecentGatheredNavigation?: { + action: string; + subject: string; + value?: number; + attributes?: AnalyticsEventAttributes; + context: AnalyticsContextValue; + }; + /** + * Stores the most recent routable extension render. + */ + mostRecentRoutableExtensionRender?: { + context: AnalyticsContextValue; + }; + /** + * Tracks whether or not a beforeunload event listener has already been + * registered. + */ + beforeUnloadRegistered: boolean; +}; + +/** + * Temporary global store for select event data. Used to make `navigate` events + * more accurate when gathered mountpoints are used. + */ +const globalEvents = getOrCreateGlobalSingleton( + 'core-plugin-api:analytics-tracker-events', + () => ({ + mostRecentGatheredNavigation: undefined, + mostRecentRoutableExtensionRender: undefined, + beforeUnloadRegistered: false, + }), +); + +/** + * Internal-only event representing when a routable extension is rendered. + */ +export const routableExtensionRenderedEvent = '_ROUTABLE-EXTENSION-RENDERED'; + +export class Tracker implements AnalyticsTracker { + constructor( + private readonly analyticsApi: AnalyticsApi, + private context: AnalyticsContextValue = { + pluginId: 'root', + extensionId: 'App', + }, + ) { + // Only register a single beforeunload event across all trackers. + if (!globalEvents.beforeUnloadRegistered) { + // Before the page unloads, attempt to capture any deferred navigation + // events that haven't yet been captured. + addEventListener( + 'beforeunload', + () => { + if (globalEvents.mostRecentGatheredNavigation) { + this.analyticsApi.captureEvent({ + ...globalEvents.mostRecentGatheredNavigation, + ...globalEvents.mostRecentRoutableExtensionRender, + }); + globalEvents.mostRecentGatheredNavigation = undefined; + globalEvents.mostRecentRoutableExtensionRender = undefined; + } + }, + { once: true, passive: true }, + ); + + // Prevent duplicate handlers from being registered. + globalEvents.beforeUnloadRegistered = true; + } + } + + setContext(context: AnalyticsContextValue) { + this.context = context; + } + + captureEvent( + action: string, + subject: string, + { + value, + attributes, + }: { value?: number; attributes?: AnalyticsEventAttributes } = {}, + ) { + // Never pass internal "_routeNodeType" context value. + const context = this.context; + + // Never fire the special "_routable-extension-rendered" internal event. + if (action === routableExtensionRenderedEvent) { + // But keep track of it if we're delaying a `navigate` event for a + // a gathered route node type. + if (globalEvents.mostRecentGatheredNavigation) { + globalEvents.mostRecentRoutableExtensionRender = { + context: { + ...context, + extensionId: 'App', + }, + }; + } + return; + } + + // If we are about to fire a real event, and we have an un-fired gathered + // mountpoint navigation on the global store, we need to fire the navigate + // event first, so this real event happens accurately after the navigation. + if (globalEvents.mostRecentGatheredNavigation) { + try { + this.analyticsApi.captureEvent({ + ...globalEvents.mostRecentGatheredNavigation, + ...globalEvents.mostRecentRoutableExtensionRender, + }); + } catch (e) { + // eslint-disable-next-line no-console + console.warn('Error during analytics event capture. %o', e); + } + + // Clear the global stores. + globalEvents.mostRecentGatheredNavigation = undefined; + globalEvents.mostRecentRoutableExtensionRender = undefined; + } + + // Never directly fire a navigation event on a gathered route with default + // contextual details. + if (action === 'navigate' && context.pluginId === 'root') { + // Instead, set it on the global store. + globalEvents.mostRecentGatheredNavigation = { + action, + subject, + value, + attributes, + context, + }; + return; + } + + try { + this.analyticsApi.captureEvent({ + action, + subject, + value, + attributes, + context, + }); + } catch (e) { + // eslint-disable-next-line no-console + console.warn('Error during analytics event capture. %o', e); + } + } +} diff --git a/packages/frontend-plugin-api/src/analytics/index.ts b/packages/frontend-plugin-api/src/analytics/index.ts new file mode 100644 index 0000000000..651e8e105e --- /dev/null +++ b/packages/frontend-plugin-api/src/analytics/index.ts @@ -0,0 +1,19 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { AnalyticsContext } from './AnalyticsContext'; +export type { AnalyticsContextValue, CommonAnalyticsContext } from './types'; +export { useAnalytics } from './useAnalytics'; diff --git a/packages/frontend-plugin-api/src/analytics/types.ts b/packages/frontend-plugin-api/src/analytics/types.ts new file mode 100644 index 0000000000..21347e2fc7 --- /dev/null +++ b/packages/frontend-plugin-api/src/analytics/types.ts @@ -0,0 +1,44 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Common analytics context attributes. + * + * @public + */ +export type CommonAnalyticsContext = { + /** + * The nearest known parent plugin where the event was captured. + */ + pluginId: string; + + /** + * The nearest known parent extension where the event was captured. + */ + /** + * The nearest known parent extension where the event was captured. + */ + extensionId: string; +}; + +/** + * Analytics context envelope. + * + * @public + */ +export type AnalyticsContextValue = CommonAnalyticsContext & { + [param in string]: string | boolean | number | undefined; +}; diff --git a/packages/frontend-plugin-api/src/analytics/useAnalytics.test.tsx b/packages/frontend-plugin-api/src/analytics/useAnalytics.test.tsx new file mode 100644 index 0000000000..beb16b1fbb --- /dev/null +++ b/packages/frontend-plugin-api/src/analytics/useAnalytics.test.tsx @@ -0,0 +1,61 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { renderHook } from '@testing-library/react'; +import { useAnalytics } from './useAnalytics'; +import { analyticsApiRef } from '@backstage/core-plugin-api'; +import { TestApiProvider } from '@backstage/test-utils'; +import React from 'react'; + +describe('useAnalytics', () => { + it('returns tracker with no implementation defined', () => { + // useApi throws an error because the Analytics API is not implemented + // But the result should still have a captureEvent method. + const { result } = renderHook(() => useAnalytics(), {}); + expect(result.current.captureEvent).toBeDefined(); + }); + + it('returns tracker from defined analytics api', () => { + const captureEvent = jest.fn(); + + // Calling the captureEvent method of the underlying implementation should + // pass along the given event as well as the default context. + const { result } = renderHook(() => useAnalytics(), { + wrapper: ({ children }) => ( + // Simulate useApi returning a valid tracker. + + {children} + + ), + }); + result.current.captureEvent('an action', 'a subject', { + value: 42, + attributes: { some: 'value' }, + }); + expect(captureEvent).toHaveBeenCalledWith({ + action: 'an action', + subject: 'a subject', + value: 42, + attributes: { + some: 'value', + }, + context: { + extensionId: 'App', + pluginId: 'root', + }, + }); + }); +}); diff --git a/packages/frontend-plugin-api/src/analytics/useAnalytics.tsx b/packages/frontend-plugin-api/src/analytics/useAnalytics.tsx new file mode 100644 index 0000000000..f3b5998de4 --- /dev/null +++ b/packages/frontend-plugin-api/src/analytics/useAnalytics.tsx @@ -0,0 +1,57 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { useApi } from '@backstage/core-plugin-api'; +import { useAnalyticsContext } from './AnalyticsContext'; +import { analyticsApiRef, AnalyticsTracker, AnalyticsApi } from '../apis'; +import { useRef } from 'react'; +import { Tracker } from './Tracker'; + +function useAnalyticsApi(): AnalyticsApi { + try { + return useApi(analyticsApiRef); + } catch { + return { captureEvent: () => {} }; + } +} + +/** + * Gets a pre-configured analytics tracker. + * + * @public + */ +export function useAnalytics(): AnalyticsTracker { + const trackerRef = useRef(null); + const context = useAnalyticsContext(); + // Our goal is to make this API truly optional for any/all consuming code + // (including tests). This hook runs last to ensure hook order is, as much as + // possible, maintained. + const analyticsApi = useAnalyticsApi(); + + function getTracker(): Tracker { + if (trackerRef.current === null) { + trackerRef.current = new Tracker(analyticsApi); + } + return trackerRef.current; + } + + const tracker = getTracker(); + // this is not ideal, but it allows to memoize the tracker + // without explicitly set the context as dependency. + tracker.setContext(context); + + return tracker; +} diff --git a/packages/frontend-plugin-api/src/apis/definitions/AlertApi.ts b/packages/frontend-plugin-api/src/apis/definitions/AlertApi.ts new file mode 100644 index 0000000000..649a930b50 --- /dev/null +++ b/packages/frontend-plugin-api/src/apis/definitions/AlertApi.ts @@ -0,0 +1,21 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { + type AlertApi, + type AlertMessage, + alertApiRef, +} from '@backstage/core-plugin-api'; diff --git a/packages/frontend-plugin-api/src/apis/definitions/AnalyticsApi.ts b/packages/frontend-plugin-api/src/apis/definitions/AnalyticsApi.ts new file mode 100644 index 0000000000..15b09482b7 --- /dev/null +++ b/packages/frontend-plugin-api/src/apis/definitions/AnalyticsApi.ts @@ -0,0 +1,131 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ApiRef, createApiRef } from '@backstage/core-plugin-api'; +import { AnalyticsContextValue } from '../../analytics/types'; + +/** + * Represents an event worth tracking in an analytics system that could inform + * how users of a Backstage instance are using its features. + * + * @public + */ +export type AnalyticsEvent = { + /** + * A string that identifies the event being tracked by the type of action the + * event represents. Be careful not to encode extra metadata in this string + * that should instead be placed in the Analytics Context or attributes. + * Examples include: + * + * - view + * - click + * - filter + * - search + * - hover + * - scroll + */ + action: string; + + /** + * A string that uniquely identifies the object that the action is being + * taken on. Examples include: + * + * - The path of the page viewed + * - The url of the link clicked + * - The value that was filtered by + * - The text that was searched for + */ + subject: string; + + /** + * An optional numeric value relevant to the event that could be aggregated + * by analytics tools. Examples include: + * + * - The index or position of the clicked element in an ordered list + * - The percentage of an element that has been scrolled through + * - The amount of time that has elapsed since a fixed point + * - A satisfaction score on a fixed scale + */ + value?: number; + + /** + * Optional, additional attributes (representing dimensions or metrics) + * specific to the event that could be forwarded on to analytics systems. + */ + attributes?: AnalyticsEventAttributes; + + /** + * Contextual metadata relating to where the event was captured and by whom. + * This could include information about the route, plugin, or extension in + * which an event was captured. + */ + context: AnalyticsContextValue; +}; + +/** + * A structure allowing other arbitrary metadata to be provided by analytics + * event emitters. + * + * @public + */ +export type AnalyticsEventAttributes = { + [attribute in string]: string | boolean | number; +}; + +/** + * Represents a tracker with methods that can be called to track events in a + * configured analytics service. + * + * @public + */ +export type AnalyticsTracker = { + captureEvent: ( + action: string, + subject: string, + options?: { + value?: number; + attributes?: AnalyticsEventAttributes; + }, + ) => void; +}; + +/** + * The Analytics API is used to track user behavior in a Backstage instance. + * + * @remarks + * + * To instrument your App or Plugin, retrieve an analytics tracker using the + * useAnalytics() hook. This will return a pre-configured AnalyticsTracker + * with relevant methods for instrumentation. + * + * @public + */ +export type AnalyticsApi = { + /** + * Primary event handler responsible for compiling and forwarding events to + * an analytics system. + */ + captureEvent(event: AnalyticsEvent): void; +}; + +/** + * The API reference of {@link AnalyticsApi}. + * + * @public + */ +export const analyticsApiRef: ApiRef = createApiRef({ + id: 'core.analytics', +}); diff --git a/packages/frontend-plugin-api/src/apis/definitions/AppLanguageApi.ts b/packages/frontend-plugin-api/src/apis/definitions/AppLanguageApi.ts new file mode 100644 index 0000000000..37ffcfa820 --- /dev/null +++ b/packages/frontend-plugin-api/src/apis/definitions/AppLanguageApi.ts @@ -0,0 +1,20 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { + type AppLanguageApi, + appLanguageApiRef, +} from '@backstage/core-plugin-api/alpha'; diff --git a/packages/frontend-plugin-api/src/apis/definitions/AppThemeApi.ts b/packages/frontend-plugin-api/src/apis/definitions/AppThemeApi.ts new file mode 100644 index 0000000000..ce62cd72c3 --- /dev/null +++ b/packages/frontend-plugin-api/src/apis/definitions/AppThemeApi.ts @@ -0,0 +1,21 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { + type AppTheme, + type AppThemeApi, + appThemeApiRef, +} from '@backstage/core-plugin-api'; diff --git a/packages/frontend-plugin-api/src/apis/definitions/ComponentsApi.ts b/packages/frontend-plugin-api/src/apis/definitions/ComponentsApi.ts new file mode 100644 index 0000000000..c5e9d2c44f --- /dev/null +++ b/packages/frontend-plugin-api/src/apis/definitions/ComponentsApi.ts @@ -0,0 +1,49 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ComponentType } from 'react'; +import { createApiRef, useApi } from '@backstage/core-plugin-api'; +import { ComponentRef } from '../../components'; + +/** + * API for looking up components based on component refs. + * + * @public + */ +export interface ComponentsApi { + // TODO: Should component refs also provide the default implementation so that we're guaranteed to get a component? + getComponent(ref: ComponentRef): ComponentType; +} + +/** + * The `ApiRef` of {@link ComponentsApi}. + * + * @public + */ +export const componentsApiRef = createApiRef({ + id: 'core.components', +}); + +/** + * @public + * Returns the component associated with the given ref. + */ +export function useComponentRef( + ref: ComponentRef, +): ComponentType { + const componentsApi = useApi(componentsApiRef); + return componentsApi.getComponent(ref); +} diff --git a/plugins/catalog-backend/src/catalog/index.ts b/packages/frontend-plugin-api/src/apis/definitions/ConfigApi.ts similarity index 88% rename from plugins/catalog-backend/src/catalog/index.ts rename to packages/frontend-plugin-api/src/apis/definitions/ConfigApi.ts index ba34673bba..968a2843ba 100644 --- a/plugins/catalog-backend/src/catalog/index.ts +++ b/packages/frontend-plugin-api/src/apis/definitions/ConfigApi.ts @@ -14,4 +14,4 @@ * limitations under the License. */ -export type { EntitiesSearchFilter, EntityFilter } from './types'; +export { type ConfigApi, configApiRef } from '@backstage/core-plugin-api'; diff --git a/packages/frontend-plugin-api/src/apis/definitions/DiscoveryApi.ts b/packages/frontend-plugin-api/src/apis/definitions/DiscoveryApi.ts new file mode 100644 index 0000000000..98b3f0bbf0 --- /dev/null +++ b/packages/frontend-plugin-api/src/apis/definitions/DiscoveryApi.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { type DiscoveryApi, discoveryApiRef } from '@backstage/core-plugin-api'; diff --git a/plugins/graphql-backend/src/index.ts b/packages/frontend-plugin-api/src/apis/definitions/ErrorApi.ts similarity index 82% rename from plugins/graphql-backend/src/index.ts rename to packages/frontend-plugin-api/src/apis/definitions/ErrorApi.ts index a9f7f92ad9..57782a05dc 100644 --- a/plugins/graphql-backend/src/index.ts +++ b/packages/frontend-plugin-api/src/apis/definitions/ErrorApi.ts @@ -14,10 +14,9 @@ * limitations under the License. */ -/** - * An experimental Backstage backend plugin for GraphQL - * - * @packageDocumentation - */ - -export * from './service/router'; +export { + type ErrorApiError, + type ErrorApiErrorContext, + type ErrorApi, + errorApiRef, +} from '@backstage/core-plugin-api'; diff --git a/plugins/kubernetes-react/src/utils/clusterLinks/index.ts b/packages/frontend-plugin-api/src/apis/definitions/FeatureFlagsApi.ts similarity index 79% rename from plugins/kubernetes-react/src/utils/clusterLinks/index.ts rename to packages/frontend-plugin-api/src/apis/definitions/FeatureFlagsApi.ts index 90a30e8277..820efc0a25 100644 --- a/plugins/kubernetes-react/src/utils/clusterLinks/index.ts +++ b/packages/frontend-plugin-api/src/apis/definitions/FeatureFlagsApi.ts @@ -15,7 +15,9 @@ */ export { - formatClusterLink, - type FormatClusterLinkOptions, -} from './formatClusterLink'; -export { clusterLinksFormatters } from './formatters'; + type FeatureFlag, + type FeatureFlagState, + type FeatureFlagsSaveOptions, + type FeatureFlagsApi, + featureFlagsApiRef, +} from '@backstage/core-plugin-api'; diff --git a/packages/frontend-plugin-api/src/apis/definitions/FetchApi.ts b/packages/frontend-plugin-api/src/apis/definitions/FetchApi.ts new file mode 100644 index 0000000000..bcc9bc6a91 --- /dev/null +++ b/packages/frontend-plugin-api/src/apis/definitions/FetchApi.ts @@ -0,0 +1,17 @@ +/* + * 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 { type FetchApi, fetchApiRef } from '@backstage/core-plugin-api'; diff --git a/packages/frontend-plugin-api/src/apis/definitions/IdentityApi.ts b/packages/frontend-plugin-api/src/apis/definitions/IdentityApi.ts new file mode 100644 index 0000000000..03503a8fba --- /dev/null +++ b/packages/frontend-plugin-api/src/apis/definitions/IdentityApi.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { type IdentityApi, identityApiRef } from '@backstage/core-plugin-api'; diff --git a/packages/frontend-plugin-api/src/apis/definitions/OAuthRequestApi.ts b/packages/frontend-plugin-api/src/apis/definitions/OAuthRequestApi.ts new file mode 100644 index 0000000000..ff7a0f2852 --- /dev/null +++ b/packages/frontend-plugin-api/src/apis/definitions/OAuthRequestApi.ts @@ -0,0 +1,23 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { + type OAuthRequesterOptions, + type OAuthRequester, + type PendingOAuthRequest, + type OAuthRequestApi, + oauthRequestApiRef, +} from '@backstage/core-plugin-api'; diff --git a/packages/frontend-plugin-api/src/apis/definitions/StorageApi.ts b/packages/frontend-plugin-api/src/apis/definitions/StorageApi.ts new file mode 100644 index 0000000000..2309d2414c --- /dev/null +++ b/packages/frontend-plugin-api/src/apis/definitions/StorageApi.ts @@ -0,0 +1,21 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { + type StorageValueSnapshot, + type StorageApi, + storageApiRef, +} from '@backstage/core-plugin-api'; diff --git a/packages/frontend-plugin-api/src/apis/definitions/alpha.ts b/packages/frontend-plugin-api/src/apis/definitions/alpha.ts new file mode 100644 index 0000000000..a4ccde1170 --- /dev/null +++ b/packages/frontend-plugin-api/src/apis/definitions/alpha.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 { appLanguageApiRef, type AppLanguageApi } from './AppLanguageApi'; diff --git a/packages/frontend-plugin-api/src/apis/definitions/auth.ts b/packages/frontend-plugin-api/src/apis/definitions/auth.ts new file mode 100644 index 0000000000..d27aebbf47 --- /dev/null +++ b/packages/frontend-plugin-api/src/apis/definitions/auth.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 { + type BackstageIdentityApi, + type BackstageIdentityResponse, + type BackstageUserIdentity, + type AuthProviderInfo, + type AuthRequestOptions, + type OAuthScope, + type OAuthApi, + type OpenIdConnectApi, + type ProfileInfoApi, + type ProfileInfo, + type SessionApi, + SessionState, + atlassianAuthApiRef, + bitbucketAuthApiRef, + bitbucketServerAuthApiRef, + githubAuthApiRef, + gitlabAuthApiRef, + googleAuthApiRef, + oktaAuthApiRef, + microsoftAuthApiRef, + oneloginAuthApiRef, +} from '@backstage/core-plugin-api'; diff --git a/packages/frontend-plugin-api/src/apis/definitions/index.ts b/packages/frontend-plugin-api/src/apis/definitions/index.ts index 8facdca2ca..f2496ee61a 100644 --- a/packages/frontend-plugin-api/src/apis/definitions/index.ts +++ b/packages/frontend-plugin-api/src/apis/definitions/index.ts @@ -23,3 +23,24 @@ export { type AppTree, type AppTreeApi, } from './AppTreeApi'; + +// This folder contains definitions for all core APIs. +// +// Plugins should rely on these APIs for functionality as much as possible. +// +// If you think some API definition is missing, please open an Issue or send a PR! + +export * from './auth'; + +export * from './AlertApi'; +export * from './AppThemeApi'; +export * from './ComponentsApi'; +export * from './ConfigApi'; +export * from './DiscoveryApi'; +export * from './ErrorApi'; +export * from './FeatureFlagsApi'; +export * from './FetchApi'; +export * from './IdentityApi'; +export * from './OAuthRequestApi'; +export * from './StorageApi'; +export * from './AnalyticsApi'; diff --git a/packages/frontend-plugin-api/src/apis/index.ts b/packages/frontend-plugin-api/src/apis/index.ts index 5a012c0553..5def6cb0f9 100644 --- a/packages/frontend-plugin-api/src/apis/index.ts +++ b/packages/frontend-plugin-api/src/apis/index.ts @@ -15,3 +15,4 @@ */ export * from './definitions'; +export * from './system'; diff --git a/packages/frontend-plugin-api/src/apis/system/ApiRef.ts b/packages/frontend-plugin-api/src/apis/system/ApiRef.ts new file mode 100644 index 0000000000..0d1f8312cb --- /dev/null +++ b/packages/frontend-plugin-api/src/apis/system/ApiRef.ts @@ -0,0 +1,21 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { + type ApiRef, + type ApiRefConfig, + createApiRef, +} from '@backstage/core-plugin-api'; diff --git a/packages/frontend-plugin-api/src/apis/system/helpers.ts b/packages/frontend-plugin-api/src/apis/system/helpers.ts new file mode 100644 index 0000000000..5de265be99 --- /dev/null +++ b/packages/frontend-plugin-api/src/apis/system/helpers.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 { createApiFactory } from '@backstage/core-plugin-api'; diff --git a/packages/frontend-plugin-api/src/apis/system/index.ts b/packages/frontend-plugin-api/src/apis/system/index.ts new file mode 100644 index 0000000000..b1bd3ac2b3 --- /dev/null +++ b/packages/frontend-plugin-api/src/apis/system/index.ts @@ -0,0 +1,21 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { useApi, useApiHolder, withApis } from './useApi'; +export { createApiRef } from './ApiRef'; +export type { ApiRefConfig } from './ApiRef'; +export * from './types'; +export * from './helpers'; diff --git a/packages/frontend-plugin-api/src/apis/system/types.ts b/packages/frontend-plugin-api/src/apis/system/types.ts new file mode 100644 index 0000000000..cc44e19e3f --- /dev/null +++ b/packages/frontend-plugin-api/src/apis/system/types.ts @@ -0,0 +1,24 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export type { + ApiRef, + AnyApiRef, + TypesToApiRefs, + ApiHolder, + ApiFactory, + AnyApiFactory, +} from '@backstage/core-plugin-api'; diff --git a/packages/frontend-plugin-api/src/apis/system/useApi.tsx b/packages/frontend-plugin-api/src/apis/system/useApi.tsx new file mode 100644 index 0000000000..d2efa49fa1 --- /dev/null +++ b/packages/frontend-plugin-api/src/apis/system/useApi.tsx @@ -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 { useApiHolder, useApi, withApis } from '@backstage/core-plugin-api'; diff --git a/packages/frontend-plugin-api/src/components/ErrorBoundary.tsx b/packages/frontend-plugin-api/src/components/ErrorBoundary.tsx index 1191b75a1d..6b457fadc9 100644 --- a/packages/frontend-plugin-api/src/components/ErrorBoundary.tsx +++ b/packages/frontend-plugin-api/src/components/ErrorBoundary.tsx @@ -14,35 +14,14 @@ * limitations under the License. */ -import React, { Component, PropsWithChildren } from 'react'; -// TODO: Dependency on MUI should be removed from core packages -import { Button } from '@material-ui/core'; -import { ErrorPanel } from '@backstage/core-components'; +import React, { Component, ComponentType, PropsWithChildren } from 'react'; import { BackstagePlugin } from '../wiring'; +import { CoreErrorBoundaryFallbackProps } from '../types'; -type DefaultErrorBoundaryFallbackProps = PropsWithChildren<{ +type ErrorBoundaryProps = PropsWithChildren<{ plugin?: BackstagePlugin; - error: Error; - resetError: () => void; + Fallback: ComponentType; }>; - -const DefaultErrorBoundaryFallback = ({ - plugin, - error, - resetError, -}: DefaultErrorBoundaryFallbackProps) => { - const title = `Error in ${plugin?.id}`; - - return ( - - - - ); -}; - -type ErrorBoundaryProps = PropsWithChildren<{ plugin?: BackstagePlugin }>; type ErrorBoundaryState = { error?: Error }; /** @internal */ @@ -62,12 +41,11 @@ export class ErrorBoundary extends Component< render() { const { error } = this.state; - const { plugin, children } = this.props; + const { plugin, children, Fallback } = this.props; if (error) { - // TODO: use a configurable error boundary fallback return ( - , - options?: { - config?: JsonObject; - }, -) { - const { config = {} } = options ?? {}; - - const app = createApp({ - features: [ - createPlugin({ - id: 'plugin', - extensions: [extension], - }), - ], - configLoader: async () => new MockConfigApi(config), - }); - - return renderWithEffects(app.createRoot()); -} +import { createExtensionTester } from '@backstage/frontend-test-utils'; const wrapInBoundaryExtension = (element: JSX.Element) => { - const id = 'plugin.extension'; const routeRef = createRouteRef(); return createExtension({ - id, - attachTo: { id: 'core.routes', input: 'routes' }, + name: 'test', + attachTo: { id: 'app/routes', input: 'routes' }, output: { element: coreExtensionData.reactElement, path: coreExtensionData.routePath, routeRef: coreExtensionData.routeRef.optional(), }, - factory({ source }) { + factory({ node }) { return { routeRef, path: '/', - element: ( - - {element} - - ), + element: {element}, }; }, }); @@ -86,7 +49,7 @@ describe('ExtensionBoundary', () => { const TextComponent = () => { return

{text}

; }; - await renderExtensionInTestApp(wrapInBoundaryExtension()); + createExtensionTester(wrapInBoundaryExtension()).render(); await waitFor(() => expect(screen.getByText(text)).toBeInTheDocument()); }); @@ -95,7 +58,7 @@ describe('ExtensionBoundary', () => { const ErrorComponent = () => { throw new Error(error); }; - await renderExtensionInTestApp(wrapInBoundaryExtension()); + createExtensionTester(wrapInBoundaryExtension()).render(); await waitFor(() => expect(screen.getByText(error)).toBeInTheDocument()); }); @@ -112,23 +75,26 @@ describe('ExtensionBoundary', () => { return null; }; - await renderExtensionInTestApp( + createExtensionTester( wrapInBoundaryExtension( , ), - ); + ).render(); - await waitFor(() => - expect(analyticsApiMock.getEvents()[0]).toMatchObject({ + await waitFor(() => { + const event = analyticsApiMock + .getEvents() + .find(e => e.subject === subject); + + expect(event).toMatchObject({ action, subject, context: { - extension: 'plugin.extension', - routeRef: 'unknown', + extensionId: 'test', }, - }), - ); + }); + }); }); }); diff --git a/packages/frontend-plugin-api/src/components/ExtensionBoundary.tsx b/packages/frontend-plugin-api/src/components/ExtensionBoundary.tsx index a9ea297216..9a8eb5b750 100644 --- a/packages/frontend-plugin-api/src/components/ExtensionBoundary.tsx +++ b/packages/frontend-plugin-api/src/components/ExtensionBoundary.tsx @@ -14,13 +14,18 @@ * limitations under the License. */ -import React, { PropsWithChildren, ReactNode, useEffect } from 'react'; +import React, { + PropsWithChildren, + ReactNode, + Suspense, + useEffect, +} from 'react'; import { AnalyticsContext, useAnalytics } from '@backstage/core-plugin-api'; -import { BackstagePlugin } from '../wiring'; import { ErrorBoundary } from './ErrorBoundary'; -import { ExtensionSuspense } from './ExtensionSuspense'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports import { routableExtensionRenderedEvent } from '../../../core-plugin-api/src/analytics/Tracker'; +import { AppNode, useComponentRef } from '../apis'; +import { coreComponentRefs } from './coreComponentRefs'; type RouteTrackerProps = PropsWithChildren<{ disableTracking?: boolean; @@ -44,29 +49,32 @@ const RouteTracker = (props: RouteTrackerProps) => { /** @public */ export interface ExtensionBoundaryProps { - id: string; - source?: BackstagePlugin; + node: AppNode; routable?: boolean; children: ReactNode; } /** @public */ export function ExtensionBoundary(props: ExtensionBoundaryProps) { - const { id, source, routable, children } = props; + const { node, routable, children } = props; + + const plugin = node.spec.source; + const Progress = useComponentRef(coreComponentRefs.progress); + const fallback = useComponentRef(coreComponentRefs.errorBoundaryFallback); // Skipping "routeRef" attribute in the new system, the extension "id" should provide more insight const attributes = { - extension: id, - pluginId: source?.id, + extensionId: node.spec.id, + pluginId: node.spec.source?.id, }; return ( - - + }> + {children} - + ); } diff --git a/packages/frontend-plugin-api/src/components/coreComponentRefs.ts b/packages/frontend-plugin-api/src/components/coreComponentRefs.ts new file mode 100644 index 0000000000..64412b8710 --- /dev/null +++ b/packages/frontend-plugin-api/src/components/coreComponentRefs.ts @@ -0,0 +1,43 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + CoreErrorBoundaryFallbackProps, + CoreNotFoundErrorPageProps, + CoreProgressProps, +} from '../types'; +import { createComponentRef } from './createComponentRef'; + +const coreProgressComponentRef = createComponentRef({ + id: 'core.components.progress', +}); + +const coreNotFoundErrorPageComponentRef = + createComponentRef({ + id: 'core.components.notFoundErrorPage', + }); + +const coreErrorBoundaryFallbackComponentRef = + createComponentRef({ + id: 'core.components.errorBoundaryFallback', + }); + +/** @public */ +export const coreComponentRefs = { + progress: coreProgressComponentRef, + notFoundErrorPage: coreNotFoundErrorPageComponentRef, + errorBoundaryFallback: coreErrorBoundaryFallbackComponentRef, +}; diff --git a/packages/frontend-plugin-api/src/components/createComponentRef.test.tsx b/packages/frontend-plugin-api/src/components/createComponentRef.test.tsx new file mode 100644 index 0000000000..9a84fe08fa --- /dev/null +++ b/packages/frontend-plugin-api/src/components/createComponentRef.test.tsx @@ -0,0 +1,25 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createComponentRef } from './createComponentRef'; + +describe('createComponentRef', () => { + it('can be created and read', () => { + const ref = createComponentRef({ id: 'foo' }); + expect(ref.id).toBe('foo'); + expect(String(ref)).toBe('ComponentRef{id=foo}'); + }); +}); diff --git a/packages/frontend-plugin-api/src/components/createComponentRef.tsx b/packages/frontend-plugin-api/src/components/createComponentRef.tsx new file mode 100644 index 0000000000..88181dd079 --- /dev/null +++ b/packages/frontend-plugin-api/src/components/createComponentRef.tsx @@ -0,0 +1,34 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** @public */ +export type ComponentRef = { + id: string; + T: T; +}; + +/** @public */ +export function createComponentRef(options: { + id: string; +}): ComponentRef { + const { id } = options; + return { + id, + toString() { + return `ComponentRef{id=${id}}`; + }, + } as ComponentRef; +} diff --git a/packages/frontend-plugin-api/src/components/index.ts b/packages/frontend-plugin-api/src/components/index.ts index 7056a59271..5066144000 100644 --- a/packages/frontend-plugin-api/src/components/index.ts +++ b/packages/frontend-plugin-api/src/components/index.ts @@ -18,3 +18,5 @@ export { ExtensionBoundary, type ExtensionBoundaryProps, } from './ExtensionBoundary'; +export { coreComponentRefs } from './coreComponentRefs'; +export { createComponentRef, type ComponentRef } from './createComponentRef'; diff --git a/packages/frontend-plugin-api/src/extensions/createApiExtension.test.ts b/packages/frontend-plugin-api/src/extensions/createApiExtension.test.ts index e90c0b6b85..c4d0239094 100644 --- a/packages/frontend-plugin-api/src/extensions/createApiExtension.test.ts +++ b/packages/frontend-plugin-api/src/extensions/createApiExtension.test.ts @@ -26,14 +26,16 @@ describe('createApiExtension', () => { factory: () => ({ foo: 'bar' }), }); - const extension = createApiExtension({ - factory, - }); - - expect(extension).toEqual({ - $$type: '@backstage/Extension', - id: 'apis.test', - attachTo: { id: 'core', input: 'apis' }, + expect( + createApiExtension({ + factory, + }), + ).toEqual({ + $$type: '@backstage/ExtensionDefinition', + version: 'v1', + kind: 'api', + namespace: 'test', + attachTo: { id: 'app', input: 'apis' }, disabled: false, configSchema: undefined, inputs: {}, @@ -45,6 +47,7 @@ describe('createApiExtension', () => { }), }, factory: expect.any(Function), + toString: expect.any(Function), }); }); @@ -65,9 +68,11 @@ describe('createApiExtension', () => { }); // boo expect(extension).toEqual({ - $$type: '@backstage/Extension', - id: 'apis.test', - attachTo: { id: 'core', input: 'apis' }, + $$type: '@backstage/ExtensionDefinition', + version: 'v1', + kind: 'api', + namespace: 'test', + attachTo: { id: 'app', input: 'apis' }, disabled: false, configSchema: undefined, inputs: {}, @@ -79,6 +84,7 @@ describe('createApiExtension', () => { }), }, factory: expect.any(Function), + toString: expect.any(Function), }); }); }); diff --git a/packages/frontend-plugin-api/src/extensions/createApiExtension.ts b/packages/frontend-plugin-api/src/extensions/createApiExtension.ts index 7b6dded022..1680332960 100644 --- a/packages/frontend-plugin-api/src/extensions/createApiExtension.ts +++ b/packages/frontend-plugin-api/src/extensions/createApiExtension.ts @@ -17,9 +17,9 @@ import { AnyApiFactory, AnyApiRef } from '@backstage/core-plugin-api'; import { PortableSchema } from '../schema'; import { - ExtensionInputValues, + ResolvedExtensionInputs, createExtension, - coreExtensionData, + createExtensionDataRef, } from '../wiring'; import { AnyExtensionInputMap } from '../wiring/createExtension'; import { Expand } from '../types'; @@ -34,7 +34,7 @@ export function createApiExtension< api: AnyApiRef; factory: (options: { config: TConfig; - inputs: Expand>; + inputs: Expand>; }) => AnyApiFactory; } | { @@ -51,12 +51,15 @@ export function createApiExtension< 'api' in options ? options.api : (factory as { api: AnyApiRef }).api; return createExtension({ - id: `apis.${apiRef.id}`, - attachTo: { id: 'core', input: 'apis' }, + kind: 'api', + // Since ApiRef IDs use a global namespace we use the namespace here in order to override + // potential plugin IDs and always end up with the format `api:` + namespace: apiRef.id, + attachTo: { id: 'app', input: 'apis' }, inputs: extensionInputs, configSchema, output: { - api: coreExtensionData.apiFactory, + api: createApiExtension.factoryDataRef, }, factory({ config, inputs }) { if (typeof factory === 'function') { @@ -66,3 +69,9 @@ export function createApiExtension< }, }); } + +/** @public */ +export namespace createApiExtension { + export const factoryDataRef = + createExtensionDataRef('core.api.factory'); +} diff --git a/packages/frontend-plugin-api/src/extensions/createAppRootElementExtension.test.tsx b/packages/frontend-plugin-api/src/extensions/createAppRootElementExtension.test.tsx new file mode 100644 index 0000000000..c8bf6ee355 --- /dev/null +++ b/packages/frontend-plugin-api/src/extensions/createAppRootElementExtension.test.tsx @@ -0,0 +1,107 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createExtensionTester } from '@backstage/frontend-test-utils'; +import { screen } from '@testing-library/react'; +import React from 'react'; +import { createSchemaFromZod } from '../schema/createSchemaFromZod'; +import { coreExtensionData } from '../wiring/coreExtensionData'; +import { createExtension } from '../wiring/createExtension'; +import { createExtensionInput } from '../wiring/createExtensionInput'; +import { createAppRootElementExtension } from './createAppRootElementExtension'; + +describe('createAppRootElementExtension', () => { + it('works with simple options and just an element', async () => { + const extension = createAppRootElementExtension({ + element:
Hello
, + }); + + expect(extension).toEqual({ + $$type: '@backstage/ExtensionDefinition', + version: 'v1', + kind: 'app-root-element', + attachTo: { id: 'app/root', input: 'elements' }, + disabled: false, + inputs: {}, + output: { + element: expect.anything(), + }, + factory: expect.any(Function), + toString: expect.any(Function), + }); + + createExtensionTester(extension).render(); + + await expect(screen.findByText('Hello')).resolves.toBeInTheDocument(); + }); + + it('works with complex options and a callback', async () => { + const schema = createSchemaFromZod(z => z.object({ name: z.string() })); + + const extension = createAppRootElementExtension({ + namespace: 'ns', + name: 'test', + configSchema: schema, + attachTo: { id: 'other', input: 'slot' }, + disabled: true, + inputs: { + children: createExtensionInput({ + element: coreExtensionData.reactElement, + }), + }, + element: ({ inputs, config }) => ( +
+ Hello, {config.name}, {inputs.children.length} +
+ ), + }); + + expect(extension).toEqual({ + $$type: '@backstage/ExtensionDefinition', + version: 'v1', + kind: 'app-root-element', + namespace: 'ns', + name: 'test', + attachTo: { id: 'other', input: 'slot' }, + configSchema: schema, + disabled: true, + inputs: { + children: createExtensionInput({ + element: coreExtensionData.reactElement, + }), + }, + output: { + element: expect.anything(), + }, + factory: expect.any(Function), + toString: expect.any(Function), + }); + + createExtensionTester(extension, { config: { name: 'Robin' } }) + .add( + createExtension({ + attachTo: { id: 'app-root-element:ns/test', input: 'children' }, + output: { element: coreExtensionData.reactElement }, + factory: () => ({ element:
}), + }), + ) + .render(); + + await expect( + screen.findByText('Hello, Robin, 1'), + ).resolves.toBeInTheDocument(); + }); +}); diff --git a/packages/frontend-plugin-api/src/extensions/createAppRootElementExtension.ts b/packages/frontend-plugin-api/src/extensions/createAppRootElementExtension.ts new file mode 100644 index 0000000000..8be82d5540 --- /dev/null +++ b/packages/frontend-plugin-api/src/extensions/createAppRootElementExtension.ts @@ -0,0 +1,71 @@ +/* + * 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 { JSX } from 'react'; +import { PortableSchema } from '../schema/types'; +import { Expand } from '../types'; +import { coreExtensionData } from '../wiring/coreExtensionData'; +import { + AnyExtensionInputMap, + ExtensionDefinition, + ResolvedExtensionInputs, + createExtension, +} from '../wiring/createExtension'; + +/** + * Creates an extension that renders a React element at the app root, outside of + * the app layout. This is useful for example for shared popups and similar. + * + * @public + */ +export function createAppRootElementExtension< + TConfig extends {}, + TInputs extends AnyExtensionInputMap, +>(options: { + namespace?: string; + name?: string; + attachTo?: { id: string; input: string }; + configSchema?: PortableSchema; + disabled?: boolean; + inputs?: TInputs; + element: + | JSX.Element + | ((options: { + inputs: Expand>; + config: TConfig; + }) => JSX.Element); +}): ExtensionDefinition { + return createExtension({ + kind: 'app-root-element', + namespace: options.namespace, + name: options.name, + attachTo: options.attachTo ?? { id: 'app/root', input: 'elements' }, + configSchema: options.configSchema, + disabled: options.disabled, + inputs: options.inputs, + output: { + element: coreExtensionData.reactElement, + }, + factory({ inputs, config }) { + return { + element: + typeof options.element === 'function' + ? options.element({ inputs, config }) + : options.element, + }; + }, + }); +} diff --git a/packages/frontend-plugin-api/src/extensions/createAppRootWrapperExtension.test.tsx b/packages/frontend-plugin-api/src/extensions/createAppRootWrapperExtension.test.tsx new file mode 100644 index 0000000000..d21cfa7583 --- /dev/null +++ b/packages/frontend-plugin-api/src/extensions/createAppRootWrapperExtension.test.tsx @@ -0,0 +1,119 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createExtensionTester } from '@backstage/frontend-test-utils'; +import { screen } from '@testing-library/react'; +import React from 'react'; +import { createSchemaFromZod } from '../schema/createSchemaFromZod'; +import { coreExtensionData } from '../wiring/coreExtensionData'; +import { createExtension } from '../wiring/createExtension'; +import { createExtensionInput } from '../wiring/createExtensionInput'; +import { createAppRootWrapperExtension } from './createAppRootWrapperExtension'; +import { createPageExtension } from './createPageExtension'; + +describe('createAppRootWrapperExtension', () => { + it('works with simple options and no props', async () => { + const extension = createAppRootWrapperExtension({ + Component: () =>
Hello
, + }); + + expect(extension).toEqual({ + $$type: '@backstage/ExtensionDefinition', + version: 'v1', + kind: 'app-root-wrapper', + attachTo: { id: 'app/root', input: 'wrappers' }, + disabled: false, + inputs: {}, + output: { + component: expect.anything(), + }, + factory: expect.any(Function), + toString: expect.any(Function), + }); + + createExtensionTester( + createPageExtension({ + defaultPath: '/', + loader: async () =>
, + }), + ) + .add(extension) + .render(); + + await expect(screen.findByText('Hello')).resolves.toBeInTheDocument(); + }); + + it('works with complex options and props', async () => { + const schema = createSchemaFromZod(z => z.object({ name: z.string() })); + + const extension = createAppRootWrapperExtension({ + namespace: 'ns', + name: 'test', + configSchema: schema, + disabled: true, + inputs: { + children: createExtensionInput({ + element: coreExtensionData.reactElement, + }), + }, + Component: ({ inputs, config, children }) => ( +
+ {children} +
+ ), + }); + + expect(extension).toEqual({ + $$type: '@backstage/ExtensionDefinition', + version: 'v1', + kind: 'app-root-wrapper', + namespace: 'ns', + name: 'test', + attachTo: { id: 'app/root', input: 'wrappers' }, + configSchema: schema, + disabled: true, + inputs: { + children: createExtensionInput({ + element: coreExtensionData.reactElement, + }), + }, + output: { + component: expect.anything(), + }, + factory: expect.any(Function), + toString: expect.any(Function), + }); + + createExtensionTester( + createPageExtension({ + defaultPath: '/', + loader: async () =>
Hello
, + }), + ) + .add(extension, { config: { name: 'Robin' } }) + .add( + createExtension({ + attachTo: { id: 'app-root-wrapper:ns/test', input: 'children' }, + output: { element: coreExtensionData.reactElement }, + factory: () => ({ element:
}), + }), + ) + .render(); + + await expect(screen.findByText('Hello')).resolves.toBeInTheDocument(); + await expect(screen.findByTestId('Robin-1')).resolves.toBeInTheDocument(); + }); +}); diff --git a/packages/frontend-plugin-api/src/extensions/createAppRootWrapperExtension.tsx b/packages/frontend-plugin-api/src/extensions/createAppRootWrapperExtension.tsx new file mode 100644 index 0000000000..bbc51806af --- /dev/null +++ b/packages/frontend-plugin-api/src/extensions/createAppRootWrapperExtension.tsx @@ -0,0 +1,84 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, { ComponentType, PropsWithChildren } from 'react'; +import { PortableSchema } from '../schema/types'; +import { + AnyExtensionInputMap, + ExtensionDefinition, + ResolvedExtensionInputs, + createExtension, +} from '../wiring/createExtension'; +import { createExtensionDataRef } from '../wiring/createExtensionDataRef'; +import { Expand } from '../types'; + +/** + * Creates an extension that renders a React wrapper at the app root, enclosing + * the app layout. This is useful for example for adding global React contexts + * and similar. + * + * @public + */ +export function createAppRootWrapperExtension< + TConfig extends {}, + TInputs extends AnyExtensionInputMap, +>(options: { + namespace?: string; + name?: string; + attachTo?: { id: string; input: string }; + configSchema?: PortableSchema; + disabled?: boolean; + inputs?: TInputs; + Component: ComponentType< + PropsWithChildren<{ + inputs: Expand>; + config: TConfig; + }> + >; +}): ExtensionDefinition { + return createExtension({ + kind: 'app-root-wrapper', + namespace: options.namespace, + name: options.name, + attachTo: options.attachTo ?? { id: 'app/root', input: 'wrappers' }, + configSchema: options.configSchema, + disabled: options.disabled, + inputs: options.inputs, + output: { + component: createAppRootWrapperExtension.componentDataRef, + }, + factory({ inputs, config }) { + const Component = (props: PropsWithChildren<{}>) => { + return ( + + {props.children} + + ); + }; + return { + component: Component, + }; + }, + }); +} + +/** @public */ +export namespace createAppRootWrapperExtension { + export const componentDataRef = + createExtensionDataRef>>( + 'app.root.wrapper', + ); +} diff --git a/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx b/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx new file mode 100644 index 0000000000..2efa106750 --- /dev/null +++ b/packages/frontend-plugin-api/src/extensions/createComponentExtension.tsx @@ -0,0 +1,98 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, { lazy, ComponentType } from 'react'; +import { + AnyExtensionInputMap, + ResolvedExtensionInputs, + createExtension, + createExtensionDataRef, +} from '../wiring'; +import { Expand } from '../types'; +import { PortableSchema } from '../schema'; +import { ExtensionBoundary, ComponentRef } from '../components'; + +/** @public */ +export function createComponentExtension< + TProps extends {}, + TConfig extends {}, + TInputs extends AnyExtensionInputMap, +>(options: { + ref: ComponentRef; + name?: string; + disabled?: boolean; + inputs?: TInputs; + configSchema?: PortableSchema; + loader: + | { + lazy: (values: { + config: TConfig; + inputs: Expand>; + }) => Promise>; + } + | { + sync: (values: { + config: TConfig; + inputs: Expand>; + }) => ComponentType; + }; +}) { + return createExtension({ + kind: 'component', + namespace: options.ref.id, + name: options.name, + attachTo: { id: 'app', input: 'components' }, + inputs: options.inputs, + disabled: options.disabled, + configSchema: options.configSchema, + output: { + component: createComponentExtension.componentDataRef, + }, + factory({ config, inputs, node }) { + let ExtensionComponent: ComponentType; + + if ('sync' in options.loader) { + ExtensionComponent = options.loader.sync({ config, inputs }); + } else { + const lazyLoader = options.loader.lazy; + ExtensionComponent = lazy(() => + lazyLoader({ config, inputs }).then(Component => ({ + default: Component, + })), + ) as unknown as ComponentType; + } + + return { + component: { + ref: options.ref, + impl: props => ( + + + + ), + }, + }; + }, + }); +} + +/** @public */ +export namespace createComponentExtension { + export const componentDataRef = createExtensionDataRef<{ + ref: ComponentRef; + impl: ComponentType; + }>('core.component.component'); +} diff --git a/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx b/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx index 84fbe5ffee..4b92d4dace 100644 --- a/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx +++ b/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx @@ -16,7 +16,7 @@ import { IconComponent } from '@backstage/core-plugin-api'; import { createSchemaFromZod } from '../schema/createSchemaFromZod'; -import { coreExtensionData, createExtension } from '../wiring'; +import { createExtension, createExtensionDataRef } from '../wiring'; import { RouteRef } from '../routing'; /** @@ -24,22 +24,25 @@ import { RouteRef } from '../routing'; * @public */ export function createNavItemExtension(options: { - id: string; + namespace?: string; + name?: string; routeRef: RouteRef; title: string; icon: IconComponent; }) { - const { id, routeRef, title, icon } = options; + const { routeRef, title, icon, namespace, name } = options; return createExtension({ - id, - attachTo: { id: 'core.nav', input: 'items' }, + namespace, + name, + kind: 'nav-item', + attachTo: { id: 'app/nav', input: 'items' }, configSchema: createSchemaFromZod(z => z.object({ title: z.string().default(title), }), ), output: { - navTarget: coreExtensionData.navTarget, + navTarget: createNavItemExtension.targetDataRef, }, factory: ({ config }) => ({ navTarget: { @@ -50,3 +53,13 @@ export function createNavItemExtension(options: { }), }); } + +/** @public */ +export namespace createNavItemExtension { + // TODO(Rugvip): Should this be broken apart into separate refs? title/icon/routeRef + export const targetDataRef = createExtensionDataRef<{ + title: string; + icon: IconComponent; + routeRef: RouteRef; + }>('core.nav-item.target'); +} diff --git a/packages/frontend-plugin-api/src/extensions/createNavLogoExtension.test.tsx b/packages/frontend-plugin-api/src/extensions/createNavLogoExtension.test.tsx new file mode 100644 index 0000000000..8c54743f1d --- /dev/null +++ b/packages/frontend-plugin-api/src/extensions/createNavLogoExtension.test.tsx @@ -0,0 +1,47 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { createNavLogoExtension } from './createNavLogoExtension'; + +jest.mock('@backstage/core-plugin-api', () => ({ + ...jest.requireActual('@backstage/core-plugin-api'), +})); + +describe('createNavLogoExtension', () => { + it('creates the extension properly', () => { + expect( + createNavLogoExtension({ + name: 'test', + logoFull:
Logo Full
, + logoIcon:
Logo Icon
, + }), + ).toEqual({ + $$type: '@backstage/ExtensionDefinition', + version: 'v1', + kind: 'nav-logo', + name: 'test', + attachTo: { id: 'app/nav', input: 'logos' }, + disabled: false, + inputs: {}, + output: { + logos: expect.anything(), + }, + factory: expect.any(Function), + toString: expect.any(Function), + }); + }); +}); diff --git a/packages/frontend-plugin-api/src/extensions/createNavLogoExtension.tsx b/packages/frontend-plugin-api/src/extensions/createNavLogoExtension.tsx new file mode 100644 index 0000000000..3d66b26d6b --- /dev/null +++ b/packages/frontend-plugin-api/src/extensions/createNavLogoExtension.tsx @@ -0,0 +1,55 @@ +/* + * 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 { createExtension, createExtensionDataRef } from '../wiring'; + +/** + * Helper for creating extensions for a nav logos. + * @public + */ +export function createNavLogoExtension(options: { + name?: string; + namespace?: string; + logoIcon: JSX.Element; + logoFull: JSX.Element; +}) { + const { logoIcon, logoFull } = options; + return createExtension({ + kind: 'nav-logo', + name: options?.name, + namespace: options?.namespace, + attachTo: { id: 'app/nav', input: 'logos' }, + output: { + logos: createNavLogoExtension.logoElementsDataRef, + }, + factory: () => { + return { + logos: { + logoIcon, + logoFull, + }, + }; + }, + }); +} + +/** @public */ +export namespace createNavLogoExtension { + export const logoElementsDataRef = createExtensionDataRef<{ + logoIcon?: JSX.Element; + logoFull?: JSX.Element; + }>('core.nav-logo.logo-elements'); +} diff --git a/packages/frontend-plugin-api/src/extensions/createPageExtension.test.tsx b/packages/frontend-plugin-api/src/extensions/createPageExtension.test.tsx index 81843558da..374400fce8 100644 --- a/packages/frontend-plugin-api/src/extensions/createPageExtension.test.tsx +++ b/packages/frontend-plugin-api/src/extensions/createPageExtension.test.tsx @@ -15,16 +15,12 @@ */ import React from 'react'; -import { renderWithEffects, wrapInTestApp } from '@backstage/test-utils'; import { useAnalytics } from '@backstage/core-plugin-api'; import { waitFor } from '@testing-library/react'; import { PortableSchema } from '../schema'; -import { - coreExtensionData, - createExtensionInput, - createPlugin, -} from '../wiring'; +import { coreExtensionData, createExtensionInput } from '../wiring'; import { createPageExtension } from './createPageExtension'; +import { createExtensionTester } from '@backstage/frontend-test-utils'; jest.mock('@backstage/core-plugin-api', () => ({ ...jest.requireActual('@backstage/core-plugin-api'), @@ -40,14 +36,16 @@ describe('createPageExtension', () => { expect( createPageExtension({ - id: 'test', + name: 'test', configSchema, loader: async () =>
, }), ).toEqual({ - $$type: '@backstage/Extension', - id: 'test', - attachTo: { id: 'core.routes', input: 'routes' }, + $$type: '@backstage/ExtensionDefinition', + version: 'v1', + name: 'test', + kind: 'page', + attachTo: { id: 'app/routes', input: 'routes' }, configSchema: expect.anything(), disabled: false, inputs: {}, @@ -57,11 +55,12 @@ describe('createPageExtension', () => { routeRef: expect.anything(), }, factory: expect.any(Function), + toString: expect.any(Function), }); expect( createPageExtension({ - id: 'test', + name: 'test', attachTo: { id: 'other', input: 'place' }, disabled: true, configSchema, @@ -73,8 +72,10 @@ describe('createPageExtension', () => { loader: async () =>
, }), ).toEqual({ - $$type: '@backstage/Extension', - id: 'test', + $$type: '@backstage/ExtensionDefinition', + version: 'v1', + name: 'test', + kind: 'page', attachTo: { id: 'other', input: 'place' }, configSchema: expect.anything(), disabled: true, @@ -89,18 +90,21 @@ describe('createPageExtension', () => { routeRef: expect.anything(), }, factory: expect.any(Function), + toString: expect.any(Function), }); expect( createPageExtension({ - id: 'test', + name: 'test', defaultPath: '/here', loader: async () =>
, }), ).toEqual({ - $$type: '@backstage/Extension', - id: 'test', - attachTo: { id: 'core.routes', input: 'routes' }, + $$type: '@backstage/ExtensionDefinition', + version: 'v1', + name: 'test', + kind: 'page', + attachTo: { id: 'app/routes', input: 'routes' }, configSchema: expect.anything(), disabled: false, inputs: {}, @@ -110,6 +114,7 @@ describe('createPageExtension', () => { routeRef: expect.anything(), }, factory: expect.any(Function), + toString: expect.any(Function), }); }); @@ -120,19 +125,12 @@ describe('createPageExtension', () => { captureEvent, }); - const extension = createPageExtension({ - id: 'plugin.page', - defaultPath: '/', - loader: async () =>
Component
, - }); - - const output = extension.factory({ - source: createPlugin({ id: 'plugin ' }), - config: { path: '/' }, - inputs: {}, - }); - - renderWithEffects(wrapInTestApp(output.element as unknown as JSX.Element)); + createExtensionTester( + createPageExtension({ + defaultPath: '/', + loader: async () =>
Component
, + }), + ).render(); await waitFor(() => expect(captureEvent).toHaveBeenCalledWith( diff --git a/packages/frontend-plugin-api/src/extensions/createPageExtension.tsx b/packages/frontend-plugin-api/src/extensions/createPageExtension.tsx index f5e258a1e4..dfe549f32b 100644 --- a/packages/frontend-plugin-api/src/extensions/createPageExtension.tsx +++ b/packages/frontend-plugin-api/src/extensions/createPageExtension.tsx @@ -20,12 +20,12 @@ import { createSchemaFromZod, PortableSchema } from '../schema'; import { coreExtensionData, createExtension, - Extension, - ExtensionInputValues, + ResolvedExtensionInputs, AnyExtensionInputMap, } from '../wiring'; import { RouteRef } from '../routing'; import { Expand } from '../types'; +import { ExtensionDefinition } from '../wiring/createExtension'; /** * Helper for creating extensions for a routable React page component. @@ -44,19 +44,18 @@ export function createPageExtension< configSchema: PortableSchema; } ) & { - id: string; + namespace?: string; + name?: string; attachTo?: { id: string; input: string }; disabled?: boolean; inputs?: TInputs; routeRef?: RouteRef; loader: (options: { config: TConfig; - inputs: Expand>; + inputs: Expand>; }) => Promise; }, -): Extension { - const { id } = options; - +): ExtensionDefinition { const configSchema = 'configSchema' in options ? options.configSchema @@ -65,8 +64,10 @@ export function createPageExtension< ) as PortableSchema); return createExtension({ - id, - attachTo: options.attachTo ?? { id: 'core.routes', input: 'routes' }, + kind: 'page', + namespace: options.namespace, + name: options.name, + attachTo: options.attachTo ?? { id: 'app/routes', input: 'routes' }, configSchema, inputs: options.inputs, disabled: options.disabled, @@ -75,7 +76,7 @@ export function createPageExtension< path: coreExtensionData.routePath, routeRef: coreExtensionData.routeRef.optional(), }, - factory({ config, inputs, source }) { + factory({ config, inputs, node }) { const ExtensionComponent = lazy(() => options .loader({ config, inputs }) @@ -86,7 +87,7 @@ export function createPageExtension< path: config.path, routeRef: options.routeRef, element: ( - + ), diff --git a/packages/frontend-plugin-api/src/extensions/createRouterExtension.test.tsx b/packages/frontend-plugin-api/src/extensions/createRouterExtension.test.tsx new file mode 100644 index 0000000000..7109e1a8aa --- /dev/null +++ b/packages/frontend-plugin-api/src/extensions/createRouterExtension.test.tsx @@ -0,0 +1,167 @@ +/* + * 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 { createSpecializedApp } from '@backstage/frontend-app-api'; +import { render, screen } from '@testing-library/react'; +import React from 'react'; +import { MockConfigApi } from '@backstage/test-utils'; +import { MemoryRouter } from 'react-router-dom'; +import { createSchemaFromZod } from '../schema/createSchemaFromZod'; +import { coreExtensionData } from '../wiring/coreExtensionData'; +import { createExtension } from '../wiring/createExtension'; +import { createExtensionInput } from '../wiring/createExtensionInput'; +import { createExtensionOverrides } from '../wiring/createExtensionOverrides'; +import { createPageExtension } from './createPageExtension'; +import { createRouterExtension } from './createRouterExtension'; + +describe('createRouterExtension', () => { + it('works with simple options and no props', async () => { + const extension = createRouterExtension({ + namespace: 'test', + Component: ({ children }) => ( + +
{children}
+
+ ), + }); + + expect(extension).toEqual({ + $$type: '@backstage/ExtensionDefinition', + version: 'v1', + kind: 'app-router-component', + namespace: 'test', + attachTo: { id: 'app/root', input: 'router' }, + disabled: false, + inputs: {}, + output: { + component: expect.anything(), + }, + factory: expect.any(Function), + toString: expect.any(Function), + }); + + const app = createSpecializedApp({ + features: [ + createExtensionOverrides({ + extensions: [ + extension, + createPageExtension({ + namespace: 'test', + defaultPath: '/', + loader: async () =>
, + }), + ], + }), + ], + }); + + render(app.createRoot()); + + await expect( + screen.findByTestId('test-contents'), + ).resolves.toBeInTheDocument(); + await expect( + screen.findByTestId('test-router'), + ).resolves.toBeInTheDocument(); + }); + + it('works with complex options and props', async () => { + const schema = createSchemaFromZod(z => z.object({ name: z.string() })); + + const extension = createRouterExtension({ + namespace: 'test', + name: 'test', + configSchema: schema, + inputs: { + children: createExtensionInput({ + element: coreExtensionData.reactElement, + }), + }, + Component: ({ inputs, config, children }) => ( + +
+ {children} +
+
+ ), + }); + + expect(extension).toEqual({ + $$type: '@backstage/ExtensionDefinition', + version: 'v1', + kind: 'app-router-component', + namespace: 'test', + name: 'test', + attachTo: { id: 'app/root', input: 'router' }, + configSchema: schema, + disabled: false, + inputs: { + children: createExtensionInput({ + element: coreExtensionData.reactElement, + }), + }, + output: { + component: expect.anything(), + }, + factory: expect.any(Function), + toString: expect.any(Function), + }); + + const app = createSpecializedApp({ + features: [ + createExtensionOverrides({ + extensions: [ + extension, + createExtension({ + namespace: 'test', + attachTo: { + id: 'app-router-component:test/test', + input: 'children', + }, + output: { element: coreExtensionData.reactElement }, // doesn't matter + factory: () => ({ element:
}), + }), + createPageExtension({ + namespace: 'test', + defaultPath: '/', + loader: async () =>
, + }), + ], + }), + ], + config: new MockConfigApi({ + app: { + extensions: [ + { + 'app-router-component:test/test': { config: { name: 'Robin' } }, + }, + ], + }, + }), + }); + + render(app.createRoot()); + + await expect( + screen.findByTestId('test-contents'), + ).resolves.toBeInTheDocument(); + await expect( + screen.findByTestId('test-router-Robin-1'), + ).resolves.toBeInTheDocument(); + }); +}); diff --git a/packages/frontend-plugin-api/src/extensions/createRouterExtension.tsx b/packages/frontend-plugin-api/src/extensions/createRouterExtension.tsx new file mode 100644 index 0000000000..32d61f7e60 --- /dev/null +++ b/packages/frontend-plugin-api/src/extensions/createRouterExtension.tsx @@ -0,0 +1,84 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, { ComponentType, PropsWithChildren } from 'react'; +import { PortableSchema } from '../schema/types'; +import { + AnyExtensionInputMap, + ExtensionDefinition, + ResolvedExtensionInputs, + createExtension, +} from '../wiring/createExtension'; +import { createExtensionDataRef } from '../wiring/createExtensionDataRef'; +import { Expand } from '../types'; + +/** + * Creates an extension that replaces the router implementation at the app root. + * This is useful to be able to for example replace the BrowserRouter with a + * MemoryRouter in tests, or to add additional props to a BrowserRouter. + * + * @public + */ +export function createRouterExtension< + TConfig extends {}, + TInputs extends AnyExtensionInputMap, +>(options: { + namespace?: string; + name?: string; + attachTo?: { id: string; input: string }; + configSchema?: PortableSchema; + disabled?: boolean; + inputs?: TInputs; + Component: ComponentType< + PropsWithChildren<{ + inputs: Expand>; + config: TConfig; + }> + >; +}): ExtensionDefinition { + return createExtension({ + kind: 'app-router-component', + namespace: options.namespace, + name: options.name, + attachTo: options.attachTo ?? { id: 'app/root', input: 'router' }, + configSchema: options.configSchema, + disabled: options.disabled, + inputs: options.inputs, + output: { + component: createRouterExtension.componentDataRef, + }, + factory({ inputs, config }) { + const Component = (props: PropsWithChildren<{}>) => { + return ( + + {props.children} + + ); + }; + return { + component: Component, + }; + }, + }); +} + +/** @public */ +export namespace createRouterExtension { + export const componentDataRef = + createExtensionDataRef>>( + 'app.router.wrapper', + ); +} diff --git a/packages/frontend-plugin-api/src/extensions/createSignInPageExtension.test.tsx b/packages/frontend-plugin-api/src/extensions/createSignInPageExtension.test.tsx new file mode 100644 index 0000000000..d8835ae788 --- /dev/null +++ b/packages/frontend-plugin-api/src/extensions/createSignInPageExtension.test.tsx @@ -0,0 +1,47 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { createExtensionTester } from '@backstage/frontend-test-utils'; +import { screen } from '@testing-library/react'; +import { createSignInPageExtension } from './createSignInPageExtension'; +import { coreExtensionData, createExtension } from '../wiring'; + +describe('createSignInPageExtension', () => { + it('renders a sign-in page', async () => { + const SignInPage = createSignInPageExtension({ + name: 'test', + loader: async () => () =>
, + }); + + createExtensionTester( + createExtension({ + name: 'dummy', + attachTo: { id: 'ignored', input: 'ignored' }, + output: { + element: coreExtensionData.reactElement, + }, + factory: () => ({ element:
}), + }), + ) + .add(SignInPage) + .render(); + + await expect( + screen.findByTestId('sign-in-page'), + ).resolves.toBeInTheDocument(); + }); +}); diff --git a/packages/frontend-plugin-api/src/extensions/createSignInPageExtension.tsx b/packages/frontend-plugin-api/src/extensions/createSignInPageExtension.tsx new file mode 100644 index 0000000000..b525cc3a7b --- /dev/null +++ b/packages/frontend-plugin-api/src/extensions/createSignInPageExtension.tsx @@ -0,0 +1,83 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, { ComponentType, lazy } from 'react'; +import { ExtensionBoundary } from '../components'; +import { PortableSchema } from '../schema'; +import { + createExtension, + ResolvedExtensionInputs, + AnyExtensionInputMap, + createExtensionDataRef, + ExtensionDefinition, +} from '../wiring'; +import { Expand } from '../types'; +import { SignInPageProps } from '@backstage/core-plugin-api'; + +/** + * + * @public + */ +export function createSignInPageExtension< + TConfig extends {}, + TInputs extends AnyExtensionInputMap, +>(options: { + namespace?: string; + name?: string; + attachTo?: { id: string; input: string }; + configSchema?: PortableSchema; + disabled?: boolean; + inputs?: TInputs; + loader: (options: { + config: TConfig; + inputs: Expand>; + }) => Promise>; +}): ExtensionDefinition { + return createExtension({ + kind: 'sign-in-page', + namespace: options?.namespace, + name: options?.name, + attachTo: options.attachTo ?? { id: 'app/root', input: 'signInPage' }, + configSchema: options.configSchema, + inputs: options.inputs, + disabled: options.disabled, + output: { + component: createSignInPageExtension.componentDataRef, + }, + factory({ config, inputs, node }) { + const ExtensionComponent = lazy(() => + options + .loader({ config, inputs }) + .then(component => ({ default: component })), + ); + + return { + component: props => ( + + + + ), + }; + }, + }); +} + +/** @public */ +export namespace createSignInPageExtension { + export const componentDataRef = createExtensionDataRef< + ComponentType + >('core.sign-in-page.component'); +} diff --git a/packages/frontend-plugin-api/src/extensions/createThemeExtension.ts b/packages/frontend-plugin-api/src/extensions/createThemeExtension.ts index d41121d51c..cc6dbdabe9 100644 --- a/packages/frontend-plugin-api/src/extensions/createThemeExtension.ts +++ b/packages/frontend-plugin-api/src/extensions/createThemeExtension.ts @@ -14,17 +14,25 @@ * limitations under the License. */ -import { createExtension, coreExtensionData } from '../wiring'; +import { createExtension, createExtensionDataRef } from '../wiring'; import { AppTheme } from '@backstage/core-plugin-api'; /** @public */ export function createThemeExtension(theme: AppTheme) { return createExtension({ - id: `themes.${theme.id}`, - attachTo: { id: 'core', input: 'themes' }, + kind: 'theme', + namespace: 'app', + name: theme.id, + attachTo: { id: 'app', input: 'themes' }, output: { - theme: coreExtensionData.theme, + theme: createThemeExtension.themeDataRef, }, factory: () => ({ theme }), }); } + +/** @public */ +export namespace createThemeExtension { + export const themeDataRef = + createExtensionDataRef('core.theme.theme'); +} diff --git a/packages/frontend-plugin-api/src/extensions/createTranslationExtension.test.ts b/packages/frontend-plugin-api/src/extensions/createTranslationExtension.test.ts new file mode 100644 index 0000000000..975901b8e5 --- /dev/null +++ b/packages/frontend-plugin-api/src/extensions/createTranslationExtension.test.ts @@ -0,0 +1,134 @@ +/* + * 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 { + createTranslationRef, + createTranslationMessages, + createTranslationResource, +} from '@backstage/core-plugin-api/alpha'; +import { createTranslationExtension } from './createTranslationExtension'; + +const translationRef = createTranslationRef({ + id: 'test', + messages: { + a: 'a', + b: 'b', + }, +}); + +describe('createTranslationExtension', () => { + it('creates a translation message extension', () => { + const messages = createTranslationMessages({ + ref: translationRef, + messages: { + a: 'A', + }, + }); + const extension = createTranslationExtension({ resource: messages }); + + expect(extension).toEqual({ + $$type: '@backstage/ExtensionDefinition', + version: 'v1', + kind: 'translation', + namespace: 'test', + attachTo: { id: 'app', input: 'translations' }, + disabled: false, + inputs: {}, + output: { + resource: createTranslationExtension.translationDataRef, + }, + factory: expect.any(Function), + toString: expect.any(Function), + }); + + expect((extension as any).factory({} as any)).toEqual({ + resource: messages, + }); + }); + + it('creates a translation resource extension', () => { + const resource = createTranslationResource({ + ref: translationRef, + translations: { + sv: () => + Promise.resolve({ + default: createTranslationMessages({ + ref: translationRef, + messages: { + a: 'Ä', + b: 'Ö', + }, + }), + }), + }, + }); + const extension = createTranslationExtension({ resource }); + + expect(extension).toEqual({ + $$type: '@backstage/ExtensionDefinition', + version: 'v1', + kind: 'translation', + namespace: 'test', + attachTo: { id: 'app', input: 'translations' }, + disabled: false, + inputs: {}, + output: { + resource: createTranslationExtension.translationDataRef, + }, + factory: expect.any(Function), + toString: expect.any(Function), + }); + + expect((extension as any).factory({} as any)).toEqual({ resource }); + }); + + it('creates a translation resource extension with a name', () => { + expect( + createTranslationExtension({ + name: 'sv', + resource: createTranslationResource({ + ref: translationRef, + translations: { + sv: () => + Promise.resolve({ + default: createTranslationMessages({ + ref: translationRef, + messages: { + a: 'Ä', + b: 'Ö', + }, + }), + }), + }, + }), + }), + ).toEqual({ + $$type: '@backstage/ExtensionDefinition', + version: 'v1', + kind: 'translation', + namespace: 'test', + name: 'sv', + attachTo: { id: 'app', input: 'translations' }, + disabled: false, + inputs: {}, + output: { + resource: createTranslationExtension.translationDataRef, + }, + factory: expect.any(Function), + toString: expect.any(Function), + }); + }); +}); diff --git a/packages/frontend-plugin-api/src/extensions/createTranslationExtension.ts b/packages/frontend-plugin-api/src/extensions/createTranslationExtension.ts new file mode 100644 index 0000000000..8497a64b88 --- /dev/null +++ b/packages/frontend-plugin-api/src/extensions/createTranslationExtension.ts @@ -0,0 +1,42 @@ +/* + * 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 { TranslationMessages, TranslationResource } from '../translation'; +import { createExtension, createExtensionDataRef } from '../wiring'; + +/** @public */ +export function createTranslationExtension(options: { + name?: string; + resource: TranslationResource | TranslationMessages; +}) { + return createExtension({ + kind: 'translation', + namespace: options.resource.id, + name: options.name, + attachTo: { id: 'app', input: 'translations' }, + output: { + resource: createTranslationExtension.translationDataRef, + }, + factory: () => ({ resource: options.resource }), + }); +} + +/** @public */ +export namespace createTranslationExtension { + export const translationDataRef = createExtensionDataRef< + TranslationResource | TranslationMessages + >('core.translation.translation'); +} diff --git a/packages/frontend-plugin-api/src/extensions/index.ts b/packages/frontend-plugin-api/src/extensions/index.ts index 00cf4f919c..562cb728cb 100644 --- a/packages/frontend-plugin-api/src/extensions/index.ts +++ b/packages/frontend-plugin-api/src/extensions/index.ts @@ -15,6 +15,13 @@ */ export { createApiExtension } from './createApiExtension'; +export { createAppRootElementExtension } from './createAppRootElementExtension'; +export { createAppRootWrapperExtension } from './createAppRootWrapperExtension'; +export { createRouterExtension } from './createRouterExtension'; export { createPageExtension } from './createPageExtension'; export { createNavItemExtension } from './createNavItemExtension'; +export { createNavLogoExtension } from './createNavLogoExtension'; +export { createSignInPageExtension } from './createSignInPageExtension'; export { createThemeExtension } from './createThemeExtension'; +export { createComponentExtension } from './createComponentExtension'; +export { createTranslationExtension } from './createTranslationExtension'; diff --git a/plugins/kubernetes-react/src/utils/index.ts b/packages/frontend-plugin-api/src/icons/index.ts similarity index 92% rename from plugins/kubernetes-react/src/utils/index.ts rename to packages/frontend-plugin-api/src/icons/index.ts index d47afaf668..9c9e45e54c 100644 --- a/plugins/kubernetes-react/src/utils/index.ts +++ b/packages/frontend-plugin-api/src/icons/index.ts @@ -13,4 +13,5 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export * from './clusterLinks'; + +export type { IconComponent } from './types'; diff --git a/packages/frontend-plugin-api/src/icons/types.ts b/packages/frontend-plugin-api/src/icons/types.ts new file mode 100644 index 0000000000..4d54629de2 --- /dev/null +++ b/packages/frontend-plugin-api/src/icons/types.ts @@ -0,0 +1,45 @@ +/* + * 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 { ComponentType } from 'react'; + +/** + * IconComponent is the common icon type used throughout Backstage when + * working with and rendering generic icons, including the app system icons. + * + * @remarks + * + * The type is based on SvgIcon from Material UI, but both do not what the plugin-api + * package to have a dependency on Material UI, nor do we want the props to be as broad + * as the SvgIconProps interface. + * + * If you have the need to forward additional props from SvgIconProps, you can + * open an issue or submit a PR to the main Backstage repo. When doing so please + * also describe your use-case and reasoning of the addition. + * + * @public + */ + +export type IconComponent = ComponentType< + /* Material UI v4 */ + | { + fontSize?: 'large' | 'small' | 'default' | 'inherit'; + } + /* Material UI v5: https://mui.com/material-ui/migration/v5-component-changes/#icon */ + | { + fontSize?: 'medium' | 'large' | 'small' | 'inherit'; + } +>; diff --git a/packages/frontend-plugin-api/src/index.ts b/packages/frontend-plugin-api/src/index.ts index 498bc96a77..263380b1f8 100644 --- a/packages/frontend-plugin-api/src/index.ts +++ b/packages/frontend-plugin-api/src/index.ts @@ -20,9 +20,19 @@ * @packageDocumentation */ +export * from './analytics'; export * from './apis'; export * from './components'; export * from './extensions'; +export * from './icons'; export * from './routing'; export * from './schema'; +export * from './apis/system'; +export * from './translation'; export * from './wiring'; + +export type { + CoreProgressProps, + CoreNotFoundErrorPageProps, + CoreErrorBoundaryFallbackProps, +} from './types'; diff --git a/packages/frontend-plugin-api/src/translation/index.ts b/packages/frontend-plugin-api/src/translation/index.ts new file mode 100644 index 0000000000..ef3ccccbe3 --- /dev/null +++ b/packages/frontend-plugin-api/src/translation/index.ts @@ -0,0 +1,28 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { + type TranslationMessages, + type TranslationMessagesOptions, + type TranslationResource, + type TranslationResourceOptions, + type TranslationRef, + type TranslationRefOptions, + createTranslationMessages, + createTranslationResource, + createTranslationRef, + useTranslationRef, +} from '@backstage/core-plugin-api/alpha'; diff --git a/packages/frontend-plugin-api/src/types.ts b/packages/frontend-plugin-api/src/types.ts index 8b6f02a942..4d0fb1ac4b 100644 --- a/packages/frontend-plugin-api/src/types.ts +++ b/packages/frontend-plugin-api/src/types.ts @@ -14,9 +14,27 @@ * limitations under the License. */ +import { ReactNode } from 'react'; +import { BackstagePlugin } from './wiring'; + // TODO(Rugvip): This might be a quite useful utility type, maybe add to @backstage/types? /** * Utility type to expand type aliases into their equivalent type. * @ignore */ export type Expand = T extends infer O ? { [K in keyof O]: O[K] } : never; + +/** @public */ +export type CoreProgressProps = {}; + +/** @public */ +export type CoreNotFoundErrorPageProps = { + children?: ReactNode; +}; + +/** @public */ +export type CoreErrorBoundaryFallbackProps = { + plugin?: BackstagePlugin; + error: Error; + resetError: () => void; +}; diff --git a/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts b/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts index 023eab57e1..a6ff41f6b0 100644 --- a/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts +++ b/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts @@ -15,27 +15,12 @@ */ import { JSX } from 'react'; -import { - AnyApiFactory, - AppTheme, - IconComponent, -} from '@backstage/core-plugin-api'; -import { createExtensionDataRef } from './createExtensionDataRef'; import { RouteRef } from '../routing'; - -/** @public */ -export type NavTarget = { - title: string; - icon: IconComponent; - routeRef: RouteRef; -}; +import { createExtensionDataRef } from './createExtensionDataRef'; /** @public */ export const coreExtensionData = { reactElement: createExtensionDataRef('core.reactElement'), routePath: createExtensionDataRef('core.routing.path'), - apiFactory: createExtensionDataRef('core.api.factory'), routeRef: createExtensionDataRef('core.routing.ref'), - navTarget: createExtensionDataRef('core.nav.target'), - theme: createExtensionDataRef('core.theme'), }; diff --git a/packages/frontend-plugin-api/src/wiring/createExtension.test.ts b/packages/frontend-plugin-api/src/wiring/createExtension.test.ts index 071272d58f..42ab21db80 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtension.test.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtension.test.ts @@ -25,7 +25,7 @@ function unused(..._any: any[]) {} describe('createExtension', () => { it('should create an extension with a simple output', () => { const baseConfig = { - id: 'test', + namespace: 'test', attachTo: { id: 'root', input: 'default' }, output: { foo: stringData, @@ -39,7 +39,7 @@ describe('createExtension', () => { }; }, }); - expect(extension.id).toBe('test'); + expect(extension.namespace).toBe('test'); // When declared as an error function without a block the TypeScript errors // are a more specific and will point at the property that is problematic. @@ -163,7 +163,7 @@ describe('createExtension', () => { it('should create an extension with a some optional output', () => { const baseConfig = { - id: 'test', + namespace: 'test', attachTo: { id: 'root', input: 'default' }, output: { foo: stringData, @@ -176,7 +176,7 @@ describe('createExtension', () => { foo: 'bar', }), }); - expect(extension.id).toBe('test'); + expect(extension.namespace).toBe('test'); createExtension({ ...baseConfig, @@ -233,7 +233,7 @@ describe('createExtension', () => { it('should create an extension with input', () => { const extension = createExtension({ - id: 'test', + namespace: 'test', attachTo: { id: 'root', input: 'default' }, inputs: { mixed: createExtensionInput({ @@ -251,34 +251,34 @@ describe('createExtension', () => { foo: stringData, }, factory({ inputs }) { - const a1: string = inputs.mixed?.[0].required; + const a1: string = inputs.mixed?.[0].output.required; // @ts-expect-error - const a2: number = inputs.mixed?.[0].required; + const a2: number = inputs.mixed?.[0].output.required; // @ts-expect-error - const a3: any = inputs.mixed?.[0].nonExistent; + const a3: any = inputs.mixed?.[0].output.nonExistent; unused(a1, a2, a3); - const b1: string | undefined = inputs.mixed?.[0].optional; + const b1: string | undefined = inputs.mixed?.[0].output.optional; // @ts-expect-error - const b2: string = inputs.mixed?.[0].optional; + const b2: string = inputs.mixed?.[0].output.optional; // @ts-expect-error - const b3: number = inputs.mixed?.[0].optional; + const b3: number = inputs.mixed?.[0].output.optional; // @ts-expect-error - const b4: number | undefined = inputs.mixed?.[0].optional; + const b4: number | undefined = inputs.mixed?.[0].output.optional; unused(b1, b2, b3, b4); - const c1: string = inputs.onlyRequired?.[0].required; + const c1: string = inputs.onlyRequired?.[0].output.required; // @ts-expect-error - const c2: number = inputs.onlyRequired?.[0].required; + const c2: number = inputs.onlyRequired?.[0].output.required; unused(c1, c2); - const d1: string | undefined = inputs.onlyOptional?.[0].optional; + const d1: string | undefined = inputs.onlyOptional?.[0].output.optional; // @ts-expect-error - const d2: string = inputs.onlyOptional?.[0].optional; + const d2: string = inputs.onlyOptional?.[0].output.optional; // @ts-expect-error - const d3: number = inputs.onlyOptional?.[0].optional; + const d3: number = inputs.onlyOptional?.[0].output.optional; // @ts-expect-error - const d4: number | undefined = inputs.onlyOptional?.[0].optional; + const d4: number | undefined = inputs.onlyOptional?.[0].output.optional; unused(d1, d2, d3, d4); return { @@ -286,6 +286,9 @@ describe('createExtension', () => { }; }, }); - expect(extension.id).toBe('test'); + expect(extension.namespace).toBe('test'); + expect(String(extension)).toBe( + 'ExtensionDefinition{namespace=test,attachTo=root@default}', + ); }); }); diff --git a/packages/frontend-plugin-api/src/wiring/createExtension.ts b/packages/frontend-plugin-api/src/wiring/createExtension.ts index ff011a5875..be76fbc069 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtension.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtension.ts @@ -14,11 +14,11 @@ * limitations under the License. */ +import { AppNode } from '../apis'; import { PortableSchema } from '../schema'; import { Expand } from '../types'; import { ExtensionDataRef } from './createExtensionDataRef'; import { ExtensionInput } from './createExtensionInput'; -import { BackstagePlugin } from './createPlugin'; /** @public */ export type AnyExtensionDataMap = { @@ -52,18 +52,28 @@ export type ExtensionDataValues = { }; /** - * Converts an extension input map into the matching concrete input values type. + * Convert a single extension input into a matching resolved input. * @public */ -export type ExtensionInputValues< +export type ResolvedExtensionInput = + { + node: AppNode; + output: ExtensionDataValues; + }; + +/** + * Converts an extension input map into a matching collection of resolved inputs. + * @public + */ +export type ResolvedExtensionInputs< TInputs extends { [name in string]: ExtensionInput }, > = { [InputName in keyof TInputs]: false extends TInputs[InputName]['config']['singleton'] - ? Array>> + ? Array>> : false extends TInputs[InputName]['config']['optional'] - ? Expand> + ? Expand> : Expand< - ExtensionDataValues | undefined + ResolvedExtensionInput | undefined >; }; @@ -73,38 +83,63 @@ export interface CreateExtensionOptions< TInputs extends AnyExtensionInputMap, TConfig, > { - id: string; + kind?: string; + namespace?: string; + name?: string; attachTo: { id: string; input: string }; disabled?: boolean; inputs?: TInputs; output: TOutput; configSchema?: PortableSchema; factory(options: { - source?: BackstagePlugin; + node: AppNode; config: TConfig; - inputs: Expand>; + inputs: Expand>; }): Expand>; } /** @public */ -export interface Extension { - $$type: '@backstage/Extension'; - id: string; - attachTo: { id: string; input: string }; - disabled: boolean; - inputs: AnyExtensionInputMap; - output: AnyExtensionDataMap; - configSchema?: PortableSchema; +export interface ExtensionDefinition { + $$type: '@backstage/ExtensionDefinition'; + readonly kind?: string; + readonly namespace?: string; + readonly name?: string; + readonly attachTo: { id: string; input: string }; + readonly disabled: boolean; + readonly configSchema?: PortableSchema; +} + +/** @internal */ +export interface InternalExtensionDefinition + extends ExtensionDefinition { + readonly version: 'v1'; + readonly inputs: AnyExtensionInputMap; + readonly output: AnyExtensionDataMap; factory(options: { - source?: BackstagePlugin; + node: AppNode; config: TConfig; - inputs: Record< - string, - undefined | Record | Array> - >; + inputs: ResolvedExtensionInputs; }): ExtensionDataValues; } +/** @internal */ +export function toInternalExtensionDefinition( + overrides: ExtensionDefinition, +): InternalExtensionDefinition { + const internal = overrides as InternalExtensionDefinition; + if (internal.$$type !== '@backstage/ExtensionDefinition') { + throw new Error( + `Invalid extension definition instance, bad type '${internal.$$type}'`, + ); + } + if (internal.version !== 'v1') { + throw new Error( + `Invalid extension definition instance, bad version '${internal.version}'`, + ); + } + return internal; +} + /** @public */ export function createExtension< TOutput extends AnyExtensionDataMap, @@ -112,18 +147,38 @@ export function createExtension< TConfig = never, >( options: CreateExtensionOptions, -): Extension { +): ExtensionDefinition { return { - ...options, + $$type: '@backstage/ExtensionDefinition', + version: 'v1', + kind: options.kind, + namespace: options.namespace, + name: options.name, + attachTo: options.attachTo, disabled: options.disabled ?? false, - $$type: '@backstage/Extension', inputs: options.inputs ?? {}, + output: options.output, + configSchema: options.configSchema, factory({ inputs, ...rest }) { // TODO: Simplify this, but TS wouldn't infer the input type for some reason return options.factory({ - inputs: inputs as Expand>, + inputs: inputs as Expand>, ...rest, }); }, - }; + toString() { + const parts: string[] = []; + if (options.kind) { + parts.push(`kind=${options.kind}`); + } + if (options.namespace) { + parts.push(`namespace=${options.namespace}`); + } + if (options.name) { + parts.push(`name=${options.name}`); + } + parts.push(`attachTo=${options.attachTo.id}@${options.attachTo.input}`); + return `ExtensionDefinition{${parts.join(',')}}`; + }, + } as InternalExtensionDefinition; } diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionDataRef.test.ts b/packages/frontend-plugin-api/src/wiring/createExtensionDataRef.test.ts new file mode 100644 index 0000000000..f7a0dc82d0 --- /dev/null +++ b/packages/frontend-plugin-api/src/wiring/createExtensionDataRef.test.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. + */ + +import { createExtensionDataRef } from './createExtensionDataRef'; + +describe('createExtensionDataRef', () => { + it('can be created and read', () => { + const ref = createExtensionDataRef('foo'); + expect(ref.id).toBe('foo'); + expect(String(ref)).toBe('ExtensionDataRef{id=foo,optional=false}'); + const refOptional = ref.optional(); + expect(refOptional.id).toBe('foo'); + expect(String(refOptional)).toBe('ExtensionDataRef{id=foo,optional=true}'); + }); +}); diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionDataRef.ts b/packages/frontend-plugin-api/src/wiring/createExtensionDataRef.ts index d0d96e85f9..a7f4e4374e 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionDataRef.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtensionDataRef.ts @@ -43,7 +43,14 @@ export function createExtensionDataRef( $$type: '@backstage/ExtensionDataRef', config: {}, optional() { - return { ...this, config: { ...this.config, optional: true } }; + return { + ...this, + config: { ...this.config, optional: true }, + }; }, - } as ConfigurableExtensionDataRef; + toString() { + const optional = Boolean(this.config.optional); + return `ExtensionDataRef{id=${id},optional=${optional}}`; + }, + } as ConfigurableExtensionDataRef; } diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionOverrides.test.ts b/packages/frontend-plugin-api/src/wiring/createExtensionOverrides.test.ts index eb69f954e4..aa00247222 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionOverrides.test.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtensionOverrides.test.ts @@ -26,6 +26,8 @@ describe('createExtensionOverrides', () => { { "$$type": "@backstage/ExtensionOverrides", "extensions": [], + "featureFlags": [], + "toString": [Function], "version": "v1", } `); @@ -36,8 +38,22 @@ describe('createExtensionOverrides', () => { createExtensionOverrides({ extensions: [ createExtension({ - id: 'a', - attachTo: { id: 'core', input: 'apis' }, + name: 'a', + attachTo: { id: 'app', input: 'apis' }, + output: {}, + factory: () => ({}), + }), + createExtension({ + namespace: 'b', + attachTo: { id: 'app', input: 'apis' }, + output: {}, + factory: () => ({}), + }), + createExtension({ + kind: 'k', + namespace: 'c', + name: 'n', + attachTo: { id: 'app', input: 'apis' }, output: {}, factory: () => ({}), }), @@ -50,16 +66,51 @@ describe('createExtensionOverrides', () => { { "$$type": "@backstage/Extension", "attachTo": { - "id": "core", + "id": "app", "input": "apis", }, + "configSchema": undefined, "disabled": false, "factory": [Function], "id": "a", "inputs": {}, "output": {}, + "toString": [Function], + "version": "v1", + }, + { + "$$type": "@backstage/Extension", + "attachTo": { + "id": "app", + "input": "apis", + }, + "configSchema": undefined, + "disabled": false, + "factory": [Function], + "id": "b", + "inputs": {}, + "output": {}, + "toString": [Function], + "version": "v1", + }, + { + "$$type": "@backstage/Extension", + "attachTo": { + "id": "app", + "input": "apis", + }, + "configSchema": undefined, + "disabled": false, + "factory": [Function], + "id": "k:c/n", + "inputs": {}, + "output": {}, + "toString": [Function], + "version": "v1", }, ], + "featureFlags": [], + "toString": [Function], "version": "v1", } `); @@ -69,8 +120,8 @@ describe('createExtensionOverrides', () => { const overrides = createExtensionOverrides({ extensions: [ createExtension({ - id: 'a', - attachTo: { id: 'core', input: 'apis' }, + namespace: 'a', + attachTo: { id: 'app', input: 'apis' }, output: {}, factory: () => ({}), }), diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionOverrides.ts b/packages/frontend-plugin-api/src/wiring/createExtensionOverrides.ts index 2c64229eb9..1f88038944 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionOverrides.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtensionOverrides.ts @@ -14,32 +14,44 @@ * limitations under the License. */ -import { Extension } from './createExtension'; +import { ExtensionDefinition } from './createExtension'; +import { + Extension, + resolveExtensionDefinition, +} from './resolveExtensionDefinition'; +import { ExtensionOverrides, FeatureFlagConfig } from './types'; /** @public */ export interface ExtensionOverridesOptions { - extensions: Extension[]; -} - -/** @public */ -export interface ExtensionOverrides { - $$type: '@backstage/ExtensionOverrides'; + extensions: ExtensionDefinition[]; + featureFlags?: FeatureFlagConfig[]; } /** @internal */ export interface InternalExtensionOverrides extends ExtensionOverrides { - version: string; - extensions: Extension[]; + readonly version: 'v1'; + readonly extensions: Extension[]; + readonly featureFlags: FeatureFlagConfig[]; } /** @public */ export function createExtensionOverrides( options: ExtensionOverridesOptions, ): ExtensionOverrides { + const extensions = options.extensions.map(def => + resolveExtensionDefinition(def), + ); + const featureFlags = options.featureFlags ?? []; return { $$type: '@backstage/ExtensionOverrides', version: 'v1', - extensions: options.extensions, + extensions, + featureFlags, + toString() { + const ex = extensions.map(String).join(','); + const ff = featureFlags.map(f => f.name).join(','); + return `ExtensionOverrides{extensions=[${ex}],featureFlags=[${ff}]}`; + }, } as InternalExtensionOverrides; } @@ -50,12 +62,12 @@ export function toInternalExtensionOverrides( const internal = overrides as InternalExtensionOverrides; if (internal.$$type !== '@backstage/ExtensionOverrides') { throw new Error( - `Invalid translation resource, bad type '${internal.$$type}'`, + `Invalid extension overrides instance, bad type '${internal.$$type}'`, ); } if (internal.version !== 'v1') { throw new Error( - `Invalid translation resource, bad version '${internal.version}'`, + `Invalid extension overrides instance, bad version '${internal.version}'`, ); } return internal; diff --git a/packages/frontend-plugin-api/src/wiring/createPlugin.test.ts b/packages/frontend-plugin-api/src/wiring/createPlugin.test.ts index 42648fcd96..c180dc9719 100644 --- a/packages/frontend-plugin-api/src/wiring/createPlugin.test.ts +++ b/packages/frontend-plugin-api/src/wiring/createPlugin.test.ts @@ -18,58 +18,45 @@ import React from 'react'; import { createApp } from '@backstage/frontend-app-api'; import { screen } from '@testing-library/react'; import { createSchemaFromZod } from '../schema/createSchemaFromZod'; -import { createPlugin, BackstagePlugin } from './createPlugin'; +import { createPlugin } from './createPlugin'; import { JsonObject } from '@backstage/types'; import { createExtension } from './createExtension'; import { createExtensionDataRef } from './createExtensionDataRef'; import { coreExtensionData } from './coreExtensionData'; import { MockConfigApi, renderWithEffects } from '@backstage/test-utils'; import { createExtensionInput } from './createExtensionInput'; +import { BackstagePlugin } from './types'; const nameExtensionDataRef = createExtensionDataRef('name'); -const TechRadarPage = createExtension({ - id: 'plugin.techradar.page', - attachTo: { id: 'test.output', input: 'names' }, +const Extension1 = createExtension({ + name: '1', + attachTo: { id: 'test/output', input: 'names' }, output: { name: nameExtensionDataRef, }, factory() { - return { name: 'TechRadar' }; + return { name: 'extension-1' }; }, }); -const CatalogPage = createExtension({ - id: 'plugin.catalog.page', - attachTo: { id: 'test.output', input: 'names' }, +const Extension2 = createExtension({ + name: '2', + attachTo: { id: 'test/output', input: 'names' }, output: { name: nameExtensionDataRef, }, configSchema: createSchemaFromZod(z => - z.object({ name: z.string().default('Catalog') }), + z.object({ name: z.string().default('extension-2') }), ), factory({ config }) { return { name: config.name }; }, }); -const TechDocsAddon = createExtension({ - id: 'plugin.techdocs.addon.example', - attachTo: { id: 'plugin.techdocs.page', input: 'addons' }, - output: { - name: nameExtensionDataRef, - }, - configSchema: createSchemaFromZod(z => - z.object({ name: z.string().default('TechDocsAddon') }), - ), - factory({ config }) { - return { name: config.name }; - }, -}); - -const TechDocsPage = createExtension({ - id: 'plugin.techdocs.page', - attachTo: { id: 'test.output', input: 'names' }, +const Extension3 = createExtension({ + name: '3', + attachTo: { id: 'test/output', input: 'names' }, inputs: { addons: createExtensionInput({ name: nameExtensionDataRef, @@ -79,13 +66,43 @@ const TechDocsPage = createExtension({ name: nameExtensionDataRef, }, factory({ inputs }) { - return { name: `TechDocs-${inputs.addons.map(n => n.name).join('-')}` }; + return { + name: `extension-3:${inputs.addons.map(n => n.output.name).join('-')}`, + }; + }, +}); + +const Child = createExtension({ + name: 'child', + attachTo: { id: 'test/3', input: 'addons' }, + output: { + name: nameExtensionDataRef, + }, + configSchema: createSchemaFromZod(z => + z.object({ name: z.string().default('child') }), + ), + factory({ config }) { + return { name: config.name }; + }, +}); + +const Child2 = createExtension({ + name: 'child2', + attachTo: { id: 'test/3', input: 'addons' }, + output: { + name: nameExtensionDataRef, + }, + configSchema: createSchemaFromZod(z => + z.object({ name: z.string().default('child2') }), + ), + factory({ config }) { + return { name: config.name }; }, }); const outputExtension = createExtension({ - id: 'test.output', - attachTo: { id: 'core', input: 'root' }, + name: 'output', + attachTo: { id: 'app', input: 'root' }, inputs: { names: createExtensionInput({ name: nameExtensionDataRef, @@ -97,7 +114,7 @@ const outputExtension = createExtension({ factory({ inputs }) { return { element: React.createElement('span', {}, [ - `Names: ${inputs.names.map(n => n.name).join(', ')}`, + `Names: ${inputs.names.map(n => n.output.name).join(', ')}`, ]), }; }, @@ -112,46 +129,41 @@ function createTestAppRoot({ }) { return createApp({ features, - configLoader: async () => new MockConfigApi(config), + configLoader: async () => ({ config: new MockConfigApi(config) }), }).createRoot(); } describe('createPlugin', () => { it('should create an empty plugin', () => { - const plugin = createPlugin({ id: 'empty' }); + const plugin = createPlugin({ id: 'test' }); expect(plugin).toBeDefined(); + expect(String(plugin)).toBe('Plugin{id=test}'); }); it('should create a plugin with extension instances', async () => { const plugin = createPlugin({ - id: 'empty', - extensions: [TechRadarPage, CatalogPage, outputExtension], + id: 'test', + extensions: [Extension1, Extension2, outputExtension], }); expect(plugin).toBeDefined(); await renderWithEffects( createTestAppRoot({ features: [plugin], - config: { app: { extensions: [{ 'core.layout': false }] } }, + config: { app: { extensions: [{ 'app/root': false }] } }, }), ); await expect( - screen.findByText('Names: TechRadar, Catalog'), + screen.findByText('Names: extension-1, extension-2'), ).resolves.toBeInTheDocument(); }); it('should create a plugin with nested extension instances', async () => { const plugin = createPlugin({ - id: 'empty', - extensions: [ - TechRadarPage, - CatalogPage, - TechDocsPage, - TechDocsAddon, - outputExtension, - ], + id: 'test', + extensions: [Extension1, Extension2, Extension3, Child, outputExtension], }); expect(plugin).toBeDefined(); @@ -161,10 +173,10 @@ describe('createPlugin', () => { config: { app: { extensions: [ - { 'core.layout': false }, + { 'app/root': false }, { - 'plugin.catalog.page': { - config: { name: 'CatalogRenamed' }, + 'test/2': { + config: { name: 'extension-2-renamed' }, }, }, ], @@ -175,8 +187,63 @@ describe('createPlugin', () => { await expect( screen.findByText( - 'Names: TechRadar, CatalogRenamed, TechDocs-TechDocsAddon', + 'Names: extension-1, extension-2-renamed, extension-3:child', ), ).resolves.toBeInTheDocument(); }); + + it('should create a plugin with nested extension instances and multiple children', async () => { + const plugin = createPlugin({ + id: 'test', + extensions: [ + Extension1, + Extension2, + Extension3, + Child, + Child2, + outputExtension, + ], + }); + expect(plugin).toBeDefined(); + + await renderWithEffects( + createTestAppRoot({ + features: [plugin], + config: { + app: { + extensions: [{ 'app/root': false }], + }, + }, + }), + ); + + await expect( + screen.findByText( + 'Names: extension-1, extension-2, extension-3:child-child2', + ), + ).resolves.toBeInTheDocument(); + }); + + it('should throw on duplicate extensions', async () => { + expect(() => + createPlugin({ + id: 'test', + extensions: [Extension1, Extension1], + }), + ).toThrow("Plugin 'test' provided duplicate extensions: test/1"); + + expect(() => + createPlugin({ + id: 'test', + extensions: [ + Extension1, + Extension2, + Extension2, + Extension3, + Extension3, + Extension3, + ], + }), + ).toThrow("Plugin 'test' provided duplicate extensions: test/2, test/3"); + }); }); diff --git a/packages/frontend-plugin-api/src/wiring/createPlugin.ts b/packages/frontend-plugin-api/src/wiring/createPlugin.ts index 84edd954ef..797c46e58e 100644 --- a/packages/frontend-plugin-api/src/wiring/createPlugin.ts +++ b/packages/frontend-plugin-api/src/wiring/createPlugin.ts @@ -14,14 +14,17 @@ * limitations under the License. */ -import { Extension } from './createExtension'; -import { ExternalRouteRef, RouteRef } from '../routing'; - -/** @public */ -export type AnyRoutes = { [name in string]: RouteRef }; - -/** @public */ -export type AnyExternalRoutes = { [name in string]: ExternalRouteRef }; +import { ExtensionDefinition } from './createExtension'; +import { + Extension, + resolveExtensionDefinition, +} from './resolveExtensionDefinition'; +import { + AnyExternalRoutes, + AnyRoutes, + BackstagePlugin, + FeatureFlagConfig, +} from './types'; /** @public */ export interface PluginOptions< @@ -31,19 +34,18 @@ export interface PluginOptions< id: string; routes?: Routes; externalRoutes?: ExternalRoutes; - extensions?: Extension[]; + extensions?: ExtensionDefinition[]; + featureFlags?: FeatureFlagConfig[]; } /** @public */ -export interface BackstagePlugin< +export interface InternalBackstagePlugin< Routes extends AnyRoutes = AnyRoutes, ExternalRoutes extends AnyExternalRoutes = AnyExternalRoutes, -> { - $$type: '@backstage/BackstagePlugin'; - id: string; - extensions: Extension[]; - routes: Routes; - externalRoutes: ExternalRoutes; +> extends BackstagePlugin { + readonly version: 'v1'; + readonly extensions: Extension[]; + readonly featureFlags: FeatureFlagConfig[]; } /** @public */ @@ -53,11 +55,51 @@ export function createPlugin< >( options: PluginOptions, ): BackstagePlugin { + const extensions = (options.extensions ?? []).map(def => + resolveExtensionDefinition(def, { namespace: options.id }), + ); + + const extensionIds = extensions.map(e => e.id); + if (extensionIds.length !== new Set(extensionIds).size) { + const duplicates = Array.from( + new Set( + extensionIds.filter((id, index) => extensionIds.indexOf(id) !== index), + ), + ); + // TODO(Rugvip): This could provide some more information about the kind + name of the extensions + throw new Error( + `Plugin '${options.id}' provided duplicate extensions: ${duplicates.join( + ', ', + )}`, + ); + } + return { - ...options, + $$type: '@backstage/BackstagePlugin', + version: 'v1', + id: options.id, routes: options.routes ?? ({} as Routes), externalRoutes: options.externalRoutes ?? ({} as ExternalRoutes), - extensions: options.extensions ?? [], - $$type: '@backstage/BackstagePlugin', - }; + featureFlags: options.featureFlags ?? [], + extensions, + toString() { + return `Plugin{id=${options.id}}`; + }, + } as InternalBackstagePlugin; +} + +/** @internal */ +export function toInternalBackstagePlugin( + plugin: BackstagePlugin, +): InternalBackstagePlugin { + const internal = plugin as InternalBackstagePlugin; + if (internal.$$type !== '@backstage/BackstagePlugin') { + throw new Error(`Invalid plugin instance, bad type '${internal.$$type}'`); + } + if (internal.version !== 'v1') { + throw new Error( + `Invalid plugin instance, bad version '${internal.version}'`, + ); + } + return internal; } diff --git a/packages/frontend-plugin-api/src/wiring/index.ts b/packages/frontend-plugin-api/src/wiring/index.ts index ec685d6c81..61f821c7ce 100644 --- a/packages/frontend-plugin-api/src/wiring/index.ts +++ b/packages/frontend-plugin-api/src/wiring/index.ts @@ -14,13 +14,14 @@ * limitations under the License. */ -export { coreExtensionData, type NavTarget } from './coreExtensionData'; +export { coreExtensionData } from './coreExtensionData'; export { createExtension, - type Extension, + type ExtensionDefinition, type CreateExtensionOptions, type ExtensionDataValues, - type ExtensionInputValues, + type ResolvedExtensionInput, + type ResolvedExtensionInputs, type AnyExtensionInputMap, type AnyExtensionDataMap, } from './createExtension'; @@ -33,15 +34,17 @@ export { type ExtensionDataRef, type ConfigurableExtensionDataRef, } from './createExtensionDataRef'; -export { - createPlugin, - type BackstagePlugin, - type PluginOptions, - type AnyRoutes, - type AnyExternalRoutes, -} from './createPlugin'; +export { createPlugin, type PluginOptions } from './createPlugin'; export { createExtensionOverrides, - type ExtensionOverrides, type ExtensionOverridesOptions, } from './createExtensionOverrides'; +export { type Extension } from './resolveExtensionDefinition'; +export { + type AnyRoutes, + type AnyExternalRoutes, + type BackstagePlugin, + type ExtensionOverrides, + type FeatureFlagConfig, + type FrontendFeature, +} from './types'; diff --git a/packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.test.ts b/packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.test.ts new file mode 100644 index 0000000000..8970cfe168 --- /dev/null +++ b/packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.test.ts @@ -0,0 +1,58 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ExtensionDefinition } from './createExtension'; +import { resolveExtensionDefinition } from './resolveExtensionDefinition'; + +const baseDef = { + $$type: '@backstage/ExtensionDefinition', + version: 'v1', + attachTo: { id: '', input: '' }, + disabled: false, +}; + +describe('resolveExtensionDefinition', () => { + it.each([ + [{ namespace: 'ns' }, 'ns'], + [{ namespace: 'n' }, 'n'], + [{ namespace: 'ns', name: 'n' }, 'ns/n'], + [{ kind: 'k', namespace: 'ns' }, 'k:ns'], + [{ kind: 'k', namespace: 'ns', name: 'n' }, 'k:ns/n'], + ])(`should resolve extension IDs %s`, (definition, expected) => { + const resolved = resolveExtensionDefinition({ + ...baseDef, + ...definition, + } as ExtensionDefinition); + expect(resolved.id).toBe(expected); + expect(String(resolved)).toBe(`Extension{id=${expected}}`); + }); + + it('should fail to resolve extension ID without namespace', () => { + expect(() => + resolveExtensionDefinition({ + ...baseDef, + kind: 'k', + } as ExtensionDefinition), + ).toThrow( + 'Extension must declare an explicit namespace or name as it could not be resolved from context, kind=k namespace=undefined name=undefined', + ); + expect(() => + resolveExtensionDefinition(baseDef as ExtensionDefinition), + ).toThrow( + 'Extension must declare an explicit namespace or name as it could not be resolved from context, kind=undefined namespace=undefined name=undefined', + ); + }); +}); diff --git a/packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.ts b/packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.ts new file mode 100644 index 0000000000..0a44de4ab4 --- /dev/null +++ b/packages/frontend-plugin-api/src/wiring/resolveExtensionDefinition.ts @@ -0,0 +1,95 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { AppNode } from '../apis'; +import { + AnyExtensionDataMap, + AnyExtensionInputMap, + ExtensionDataValues, + ExtensionDefinition, + ResolvedExtensionInputs, + toInternalExtensionDefinition, +} from './createExtension'; +import { PortableSchema } from '../schema'; + +/** @public */ +export interface Extension { + $$type: '@backstage/Extension'; + readonly id: string; + readonly attachTo: { id: string; input: string }; + readonly disabled: boolean; + readonly configSchema?: PortableSchema; +} + +/** @internal */ +export interface InternalExtension extends Extension { + readonly version: 'v1'; + readonly inputs: AnyExtensionInputMap; + readonly output: AnyExtensionDataMap; + factory(options: { + node: AppNode; + config: TConfig; + inputs: ResolvedExtensionInputs; + }): ExtensionDataValues; +} + +/** @internal */ +export function toInternalExtension( + overrides: Extension, +): InternalExtension { + const internal = overrides as InternalExtension; + if (internal.$$type !== '@backstage/Extension') { + throw new Error( + `Invalid extension instance, bad type '${internal.$$type}'`, + ); + } + if (internal.version !== 'v1') { + throw new Error( + `Invalid extension instance, bad version '${internal.version}'`, + ); + } + return internal; +} + +/** @internal */ +export function resolveExtensionDefinition( + definition: ExtensionDefinition, + context?: { namespace?: string }, +): Extension { + const internalDefinition = toInternalExtensionDefinition(definition); + const { name, kind, namespace: _, ...rest } = internalDefinition; + const namespace = internalDefinition.namespace ?? context?.namespace; + + const namePart = + name && namespace ? `${namespace}/${name}` : namespace || name; + if (!namePart) { + throw new Error( + `Extension must declare an explicit namespace or name as it could not be resolved from context, kind=${kind} namespace=${namespace} name=${name}`, + ); + } + + const id = kind ? `${kind}:${namePart}` : namePart; + + return { + ...rest, + $$type: '@backstage/Extension', + version: 'v1', + id, + toString() { + return `Extension{id=${id}}`; + }, + } as Extension; +} diff --git a/packages/frontend-plugin-api/src/wiring/types.ts b/packages/frontend-plugin-api/src/wiring/types.ts new file mode 100644 index 0000000000..7e0650e06c --- /dev/null +++ b/packages/frontend-plugin-api/src/wiring/types.ts @@ -0,0 +1,52 @@ +/* + * 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 { ExternalRouteRef, RouteRef, SubRouteRef } from '../routing'; + +/** + * Feature flag configuration. + * + * @public + */ +export type FeatureFlagConfig = { + /** Feature flag name */ + name: string; +}; + +/** @public */ +export type AnyRoutes = { [name in string]: RouteRef | SubRouteRef }; + +/** @public */ +export type AnyExternalRoutes = { [name in string]: ExternalRouteRef }; + +/** @public */ +export interface BackstagePlugin< + Routes extends AnyRoutes = AnyRoutes, + ExternalRoutes extends AnyExternalRoutes = AnyExternalRoutes, +> { + readonly $$type: '@backstage/BackstagePlugin'; + readonly id: string; + readonly routes: Routes; + readonly externalRoutes: ExternalRoutes; +} + +/** @public */ +export interface ExtensionOverrides { + readonly $$type: '@backstage/ExtensionOverrides'; +} + +/** @public */ +export type FrontendFeature = BackstagePlugin | ExtensionOverrides; diff --git a/plugins/catalog-graphql/.eslintrc.js b/packages/frontend-test-utils/.eslintrc.js similarity index 100% rename from plugins/catalog-graphql/.eslintrc.js rename to packages/frontend-test-utils/.eslintrc.js diff --git a/packages/frontend-test-utils/CHANGELOG.md b/packages/frontend-test-utils/CHANGELOG.md new file mode 100644 index 0000000000..dc3555499e --- /dev/null +++ b/packages/frontend-test-utils/CHANGELOG.md @@ -0,0 +1,113 @@ +# @backstage/frontend-test-utils + +## 0.1.1 + +### Patch Changes + +- f7566f9: Updates to reflect the `app/router` extension having been renamed to `app/root`. +- 516fd3e: Updated README to reflect release status +- c97fa1c: Added `elements`, `wrappers`, and `router` inputs to `app/root`, that let you add things to the root of the React tree above the layout. You can use the `createAppRootElementExtension`, `createAppRootWrapperExtension`, and `createRouterExtension` extension creator, respectively, to conveniently create such extensions. These are all optional, and if you do not supply a router a default one will be used (`BrowserRouter` in regular runs, `MemoryRouter` in tests/CI). +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/frontend-app-api@0.5.0 + - @backstage/test-utils@1.4.7 + - @backstage/types@1.1.1 + +## 0.1.1-next.2 + +### Patch Changes + +- 516fd3e: Updated README to reflect release status +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.1-next.2 + - @backstage/frontend-app-api@0.4.1-next.2 + +## 0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-app-api@0.4.1-next.1 + - @backstage/frontend-plugin-api@0.4.1-next.1 + - @backstage/test-utils@1.4.7-next.1 + - @backstage/types@1.1.1 + +## 0.1.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.1-next.0 + - @backstage/frontend-app-api@0.4.1-next.0 + - @backstage/test-utils@1.4.7-next.0 + - @backstage/types@1.1.1 + +## 0.1.0 + +### Minor Changes + +- 59fabd5: New testing utility library for `@backstage/frontend-app-api` and `@backstage/frontend-plugin-api`. +- af7bc3e: Switched all core extensions to instead use the namespace `'app'`. + +### Patch Changes + +- 59fabd5: Added `createExtensionTester` for rendering extensions in tests. +- 7e4b0db: The `createExtensionTester` helper is now able to render more than one route in the test app. +- 818eea4: Updates for compatibility with the new extension IDs. +- b9aa6e4: Migrate `renderInTestApp` to `@backstage/frontend-test-utils` for testing individual React components in an app. +- e539735: Updates for `core.router` addition. +- c21c9cf: Re-export mock API implementations as well as `TestApiProvider`, `TestApiRegistry`, `withLogCollector`, and `setupRequestMockHandlers` from `@backstage/test-utils`. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0 + - @backstage/frontend-app-api@0.4.0 + - @backstage/test-utils@1.4.6 + - @backstage/types@1.1.1 + +## 0.1.0-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-app-api@0.4.0-next.3 + - @backstage/frontend-plugin-api@0.4.0-next.3 + - @backstage/test-utils@1.4.6-next.2 + - @backstage/types@1.1.1 + +## 0.1.0-next.2 + +### Patch Changes + +- 818eea4: Updates for compatibility with the new extension IDs. +- b9aa6e4: Migrate `renderInTestApp` to `@backstage/frontend-test-utils` for testing individual React components in an app. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.2 + - @backstage/frontend-app-api@0.4.0-next.2 + - @backstage/test-utils@1.4.6-next.2 + - @backstage/types@1.1.1 + +## 0.1.0-next.1 + +### Patch Changes + +- e539735435: Updates for `core.router` addition. +- c21c9cf07b: Re-export mock API implementations as well as `TestApiProvider`, `TestApiRegistry`, `withLogCollector`, and `setupRequestMockHandlers` from `@backstage/test-utils`. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/frontend-app-api@0.4.0-next.1 + - @backstage/test-utils@1.4.6-next.1 + - @backstage/types@1.1.1 + +## 0.1.0-next.0 + +### Minor Changes + +- 59fabd5106: New testing utility library for `@backstage/frontend-app-api` and `@backstage/frontend-plugin-api`. + +### Patch Changes + +- 59fabd5106: Added `createExtensionTester` for rendering extensions in tests. +- Updated dependencies + - @backstage/frontend-app-api@0.3.1-next.0 + - @backstage/frontend-plugin-api@0.3.1-next.0 + - @backstage/test-utils@1.4.6-next.0 + - @backstage/types@1.1.1 diff --git a/packages/frontend-test-utils/README.md b/packages/frontend-test-utils/README.md new file mode 100644 index 0000000000..455d112773 --- /dev/null +++ b/packages/frontend-test-utils/README.md @@ -0,0 +1,14 @@ +# @backstage/frontend-test-utils + +**The [new frontend system](https://backstage.io/docs/frontend-system/) that this package is part of is in alpha, and we do not yet recommend using it for production deployments** + +Contains utilities that can be used when testing frontend features such as extensions. + +## Installation + +Install the package via Yarn into your own packages: + +```sh +cd # if within a monorepo +yarn add --dev @backstage/frontend-test-utils +``` diff --git a/packages/frontend-test-utils/api-report.md b/packages/frontend-test-utils/api-report.md new file mode 100644 index 0000000000..d67518050d --- /dev/null +++ b/packages/frontend-test-utils/api-report.md @@ -0,0 +1,87 @@ +## API Report File for "@backstage/frontend-test-utils" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +/// + +import { AnalyticsApi } from '@backstage/frontend-plugin-api'; +import { AnalyticsEvent } from '@backstage/frontend-plugin-api'; +import { ErrorWithContext } from '@backstage/test-utils'; +import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; +import { JsonObject } from '@backstage/types'; +import { MockConfigApi } from '@backstage/test-utils'; +import { MockErrorApi } from '@backstage/test-utils'; +import { MockErrorApiOptions } from '@backstage/test-utils'; +import { MockFetchApi } from '@backstage/test-utils'; +import { MockFetchApiOptions } from '@backstage/test-utils'; +import { MockPermissionApi } from '@backstage/test-utils'; +import { MockStorageApi } from '@backstage/test-utils'; +import { MockStorageBucket } from '@backstage/test-utils'; +import { RenderResult } from '@testing-library/react'; +import { setupRequestMockHandlers } from '@backstage/test-utils'; +import { TestApiProvider } from '@backstage/test-utils'; +import { TestApiProviderProps } from '@backstage/test-utils'; +import { TestApiRegistry } from '@backstage/test-utils'; +import { withLogCollector } from '@backstage/test-utils'; + +// @public (undocumented) +export function createExtensionTester( + subject: ExtensionDefinition, + options?: { + config?: TConfig; + }, +): ExtensionTester; + +export { ErrorWithContext }; + +// @public (undocumented) +export class ExtensionTester { + // (undocumented) + add( + extension: ExtensionDefinition, + options?: { + config?: TConfig; + }, + ): ExtensionTester; + // (undocumented) + render(options?: { config?: JsonObject }): RenderResult; +} + +// @public +export class MockAnalyticsApi implements AnalyticsApi { + // (undocumented) + captureEvent(event: AnalyticsEvent): void; + // (undocumented) + getEvents(): AnalyticsEvent[]; +} + +export { MockConfigApi }; + +export { MockErrorApi }; + +export { MockErrorApiOptions }; + +export { MockFetchApi }; + +export { MockFetchApiOptions }; + +export { MockPermissionApi }; + +export { MockStorageApi }; + +export { MockStorageBucket }; + +// @public +export function renderInTestApp(element: JSX.Element): RenderResult; + +export { setupRequestMockHandlers }; + +export { TestApiProvider }; + +export { TestApiProviderProps }; + +export { TestApiRegistry }; + +export { withLogCollector }; +``` diff --git a/packages/frontend-test-utils/catalog-info.yaml b/packages/frontend-test-utils/catalog-info.yaml new file mode 100644 index 0000000000..e2d2a57897 --- /dev/null +++ b/packages/frontend-test-utils/catalog-info.yaml @@ -0,0 +1,9 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: backstage-frontend-test-utils + title: '@backstage/frontend-test-utils' +spec: + lifecycle: experimental + type: backstage-web-library + owner: maintainers diff --git a/packages/frontend-test-utils/package.json b/packages/frontend-test-utils/package.json new file mode 100644 index 0000000000..fbe9e3dec6 --- /dev/null +++ b/packages/frontend-test-utils/package.json @@ -0,0 +1,44 @@ +{ + "name": "@backstage/frontend-test-utils", + "version": "0.1.1", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "main": "dist/index.esm.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "web-library" + }, + "sideEffects": false, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "devDependencies": { + "@backstage/cli": "workspace:^", + "@testing-library/jest-dom": "^6.0.0", + "@types/react": "*" + }, + "files": [ + "dist" + ], + "dependencies": { + "@backstage/frontend-app-api": "workspace:^", + "@backstage/frontend-plugin-api": "workspace:^", + "@backstage/test-utils": "workspace:^", + "@backstage/types": "workspace:^" + }, + "peerDependencies": { + "@testing-library/react": "^12.1.3 || ^13.0.0 || ^14.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-router-dom": "6.0.0-beta.0 || ^6.3.0" + } +} diff --git a/packages/frontend-test-utils/src/apis/AnalyticsApi/MockAnalyticsApi.test.ts b/packages/frontend-test-utils/src/apis/AnalyticsApi/MockAnalyticsApi.test.ts new file mode 100644 index 0000000000..a84ffd91aa --- /dev/null +++ b/packages/frontend-test-utils/src/apis/AnalyticsApi/MockAnalyticsApi.test.ts @@ -0,0 +1,64 @@ +/* + * 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 { MockAnalyticsApi } from './MockAnalyticsApi'; + +describe('MockAnalyticsApi', () => { + const context = { + pluginId: 'some-plugin', + extensionId: 'some-extension', + }; + + it('should collect events', () => { + const api = new MockAnalyticsApi(); + + api.captureEvent({ action: 'action-1', subject: 'subject-1', context }); + api.captureEvent({ + action: 'action-2', + subject: 'subject-2', + value: 42, + context, + }); + api.captureEvent({ + action: 'action-3', + subject: 'subject-3', + value: 1337, + attributes: { some: 'context' }, + context, + }); + + expect(api.getEvents()[0]).toMatchObject({ + subject: 'subject-1', + action: 'action-1', + context, + }); + expect(api.getEvents()[1]).toMatchObject({ + subject: 'subject-2', + action: 'action-2', + value: 42, + context, + }); + expect(api.getEvents()[2]).toMatchObject({ + subject: 'subject-3', + action: 'action-3', + value: 1337, + context, + attributes: { + some: 'context', + }, + }); + }); +}); diff --git a/packages/frontend-test-utils/src/apis/AnalyticsApi/MockAnalyticsApi.ts b/packages/frontend-test-utils/src/apis/AnalyticsApi/MockAnalyticsApi.ts new file mode 100644 index 0000000000..f6ccf4e9d1 --- /dev/null +++ b/packages/frontend-test-utils/src/apis/AnalyticsApi/MockAnalyticsApi.ts @@ -0,0 +1,43 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { AnalyticsApi, AnalyticsEvent } from '@backstage/frontend-plugin-api'; + +/** + * Mock implementation of {@link frontend-plugin-api#AnalyticsApi} with helpers to ensure that events are sent correctly. + * Use getEvents in tests to verify captured events. + * + * @public + */ +export class MockAnalyticsApi implements AnalyticsApi { + private events: AnalyticsEvent[] = []; + + captureEvent(event: AnalyticsEvent) { + const { action, subject, value, attributes, context } = event; + + this.events.push({ + action, + subject, + context, + ...(value !== undefined ? { value } : {}), + ...(attributes !== undefined ? { attributes } : {}), + }); + } + + getEvents(): AnalyticsEvent[] { + return this.events; + } +} diff --git a/packages/frontend-test-utils/src/apis/AnalyticsApi/index.ts b/packages/frontend-test-utils/src/apis/AnalyticsApi/index.ts new file mode 100644 index 0000000000..dc5fd062aa --- /dev/null +++ b/packages/frontend-test-utils/src/apis/AnalyticsApi/index.ts @@ -0,0 +1,17 @@ +/* + * 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 { MockAnalyticsApi } from './MockAnalyticsApi'; diff --git a/packages/frontend-test-utils/src/apis/index.ts b/packages/frontend-test-utils/src/apis/index.ts new file mode 100644 index 0000000000..1230be9be0 --- /dev/null +++ b/packages/frontend-test-utils/src/apis/index.ts @@ -0,0 +1,29 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { + MockConfigApi, + type ErrorWithContext, + MockErrorApi, + type MockErrorApiOptions, + MockFetchApi, + type MockFetchApiOptions, + MockPermissionApi, + MockStorageApi, + type MockStorageBucket, +} from '@backstage/test-utils'; + +export { MockAnalyticsApi } from './AnalyticsApi/MockAnalyticsApi'; diff --git a/packages/frontend-test-utils/src/app/createExtensionTester.test.tsx b/packages/frontend-test-utils/src/app/createExtensionTester.test.tsx new file mode 100644 index 0000000000..d53344f7fd --- /dev/null +++ b/packages/frontend-test-utils/src/app/createExtensionTester.test.tsx @@ -0,0 +1,232 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, { useCallback } from 'react'; +import { Link } from 'react-router-dom'; +import { fireEvent, screen, waitFor } from '@testing-library/react'; +import { + analyticsApiRef, + configApiRef, + coreExtensionData, + createApiExtension, + createApiFactory, + createExtension, + createSchemaFromZod, + useAnalytics, + useApi, +} from '@backstage/frontend-plugin-api'; +import { MockAnalyticsApi } from '../apis'; +import { createExtensionTester } from './createExtensionTester'; + +describe('createExtensionTester', () => { + const defaultDefinition = { + namespace: 'test', + attachTo: { id: 'ignored', input: 'ignored' }, + output: { element: coreExtensionData.reactElement }, + factory: () => ({ element:
test
}), + }; + + it('should render a simple extension', async () => { + const extension = createExtension(defaultDefinition); + const tester = createExtensionTester(extension); + tester.render(); + await expect(screen.findByText('test')).resolves.toBeInTheDocument(); + }); + + it('should render an extension even if disabled by default', async () => { + const extension = createExtension({ + ...defaultDefinition, + disabled: true, + }); + const tester = createExtensionTester(extension); + tester.render(); + await expect(screen.findByText('test')).resolves.toBeInTheDocument(); + }); + + it("should fail to render an extension that doesn't output a react element", async () => { + const extension = createExtension({ + ...defaultDefinition, + output: { path: coreExtensionData.routePath }, + factory: () => ({ path: '/foo' }), + }); + const tester = createExtensionTester(extension); + expect(() => tester.render()).toThrow( + "Failed to instantiate extension 'app/routes', input 'routes' did not receive required extension data 'core.reactElement' from extension 'test'", + ); + }); + + it('should render multiple extensions', async () => { + const indexPageExtension = createExtension({ + ...defaultDefinition, + factory: () => ({ + element: ( +
+ Index page See details +
+ ), + }), + }); + const detailsPageExtension = createExtension({ + ...defaultDefinition, + name: 'details', + attachTo: { id: 'app/routes', input: 'routes' }, + output: { + path: coreExtensionData.routePath, + element: coreExtensionData.reactElement, + }, + factory: () => ({ path: '/details', element:
Details page
}), + }); + + const tester = createExtensionTester(indexPageExtension); + tester.add(detailsPageExtension); + tester.render(); + + await expect(screen.findByText('Index page')).resolves.toBeInTheDocument(); + + fireEvent.click(screen.getByRole('link', { name: 'See details' })); + + await expect( + screen.findByText('Details page'), + ).resolves.toBeInTheDocument(); + }); + + it('should accepts a custom config', async () => { + const indexPageExtension = createExtension({ + ...defaultDefinition, + configSchema: createSchemaFromZod(z => + z.object({ title: z.string().optional() }), + ), + factory: ({ config }) => { + const Component = () => { + const configApi = useApi(configApiRef); + const appTitle = configApi.getOptionalString('app.title'); + return ( +
+

{appTitle ?? 'Backstafe app'}

+

{config.title ?? 'Index page'}

+ See details +
+ ); + }; + return { + element: , + }; + }, + }); + + const detailsPageExtension = createExtension({ + ...defaultDefinition, + name: 'details', + attachTo: { id: 'app/routes', input: 'routes' }, + configSchema: createSchemaFromZod(z => + z.object({ title: z.string().optional() }), + ), + output: { + path: coreExtensionData.routePath, + element: coreExtensionData.reactElement, + }, + factory: ({ config }) => ({ + path: '/details', + element:
{config.title ?? 'Details page'}
, + }), + }); + + const tester = createExtensionTester(indexPageExtension, { + config: { title: 'Custom index' }, + }); + + tester.add(detailsPageExtension, { + config: { title: 'Custom details' }, + }); + + tester.render({ + config: { + app: { + title: 'Custom app', + }, + }, + }); + + await expect( + screen.findByRole('heading', { name: 'Custom app' }), + ).resolves.toBeInTheDocument(); + + await expect( + screen.findByRole('heading', { name: 'Custom index' }), + ).resolves.toBeInTheDocument(); + + fireEvent.click(screen.getByRole('link', { name: 'See details' })); + + await expect( + screen.findByText('Custom details'), + ).resolves.toBeInTheDocument(); + }); + + it('should capture click events in analytics', async () => { + // Mocking the analytics api implementation + const analyticsApiMock = new MockAnalyticsApi(); + + const analyticsApiOverride = createApiExtension({ + factory: createApiFactory({ + api: analyticsApiRef, + deps: {}, + factory: () => analyticsApiMock, + }), + }); + + const indexPageExtension = createExtension({ + ...defaultDefinition, + factory: () => { + const Component = () => { + const analyticsApi = useAnalytics(); + const handleClick = useCallback(() => { + analyticsApi.captureEvent('click', 'See details'); + }, [analyticsApi]); + return ( +
+ Index Page + +
+ ); + }; + + return { + element: , + }; + }, + }); + + const tester = createExtensionTester(indexPageExtension); + + // Overriding the analytics api extension + tester.add(analyticsApiOverride); + + tester.render(); + + fireEvent.click(await screen.findByRole('button', { name: 'See details' })); + + await waitFor(() => + expect(analyticsApiMock.getEvents()).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + action: 'click', + subject: 'See details', + }), + ]), + ), + ); + }); +}); diff --git a/packages/frontend-test-utils/src/app/createExtensionTester.tsx b/packages/frontend-test-utils/src/app/createExtensionTester.tsx new file mode 100644 index 0000000000..a98879fbba --- /dev/null +++ b/packages/frontend-test-utils/src/app/createExtensionTester.tsx @@ -0,0 +1,203 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { MemoryRouter, Link } from 'react-router-dom'; +import { RenderResult, render } from '@testing-library/react'; +import { createSpecializedApp } from '@backstage/frontend-app-api'; +import { + ExtensionDefinition, + IconComponent, + RouteRef, + coreExtensionData, + createExtension, + createExtensionInput, + createExtensionOverrides, + createNavItemExtension, + createRouterExtension, + useRouteRef, +} from '@backstage/frontend-plugin-api'; +import { MockConfigApi } from '@backstage/test-utils'; +import { JsonArray, JsonObject, JsonValue } from '@backstage/types'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { resolveExtensionDefinition } from '../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { toInternalExtensionDefinition } from '../../../frontend-plugin-api/src/wiring/createExtension'; + +const NavItem = (props: { + routeRef: RouteRef; + title: string; + icon: IconComponent; +}) => { + const { routeRef, title, icon: Icon } = props; + const to = useRouteRef(routeRef)(); + return ( +
  • + + {title} + +
  • + ); +}; + +const TestAppNavExtension = createExtension({ + namespace: 'app', + name: 'nav', + attachTo: { id: 'app/layout', input: 'nav' }, + inputs: { + items: createExtensionInput({ + target: createNavItemExtension.targetDataRef, + }), + }, + output: { + element: coreExtensionData.reactElement, + }, + factory({ inputs }) { + return { + element: ( + + ), + }; + }, +}); + +/** @public */ +export class ExtensionTester { + /** @internal */ + static forSubject( + subject: ExtensionDefinition, + options?: { config?: TConfig }, + ): ExtensionTester { + const tester = new ExtensionTester(); + const { output, factory, ...rest } = toInternalExtensionDefinition(subject); + // attaching to app/routes to render as index route + const extension = createExtension({ + ...rest, + attachTo: { id: 'app/routes', input: 'routes' }, + output: { + ...output, + path: coreExtensionData.routePath, + }, + factory: params => ({ + ...factory(params), + path: '/', + }), + }); + tester.add(extension, options); + return tester; + } + + readonly #extensions = new Array<{ + id: string; + definition: ExtensionDefinition; + config?: JsonValue; + }>(); + + add( + extension: ExtensionDefinition, + options?: { config?: TConfig }, + ): ExtensionTester { + const { name, namespace } = extension; + + const definition = { + ...extension, + // setting name "test" as fallback + name: !namespace && !name ? 'test' : name, + }; + + const { id } = resolveExtensionDefinition(definition); + + this.#extensions.push({ + id, + definition, + config: options?.config as JsonValue, + }); + + return this; + } + + render(options?: { config?: JsonObject }): RenderResult { + const { config = {} } = options ?? {}; + + const [subject, ...rest] = this.#extensions; + if (!subject) { + throw new Error( + 'No subject found. At least one extension should be added to the tester.', + ); + } + + const extensionsConfig: JsonArray = [ + ...rest.map(extension => ({ + [extension.id]: { + config: extension.config, + }, + })), + { + [subject.id]: { + config: subject.config, + disabled: false, + }, + }, + ]; + + const finalConfig = { + ...config, + app: { + ...(typeof config.app === 'object' ? config.app : undefined), + extensions: extensionsConfig, + }, + }; + + const app = createSpecializedApp({ + features: [ + createExtensionOverrides({ + extensions: [ + ...this.#extensions.map(extension => extension.definition), + TestAppNavExtension, + createRouterExtension({ + namespace: 'test', + Component: ({ children }) => ( + {children} + ), + }), + ], + }), + ], + config: new MockConfigApi(finalConfig), + }); + + return render(app.createRoot()); + } +} + +/** @public */ +export function createExtensionTester( + subject: ExtensionDefinition, + options?: { config?: TConfig }, +): ExtensionTester { + return ExtensionTester.forSubject(subject, options); +} diff --git a/packages/frontend-test-utils/src/app/index.ts b/packages/frontend-test-utils/src/app/index.ts new file mode 100644 index 0000000000..3f19146c5c --- /dev/null +++ b/packages/frontend-test-utils/src/app/index.ts @@ -0,0 +1,22 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { + createExtensionTester, + type ExtensionTester, +} from './createExtensionTester'; + +export { renderInTestApp } from './renderInTestApp'; diff --git a/packages/frontend-test-utils/src/app/renderInTestApp.test.tsx b/packages/frontend-test-utils/src/app/renderInTestApp.test.tsx new file mode 100644 index 0000000000..a56ae2f140 --- /dev/null +++ b/packages/frontend-test-utils/src/app/renderInTestApp.test.tsx @@ -0,0 +1,68 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, { useCallback } from 'react'; +import { screen, fireEvent } from '@testing-library/react'; +import { + MockAnalyticsApi, + TestApiProvider, +} from '@backstage/frontend-test-utils'; +import { analyticsApiRef, useAnalytics } from '@backstage/frontend-plugin-api'; +import { renderInTestApp } from './renderInTestApp'; + +describe('renderInTestApp', () => { + it('should render the given component in a page', async () => { + const IndexPage = () =>
    Index Page
    ; + renderInTestApp(); + expect(screen.getByText('Index Page')).toBeInTheDocument(); + }); + + it('should works with apis provider', async () => { + const IndexPage = () => { + const analyticsApi = useAnalytics(); + const handleClick = useCallback(() => { + analyticsApi.captureEvent('click', 'See details'); + }, [analyticsApi]); + return ( +
    + Index Page + + See details + +
    + ); + }; + + const analyticsApiMock = new MockAnalyticsApi(); + + renderInTestApp( + + + , + ); + + fireEvent.click(screen.getByRole('link', { name: 'See details' })); + + expect(analyticsApiMock.getEvents()).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + action: 'click', + subject: 'See details', + }), + ]), + ); + }); +}); diff --git a/packages/frontend-test-utils/src/app/renderInTestApp.tsx b/packages/frontend-test-utils/src/app/renderInTestApp.tsx new file mode 100644 index 0000000000..0cd05741b0 --- /dev/null +++ b/packages/frontend-test-utils/src/app/renderInTestApp.tsx @@ -0,0 +1,38 @@ +/* + * 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 { + coreExtensionData, + createExtension, +} from '@backstage/frontend-plugin-api'; +import { createExtensionTester } from './createExtensionTester'; + +/** + * @public + * Renders the given element in a test app, for use in unit tests. + */ +export function renderInTestApp(element: JSX.Element) { + const extension = createExtension({ + namespace: 'test', + attachTo: { id: 'app', input: 'root' }, + output: { + element: coreExtensionData.reactElement, + }, + factory: () => ({ element }), + }); + const tester = createExtensionTester(extension); + return tester.render(); +} diff --git a/packages/frontend-test-utils/src/index.ts b/packages/frontend-test-utils/src/index.ts new file mode 100644 index 0000000000..0dab8e75b7 --- /dev/null +++ b/packages/frontend-test-utils/src/index.ts @@ -0,0 +1,31 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @packageDocumentation + * + * Contains utilities that can be used when testing frontend features such as extensions. + */ + +export * from './apis'; +export * from './app'; + +export { TestApiProvider, TestApiRegistry } from '@backstage/test-utils'; +export type { TestApiProviderProps } from '@backstage/test-utils'; + +export { withLogCollector } from '@backstage/test-utils'; + +export { setupRequestMockHandlers } from '@backstage/test-utils'; diff --git a/packages/frontend-test-utils/src/setupTests.ts b/packages/frontend-test-utils/src/setupTests.ts new file mode 100644 index 0000000000..c30f1d15cb --- /dev/null +++ b/packages/frontend-test-utils/src/setupTests.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. + */ + +import '@testing-library/jest-dom'; diff --git a/packages/integration-aws-node/CHANGELOG.md b/packages/integration-aws-node/CHANGELOG.md index 87156a5623..175541de5f 100644 --- a/packages/integration-aws-node/CHANGELOG.md +++ b/packages/integration-aws-node/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/integration-aws-node +## 0.1.8 + +### Patch Changes + +- 20d97d28a3: Updated dependency `aws-sdk-client-mock-jest` to `^3.0.0`. +- 3d043526f4: Updated dependency `aws-sdk-client-mock` to `^3.0.0`. +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + ## 0.1.7 ### Patch Changes diff --git a/packages/integration-aws-node/package.json b/packages/integration-aws-node/package.json index 00edc99503..92108c1cca 100644 --- a/packages/integration-aws-node/package.json +++ b/packages/integration-aws-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/integration-aws-node", "description": "Helpers for fetching AWS account credentials", - "version": "0.1.7", + "version": "0.1.8", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/integration-react/CHANGELOG.md b/packages/integration-react/CHANGELOG.md index a23564adad..fd6a47e4e7 100644 --- a/packages/integration-react/CHANGELOG.md +++ b/packages/integration-react/CHANGELOG.md @@ -1,5 +1,60 @@ # @backstage/integration-react +## 1.1.23 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + +## 1.1.23-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + +## 1.1.22 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + +## 1.1.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/config@1.1.1 + +## 1.1.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/config@1.1.1 + +## 1.1.21 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/integration@1.7.2 + - @backstage/core-plugin-api@1.8.0 + - @backstage/config@1.1.1 + ## 1.1.21-next.1 ### Patch Changes diff --git a/packages/integration-react/package.json b/packages/integration-react/package.json index 807ae468d0..f1592628ab 100644 --- a/packages/integration-react/package.json +++ b/packages/integration-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/integration-react", "description": "Frontend package for managing integrations towards external systems", - "version": "1.1.21-next.1", + "version": "1.1.23", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/integration/CHANGELOG.md b/packages/integration/CHANGELOG.md index bf500bc707..8dd9ec3915 100644 --- a/packages/integration/CHANGELOG.md +++ b/packages/integration/CHANGELOG.md @@ -1,5 +1,45 @@ # @backstage/integration +## 1.8.0 + +### Minor Changes + +- 870db76: Implemented `readTree` for Gitea provider to support TechDocs functionality + +### Patch Changes + +- 99fb541: Updated dependency `@azure/identity` to `^4.0.0`. +- Updated dependencies + - @backstage/config@1.1.1 + +## 1.8.0-next.1 + +### Patch Changes + +- 99fb54183b: Updated dependency `@azure/identity` to `^4.0.0`. +- Updated dependencies + - @backstage/config@1.1.1 + +## 1.8.0-next.0 + +### Minor Changes + +- 870db76a45: Implemented `readTree` for Gitea provider to support TechDocs functionality + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.1 + +## 1.7.2 + +### Patch Changes + +- 243c655a68: JSDoc and Error message updates to handle `Azure Active Directory` re-brand to `Entra ID` +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- Updated dependencies + - @backstage/config@1.1.1 + ## 1.7.2-next.0 ### Patch Changes diff --git a/packages/integration/api-report.md b/packages/integration/api-report.md index f64c06257e..634e03dbfc 100644 --- a/packages/integration/api-report.md +++ b/packages/integration/api-report.md @@ -419,12 +419,30 @@ export function getGerritRequestOptions(config: GerritIntegrationConfig): { headers?: Record; }; +// @public +export function getGiteaArchiveUrl( + config: GiteaIntegrationConfig, + url: string, +): string; + +// @public +export function getGiteaEditContentsUrl( + config: GiteaIntegrationConfig, + url: string, +): string; + // @public export function getGiteaFileContentsUrl( config: GiteaIntegrationConfig, url: string, ): string; +// @public +export function getGiteaLatestCommitUrl( + config: GiteaIntegrationConfig, + url: string, +): string; + // @public export function getGiteaRequestOptions(config: GiteaIntegrationConfig): { headers?: Record; @@ -658,6 +676,18 @@ export function parseGerritGitilesUrl( // @public export function parseGerritJsonResponse(response: Response): Promise; +// @public +export function parseGiteaUrl( + config: GiteaIntegrationConfig, + url: string, +): { + url: string; + owner: string; + name: string; + ref: string; + path: string; +}; + // @public export type PersonalAccessTokenCredential = AzureCredentialBase & { kind: 'PersonalAccessToken'; diff --git a/packages/integration/package.json b/packages/integration/package.json index e701d8b1cd..7e57293903 100644 --- a/packages/integration/package.json +++ b/packages/integration/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/integration", "description": "Helpers for managing integrations towards external systems", - "version": "1.7.2-next.0", + "version": "1.8.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,7 +33,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@azure/identity": "^3.2.1", + "@azure/identity": "^4.0.0", "@backstage/config": "workspace:^", "@octokit/auth-app": "^4.0.0", "@octokit/rest": "^19.0.3", diff --git a/packages/integration/src/gitea/core.test.ts b/packages/integration/src/gitea/core.test.ts index 125f3077ef..fe6381d52e 100644 --- a/packages/integration/src/gitea/core.test.ts +++ b/packages/integration/src/gitea/core.test.ts @@ -18,9 +18,12 @@ import { setupServer } from 'msw/node'; import { setupRequestMockHandlers } from '../helpers'; import { GiteaIntegrationConfig } from './config'; import { + getGiteaArchiveUrl, getGiteaEditContentsUrl, getGiteaFileContentsUrl, + getGiteaLatestCommitUrl, getGiteaRequestOptions, + parseGiteaUrl, } from './core'; describe('gitea core', () => { @@ -59,6 +62,38 @@ describe('gitea core', () => { }); }); + describe('getGiteaArchiveUrl', () => { + it('can create an url from arguments', () => { + const config: GiteaIntegrationConfig = { + host: 'gitea.example.com', + }; + expect( + getGiteaArchiveUrl( + config, + 'https://gitea.example.com/owner/repo/src/branch/branch_name', + ), + ).toEqual( + 'https://gitea.example.com/api/v1/repos/owner/repo/archive/branch_name.tar.gz', + ); + }); + }); + + describe('getGiteaLatestCommitUrl', () => { + it('can create an url from arguments', () => { + const config: GiteaIntegrationConfig = { + host: 'gitea.example.com', + }; + expect( + getGiteaLatestCommitUrl( + config, + 'https://gitea.example.com/owner/repo/src/branch/branch_name/', + ), + ).toEqual( + 'https://gitea.example.com/api/v1/repos/owner/repo/git/commits/branch_name', + ); + }); + }); + describe('getGerritRequestOptions', () => { it('adds token header when only a password is specified', () => { const authRequest: GiteaIntegrationConfig = { @@ -90,4 +125,61 @@ describe('gitea core', () => { ).toEqual(basicAuthentication); }); }); + + describe('parseGiteaUrl', () => { + it('can fetch gitea url', () => { + const config: GiteaIntegrationConfig = { + host: 'gitea.example.com', + }; + expect( + parseGiteaUrl( + config, + 'https://gitea.example.com/owner/repo/src/branch/branch_name/', + ), + ).toEqual({ + url: 'https://gitea.example.com', + owner: 'owner', + name: 'repo', + ref: 'branch_name', + path: '', + }); + }); + + it('provide path without starting slash', () => { + const config: GiteaIntegrationConfig = { + host: 'gitea.example.com', + }; + expect( + parseGiteaUrl( + config, + 'https://gitea.example.com/owner/repo/src/branch/branch_name/simple/path', + ), + ).toEqual({ + url: 'https://gitea.example.com', + owner: 'owner', + name: 'repo', + ref: 'branch_name', + path: 'simple/path', + }); + }); + + it('use base url if provided', () => { + const config: GiteaIntegrationConfig = { + host: 'gitea.example.com', + baseUrl: 'https://base-gitea.example.com', + }; + expect( + parseGiteaUrl( + config, + 'https://base-gitea.example.com/owner/repo/src/branch/branch_name/', + ), + ).toEqual({ + url: 'https://base-gitea.example.com', + owner: 'owner', + name: 'repo', + ref: 'branch_name', + path: '', + }); + }); + }); }); diff --git a/packages/integration/src/gitea/core.ts b/packages/integration/src/gitea/core.ts index ee3fec12fc..95caa24c06 100644 --- a/packages/integration/src/gitea/core.ts +++ b/packages/integration/src/gitea/core.ts @@ -33,16 +33,8 @@ export function getGiteaEditContentsUrl( config: GiteaIntegrationConfig, url: string, ) { - try { - const baseUrl = config.baseUrl ?? `https://${config.host}`; - const [_blank, owner, name, _src, _branch, ref, ...path] = url - .replace(baseUrl, '') - .split('/'); - const pathWithoutSlash = path.join('/').replace(/^\//, ''); - return `${baseUrl}/${owner}/${name}/_edit/${ref}/${pathWithoutSlash}`; - } catch (e) { - throw new Error(`Incorrect URL: ${url}, ${e}`); - } + const giteaUrl = parseGiteaUrl(config, url); + return `${giteaUrl.url}/${giteaUrl.owner}/${giteaUrl.name}/_edit/${giteaUrl.ref}/${giteaUrl.path}`; } /** @@ -63,17 +55,52 @@ export function getGiteaFileContentsUrl( config: GiteaIntegrationConfig, url: string, ) { - try { - const baseUrl = config.baseUrl ?? `https://${config.host}`; - const [_blank, owner, name, _src, _branch, ref, ...path] = url - .replace(baseUrl, '') - .split('/'); - const pathWithoutSlash = path.join('/').replace(/^\//, ''); + const giteaUrl = parseGiteaUrl(config, url); + return `${giteaUrl.url}/api/v1/repos/${giteaUrl.owner}/${giteaUrl.name}/contents/${giteaUrl.path}?ref=${giteaUrl.ref}`; +} - return `${baseUrl}/api/v1/repos/${owner}/${name}/contents/${pathWithoutSlash}?ref=${ref}`; - } catch (e) { - throw new Error(`Incorrect URL: ${url}, ${e}`); - } +/** + * Given a URL pointing to a repository/path, returns a URL + * for archive contents of the repository. + * + * @remarks + * + * Converts + * from: https://gitea.com/a/b/src/branchname + * or: https://gitea.com/api/v1/repos/a/b/archive/branchname.tar.gz + * + * @param url - A URL pointing to a repository/path + * @param config - The relevant provider config + * @public + */ +export function getGiteaArchiveUrl( + config: GiteaIntegrationConfig, + url: string, +) { + const giteaUrl = parseGiteaUrl(config, url); + return `${giteaUrl.url}/api/v1/repos/${giteaUrl.owner}/${giteaUrl.name}/archive/${giteaUrl.ref}.tar.gz`; +} + +/** + * Given a URL pointing to a repository branch, returns a URL + * for latest commit information. + * + * @remarks + * + * Converts + * from: https://gitea.com/a/b/src/branchname + * or: https://gitea.com/api/v1/repos/a/b/git/commits/branchname + * + * @param url - A URL pointing to a repository branch + * @param config - The relevant provider config + * @public + */ +export function getGiteaLatestCommitUrl( + config: GiteaIntegrationConfig, + url: string, +) { + const giteaUrl = parseGiteaUrl(config, url); + return `${giteaUrl.url}/api/v1/repos/${giteaUrl.owner}/${giteaUrl.name}/git/commits/${giteaUrl.ref}`; } /** @@ -104,3 +131,39 @@ export function getGiteaRequestOptions(config: GiteaIntegrationConfig): { headers, }; } + +/** + * Return parsed git url properties. + * + * @param config - A Gitea provider config + * @param url - A URL pointing to a repository + * @public + */ +export function parseGiteaUrl( + config: GiteaIntegrationConfig, + url: string, +): { + url: string; + owner: string; + name: string; + ref: string; + path: string; +} { + const baseUrl = config.baseUrl ?? `https://${config.host}`; + try { + const [_blank, owner, name, _src, _branch, ref, ...path] = url + .replace(baseUrl, '') + .split('/'); + const pathWithoutSlash = path.join('/').replace(/^\//, ''); + + return { + url: baseUrl, + owner: owner, + name: name, + ref: ref, + path: pathWithoutSlash, + }; + } catch (e) { + throw new Error(`Incorrect URL: ${url}, ${e}`); + } +} diff --git a/packages/integration/src/gitea/index.ts b/packages/integration/src/gitea/index.ts index 6b951b1fb0..071509d699 100644 --- a/packages/integration/src/gitea/index.ts +++ b/packages/integration/src/gitea/index.ts @@ -14,6 +14,13 @@ * limitations under the License. */ export { GiteaIntegration } from './GiteaIntegration'; -export { getGiteaRequestOptions, getGiteaFileContentsUrl } from './core'; +export { + getGiteaEditContentsUrl, + getGiteaFileContentsUrl, + getGiteaArchiveUrl, + getGiteaLatestCommitUrl, + getGiteaRequestOptions, + parseGiteaUrl, +} from './core'; export { readGiteaConfig } from './config'; export type { GiteaIntegrationConfig } from './config'; diff --git a/packages/release-manifests/CHANGELOG.md b/packages/release-manifests/CHANGELOG.md index 001c7b2055..2176118ea2 100644 --- a/packages/release-manifests/CHANGELOG.md +++ b/packages/release-manifests/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/release-manifests +## 0.0.11 + +### Patch Changes + +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. + ## 0.0.10 ### Patch Changes diff --git a/packages/release-manifests/package.json b/packages/release-manifests/package.json index 0f12ca225a..f9de4d6d2d 100644 --- a/packages/release-manifests/package.json +++ b/packages/release-manifests/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/release-manifests", "description": "Helper library for receiving release manifests", - "version": "0.0.10", + "version": "0.0.11", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/repo-tools/CHANGELOG.md b/packages/repo-tools/CHANGELOG.md index 18ef451c79..02ecf90bdc 100644 --- a/packages/repo-tools/CHANGELOG.md +++ b/packages/repo-tools/CHANGELOG.md @@ -1,5 +1,146 @@ # @backstage/repo-tools +## 0.5.2 + +### Patch Changes + +- 883782e: Updated the OpenAPI template to export the `TypedResponse` interface so that client code can leverage it +- 7acbb5a: Removed `mock-fs` dev dependency. +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/cli-node@0.2.2 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + +## 0.5.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.2 + - @backstage/cli-node@0.2.2-next.0 + +## 0.5.2-next.1 + +### Patch Changes + +- 7acbb5a: Removed `mock-fs` dev dependency. +- Updated dependencies + - @backstage/cli-node@0.2.2-next.0 + - @backstage/backend-common@0.20.1-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + +## 0.5.2-next.0 + +### Patch Changes + +- 883782e: Updated the OpenAPI template to export the `TypedResponse` interface so that client code can leverage it +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.1 + - @backstage/errors@1.2.3 + +## 0.5.0 + +### Minor Changes + +- aea8f8d: **BREAKING**: API Reports generated for sub-path exports now place the name as a suffix rather than prefix, for example `api-report-alpha.md` instead of `alpha-api-report.md`. When upgrading to this version you'll need to re-create any such API reports and delete the old ones. +- 3834067: Adds a new command `schema openapi generate-client` that creates a Typescript client with Backstage flavor, including the discovery API and fetch API. This command doesn't currently generate a complete client and needs to be wrapped or exported manually by a separate Backstage plugin. See `@backstage/catalog-client/src/generated` for example output. + +### Patch Changes + +- f909e9d: Includes templates in @backstage/repo-tools package and use them in the CLI +- da3c4db: Updates the `schema openapi generate-client` command to export all generated types from the generated directory. +- 7959f23: The `api-reports` command now checks for api report files that no longer apply. + If it finds such files, it's treated basically the same as report errors do, and + the check fails. + + For example, if you had an `api-report-alpha.md` but then removed the alpha + export, the reports generator would now report that this file needs to be + deleted. + +- f49e237: Fixed a bug where `schema openapi init` created an invalid test command. +- f91be2c: Updated dependency `@stoplight/types` to `^14.0.0`. +- 45bfb20: Execute `openapi-generator-cli` from `@backstage/repo-tools` directory to force it to use our openapitools.json config file. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/cli-node@0.2.1 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + +## 0.5.0-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/errors@1.2.3 + +## 0.5.0-next.1 + +### Patch Changes + +- f909e9d: Includes templates in @backstage/repo-tools package and use them in the CLI +- da3c4db: Updates the `schema openapi generate-client` command to export all generated types from the generated directory. +- 7959f23: The `api-reports` command now checks for api report files that no longer apply. + If it finds such files, it's treated basically the same as report errors do, and + the check fails. + + For example, if you had an `api-report-alpha.md` but then removed the alpha + export, the reports generator would now report that this file needs to be + deleted. + +- f49e237: Fixed a bug where `schema openapi init` created an invalid test command. +- f91be2c: Updated dependency `@stoplight/types` to `^14.0.0`. +- 45bfb20: Execute `openapi-generator-cli` from `@backstage/repo-tools` directory to force it to use our openapitools.json config file. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/errors@1.2.3 + +## 0.5.0-next.0 + +### Minor Changes + +- aea8f8d329: **BREAKING**: API Reports generated for sub-path exports now place the name as a suffix rather than prefix, for example `api-report-alpha.md` instead of `alpha-api-report.md`. When upgrading to this version you'll need to re-create any such API reports and delete the old ones. +- 38340678c3: Adds a new command `schema openapi generate-client` that creates a Typescript client with Backstage flavor, including the discovery API and fetch API. This command doesn't currently generate a complete client and needs to be wrapped or exported manually by a separate Backstage plugin. See `@backstage/catalog-client/src/generated` for example output. + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.2.0 + - @backstage/errors@1.2.3 + +## 0.4.0 + +### Minor Changes + +- 4e36abef14: Remove support for the deprecated `--experimental-type-build` option for `package build`. +- 6694b369a3: Adds a new command `schema openapi test` that performs runtime validation of your OpenAPI specs using your test data. Under the hood, we're using Optic to perform this check, really cool work by them! + + To use this new command, you will have to run `yarn add @useoptic/optic` in the root of your repo. + +### Patch Changes + +- Updated dependencies + - @backstage/cli-node@0.2.0 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + ## 0.4.0-next.0 ### Minor Changes diff --git a/packages/repo-tools/openapitools.json b/packages/repo-tools/openapitools.json new file mode 100644 index 0000000000..65c0d8ead7 --- /dev/null +++ b/packages/repo-tools/openapitools.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../node_modules/@openapitools/openapi-generator-cli/config.schema.json", + "spaces": 2, + "generator-cli": { + "version": "6.5.0" + } +} diff --git a/packages/repo-tools/package.json b/packages/repo-tools/package.json index 663695a764..c8f832af01 100644 --- a/packages/repo-tools/package.json +++ b/packages/repo-tools/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/repo-tools", "description": "CLI for Backstage repo tooling ", - "version": "0.4.0-next.0", + "version": "0.5.2", "publishConfig": { "access": "public" }, @@ -32,6 +32,7 @@ "dependencies": { "@apidevtools/swagger-parser": "^10.1.0", "@apisyouwonthate/style-guide": "^1.4.0", + "@backstage/backend-common": "workspace:^", "@backstage/catalog-model": "workspace:^", "@backstage/cli-common": "workspace:^", "@backstage/cli-node": "workspace:^", @@ -39,13 +40,14 @@ "@manypkg/get-packages": "^1.1.3", "@microsoft/api-documenter": "^7.22.33", "@microsoft/api-extractor": "^7.36.4", + "@openapitools/openapi-generator-cli": "^2.7.0", "@stoplight/spectral-core": "^1.18.0", "@stoplight/spectral-formatters": "^1.1.0", "@stoplight/spectral-functions": "^1.7.2", "@stoplight/spectral-parsers": "^1.0.2", "@stoplight/spectral-rulesets": "^1.18.0", "@stoplight/spectral-runtime": "^1.1.2", - "@stoplight/types": "^13.14.0", + "@stoplight/types": "^14.0.0", "chalk": "^4.0.0", "codeowners-utils": "^1.0.2", "commander": "^9.1.0", @@ -61,13 +63,12 @@ "yaml-diff-patch": "^2.0.0" }, "devDependencies": { + "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@backstage/types": "workspace:^", "@types/is-glob": "^4.0.2", - "@types/mock-fs": "^4.13.0", "@types/node": "^18.17.8", - "@types/prettier": "^2.0.0", - "mock-fs": "^5.2.0" + "@types/prettier": "^2.0.0" }, "peerDependencies": { "@microsoft/api-extractor-model": "*", @@ -84,7 +85,9 @@ }, "files": [ "bin", - "dist/**/*.js" + "dist/**/*.js", + "templates", + "openapitools.json" ], "nodemonConfig": { "watch": "./src", diff --git a/packages/repo-tools/src/commands/api-reports/api-extractor.ts b/packages/repo-tools/src/commands/api-reports/api-extractor.ts index ce3e6f5b20..b8c241bb0b 100644 --- a/packages/repo-tools/src/commands/api-reports/api-extractor.ts +++ b/packages/repo-tools/src/commands/api-reports/api-extractor.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import { groupBy } from 'lodash'; import { resolve as resolvePath, relative as relativePath, @@ -363,7 +364,9 @@ export async function runApiExtraction({ } const warnings = new Array(); - for (const { packageDir, name } of packageEntryPoints) { + for (const [packageDir, group] of Object.entries( + groupBy(packageEntryPoints, ep => ep.packageDir), + )) { console.log(`## Processing ${packageDir}`); const noBail = Array.isArray(allowWarnings) ? allowWarnings.some(aw => aw === packageDir || minimatch(packageDir, aw)) @@ -374,209 +377,242 @@ export async function runApiExtraction({ './dist-types', packageDir, ); + const names = group.map(ep => ep.name); - const prefix = name === 'index' ? '' : `${name}-`; - const reportFileName = `${prefix}api-report.md`; - const reportPath = resolvePath(projectFolder, reportFileName); + const remainingReportFiles = new Set( + fs + .readdirSync(projectFolder) + .filter( + filename => + filename.match(/^(.+)-api-report\.md$/) || + filename.match(/^api-report(-.+)?\.md$/), + ), + ); - const warningCountBefore = await countApiReportWarnings(reportPath); + for (const name of names) { + const suffix = name === 'index' ? '' : `-${name}`; + const reportFileName = `api-report${suffix}.md`; + const reportPath = resolvePath(projectFolder, reportFileName); + remainingReportFiles.delete(reportFileName); - const extractorConfig = ExtractorConfig.prepare({ - configObject: { - mainEntryPointFilePath: resolvePath(packageFolder, `src/${name}.d.ts`), - bundledPackages: [], + const warningCountBefore = await countApiReportWarnings(reportPath); - compiler: { - tsconfigFilePath, - }, - - apiReport: { - enabled: true, - reportFileName, - reportFolder: projectFolder, - reportTempFolder: resolvePath( - outputDir, - `${prefix}`, + const extractorConfig = ExtractorConfig.prepare({ + configObject: { + mainEntryPointFilePath: resolvePath( + packageFolder, + `src/${name}.d.ts`, ), - }, + bundledPackages: [], - docModel: { - // TODO(Rugvip): This skips docs for non-index entry points. We can try to work around it, but - // most likely it makes sense to wait for API Extractor to natively support exports. - enabled: name === 'index', - apiJsonFilePath: resolvePath( - outputDir, - `${prefix}.api.json`, - ), - }, + compiler: { + tsconfigFilePath, + }, - dtsRollup: { - enabled: false, - }, + apiReport: { + enabled: true, + reportFileName, + reportFolder: projectFolder, + reportTempFolder: resolvePath( + outputDir, + `${suffix}`, + ), + }, - tsdocMetadata: { - enabled: false, - }, + docModel: { + // TODO(Rugvip): This skips docs for non-index entry points. We can try to work around it, but + // most likely it makes sense to wait for API Extractor to natively support exports. + enabled: name === 'index', + apiJsonFilePath: resolvePath( + outputDir, + `${suffix}.api.json`, + ), + }, - messages: { - // Silence compiler warnings, as these will prevent the CI build to work - compilerMessageReporting: { - default: { - logLevel: 'none' as ExtractorLogLevel.None, - // These contain absolute file paths, so can't be included in the report - // addToApiReportFile: true, - }, - }, - extractorMessageReporting: { - default: { - logLevel: 'warning' as ExtractorLogLevel.Warning, - addToApiReportFile: true, - }, - ...messagesConf, - }, - tsdocMessageReporting: { - default: { - logLevel: 'warning' as ExtractorLogLevel.Warning, - addToApiReportFile: true, + dtsRollup: { + enabled: false, + }, + + tsdocMetadata: { + enabled: false, + }, + + messages: { + // Silence compiler warnings, as these will prevent the CI build to work + compilerMessageReporting: { + default: { + logLevel: 'none' as ExtractorLogLevel.None, + // These contain absolute file paths, so can't be included in the report + // addToApiReportFile: true, + }, + }, + extractorMessageReporting: { + default: { + logLevel: 'warning' as ExtractorLogLevel.Warning, + addToApiReportFile: true, + }, + ...messagesConf, + }, + tsdocMessageReporting: { + default: { + logLevel: 'warning' as ExtractorLogLevel.Warning, + addToApiReportFile: true, + }, }, }, + + newlineKind: 'lf', + + projectFolder, }, - - newlineKind: 'lf', - - projectFolder, - }, - configObjectFullPath: projectFolder, - packageJsonFullPath: resolvePath(projectFolder, 'package.json'), - tsdocConfigFile: await getTsDocConfig(), - ignoreMissingEntryPoint: true, - }); - - // The `packageFolder` needs to point to the location within `dist-types` in order for relative - // paths to be logged. Unfortunately the `prepare` method above derives it from the `packageJsonFullPath`, - // which needs to point to the actual file, so we override `packageFolder` afterwards. - ( - extractorConfig as { - packageFolder: string; - } - ).packageFolder = packageFolder; - - if (!compilerState) { - compilerState = CompilerState.create(extractorConfig, { - additionalEntryPoints: entryPoints, + configObjectFullPath: projectFolder, + packageJsonFullPath: resolvePath(projectFolder, 'package.json'), + tsdocConfigFile: await getTsDocConfig(), + ignoreMissingEntryPoint: true, }); - } - // Message verbosity can't be configured, so just skip the check instead - (Extractor as any)._checkCompilerCompatibility = () => {}; - - let shouldLogInstructions = false; - let conflictingFile: undefined | string = undefined; - - // Invoke API Extractor - const extractorResult = Extractor.invoke(extractorConfig, { - localBuild: isLocalBuild, - showVerboseMessages: false, - showDiagnostics: false, - messageCallback(message) { - if (message.text.includes('The API report file is missing')) { - shouldLogInstructions = true; + // The `packageFolder` needs to point to the location within `dist-types` in order for relative + // paths to be logged. Unfortunately the `prepare` method above derives it from the `packageJsonFullPath`, + // which needs to point to the actual file, so we override `packageFolder` afterwards. + ( + extractorConfig as { + packageFolder: string; } - if ( - message.text.includes( - 'You have changed the public API signature for this project.', - ) - ) { - shouldLogInstructions = true; - const match = message.text.match( - /Please copy the file "(.*)" to "api-report\.md"/, - ); - if (match) { - conflictingFile = match[1]; + ).packageFolder = packageFolder; + + if (!compilerState) { + compilerState = CompilerState.create(extractorConfig, { + additionalEntryPoints: entryPoints, + }); + } + + // Message verbosity can't be configured, so just skip the check instead + (Extractor as any)._checkCompilerCompatibility = () => {}; + + let shouldLogInstructions = false; + let conflictingFile: undefined | string = undefined; + + // Invoke API Extractor + const extractorResult = Extractor.invoke(extractorConfig, { + localBuild: isLocalBuild, + showVerboseMessages: false, + showDiagnostics: false, + messageCallback(message) { + if (message.text.includes('The API report file is missing')) { + shouldLogInstructions = true; } - } - }, - compilerState, - }); - - // This release tag validation makes sure that the release tag of known entry points match expectations. - // The root index entrypoint is only allowed @public exports, while /alpha and /beta only allow @alpha and @beta. - if ( - validateReleaseTags && - fs.pathExistsSync(extractorConfig.reportFilePath) - ) { - if (['index', 'alpha', 'beta'].includes(name)) { - const report = await fs.readFile( - extractorConfig.reportFilePath, - 'utf8', - ); - const lines = report.split(/\r?\n/); - const expectedTag = name === 'index' ? 'public' : name; - for (let i = 0; i < lines.length; i += 1) { - const line = lines[i]; - const match = line.match(/^\/\/ @(alpha|beta|public)/); - if (match && match[1] !== expectedTag) { - // Because of limitations in the type script rollup logic we need to allow public exports from the other release stages - // TODO(Rugvip): Try to work around the need for this exception - if (expectedTag !== 'public' && match[1] === 'public') { - continue; - } - throw new Error( - `Unexpected release tag ${match[1]} in ${ - extractorConfig.reportFilePath - } at line ${i + 1}`, + if ( + message.text.includes( + 'You have changed the public API signature for this project.', + ) + ) { + shouldLogInstructions = true; + const match = message.text.match( + /Please copy the file "(.*)" to "api-report\.md"/, ); + if (match) { + conflictingFile = match[1]; + } + } + }, + compilerState, + }); + + // This release tag validation makes sure that the release tag of known entry points match expectations. + // The root index entrypoint is only allowed @public exports, while /alpha and /beta only allow @alpha and @beta. + if ( + validateReleaseTags && + fs.pathExistsSync(extractorConfig.reportFilePath) + ) { + if (['index', 'alpha', 'beta'].includes(name)) { + const report = await fs.readFile( + extractorConfig.reportFilePath, + 'utf8', + ); + const lines = report.split(/\r?\n/); + const expectedTag = name === 'index' ? 'public' : name; + for (let i = 0; i < lines.length; i += 1) { + const line = lines[i]; + const match = line.match(/^\/\/ @(alpha|beta|public)/); + if (match && match[1] !== expectedTag) { + // Because of limitations in the type script rollup logic we need to allow public exports from the other release stages + // TODO(Rugvip): Try to work around the need for this exception + if (expectedTag !== 'public' && match[1] === 'public') { + continue; + } + throw new Error( + `Unexpected release tag ${match[1]} in ${ + extractorConfig.reportFilePath + } at line ${i + 1}`, + ); + } } } } - } - - if (!extractorResult.succeeded) { - if (shouldLogInstructions) { - logApiReportInstructions(); - - if (conflictingFile) { - console.log(''); - console.log( - `The conflicting file is ${relativePath( - tmpDir, - conflictingFile, - )}, with the following content:`, - ); - console.log(''); - - const content = await fs.readFile(conflictingFile, 'utf8'); - console.log(content); + if (!extractorResult.succeeded) { + if (shouldLogInstructions) { logApiReportInstructions(); + + if (conflictingFile) { + console.log(''); + console.log( + `The conflicting file is ${relativePath( + tmpDir, + conflictingFile, + )}, with the following content:`, + ); + console.log(''); + + const content = await fs.readFile(conflictingFile, 'utf8'); + console.log(content); + + logApiReportInstructions(); + } } + + throw new Error( + `API Extractor completed with ${extractorResult.errorCount} errors` + + ` and ${extractorResult.warningCount} warnings`, + ); } - throw new Error( - `API Extractor completed with ${extractorResult.errorCount} errors` + - ` and ${extractorResult.warningCount} warnings`, - ); + const warningCountAfter = await countApiReportWarnings(reportPath); + if (noBail) { + console.log(`Skipping warnings check for ${packageDir}`); + } + if (warningCountAfter > 0 && !noBail) { + throw new Error( + `The API Report for ${packageDir} is not allowed to have warnings`, + ); + } + if (warningCountAfter === 0 && allowWarningPkg.includes(packageDir)) { + console.log( + `No need to allow warnings for ${packageDir}, it does not have any`, + ); + } + if (warningCountAfter > warningCountBefore) { + warnings.push( + `The API Report for ${packageDir} introduces new warnings. ` + + 'Please fix these warnings in order to keep the API Reports tidy.', + ); + } } - const warningCountAfter = await countApiReportWarnings(reportPath); - if (noBail) { - console.log(`Skipping warnings check for ${packageDir}`); - } - if (warningCountAfter > 0 && !noBail) { - throw new Error( - `The API Report for ${packageDir} is not allowed to have warnings`, - ); - } - if (warningCountAfter === 0 && allowWarningPkg.includes(packageDir)) { - console.log( - `No need to allow warnings for ${packageDir}, it does not have any`, - ); - } - if (warningCountAfter > warningCountBefore) { - warnings.push( - `The API Report for ${packageDir} introduces new warnings. ` + - 'Please fix these warnings in order to keep the API Reports tidy.', - ); + if (remainingReportFiles.size > 0) { + if (isLocalBuild) { + for (const f of remainingReportFiles) { + fs.rmSync(resolvePath(projectFolder, f)); + console.log(`Deleted deprecated API report ${f}`); + } + } else { + const staleList = [...remainingReportFiles] + .map(f => join(packageDir, f)) + .join(', '); + throw new Error( + `The API Report(s) ${staleList} are no longer relevant and should be deleted`, + ); + } } } diff --git a/packages/repo-tools/src/commands/api-reports/api-reports.test.ts b/packages/repo-tools/src/commands/api-reports/api-reports.test.ts index 0ffd8c5342..d1f7a3836c 100644 --- a/packages/repo-tools/src/commands/api-reports/api-reports.test.ts +++ b/packages/repo-tools/src/commands/api-reports/api-reports.test.ts @@ -14,8 +14,8 @@ * limitations under the License. */ -import mockFs from 'mock-fs'; -import { normalize, resolve as resolvePath } from 'path'; +import { createMockDirectory } from '@backstage/backend-test-utils'; +import { normalize } from 'path'; import * as pathsLib from '../../lib/paths'; import { @@ -47,38 +47,38 @@ jest.mock('./api-extractor', () => ({ const projectPaths = pathsLib.paths; +const mockDir = createMockDirectory(); + +jest.spyOn(projectPaths, 'targetRoot', 'get').mockReturnValue(mockDir.path); jest - .spyOn(projectPaths, 'targetRoot', 'get') - .mockReturnValue(normalize('/root')); -jest.spyOn(projectPaths, 'resolveTargetRoot').mockImplementation((...path) => { - return resolvePath(normalize('/root'), ...path); -}); + .spyOn(projectPaths, 'resolveTargetRoot') + .mockImplementation((...path) => mockDir.resolve(...path)); jest.spyOn(PackageGraph, 'listTargetPackages').mockResolvedValue([ { - dir: '/root/packages/package-a', + dir: normalize(mockDir.resolve('packages/package-a')), packageJson: { name: 'package-a', version: '0.0.0' }, }, { - dir: '/root/packages/package-b', + dir: normalize(mockDir.resolve('packages/package-b')), packageJson: { name: 'package-b', version: '0.0.0' }, }, { - dir: '/root/plugins/plugin-a', + dir: normalize(mockDir.resolve('plugins/plugin-a')), packageJson: { name: 'plugin-a', version: '0.0.0' }, }, { - dir: '/root/plugins/plugin-b', + dir: normalize(mockDir.resolve('plugins/plugin-b')), packageJson: { name: 'plugin-b', version: '0.0.0' }, }, { - dir: '/root/plugins/plugin-c', + dir: normalize(mockDir.resolve('plugins/plugin-c')), packageJson: { name: 'plugin-c', version: '0.0.0' }, }, ]); describe('buildApiReports', () => { beforeEach(() => { - mockFs({ + mockDir.setContent({ [projectPaths.targetRoot]: { 'package.json': JSON.stringify({ workspaces: { packages: ['packages/*', 'plugins/*'] }, @@ -109,7 +109,6 @@ describe('buildApiReports', () => { }); afterEach(() => { - mockFs.restore(); jest.clearAllMocks(); }); @@ -138,11 +137,11 @@ describe('buildApiReports', () => { normalize('plugins/plugin-b'), normalize('plugins/plugin-c'), ], - tsconfigFilePath: resolvePath('/root/tsconfig.json'), + tsconfigFilePath: mockDir.resolve('tsconfig.json'), allowWarnings: [], omitMessages: [], isLocalBuild: true, - outputDir: resolvePath('/root/node_modules/.cache/api-extractor'), + outputDir: mockDir.resolve('node_modules/.cache/api-extractor'), }); expect(runCliExtraction).toHaveBeenCalledWith({ packageDirs: [ @@ -171,11 +170,11 @@ describe('buildApiReports', () => { expect(runApiExtraction).toHaveBeenCalledWith({ packageDirs: [normalize('packages/package-a')], - tsconfigFilePath: resolvePath('/root/tsconfig.json'), + tsconfigFilePath: mockDir.resolve('tsconfig.json'), allowWarnings: [], omitMessages: [], isLocalBuild: true, - outputDir: resolvePath('/root/node_modules/.cache/api-extractor'), + outputDir: mockDir.resolve('node_modules/.cache/api-extractor'), }); expect(runCliExtraction).toHaveBeenCalledWith({ packageDirs: [normalize('packages/package-a')], @@ -200,11 +199,11 @@ describe('buildApiReports', () => { normalize('packages/package-a'), normalize('packages/package-b'), ], - tsconfigFilePath: resolvePath('/root/tsconfig.json'), + tsconfigFilePath: mockDir.resolve('tsconfig.json'), allowWarnings: [], omitMessages: [], isLocalBuild: true, - outputDir: resolvePath('/root/node_modules/.cache/api-extractor'), + outputDir: mockDir.resolve('node_modules/.cache/api-extractor'), }); expect(runCliExtraction).toHaveBeenCalledWith({ packageDirs: [ @@ -232,11 +231,11 @@ describe('buildApiReports', () => { normalize('packages/package-a'), normalize('packages/package-b'), ], - tsconfigFilePath: resolvePath('/root/tsconfig.json'), + tsconfigFilePath: mockDir.resolve('tsconfig.json'), allowWarnings: [], omitMessages: [], isLocalBuild: true, - outputDir: resolvePath('/root/node_modules/.cache/api-extractor'), + outputDir: mockDir.resolve('node_modules/.cache/api-extractor'), }); expect(runCliExtraction).toHaveBeenCalledWith({ packageDirs: [ @@ -267,11 +266,11 @@ describe('buildApiReports', () => { normalize('packages/package-b'), normalize('plugins/plugin-a'), ], - tsconfigFilePath: resolvePath('/root/tsconfig.json'), + tsconfigFilePath: mockDir.resolve('tsconfig.json'), allowWarnings: [], omitMessages: [], isLocalBuild: true, - outputDir: resolvePath('/root/node_modules/.cache/api-extractor'), + outputDir: mockDir.resolve('node_modules/.cache/api-extractor'), }); expect(runCliExtraction).toHaveBeenCalledWith({ packageDirs: [ @@ -305,11 +304,11 @@ describe('buildApiReports', () => { normalize('plugins/plugin-b'), normalize('plugins/plugin-c'), ], - tsconfigFilePath: resolvePath('/root/tsconfig.json'), + tsconfigFilePath: mockDir.resolve('tsconfig.json'), allowWarnings: [], omitMessages: [], isLocalBuild: true, - outputDir: resolvePath('/root/node_modules/.cache/api-extractor'), + outputDir: mockDir.resolve('node_modules/.cache/api-extractor'), }); expect(runCliExtraction).toHaveBeenCalledWith({ packageDirs: [ @@ -338,11 +337,11 @@ describe('buildApiReports', () => { normalize('packages/package-a'), normalize('packages/package-b'), ], - tsconfigFilePath: resolvePath('/root/tsconfig.json'), + tsconfigFilePath: mockDir.resolve('tsconfig.json'), allowWarnings: ['packages/package-a'], omitMessages: [], isLocalBuild: true, - outputDir: resolvePath('/root/node_modules/.cache/api-extractor'), + outputDir: mockDir.resolve('node_modules/.cache/api-extractor'), }); }); @@ -359,11 +358,11 @@ describe('buildApiReports', () => { normalize('packages/package-a'), normalize('packages/package-b'), ], - tsconfigFilePath: resolvePath('/root/tsconfig.json'), + tsconfigFilePath: mockDir.resolve('tsconfig.json'), allowWarnings: ['packages/package-a', 'packages/package-b'], omitMessages: [], isLocalBuild: true, - outputDir: resolvePath('/root/node_modules/.cache/api-extractor'), + outputDir: mockDir.resolve('node_modules/.cache/api-extractor'), }); }); @@ -380,11 +379,11 @@ describe('buildApiReports', () => { normalize('packages/package-a'), normalize('packages/package-b'), ], - tsconfigFilePath: resolvePath('/root/tsconfig.json'), + tsconfigFilePath: mockDir.resolve('tsconfig.json'), allowWarnings: ['packages/package-a', 'packages/package-b'], omitMessages: [], isLocalBuild: true, - outputDir: resolvePath('/root/node_modules/.cache/api-extractor'), + outputDir: mockDir.resolve('node_modules/.cache/api-extractor'), }); }); }); @@ -402,11 +401,11 @@ describe('buildApiReports', () => { normalize('packages/package-a'), normalize('packages/package-b'), ], - tsconfigFilePath: resolvePath('/root/tsconfig.json'), + tsconfigFilePath: mockDir.resolve('tsconfig.json'), allowWarnings: true, omitMessages: [], isLocalBuild: true, - outputDir: resolvePath('/root/node_modules/.cache/api-extractor'), + outputDir: mockDir.resolve('node_modules/.cache/api-extractor'), }); }); }); @@ -424,11 +423,11 @@ describe('buildApiReports', () => { normalize('packages/package-a'), normalize('packages/package-b'), ], - tsconfigFilePath: resolvePath('/root/tsconfig.json'), + tsconfigFilePath: mockDir.resolve('tsconfig.json'), allowWarnings: [], omitMessages: ['ae-missing-release-tag'], isLocalBuild: true, - outputDir: resolvePath('/root/node_modules/.cache/api-extractor'), + outputDir: mockDir.resolve('node_modules/.cache/api-extractor'), }); }); @@ -445,11 +444,11 @@ describe('buildApiReports', () => { normalize('packages/package-a'), normalize('packages/package-b'), ], - tsconfigFilePath: resolvePath('/root/tsconfig.json'), + tsconfigFilePath: mockDir.resolve('tsconfig.json'), allowWarnings: [], omitMessages: ['ae-missing-release-tag', 'ae-missing-annotations'], isLocalBuild: true, - outputDir: resolvePath('/root/node_modules/.cache/api-extractor'), + outputDir: mockDir.resolve('node_modules/.cache/api-extractor'), }); }); @@ -466,11 +465,11 @@ describe('buildApiReports', () => { normalize('packages/package-a'), normalize('packages/package-b'), ], - tsconfigFilePath: resolvePath('/root/tsconfig.json'), + tsconfigFilePath: mockDir.resolve('tsconfig.json'), allowWarnings: [], omitMessages: ['ae-missing-release-tag', 'ae-missing-annotations'], isLocalBuild: true, - outputDir: resolvePath('/root/node_modules/.cache/api-extractor'), + outputDir: mockDir.resolve('node_modules/.cache/api-extractor'), }); }); }); @@ -488,11 +487,11 @@ describe('buildApiReports', () => { normalize('packages/package-a'), normalize('packages/package-b'), ], - tsconfigFilePath: resolvePath('/root/tsconfig.json'), + tsconfigFilePath: mockDir.resolve('tsconfig.json'), allowWarnings: [], omitMessages: [], isLocalBuild: false, - outputDir: resolvePath('/root/node_modules/.cache/api-extractor'), + outputDir: mockDir.resolve('node_modules/.cache/api-extractor'), }); expect(runCliExtraction).toHaveBeenCalledWith({ packageDirs: [ @@ -513,8 +512,8 @@ describe('buildApiReports', () => { await buildApiReports(paths, opts); expect(buildDocs).toHaveBeenCalledWith({ - inputDir: resolvePath('/root/node_modules/.cache/api-extractor'), - outputDir: resolvePath('/root/docs/reference'), + inputDir: mockDir.resolve('node_modules/.cache/api-extractor'), + outputDir: mockDir.resolve('docs/reference'), }); }); }); diff --git a/packages/repo-tools/src/commands/index.ts b/packages/repo-tools/src/commands/index.ts index 4f9ea87708..d9c6d892f5 100644 --- a/packages/repo-tools/src/commands/index.ts +++ b/packages/repo-tools/src/commands/index.ts @@ -32,14 +32,18 @@ function registerSchemaCommand(program: Command) { .description( 'Verify that all OpenAPI schemas are valid and have a matching `schemas/openapi.generated.ts` file.', ) - .action(lazy(() => import('./openapi/verify').then(m => m.bulkCommand))); + .action( + lazy(() => import('./openapi/schema/verify').then(m => m.bulkCommand)), + ); openApiCommand .command('generate [paths...]') .description( 'Generates a Typescript file from an OpenAPI yaml spec. For use with the `@backstage/backend-openapi-utils` ApiRouter type.', ) - .action(lazy(() => import('./openapi/generate').then(m => m.bulkCommand))); + .action( + lazy(() => import('./openapi/schema/generate').then(m => m.bulkCommand)), + ); openApiCommand .command('lint [paths...]') @@ -60,6 +64,16 @@ function registerSchemaCommand(program: Command) { .command('init ') .description('Creates any config needed for the test command.') .action(lazy(() => import('./openapi/test/init').then(m => m.default))); + + openApiCommand + .command('generate-client') + .requiredOption('--input-spec ') + .requiredOption('--output-directory ') + .action( + lazy(() => + import('./openapi/client/generate').then(m => m.singleCommand), + ), + ); } export function registerCommands(program: Command) { diff --git a/packages/repo-tools/src/commands/openapi/client/generate.ts b/packages/repo-tools/src/commands/openapi/client/generate.ts new file mode 100644 index 0000000000..f827f1005f --- /dev/null +++ b/packages/repo-tools/src/commands/openapi/client/generate.ts @@ -0,0 +1,100 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import chalk from 'chalk'; +import { resolve } from 'path'; +import { OPENAPI_IGNORE_FILES, OUTPUT_PATH } from '../constants'; +import { paths as cliPaths } from '../../../lib/paths'; +import { mkdirpSync } from 'fs-extra'; +import fs from 'fs-extra'; +import { exec } from '../../../lib/exec'; +import { resolvePackagePath } from '@backstage/backend-common'; + +async function generate(spec: string, outputDirectory: string) { + const resolvedOpenapiPath = resolve(spec); + const resolvedOutputDirectory = resolve(outputDirectory, OUTPUT_PATH); + mkdirpSync(resolvedOutputDirectory); + + await fs.mkdirp(resolvedOutputDirectory); + + await fs.writeFile( + resolve(resolvedOutputDirectory, '.openapi-generator-ignore'), + OPENAPI_IGNORE_FILES.join('\n'), + ); + + await exec( + 'node', + [ + resolvePackagePath('@openapitools/openapi-generator-cli', 'main.js'), + 'generate', + '-i', + resolvedOpenapiPath, + '-o', + resolvedOutputDirectory, + '-g', + 'typescript', + '-c', + resolvePackagePath( + '@backstage/repo-tools', + 'templates/typescript-backstage.yaml', + ), + '--generator-key', + 'v3.0', + ], + { + maxBuffer: Number.MAX_VALUE, + cwd: resolvePackagePath('@backstage/repo-tools'), + env: { + ...process.env, + }, + }, + ); + + await exec( + `yarn backstage-cli package lint --fix ${resolvedOutputDirectory}`, + ); + + const prettier = cliPaths.resolveTargetRoot('node_modules/.bin/prettier'); + if (prettier) { + await exec(`${prettier} --write ${resolvedOutputDirectory}`); + } + + fs.removeSync(resolve(resolvedOutputDirectory, '.openapi-generator-ignore')); + + fs.rmSync(resolve(resolvedOutputDirectory, '.openapi-generator'), { + recursive: true, + force: true, + }); +} + +export async function singleCommand({ + inputSpec, + outputDirectory, +}: { + inputSpec: string; + outputDirectory: string; +}): Promise { + try { + await generate(inputSpec, outputDirectory); + console.log(chalk.green(`Generated client for ${inputSpec}`)); + } catch (err) { + console.log(); + console.log(chalk.red(`Client generation failed in ${outputDirectory}:`)); + console.log(err); + + process.exit(1); + } +} diff --git a/packages/repo-tools/src/commands/openapi/constants.ts b/packages/repo-tools/src/commands/openapi/constants.ts index defef4ab53..2e7a57522a 100644 --- a/packages/repo-tools/src/commands/openapi/constants.ts +++ b/packages/repo-tools/src/commands/openapi/constants.ts @@ -19,3 +19,44 @@ export const YAML_SCHEMA_PATH = 'src/schema/openapi.yaml'; export const TS_MODULE = 'src/schema/openapi.generated'; export const TS_SCHEMA_PATH = `${TS_MODULE}.ts`; + +export const GENERATOR_VERSION = `1.0.0`; +export const GENERATOR_NAME = 'typescript-backstage'; +export const GENERATOR_FILE = `packages/template-openapi-plugin-client/generator/target/${GENERATOR_NAME}-openapi-generator-${GENERATOR_VERSION}.jar`; + +export const OUTPUT_PATH = 'src/generated'; + +export const OPENAPI_IGNORE_FILES = [ + // Get rid of the default files. + '*.md', + // The rest of these have to be explicit, otherwise they get added if this was a *.* + 'apis/baseapi.ts', + 'apis/exception.ts', + 'auth/*', + 'http/*', + 'middleware.ts', + 'servers.ts', + 'util.ts', + 'configuration.ts', + 'rxjsStub.ts', + '.gitignore', + + // Override the created version. + 'apis/*.ts', + '!apis/*.client.ts', + 'models/*.ts', + '!models/*.model.ts', + + // Always include index.ts files. + '!index.ts', + '!**/index.ts', + + // Weird API typings. + 'types/ObjectParamAPI.ts', + 'types/ObservableAPI.ts', + 'types/PromiseAPI.ts', + + 'git_push.sh', + 'package.json', + 'tsconfig.json', +]; diff --git a/packages/repo-tools/src/commands/openapi/generate.ts b/packages/repo-tools/src/commands/openapi/schema/generate.ts similarity index 95% rename from packages/repo-tools/src/commands/openapi/generate.ts rename to packages/repo-tools/src/commands/openapi/schema/generate.ts index 52b8e5b840..cd9f572f2d 100644 --- a/packages/repo-tools/src/commands/openapi/generate.ts +++ b/packages/repo-tools/src/commands/openapi/schema/generate.ts @@ -18,9 +18,9 @@ import fs from 'fs-extra'; import YAML from 'js-yaml'; import chalk from 'chalk'; import { resolve } from 'path'; -import { paths as cliPaths } from '../../lib/paths'; -import { runner } from './runner'; -import { TS_SCHEMA_PATH, YAML_SCHEMA_PATH } from './constants'; +import { paths as cliPaths } from '../../../lib/paths'; +import { runner } from '../runner'; +import { TS_SCHEMA_PATH, YAML_SCHEMA_PATH } from '../constants'; import { promisify } from 'util'; import { exec as execCb } from 'child_process'; diff --git a/packages/repo-tools/src/commands/openapi/verify.ts b/packages/repo-tools/src/commands/openapi/schema/verify.ts similarity index 93% rename from packages/repo-tools/src/commands/openapi/verify.ts rename to packages/repo-tools/src/commands/openapi/schema/verify.ts index 2808e72702..7120dd67ad 100644 --- a/packages/repo-tools/src/commands/openapi/verify.ts +++ b/packages/repo-tools/src/commands/openapi/schema/verify.ts @@ -21,9 +21,9 @@ import { join } from 'path'; import chalk from 'chalk'; import { relative as relativePath, resolve as resolvePath } from 'path'; import Parser from '@apidevtools/swagger-parser'; -import { runner } from './runner'; -import { paths as cliPaths } from '../../lib/paths'; -import { TS_MODULE, TS_SCHEMA_PATH, YAML_SCHEMA_PATH } from './constants'; +import { runner } from '../runner'; +import { paths as cliPaths } from '../../../lib/paths'; +import { TS_MODULE, TS_SCHEMA_PATH, YAML_SCHEMA_PATH } from '../constants'; async function verify(directoryPath: string) { const openapiPath = join(directoryPath, YAML_SCHEMA_PATH); diff --git a/packages/repo-tools/src/commands/openapi/test/init.ts b/packages/repo-tools/src/commands/openapi/test/init.ts index 13c3aeb2b6..a38416aabb 100644 --- a/packages/repo-tools/src/commands/openapi/test/init.ts +++ b/packages/repo-tools/src/commands/openapi/test/init.ts @@ -35,7 +35,7 @@ async function init(directoryPath: string) { ); } const opticConfigFilePath = join(directoryPath, 'optic.yml'); - if (!(await fs.pathExists(opticConfigFilePath))) { + if (await fs.pathExists(opticConfigFilePath)) { throw new Error(`This directory already has an optic.yml file. Exiting.`); } await fs.writeFile( @@ -56,7 +56,7 @@ capture: # 🔧 Specify a command that will generate traffic command: yarn backstage-cli package test --no-watch ${ROUTER_TEST_PATHS.map( e => `"${e}"`, - ).join(',')} + ).join(' ')} `, ); if (await cliPaths.resolveTargetRoot('node_modules/.bin/prettier')) { diff --git a/packages/repo-tools/templates/typescript-backstage.yaml b/packages/repo-tools/templates/typescript-backstage.yaml new file mode 100644 index 0000000000..b2b068856d --- /dev/null +++ b/packages/repo-tools/templates/typescript-backstage.yaml @@ -0,0 +1,21 @@ +templateDir: templates/typescript-backstage + +files: + api.mustache: + templateType: API + # For some reason, they check for destinationFilename differences. We have to change the ending to override the file. + destinationFilename: .client.ts + model.mustache: + templateType: Model + destinationFilename: .model.ts + models/models_all.mustache: + templateType: SupportingFiles + destinationFilename: models/index.ts + types/fetch.ts: {} + types/discovery.ts: {} + apis/index.mustache: + templateType: SupportingFiles + destinationFilename: apis/index.ts + pluginId.mustache: + templateType: SupportingFiles + destinationFilename: pluginId.ts diff --git a/packages/repo-tools/templates/typescript-backstage/api.mustache b/packages/repo-tools/templates/typescript-backstage/api.mustache new file mode 100644 index 0000000000..8043d6e2f4 --- /dev/null +++ b/packages/repo-tools/templates/typescript-backstage/api.mustache @@ -0,0 +1,119 @@ +{{>licenseInfo}} +import { DiscoveryApi } from '../types/discovery'; +import { FetchApi } from '../types/fetch'; +import crossFetch from 'cross-fetch'; +import {pluginId} from '../pluginId'; +import * as parser from 'uri-template'; + +{{#imports}} +import { {{classname}} } from '{{filename}}.model{{importFileExtension}}'; +{{/imports}} + +/** + * Wraps the Response type to convey a type on the json call. + * + * @public + */ +export type TypedResponse = Omit & { + json: () => Promise; +}; + +{{#operations}} + +/** + * Options you can pass into a request for additional information. + * + * @public + */ +export interface RequestOptions { + token?: string; +} + +/** + * {{{description}}}{{^description}}no description{{/description}} + */ +export class {{classname}}Client { + private readonly discoveryApi: DiscoveryApi; + private readonly fetchApi: FetchApi; + + constructor(options: { + discoveryApi: { getBaseUrl(pluginId: string): Promise }; + fetchApi?: { fetch: typeof fetch }; + }) { + this.discoveryApi = options.discoveryApi; + this.fetchApi = options.fetchApi || { fetch: crossFetch }; + } + + {{#operation}} + /** + {{#notes}} + * {{¬es}} + {{/notes}} + {{#summary}} + * {{&summary}} + {{/summary}} + {{#allParams}} + * @param {{paramName}} {{description}} + {{/allParams}} + */ + public async {{nickname}}( + // @ts-ignore + request: { + {{#hasPathParams}} + path: { + {{#pathParams}} + {{paramName}}{{^required}}?{{/required}}: {{{dataType}}}, + {{/pathParams}} + }, + {{/hasPathParams}} + {{#hasBodyParam}} + {{#bodyParam}} + body: {{{dataType}}}, + {{/bodyParam}} + {{/hasBodyParam}} + {{#hasQueryParams}} + query: { + {{#queryParams}} + {{paramName}}{{^required}}?{{/required}}: {{{dataType}}}, + {{/queryParams}} + }, + {{/hasQueryParams}} + {{#hasHeaderParams}} + header: { + {{#headerParams}} + {{paramName}}{{^required}}?{{/required}}: {{{dataType}}}, + {{/headerParams}} + }, + {{/hasHeaderParams}} + }, + options?: RequestOptions + ): Promise> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `{{{path}}}{{#hasQueryParams}}{?{{#queryParams}}{{baseName}}{{#isArray}}{{#isExplode}}*{{/isExplode}}{{/isArray}}{{^-last}},{{/-last}}{{/queryParams}}}{{/hasQueryParams}}`; + + const uri = parser.parse(uriTemplate).expand({ + {{#pathParams}} + {{baseName}}: request.path.{{paramName}}, + {{/pathParams}} + {{#hasQueryParams}} + ...request.query, + {{/hasQueryParams}} + }) + + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { + headers: { + {{#hasHeaderParams}} + ...request.header, + {{/hasHeaderParams}} + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: '{{httpMethod}}', + {{#hasBodyParam}} body: JSON.stringify(request.body), {{/hasBodyParam}} + }); + } + + {{/operation}} +} +{{/operations}} diff --git a/packages/repo-tools/templates/typescript-backstage/apis/index.mustache b/packages/repo-tools/templates/typescript-backstage/apis/index.mustache new file mode 100644 index 0000000000..4c8996c5ee --- /dev/null +++ b/packages/repo-tools/templates/typescript-backstage/apis/index.mustache @@ -0,0 +1,3 @@ +// + +export * from './DefaultApi.client'; diff --git a/packages/repo-tools/templates/typescript-backstage/index.mustache b/packages/repo-tools/templates/typescript-backstage/index.mustache new file mode 100644 index 0000000000..b95e48ff08 --- /dev/null +++ b/packages/repo-tools/templates/typescript-backstage/index.mustache @@ -0,0 +1,4 @@ +// + +export * from './apis'; +export * from './models'; \ No newline at end of file diff --git a/packages/repo-tools/templates/typescript-backstage/model.mustache b/packages/repo-tools/templates/typescript-backstage/model.mustache new file mode 100644 index 0000000000..1f288380e0 --- /dev/null +++ b/packages/repo-tools/templates/typescript-backstage/model.mustache @@ -0,0 +1,43 @@ +// + +{{#models}} +{{#model}} +{{#tsImports}} +import { {{classname}} } from '{{filename}}.model{{importFileExtension}}'; +{{/tsImports}} + +{{#description}} +/** +* {{{.}}} +*/ +{{/description}} +{{^isEnum}} +export interface {{classname}} { +{{#additionalPropertiesType}} + [key: string]: {{{additionalPropertiesType}}}; +{{/additionalPropertiesType}} +{{#vars}} +{{#description}} + /** + * {{{.}}} + */ +{{/description}} + '{{name}}'{{^required}}?{{/required}}: {{#isEnum}}{{{datatypeWithEnum}}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{#isNullable}} | null{{/isNullable}}; +{{/vars}} +} + +{{#hasEnums}} + +{{#vars}} +{{#isEnum}} +export type {{classname}}{{enumName}} ={{#allowableValues}}{{#values}} "{{.}}" {{^-last}}|{{/-last}}{{/values}}{{/allowableValues}}; +{{/isEnum}} +{{/vars}} + +{{/hasEnums}} +{{/isEnum}} +{{#isEnum}} +export type {{classname}} ={{#allowableValues}}{{#values}} "{{.}}" {{^-last}}|{{/-last}}{{/values}}{{/allowableValues}}; +{{/isEnum}} +{{/model}} +{{/models}} \ No newline at end of file diff --git a/packages/repo-tools/templates/typescript-backstage/models/models_all.mustache b/packages/repo-tools/templates/typescript-backstage/models/models_all.mustache new file mode 100644 index 0000000000..d076cfb3ff --- /dev/null +++ b/packages/repo-tools/templates/typescript-backstage/models/models_all.mustache @@ -0,0 +1,7 @@ +// + +{{#models}} +{{#model}} +export * from '{{{ importPath }}}.model{{importFileExtension}}' +{{/model}} +{{/models}} \ No newline at end of file diff --git a/packages/repo-tools/templates/typescript-backstage/pluginId.mustache b/packages/repo-tools/templates/typescript-backstage/pluginId.mustache new file mode 100644 index 0000000000..8bc8461cc9 --- /dev/null +++ b/packages/repo-tools/templates/typescript-backstage/pluginId.mustache @@ -0,0 +1,6 @@ + +{{#servers}} +{{#-last}} +export const pluginId = "{{url}}"; +{{/-last}} +{{/servers}} \ No newline at end of file diff --git a/packages/repo-tools/templates/typescript-backstage/types/discovery.ts b/packages/repo-tools/templates/typescript-backstage/types/discovery.ts new file mode 100644 index 0000000000..a7f87d3780 --- /dev/null +++ b/packages/repo-tools/templates/typescript-backstage/types/discovery.ts @@ -0,0 +1,22 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This is a copy of the DiscoveryApi, to avoid importing core-plugin-api. + */ +export type DiscoveryApi = { + getBaseUrl(pluginId: string): Promise; +}; diff --git a/packages/repo-tools/templates/typescript-backstage/types/fetch.ts b/packages/repo-tools/templates/typescript-backstage/types/fetch.ts new file mode 100644 index 0000000000..3de56c028e --- /dev/null +++ b/packages/repo-tools/templates/typescript-backstage/types/fetch.ts @@ -0,0 +1,22 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This is a copy of FetchApi, to avoid importing core-plugin-api. + */ +export type FetchApi = { + fetch: typeof fetch; +}; diff --git a/packages/techdocs-cli-embedded-app/CHANGELOG.md b/packages/techdocs-cli-embedded-app/CHANGELOG.md index b635bbc871..0e6163e1b7 100644 --- a/packages/techdocs-cli-embedded-app/CHANGELOG.md +++ b/packages/techdocs-cli-embedded-app/CHANGELOG.md @@ -1,5 +1,194 @@ # techdocs-cli-embedded-app +## 0.2.90 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/cli@0.25.1 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-techdocs-react@1.1.15 + - @backstage/plugin-techdocs@1.9.3 + - @backstage/plugin-catalog@1.16.1 + - @backstage/app-defaults@1.4.7 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.3 + - @backstage/test-utils@1.4.7 + - @backstage/theme@0.5.0 + +## 0.2.90-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.16.1-next.2 + - @backstage/plugin-techdocs@1.9.3-next.2 + - @backstage/cli@0.25.1-next.1 + - @backstage/integration-react@1.1.23-next.0 + +## 0.2.90-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/app-defaults@1.4.7-next.1 + - @backstage/cli@0.25.1-next.1 + - @backstage/core-app-api@1.11.3-next.0 + - @backstage/integration-react@1.1.23-next.0 + - @backstage/test-utils@1.4.7-next.1 + - @backstage/plugin-catalog@1.16.1-next.1 + - @backstage/plugin-techdocs@1.9.3-next.1 + - @backstage/plugin-techdocs-react@1.1.15-next.1 + - @backstage/config@1.1.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0 + +## 0.2.90-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/cli@0.25.1-next.0 + - @backstage/plugin-techdocs-react@1.1.15-next.0 + - @backstage/plugin-techdocs@1.9.3-next.0 + - @backstage/plugin-catalog@1.16.1-next.0 + - @backstage/app-defaults@1.4.7-next.0 + - @backstage/integration-react@1.1.22 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.2 + - @backstage/core-plugin-api@1.8.1 + - @backstage/test-utils@1.4.7-next.0 + - @backstage/theme@0.5.0 + +## 0.2.89 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/cli@0.25.0 + - @backstage/theme@0.5.0 + - @backstage/plugin-catalog@1.16.0 + - @backstage/core-app-api@1.11.2 + - @backstage/test-utils@1.4.6 + - @backstage/plugin-techdocs@1.9.2 + - @backstage/app-defaults@1.4.6 + - @backstage/integration-react@1.1.22 + - @backstage/plugin-techdocs-react@1.1.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + +## 0.2.89-next.4 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.25.0-next.3 + - @backstage/core-components@0.13.9-next.3 + - @backstage/app-defaults@1.4.6-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/test-utils@1.4.6-next.2 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog@1.16.0-next.4 + - @backstage/plugin-techdocs@1.9.2-next.4 + - @backstage/plugin-techdocs-react@1.1.14-next.3 + +## 0.2.89-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.25.0-next.2 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-techdocs@1.9.2-next.3 + - @backstage/plugin-catalog@1.16.0-next.3 + - @backstage/app-defaults@1.4.6-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/test-utils@1.4.6-next.2 + - @backstage/plugin-techdocs-react@1.1.14-next.2 + +## 0.2.89-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/cli@0.25.0-next.1 + - @backstage/plugin-catalog@1.16.0-next.2 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/test-utils@1.4.6-next.1 + - @backstage/plugin-techdocs@1.9.2-next.2 + - @backstage/app-defaults@1.4.6-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-techdocs-react@1.1.14-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + +## 0.2.89-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.16.0-next.1 + - @backstage/plugin-techdocs@1.9.2-next.1 + +## 0.2.89-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/plugin-catalog@1.16.0-next.0 + - @backstage/plugin-techdocs@1.9.2-next.0 + - @backstage/cli@0.24.1-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/app-defaults@1.4.6-next.0 + - @backstage/core-app-api@1.11.2-next.0 + - @backstage/integration-react@1.1.22-next.0 + - @backstage/test-utils@1.4.6-next.0 + - @backstage/plugin-techdocs-react@1.1.14-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + +## 0.2.88 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.24.0 + - @backstage/core-components@0.13.8 + - @backstage/plugin-catalog@1.15.0 + - @backstage/plugin-techdocs@1.9.0 + - @backstage/integration-react@1.1.21 + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-techdocs-react@1.1.13 + - @backstage/app-defaults@1.4.5 + - @backstage/core-app-api@1.11.1 + - @backstage/test-utils@1.4.5 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + ## 0.2.88-next.2 ### Patch Changes diff --git a/packages/techdocs-cli-embedded-app/package.json b/packages/techdocs-cli-embedded-app/package.json index 75000b552b..8e30395052 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.88-next.2", + "version": "0.2.90", "private": true, "backstage": { "role": "frontend" diff --git a/packages/techdocs-cli/CHANGELOG.md b/packages/techdocs-cli/CHANGELOG.md index 792490abaf..f65ed4bd46 100644 --- a/packages/techdocs-cli/CHANGELOG.md +++ b/packages/techdocs-cli/CHANGELOG.md @@ -1,5 +1,129 @@ # @techdocs/cli +## 1.8.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-techdocs-node@1.11.1 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + +## 1.8.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-techdocs-node@1.11.1-next.2 + +## 1.8.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-techdocs-node@1.11.1-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + +## 1.8.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/plugin-techdocs-node@1.11.1-next.0 + +## 1.8.0 + +### Minor Changes + +- d15d483: Add command `--runAsDefaultUser` for `@techdocs/cli generate` to bypass running the docker builds as host user for macOS and Linux. +- b2dccad: Support passing additional `mkdocs-server` CLI parameters (`--dirtyreload`, `--strict` and `--clean`) when run in containerized mode. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-techdocs-node@1.11.0 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + +## 1.8.0-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/plugin-techdocs-node@1.11.0-next.3 + +## 1.8.0-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/plugin-techdocs-node@1.11.0-next.2 + +## 1.8.0-next.1 + +### Minor Changes + +- b2dccad7b3: Support passing additional `mkdocs-server` CLI parameters (`--dirtyreload`, `--strict` and `--clean`) when run in containerized mode. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs-node@1.11.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + +## 1.8.0-next.0 + +### Minor Changes + +- d15d483a49: Add command `--runAsDefaultUser` for `@techdocs/cli generate` to bypass running the docker builds as host user for macOS and Linux. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-techdocs-node@1.11.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + +## 1.7.0 + +### Minor Changes + +- 8600b86820: validate Docker status before running mkdocs server + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs-node@1.10.0 + - @backstage/backend-common@0.19.9 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + ## 1.6.1-next.2 ### Patch Changes diff --git a/packages/techdocs-cli/cli-report.md b/packages/techdocs-cli/cli-report.md index 890718b0d2..9777b2c4b8 100644 --- a/packages/techdocs-cli/cli-report.md +++ b/packages/techdocs-cli/cli-report.md @@ -38,6 +38,7 @@ Options: --omitTechdocsCoreMkdocsPlugin --legacyCopyReadmeMdToIndexMd --defaultPlugin [defaultPlugins...] + --runAsDefaultUser -h, --help ``` @@ -107,6 +108,9 @@ Options: --preview-app-bundle-path --preview-app-port -c, --mkdocs-config-file-name + --mkdocs-parameter-clean + --mkdocs-parameter-dirtyreload + --mkdocs-parameter-strict -h, --help ``` diff --git a/packages/techdocs-cli/package.json b/packages/techdocs-cli/package.json index fc50468351..4d4fc997b6 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.6.1-next.2", + "version": "1.8.1", "publishConfig": { "access": "public" }, diff --git a/packages/techdocs-cli/src/commands/generate/generate.ts b/packages/techdocs-cli/src/commands/generate/generate.ts index 934eaf1efd..bf6910ff4a 100644 --- a/packages/techdocs-cli/src/commands/generate/generate.ts +++ b/packages/techdocs-cli/src/commands/generate/generate.ts @@ -114,6 +114,7 @@ export default async function generate(opts: OptionValues) { etag: opts.etag, logStream: getLogStream(logger), siteOptions: { name: opts.siteName }, + runAsDefaultUser: opts.runAsDefaultUser, }); if (configIsTemporary) { diff --git a/packages/techdocs-cli/src/commands/index.ts b/packages/techdocs-cli/src/commands/index.ts index 10a00da513..ac9523e639 100644 --- a/packages/techdocs-cli/src/commands/index.ts +++ b/packages/techdocs-cli/src/commands/index.ts @@ -75,6 +75,11 @@ export function registerCommands(program: Command) { 'Plugins which should be added automatically to the mkdocs.yaml file', [], ) + .option( + '--runAsDefaultUser', + 'Bypass setting the container user as the same user and group id as host for Linux and MacOS', + false, + ) .alias('build') .action(lazy(() => import('./generate/generate').then(m => m.default))); @@ -289,6 +294,21 @@ export function registerCommands(program: Command) { '-c, --mkdocs-config-file-name ', 'Mkdocs config file name', ) + .option( + '--mkdocs-parameter-clean', + 'Pass "--clean" parameter to mkdocs server running in containerized environment', + false, + ) + .option( + '--mkdocs-parameter-dirtyreload', + 'Pass "--dirtyreload" parameter to mkdocs server running in containerized environment', + false, + ) + .option( + '--mkdocs-parameter-strict', + 'Pass "--strict" parameter to mkdocs server running in containerized environment', + false, + ) .hook('preAction', command => { if ( command.opts().previewAppPort !== defaultPreviewAppPort && diff --git a/packages/techdocs-cli/src/commands/serve/mkdocs.ts b/packages/techdocs-cli/src/commands/serve/mkdocs.ts index c061d4474f..00c5e5f0ed 100644 --- a/packages/techdocs-cli/src/commands/serve/mkdocs.ts +++ b/packages/techdocs-cli/src/commands/serve/mkdocs.ts @@ -21,6 +21,7 @@ import { runMkdocsServer } from '../../lib/mkdocsServer'; import { LogFunc, waitForSignal } from '../../lib/run'; import { getMkdocsYml } from '@backstage/plugin-techdocs-node'; import fs from 'fs-extra'; +import { checkIfDockerIsOperational } from './utils'; export default async function serveMkdocs(opts: OptionValues) { const logger = createLogger({ verbose: opts.verbose }); @@ -29,6 +30,13 @@ export default async function serveMkdocs(opts: OptionValues) { const localAddr = `http://127.0.0.1:${opts.port}`; const expectedDevAddr = opts.docker ? dockerAddr : localAddr; + if (opts.docker) { + const isDockerOperational = await checkIfDockerIsOperational(logger); + if (!isDockerOperational) { + return; + } + } + const { path: mkdocsYmlPath, configIsTemporary } = await getMkdocsYml( './', opts.siteName, diff --git a/packages/techdocs-cli/src/commands/serve/serve.ts b/packages/techdocs-cli/src/commands/serve/serve.ts index 5fcf1787d3..de681c2de4 100644 --- a/packages/techdocs-cli/src/commands/serve/serve.ts +++ b/packages/techdocs-cli/src/commands/serve/serve.ts @@ -24,6 +24,7 @@ import { LogFunc, waitForSignal } from '../../lib/run'; import { createLogger } from '../../lib/utility'; import { getMkdocsYml } from '@backstage/plugin-techdocs-node'; import fs from 'fs-extra'; +import { checkIfDockerIsOperational } from './utils'; function findPreviewBundlePath(): string { try { @@ -73,6 +74,14 @@ export default async function serve(opts: OptionValues) { mkdocsConfigFileName, }); + // Validate that Docker is up and running + if (opts.docker) { + const isDockerOperational = await checkIfDockerIsOperational(logger); + if (!isDockerOperational) { + return; + } + } + let mkdocsServerHasStarted = false; const mkdocsLogFunc: LogFunc = data => { // Sometimes the lines contain an unnecessary extra new line @@ -107,6 +116,9 @@ export default async function serve(opts: OptionValues) { stdoutLogFunc: mkdocsLogFunc, stderrLogFunc: mkdocsLogFunc, mkdocsConfigFileName: mkdocsYmlPath, + mkdocsParameterClean: opts.mkdocsParameterClean, + mkdocsParameterDirtyReload: opts.mkdocsParameterDirtyReload, + mkdocsParameterStrict: opts.mkdocsParameterStrict, }); // Wait until mkdocs server has started so that Backstage starts with docs loaded diff --git a/packages/techdocs-cli/src/commands/serve/utils.ts b/packages/techdocs-cli/src/commands/serve/utils.ts new file mode 100644 index 0000000000..2b19b0fbc0 --- /dev/null +++ b/packages/techdocs-cli/src/commands/serve/utils.ts @@ -0,0 +1,38 @@ +/* + * 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 { promisify } from 'util'; +import * as winston from 'winston'; +import { execFile } from 'child_process'; + +export async function checkIfDockerIsOperational( + logger: winston.Logger, +): Promise { + logger.info('Checking Docker status...'); + try { + const runCheck = promisify(execFile); + await runCheck('docker', ['info'], { shell: true }); + logger.info( + 'Docker is up and running. Proceed to starting up mkdocs server', + ); + return true; + } catch { + logger.error( + 'Docker is not running. Exiting. Please check status of Docker daemon with `docker info` before re-running', + ); + return false; + } +} diff --git a/packages/techdocs-cli/src/lib/mkdocsServer.test.ts b/packages/techdocs-cli/src/lib/mkdocsServer.test.ts index 8484c4e242..83f9c9f382 100644 --- a/packages/techdocs-cli/src/lib/mkdocsServer.test.ts +++ b/packages/techdocs-cli/src/lib/mkdocsServer.test.ts @@ -97,6 +97,24 @@ describe('runMkdocsServer', () => { expect.objectContaining({}), ); }); + + it('should accept additinoal mkdocs CLI parameters', async () => { + await runMkdocsServer({ + mkdocsParameterClean: true, + mkdocsParameterStrict: true, + }); + expect(run).toHaveBeenCalledWith( + 'docker', + expect.arrayContaining([ + 'serve', + '--dev-addr', + '0.0.0.0:8000', + '--clean', + '--strict', + ]), + expect.objectContaining({}), + ); + }); }); describe('mkdocs', () => { diff --git a/packages/techdocs-cli/src/lib/mkdocsServer.ts b/packages/techdocs-cli/src/lib/mkdocsServer.ts index 42409acb46..a793643367 100644 --- a/packages/techdocs-cli/src/lib/mkdocsServer.ts +++ b/packages/techdocs-cli/src/lib/mkdocsServer.ts @@ -26,6 +26,9 @@ export const runMkdocsServer = async (options: { stdoutLogFunc?: LogFunc; stderrLogFunc?: LogFunc; mkdocsConfigFileName?: string; + mkdocsParameterClean?: boolean; + mkdocsParameterDirtyReload?: boolean; + mkdocsParameterStrict?: boolean; }): Promise => { const port = options.port ?? '8000'; const useDocker = options.useDocker ?? true; @@ -55,6 +58,9 @@ export const runMkdocsServer = async (options: { ...(options.mkdocsConfigFileName ? ['--config-file', options.mkdocsConfigFileName] : []), + ...(options.mkdocsParameterClean ? ['--clean'] : []), + ...(options.mkdocsParameterDirtyReload ? ['--dirtyreload'] : []), + ...(options.mkdocsParameterStrict ? ['--strict'] : []), ], { stdoutLogFunc: options.stdoutLogFunc, @@ -72,6 +78,9 @@ export const runMkdocsServer = async (options: { ...(options.mkdocsConfigFileName ? ['--config-file', options.mkdocsConfigFileName] : []), + ...(options.mkdocsParameterClean ? ['--clean'] : []), + ...(options.mkdocsParameterDirtyReload ? ['--dirtyreload'] : []), + ...(options.mkdocsParameterStrict ? ['--strict'] : []), ], { stdoutLogFunc: options.stdoutLogFunc, diff --git a/packages/test-utils/CHANGELOG.md b/packages/test-utils/CHANGELOG.md index 9580b4855f..c4f342b554 100644 --- a/packages/test-utils/CHANGELOG.md +++ b/packages/test-utils/CHANGELOG.md @@ -1,5 +1,113 @@ # @backstage/test-utils +## 1.4.7 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.3 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + +## 1.4.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-app-api@1.11.3-next.0 + - @backstage/plugin-permission-react@0.4.19-next.1 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.11 + +## 1.4.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-react@0.4.19-next.0 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.2 + - @backstage/core-plugin-api@1.8.1 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.11 + +## 1.4.6 + +### Patch Changes + +- e8f2ace: Deprecated `mockBreakpoint`, as it is now available from `@backstage/core-components/testUtils` instead. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/theme@0.5.0 + - @backstage/core-app-api@1.11.2 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-react@0.4.18 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## 1.4.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-react@0.4.18-next.1 + +## 1.4.6-next.1 + +### Patch Changes + +- e8f2acef80: Deprecated `mockBreakpoint`, as it is now available from `@backstage/core-components/testUtils` instead. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.10 + +## 1.4.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/core-app-api@1.11.2-next.0 + - @backstage/plugin-permission-react@0.4.18-next.0 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.10 + +## 1.4.5 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-permission-react@0.4.17 + - @backstage/core-app-api@1.11.1 + - @backstage/theme@0.4.4 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + ## 1.4.5-next.0 ### Patch Changes diff --git a/packages/test-utils/alpha-api-report.md b/packages/test-utils/api-report-alpha.md similarity index 100% rename from packages/test-utils/alpha-api-report.md rename to packages/test-utils/api-report-alpha.md diff --git a/packages/test-utils/api-report.md b/packages/test-utils/api-report.md index 60bd352726..913413acd1 100644 --- a/packages/test-utils/api-report.md +++ b/packages/test-utils/api-report.md @@ -74,7 +74,7 @@ export class MockAnalyticsApi implements AnalyticsApi { getEvents(): AnalyticsEvent[]; } -// @public +// @public @deprecated export function mockBreakpoint(options: { matches: boolean }): void; // @public diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index c14d1edc8a..43b9c29a10 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/test-utils", "description": "Utilities to test Backstage plugins and apps.", - "version": "1.4.5-next.0", + "version": "1.4.7", "publishConfig": { "access": "public" }, diff --git a/packages/test-utils/src/testUtils/mockBreakpoint.ts b/packages/test-utils/src/testUtils/mockBreakpoint.ts index 78d7c9497f..c674c98f06 100644 --- a/packages/test-utils/src/testUtils/mockBreakpoint.ts +++ b/packages/test-utils/src/testUtils/mockBreakpoint.ts @@ -25,6 +25,7 @@ * https://mui.com/material-ui/react-use-media-query/#testing * * @public + * @deprecated Import from `@backstage/core-components/testUtils` instead. */ export default function mockBreakpoint(options: { matches: boolean }) { Object.defineProperty(window, 'matchMedia', { diff --git a/packages/theme/CHANGELOG.md b/packages/theme/CHANGELOG.md index b2583c299a..323fc8062d 100644 --- a/packages/theme/CHANGELOG.md +++ b/packages/theme/CHANGELOG.md @@ -1,5 +1,33 @@ # @backstage/theme +## 0.5.0 + +### Minor Changes + +- 4d9e3b3: Added a global `OverrideComponentNameToClassKeys` for other plugins and packages to populate using module augmentation. This will in turn will provide component style override types for `createUnifiedTheme`. + +### Patch Changes + +- cd0dd4c: Align Material UI v5 `Paper` component background color in dark mode to v4. + +## 0.5.0-next.1 + +### Patch Changes + +- cd0dd4c: Align Material UI v5 `Paper` component background color in dark mode to v4. + +## 0.5.0-next.0 + +### Minor Changes + +- 4d9e3b39e4: Added a global `OverrideComponentNameToClassKeys` for other plugins and packages to populate using module augmentation. This will in turn will provide component style override types for `createUnifiedTheme`. + +## 0.4.4 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. + ## 0.4.4-next.0 ### Patch Changes diff --git a/packages/theme/api-report.md b/packages/theme/api-report.md index 4ab05e8770..21d6be6a78 100644 --- a/packages/theme/api-report.md +++ b/packages/theme/api-report.md @@ -15,6 +15,7 @@ import { Theme as Theme_3 } from '@material-ui/core'; import { ThemeOptions } from '@mui/material/styles'; import { ThemeOptions as ThemeOptions_2 } from '@material-ui/core/styles'; import type { ThemeOptions as ThemeOptions_3 } from '@material-ui/core'; +import { UnifiedTheme as UnifiedTheme_2 } from '@backstage/theme'; // @public @deprecated export type BackstagePalette = Palette & BackstagePaletteAdditions; @@ -216,6 +217,9 @@ export function genPageTheme(props: { // @public @deprecated export const lightTheme: Theme_3; +// @public +export interface OverrideComponentNameToClassKeys {} + // @public export type PageTheme = { colors: string[]; @@ -401,8 +405,8 @@ export type SupportedVersions = 'v4' | 'v5'; // @public export const themes: { - light: UnifiedTheme; - dark: UnifiedTheme; + light: UnifiedTheme_2; + dark: UnifiedTheme_2; }; // @public diff --git a/packages/theme/package.json b/packages/theme/package.json index 7aed800cbc..56179fae19 100644 --- a/packages/theme/package.json +++ b/packages/theme/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/theme", "description": "material-ui theme for use with Backstage.", - "version": "0.4.4-next.0", + "version": "0.5.0", "publishConfig": { "access": "public", "main": "dist/index.esm.js", @@ -45,6 +45,9 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", + "@mui/styles": "^5.14.18", + "@testing-library/jest-dom": "^6.0.0", + "@testing-library/react": "^14.0.0", "@types/react": "^16.13.1 || ^17.0.0" }, "files": [ diff --git a/plugins/graphql-backend/src/setupTests.ts b/packages/theme/src/setupTests.ts similarity index 94% rename from plugins/graphql-backend/src/setupTests.ts rename to packages/theme/src/setupTests.ts index d3232290a7..963c0f188b 100644 --- a/plugins/graphql-backend/src/setupTests.ts +++ b/packages/theme/src/setupTests.ts @@ -14,4 +14,4 @@ * limitations under the License. */ -export {}; +import '@testing-library/jest-dom'; diff --git a/packages/theme/src/unified/UnifiedThemeProvider.test.tsx b/packages/theme/src/unified/UnifiedThemeProvider.test.tsx new file mode 100644 index 0000000000..da4af5abab --- /dev/null +++ b/packages/theme/src/unified/UnifiedThemeProvider.test.tsx @@ -0,0 +1,86 @@ +/* + * 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 { + useTheme as useV4Theme, + makeStyles as makeV4Styles, +} from '@material-ui/core/styles'; +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'; + +describe('UnifiedThemeProvider', () => { + it('provides a themes for v4 and v5 directly', () => { + function MyV4Component() { + const theme = useV4Theme(); + return v4-grey: {theme.palette.grey[500]}; + } + function MyV5Component() { + const theme = useV5Theme(); + return v5-grey: {theme.palette.grey[500]}; + } + + render( + + + + , + ); + + expect(screen.getByText('v4-grey: #9e9e9e')).toBeInTheDocument(); + expect(screen.getByText('v5-grey: #9e9e9e')).toBeInTheDocument(); + }); + + it('provides a themes for v4 and v5 through makeStyles', () => { + const useV4Styles = makeV4Styles(theme => ({ + root: { + color: theme.palette.grey[500], + }, + })); + const useV5Styles = makeV5Styles(theme => ({ + root: { + color: theme.palette.grey[500], + }, + })); + + function MyV4Component() { + const classes = useV4Styles(); + return v4; + } + function MyV5Component() { + const classes = useV5Styles(); + return v5; + } + + render( + + + + , + ); + + expect(window.getComputedStyle(screen.getByText('v4')).color).toBe( + 'rgb(158, 158, 158)', + ); + expect(window.getComputedStyle(screen.getByText('v5')).color).toBe( + 'rgb(158, 158, 158)', + ); + }); +}); diff --git a/packages/theme/src/v5/defaultComponentThemes.ts b/packages/theme/src/v5/defaultComponentThemes.ts index e484300818..60caa47e90 100644 --- a/packages/theme/src/v5/defaultComponentThemes.ts +++ b/packages/theme/src/v5/defaultComponentThemes.ts @@ -239,4 +239,7 @@ export const defaultComponentThemes: ThemeOptions['components'] = { underline: 'hover', }, }, + MuiPaper: { + styleOverrides: { root: { backgroundImage: 'unset' } }, + }, }; diff --git a/packages/theme/src/v5/types.test.ts b/packages/theme/src/v5/types.test.ts new file mode 100644 index 0000000000..12bd0ff2b8 --- /dev/null +++ b/packages/theme/src/v5/types.test.ts @@ -0,0 +1,47 @@ +/* + * 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 { palettes } from '../base'; +import { createUnifiedTheme } from '../unified'; + +declare module '@backstage/theme' { + interface OverrideComponentNameToClassKeys { + MyTestComponent: 'root' | 'header'; + } +} + +describe('OverrideComponentNameToClassKeys', () => { + it('should provide type safe component style overrides', () => { + const theme = createUnifiedTheme({ + palette: palettes.light, + components: { + MyTestComponent: { + styleOverrides: { + root: { + color: '#f00', + }, + // @ts-expect-error + invalid: { + color: '#b45', + }, + }, + }, + }, + }); + + expect(theme).toBeDefined(); + }); +}); diff --git a/packages/theme/src/v5/types.ts b/packages/theme/src/v5/types.ts index 0d6d46cef9..aa80c903fa 100644 --- a/packages/theme/src/v5/types.ts +++ b/packages/theme/src/v5/types.ts @@ -19,6 +19,8 @@ import { BackstagePaletteAdditions, BackstageThemeAdditions, } from '../base/types'; +// eslint-disable-next-line no-restricted-imports +import { OverridesStyleRules } from '@mui/material/styles/overrides'; declare module '@mui/material/styles' { interface Palette extends BackstagePaletteAdditions {} @@ -35,3 +37,30 @@ declare module '@mui/material/styles' { declare module '@mui/private-theming/defaultTheme' { interface DefaultTheme extends Theme {} } + +/** + * Merge interface declarations into this type to register overrides for your components. + * + * @public + * @example + * ```ts + * declare module '@backstage/theme' { + * interface OverrideComponentNameToClassKeys { + * MyComponent: 'root' | 'header'; + * } + * } + * ``` + */ +export interface OverrideComponentNameToClassKeys {} + +type BackstageComponentOverrides = { + [TName in keyof OverrideComponentNameToClassKeys]?: { + styleOverrides?: Partial< + OverridesStyleRules + >; + }; +}; + +declare module '@mui/material/styles' { + interface Components extends BackstageComponentOverrides {} +} diff --git a/packages/version-bridge/CHANGELOG.md b/packages/version-bridge/CHANGELOG.md index 7e7a708be1..1ff0a048a2 100644 --- a/packages/version-bridge/CHANGELOG.md +++ b/packages/version-bridge/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/version-bridge +## 1.0.7 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. + ## 1.0.7-next.0 ### Patch Changes diff --git a/packages/version-bridge/package.json b/packages/version-bridge/package.json index 4cb6119071..f40ef91d0c 100644 --- a/packages/version-bridge/package.json +++ b/packages/version-bridge/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/version-bridge", "description": "Utilities used by @backstage packages to support multiple concurrent versions", - "version": "1.0.7-next.0", + "version": "1.0.7", "publishConfig": { "access": "public", "main": "dist/index.esm.js", diff --git a/plugins/adr-backend/CHANGELOG.md b/plugins/adr-backend/CHANGELOG.md index b6e94e72c7..adc0cf284f 100644 --- a/plugins/adr-backend/CHANGELOG.md +++ b/plugins/adr-backend/CHANGELOG.md @@ -1,5 +1,151 @@ # @backstage/plugin-adr-backend +## 0.4.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/plugin-adr-common@0.2.19 + - @backstage/plugin-search-common@1.2.10 + +## 0.4.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + +## 0.4.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-adr-common@0.2.18 + - @backstage/plugin-search-common@1.2.9 + +## 0.4.6-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/plugin-adr-common@0.2.18 + - @backstage/plugin-search-common@1.2.9 + +## 0.4.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/catalog-client@1.5.0 + - @backstage/integration@1.8.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-adr-common@0.2.18 + - @backstage/plugin-search-common@1.2.9 + +## 0.4.5-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/plugin-adr-common@0.2.18-next.1 + - @backstage/plugin-search-common@1.2.8 + +## 0.4.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/plugin-adr-common@0.2.18-next.1 + - @backstage/plugin-search-common@1.2.8 + +## 0.4.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-adr-common@0.2.18-next.1 + - @backstage/plugin-search-common@1.2.8 + +## 0.4.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-adr-common@0.2.18-next.0 + - @backstage/plugin-search-common@1.2.8 + +## 0.4.4 + +### Patch Changes + +- 68f8a55622: Updated dependency `@types/marked` to `^5.0.0`. +- Updated dependencies + - @backstage/integration@1.7.2 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-adr-common@0.2.17 + - @backstage/plugin-search-common@1.2.8 + ## 0.4.4-next.2 ### Patch Changes diff --git a/plugins/adr-backend/package.json b/plugins/adr-backend/package.json index 51051e7bbc..24cebdff04 100644 --- a/plugins/adr-backend/package.json +++ b/plugins/adr-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-adr-backend", - "version": "0.4.4-next.2", + "version": "0.4.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -50,7 +50,6 @@ "@backstage/cli": "workspace:^", "@types/marked": "^5.0.0", "@types/supertest": "^2.0.8", - "msw": "^1.0.0", "supertest": "^6.1.3" }, "files": [ diff --git a/plugins/adr-common/CHANGELOG.md b/plugins/adr-common/CHANGELOG.md index e9e1c68cf0..84c285a1a8 100644 --- a/plugins/adr-common/CHANGELOG.md +++ b/plugins/adr-common/CHANGELOG.md @@ -1,5 +1,50 @@ # @backstage/plugin-adr-common +## 0.2.19 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/integration@1.8.0 + - @backstage/plugin-search-common@1.2.10 + +## 0.2.18 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-search-common@1.2.9 + +## 0.2.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-search-common@1.2.8 + +## 0.2.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-search-common@1.2.8 + +## 0.2.17 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.2 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-search-common@1.2.8 + ## 0.2.17-next.0 ### Patch Changes diff --git a/plugins/adr-common/package.json b/plugins/adr-common/package.json index e737f1fcf9..d05b585c7d 100644 --- a/plugins/adr-common/package.json +++ b/plugins/adr-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-adr-common", "description": "Common functionalities for the adr plugin", - "version": "0.2.17-next.0", + "version": "0.2.19", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/adr/CHANGELOG.md b/plugins/adr/CHANGELOG.md index 570878106a..8cf8b2c28e 100644 --- a/plugins/adr/CHANGELOG.md +++ b/plugins/adr/CHANGELOG.md @@ -1,5 +1,166 @@ # @backstage/plugin-adr +## 0.6.12 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/plugin-search-react@1.7.5 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-adr-common@0.2.19 + - @backstage/plugin-search-common@1.2.10 + +## 0.6.12-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.1-next.2 + - @backstage/plugin-catalog-react@1.9.3-next.2 + - @backstage/plugin-search-react@1.7.5-next.2 + - @backstage/integration-react@1.1.23-next.0 + +## 0.6.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/frontend-plugin-api@0.4.1-next.1 + - @backstage/integration-react@1.1.23-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/plugin-search-react@1.7.5-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-adr-common@0.2.18 + - @backstage/plugin-search-common@1.2.9 + +## 0.6.12-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/frontend-plugin-api@0.4.1-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/integration-react@1.1.22 + - @backstage/plugin-search-react@1.7.5-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-adr-common@0.2.18 + - @backstage/plugin-search-common@1.2.9 + +## 0.6.11 + +### Patch Changes + +- 5814122: Updated `/alpha` exports to fit new naming patterns. +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- fb8f3bd: Updated alpha translation message keys to use nested format and camel case. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/frontend-plugin-api@0.4.0 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/plugin-search-react@1.7.4 + - @backstage/integration-react@1.1.22 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-adr-common@0.2.18 + - @backstage/plugin-search-common@1.2.9 + +## 0.6.11-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/frontend-plugin-api@0.4.0-next.3 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-adr-common@0.2.18-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + - @backstage/plugin-search-common@1.2.8 + - @backstage/plugin-search-react@1.7.4-next.3 + +## 0.6.11-next.2 + +### Patch Changes + +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.2 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/plugin-search-react@1.7.4-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-adr-common@0.2.18-next.1 + - @backstage/plugin-search-common@1.2.8 + +## 0.6.11-next.1 + +### Patch Changes + +- fb8f3bdbc2: Updated alpha translation message keys to use nested format and camel case. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-search-react@1.7.4-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-adr-common@0.2.18-next.1 + - @backstage/plugin-search-common@1.2.8 + +## 0.6.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/plugin-search-react@1.7.4-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/frontend-plugin-api@0.3.1-next.0 + - @backstage/integration-react@1.1.22-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-adr-common@0.2.18-next.0 + - @backstage/plugin-search-common@1.2.8 + +## 0.6.9 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/frontend-plugin-api@0.3.0 + - @backstage/integration-react@1.1.21 + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-search-react@1.7.2 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-adr-common@0.2.17 + - @backstage/plugin-search-common@1.2.8 + ## 0.6.9-next.2 ### Patch Changes diff --git a/plugins/adr/README.md b/plugins/adr/README.md index e6178f003b..3e8647a8fa 100644 --- a/plugins/adr/README.md +++ b/plugins/adr/README.md @@ -2,7 +2,7 @@ Welcome to the ADR plugin! -This plugin allows you to browse ADRs associated with your entities as well as a way to discover ADRs across others entities via Backstage Search. Use this to learn from the past experience of other projects to guide your own architecture decisions. +This plugin allows you to explore ADRs (Architecture Decision Records) associated with your entities, as well as discover ADRs across other entities using Backstage Search. Use this to inform your own architectural decisions based on the experiences of previous projects. ![ADR tab](./docs/adr-tab.png) diff --git a/plugins/adr/alpha-api-report.md b/plugins/adr/api-report-alpha.md similarity index 67% rename from plugins/adr/alpha-api-report.md rename to plugins/adr/api-report-alpha.md index 5740556904..bfa27a6d4f 100644 --- a/plugins/adr/alpha-api-report.md +++ b/plugins/adr/api-report-alpha.md @@ -4,11 +4,11 @@ ```ts import { BackstagePlugin } from '@backstage/frontend-plugin-api'; -import { Extension } from '@backstage/frontend-plugin-api'; +import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { TranslationRef } from '@backstage/core-plugin-api/alpha'; // @alpha (undocumented) -export const AdrSearchResultListItemExtension: Extension<{ +export const adrSearchResultListItemExtension: ExtensionDefinition<{ lineClamp: number; noTrack: boolean; }>; @@ -17,9 +17,9 @@ export const AdrSearchResultListItemExtension: Extension<{ export const adrTranslationRef: TranslationRef< 'adr', { - readonly content_header_title: 'Architecture Decision Records'; - readonly failed_to_fetch: 'Failed to fetch ADRs'; - readonly no_adrs: 'No ADRs found'; + readonly contentHeaderTitle: 'Architecture Decision Records'; + readonly failedToFetch: 'Failed to fetch ADRs'; + readonly notFound: 'No ADRs found'; } >; diff --git a/plugins/adr/package.json b/plugins/adr/package.json index 0568edc8d7..35c89ce255 100644 --- a/plugins/adr/package.json +++ b/plugins/adr/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-adr", - "version": "0.6.9-next.2", + "version": "0.6.12", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -51,10 +51,8 @@ "@backstage/plugin-catalog-react": "workspace:^", "@backstage/plugin-search-common": "workspace:^", "@backstage/plugin-search-react": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.61", "@types/react": "^16.13.1 || ^17.0.0", "lodash": "^4.17.21", "react-markdown": "^8.0.0", @@ -68,16 +66,9 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", - "@backstage/dev-utils": "workspace:^", - "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "@types/git-url-parse": "^9.0.0", - "cross-fetch": "^4.0.0", - "msw": "^1.0.0" + "@testing-library/react": "^14.0.0" }, "files": [ "dist" diff --git a/plugins/adr/src/alpha.tsx b/plugins/adr/src/alpha.tsx index 1f6fa0711d..4abba11fcf 100644 --- a/plugins/adr/src/alpha.tsx +++ b/plugins/adr/src/alpha.tsx @@ -29,9 +29,8 @@ function isAdrDocument(result: any): result is AdrDocument { } /** @alpha */ -export const AdrSearchResultListItemExtension = +export const adrSearchResultListItemExtension = createSearchResultListItemExtension({ - id: 'adr', configSchema: createSchemaFromZod(z => z.object({ // TODO: Define how the icon can be configurable @@ -54,5 +53,5 @@ export const AdrSearchResultListItemExtension = /** @alpha */ export default createPlugin({ id: 'adr', - extensions: [AdrSearchResultListItemExtension], + extensions: [adrSearchResultListItemExtension], }); diff --git a/plugins/adr/src/components/EntityAdrContent/EntityAdrContent.tsx b/plugins/adr/src/components/EntityAdrContent/EntityAdrContent.tsx index 261dd994fb..5c8d244d26 100644 --- a/plugins/adr/src/components/EntityAdrContent/EntityAdrContent.tsx +++ b/plugins/adr/src/components/EntityAdrContent/EntityAdrContent.tsx @@ -219,7 +219,7 @@ export const EntityAdrContent = (props: { return ( - + {appSupportConfigured && } @@ -230,7 +230,7 @@ export const EntityAdrContent = (props: { {loading && } {entityHasAdrs && !loading && error && ( - + )} {entityHasAdrs && @@ -257,7 +257,7 @@ export const EntityAdrContent = (props: { ) : ( - {t('no_adrs')} + {t('notFound')} ))} ); diff --git a/plugins/adr/src/translations.ts b/plugins/adr/src/translations.ts index cc0995f597..038b0fd064 100644 --- a/plugins/adr/src/translations.ts +++ b/plugins/adr/src/translations.ts @@ -19,8 +19,8 @@ import { createTranslationRef } from '@backstage/core-plugin-api/alpha'; export const adrTranslationRef = createTranslationRef({ id: 'adr', messages: { - content_header_title: 'Architecture Decision Records', - failed_to_fetch: 'Failed to fetch ADRs', - no_adrs: 'No ADRs found', + contentHeaderTitle: 'Architecture Decision Records', + failedToFetch: 'Failed to fetch ADRs', + notFound: 'No ADRs found', }, }); diff --git a/plugins/airbrake-backend/CHANGELOG.md b/plugins/airbrake-backend/CHANGELOG.md index cdb9f53d53..2a7c655a2d 100644 --- a/plugins/airbrake-backend/CHANGELOG.md +++ b/plugins/airbrake-backend/CHANGELOG.md @@ -1,5 +1,96 @@ # @backstage/plugin-airbrake-backend +## 0.3.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + +## 0.3.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + +## 0.3.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + +## 0.3.6-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/config@1.1.1 + +## 0.3.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + +## 0.3.5-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/config@1.1.1 + +## 0.3.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/config@1.1.1 + +## 0.3.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + +## 0.3.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + +## 0.3.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/config@1.1.1 + ## 0.3.4-next.2 ### Patch Changes diff --git a/plugins/airbrake-backend/package.json b/plugins/airbrake-backend/package.json index 434aef9372..f424ba8ce7 100644 --- a/plugins/airbrake-backend/package.json +++ b/plugins/airbrake-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-airbrake-backend", - "version": "0.3.4-next.2", + "version": "0.3.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -42,7 +42,6 @@ "@backstage/cli": "workspace:^", "@types/http-proxy-middleware": "^0.19.3", "@types/supertest": "^2.0.8", - "msw": "^1.0.0", "supertest": "^6.1.6" }, "files": [ diff --git a/plugins/airbrake/CHANGELOG.md b/plugins/airbrake/CHANGELOG.md index a09ac986c6..4636c27068 100644 --- a/plugins/airbrake/CHANGELOG.md +++ b/plugins/airbrake/CHANGELOG.md @@ -1,5 +1,131 @@ # @backstage/plugin-airbrake +## 0.3.29 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/dev-utils@1.0.26 + - @backstage/catalog-model@1.4.3 + - @backstage/test-utils@1.4.7 + +## 0.3.29-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + - @backstage/dev-utils@1.0.26-next.2 + +## 0.3.29-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/dev-utils@1.0.26-next.1 + - @backstage/test-utils@1.4.7-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + +## 0.3.29-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/dev-utils@1.0.26-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/test-utils@1.4.7-next.0 + +## 0.3.28 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/test-utils@1.4.6 + - @backstage/dev-utils@1.0.25 + - @backstage/catalog-model@1.4.3 + +## 0.3.28-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/dev-utils@1.0.25-next.3 + - @backstage/test-utils@1.4.6-next.2 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## 0.3.28-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/dev-utils@1.0.25-next.2 + - @backstage/test-utils@1.4.6-next.2 + +## 0.3.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/test-utils@1.4.6-next.1 + - @backstage/dev-utils@1.0.25-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## 0.3.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/dev-utils@1.0.25-next.0 + - @backstage/test-utils@1.4.6-next.0 + - @backstage/catalog-model@1.4.3 + +## 0.3.26 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/test-utils@1.4.5 + - @backstage/theme@0.4.4 + - @backstage/dev-utils@1.0.23 + - @backstage/catalog-model@1.4.3 + ## 0.3.26-next.2 ### Patch Changes diff --git a/plugins/airbrake/package.json b/plugins/airbrake/package.json index e5a872e1c6..3cf1107fe0 100644 --- a/plugins/airbrake/package.json +++ b/plugins/airbrake/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-airbrake", - "version": "0.3.26-next.2", + "version": "0.3.29", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,10 +35,8 @@ "@backstage/dev-utils": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", "@backstage/test-utils": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.61", "@types/react": "^16.13.1 || ^17.0.0", "react-use": "^17.2.4" }, @@ -55,7 +53,6 @@ "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, "files": [ diff --git a/plugins/airbrake/src/components/EntityAirbrakeWidget/EntityAirbrakeWidget.tsx b/plugins/airbrake/src/components/EntityAirbrakeWidget/EntityAirbrakeWidget.tsx index 3e82d60d81..666a7ffea2 100644 --- a/plugins/airbrake/src/components/EntityAirbrakeWidget/EntityAirbrakeWidget.tsx +++ b/plugins/airbrake/src/components/EntityAirbrakeWidget/EntityAirbrakeWidget.tsx @@ -22,7 +22,6 @@ import { Progress, } from '@backstage/core-components'; import { useApi } from '@backstage/core-plugin-api'; -import { BackstageTheme } from '@backstage/theme'; import { Grid, Typography } from '@material-ui/core'; import { makeStyles } from '@material-ui/core/styles'; import React from 'react'; @@ -31,11 +30,11 @@ import { airbrakeApiRef } from '../../api'; import { MissingAnnotationEmptyState } from '@backstage/plugin-catalog-react'; import { AIRBRAKE_PROJECT_ID_ANNOTATION, useProjectId } from '../useProjectId'; -const useStyles = makeStyles(() => ({ +const useStyles = makeStyles({ multilineText: { whiteSpace: 'pre-wrap', }, -})); +}); export const EntityAirbrakeWidget = ({ entity }: { entity: Entity }) => { const classes = useStyles(); diff --git a/plugins/allure/CHANGELOG.md b/plugins/allure/CHANGELOG.md index 207a3723c3..bf9aaa61df 100644 --- a/plugins/allure/CHANGELOG.md +++ b/plugins/allure/CHANGELOG.md @@ -1,5 +1,112 @@ # @backstage/plugin-allure +## 0.1.45 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## 0.1.45-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.1.45-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + +## 0.1.45-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + +## 0.1.44 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + +## 0.1.44-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## 0.1.44-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## 0.1.44-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## 0.1.44-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + +## 0.1.42 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + ## 0.1.42-next.2 ### Patch Changes diff --git a/plugins/allure/package.json b/plugins/allure/package.json index 947acfa34f..991c2a8944 100644 --- a/plugins/allure/package.json +++ b/plugins/allure/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-allure", "description": "A Backstage plugin that integrates with Allure", - "version": "0.1.42-next.2", + "version": "0.1.45", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,10 +34,6 @@ "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", - "@backstage/theme": "workspace:^", - "@material-ui/core": "^4.12.2", - "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.61", "@types/react": "^16.13.1 || ^17.0.0", "react-use": "^17.2.4" }, @@ -48,13 +44,11 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", "@backstage/dev-utils": "workspace:^", "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, "files": [ diff --git a/plugins/analytics-module-ga/CHANGELOG.md b/plugins/analytics-module-ga/CHANGELOG.md index b38c520e15..5135b15ac1 100644 --- a/plugins/analytics-module-ga/CHANGELOG.md +++ b/plugins/analytics-module-ga/CHANGELOG.md @@ -1,5 +1,95 @@ # @backstage/plugin-analytics-module-ga +## 0.1.37 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/config@1.1.1 + +## 0.1.37-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/config@1.1.1 + +## 0.1.37-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1 + +## 0.1.36 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/config@1.1.1 + +## 0.1.36-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + +## 0.1.36-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/config@1.1.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## 0.1.36-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + +## 0.1.36-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/config@1.1.1 + +## 0.1.35 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/config@1.1.1 + ## 0.1.35-next.2 ### Patch Changes diff --git a/plugins/analytics-module-ga/package.json b/plugins/analytics-module-ga/package.json index 402ac7d1d9..3d367a5889 100644 --- a/plugins/analytics-module-ga/package.json +++ b/plugins/analytics-module-ga/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-analytics-module-ga", - "version": "0.1.35-next.2", + "version": "0.1.37", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,12 +32,7 @@ "@backstage/config": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", - "@backstage/theme": "workspace:^", - "@material-ui/core": "^4.12.2", - "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.61", - "react-ga": "^3.3.0", - "react-use": "^17.2.4" + "react-ga": "^3.3.0" }, "peerDependencies": { "react": "^16.13.1 || ^17.0.0 || ^18.0.0", @@ -46,15 +41,11 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", "@backstage/dev-utils": "workspace:^", - "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "@types/react": "^16.13.1 || ^17.0.0", - "msw": "^1.0.0" + "@types/react": "^16.13.1 || ^17.0.0" }, "files": [ "dist", diff --git a/plugins/analytics-module-ga4/CHANGELOG.md b/plugins/analytics-module-ga4/CHANGELOG.md index d5f6248fef..6529fc3711 100644 --- a/plugins/analytics-module-ga4/CHANGELOG.md +++ b/plugins/analytics-module-ga4/CHANGELOG.md @@ -1,5 +1,97 @@ # @backstage/plugin-analytics-module-ga4 +## 0.1.8 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/config@1.1.1 + +## 0.1.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/config@1.1.1 + +## 0.1.8-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1 + +## 0.1.7 + +### Patch Changes + +- af6f227: Disabled `send_page_view` to get rid of events duplication +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/config@1.1.1 + +## 0.1.7-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + +## 0.1.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/config@1.1.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## 0.1.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + +## 0.1.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/config@1.1.1 + +## 0.1.6 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 504614d313: Updated dependency `@types/jest` to `^29.0.0`. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/config@1.1.1 + ## 0.1.6-next.2 ### Patch Changes diff --git a/plugins/analytics-module-ga4/README.md b/plugins/analytics-module-ga4/README.md index 93138a8235..2d8c930e30 100644 --- a/plugins/analytics-module-ga4/README.md +++ b/plugins/analytics-module-ga4/README.md @@ -87,6 +87,7 @@ Additional dimensional data can be captured using custom dimensions, like this: attribute names will be prefixed by `a_`. 5. `allowedContexts` and `allowedAttributes` are optional, if not provided, no additional context and attributes will be sent. 6. if `allowedContexts` or `allowedAttributes` is set to '\*', all context and attributes will be sent. +7. `enableSendPageView` is used to send default events and is disabled by default. ```yaml app: diff --git a/plugins/analytics-module-ga4/config.d.ts b/plugins/analytics-module-ga4/config.d.ts index 4834d75f58..0a60ee5f9e 100644 --- a/plugins/analytics-module-ga4/config.d.ts +++ b/plugins/analytics-module-ga4/config.d.ts @@ -54,6 +54,14 @@ export interface Config { */ debug?: boolean; + /** + * Whether to send default send_page_view event. + * Defaults to false. + * + * @visibility frontend + */ + enableSendPageView?: boolean; + /** * Prevents events from actually being sent when set to true. Defaults * to false. diff --git a/plugins/analytics-module-ga4/package.json b/plugins/analytics-module-ga4/package.json index ca65894eea..97b610c2bf 100644 --- a/plugins/analytics-module-ga4/package.json +++ b/plugins/analytics-module-ga4/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-analytics-module-ga4", - "version": "0.1.6-next.2", + "version": "0.1.8", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,9 +32,7 @@ "@backstage/config": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", - "@backstage/theme": "workspace:^", - "react-ga4": "^2.0.0", - "react-use": "^17.2.4" + "react-ga4": "^2.0.0" }, "peerDependencies": { "react": "^16.13.1 || ^17.0.0 || ^18.0.0", @@ -43,16 +41,12 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", "@backstage/dev-utils": "workspace:^", - "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", "@types/jest": "^29.0.0", - "@types/react": "^16.13.1 || ^17.0.0", - "msw": "^1.0.0" + "@types/react": "^16.13.1 || ^17.0.0" }, "files": [ "dist", diff --git a/plugins/analytics-module-ga4/src/apis/implementations/AnalyticsApi/GoogleAnalytics4.ts b/plugins/analytics-module-ga4/src/apis/implementations/AnalyticsApi/GoogleAnalytics4.ts index 399366b804..9abf4719c6 100644 --- a/plugins/analytics-module-ga4/src/apis/implementations/AnalyticsApi/GoogleAnalytics4.ts +++ b/plugins/analytics-module-ga4/src/apis/implementations/AnalyticsApi/GoogleAnalytics4.ts @@ -47,6 +47,7 @@ export class GoogleAnalytics4 implements AnalyticsApi { measurementId: string; testMode: boolean; debug: boolean; + enableSendPageView: boolean; contentGroupBy?: string; allowedContexts?: string[]; allowedAttributes?: string[]; @@ -58,6 +59,7 @@ export class GoogleAnalytics4 implements AnalyticsApi { userIdTransform = 'sha-256', testMode, debug, + enableSendPageView, contentGroupBy, allowedContexts, allowedAttributes, @@ -70,6 +72,7 @@ export class GoogleAnalytics4 implements AnalyticsApi { }, gtagOptions: { debug_mode: debug, + send_page_view: enableSendPageView, }, }); @@ -112,6 +115,9 @@ export class GoogleAnalytics4 implements AnalyticsApi { const identity = config.getOptionalString('app.analytics.ga4.identity') || 'disabled'; const debug = config.getOptionalBoolean('app.analytics.ga4.debug') ?? false; + const enableSendPageView = + config.getOptionalBoolean('app.analytics.ga4.enableSendPageView') ?? + false; const testMode = config.getOptionalBoolean('app.analytics.ga4.testMode') ?? false; @@ -138,6 +144,7 @@ export class GoogleAnalytics4 implements AnalyticsApi { measurementId: measurementId, testMode, debug, + enableSendPageView, contentGroupBy, allowedContexts, allowedAttributes, diff --git a/plugins/analytics-module-newrelic-browser/CHANGELOG.md b/plugins/analytics-module-newrelic-browser/CHANGELOG.md index 6bf3c52b29..0f9b210d9a 100644 --- a/plugins/analytics-module-newrelic-browser/CHANGELOG.md +++ b/plugins/analytics-module-newrelic-browser/CHANGELOG.md @@ -1,5 +1,89 @@ # @backstage/plugin-analytics-module-newrelic-browser +## 0.0.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/config@1.1.1 + +## 0.0.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/config@1.1.1 + +## 0.0.6-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1 + +## 0.0.5 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/config@1.1.1 + +## 0.0.5-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1-next.1 + +## 0.0.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## 0.0.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + +## 0.0.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/config@1.1.1 + +## 0.0.4 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/config@1.1.1 + ## 0.0.4-next.2 ### Patch Changes diff --git a/plugins/analytics-module-newrelic-browser/package.json b/plugins/analytics-module-newrelic-browser/package.json index 8f6c8cb875..0815b62b6c 100644 --- a/plugins/analytics-module-newrelic-browser/package.json +++ b/plugins/analytics-module-newrelic-browser/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-analytics-module-newrelic-browser", - "version": "0.0.4-next.2", + "version": "0.0.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -26,21 +26,16 @@ "@backstage/config": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", - "@newrelic/browser-agent": "^1.236.0", - "react-use": "^17.2.4" + "@newrelic/browser-agent": "^1.236.0" }, "peerDependencies": { "react": "^16.13.1 || ^17.0.0 || ^18.0.0" }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", "@backstage/dev-utils": "workspace:^", - "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "msw": "^1.0.0" + "@testing-library/react": "^14.0.0" }, "files": [ "dist", diff --git a/plugins/apache-airflow/CHANGELOG.md b/plugins/apache-airflow/CHANGELOG.md index 29380e22e6..9c2a434030 100644 --- a/plugins/apache-airflow/CHANGELOG.md +++ b/plugins/apache-airflow/CHANGELOG.md @@ -1,5 +1,81 @@ # @backstage/plugin-apache-airflow +## 0.2.19 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + +## 0.2.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + +## 0.2.19-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/core-plugin-api@1.8.1 + +## 0.2.18 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + +## 0.2.18-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + +## 0.2.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## 0.2.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + +## 0.2.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + +## 0.2.17 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + ## 0.2.17-next.2 ### Patch Changes diff --git a/plugins/apache-airflow/package.json b/plugins/apache-airflow/package.json index 12182c85fb..489fcde5e8 100644 --- a/plugins/apache-airflow/package.json +++ b/plugins/apache-airflow/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-apache-airflow", - "version": "0.2.17-next.2", + "version": "0.2.19", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -52,7 +52,6 @@ "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, "files": [ diff --git a/plugins/api-docs-module-protoc-gen-doc/CHANGELOG.md b/plugins/api-docs-module-protoc-gen-doc/CHANGELOG.md index b31c53f633..2c96409cab 100644 --- a/plugins/api-docs-module-protoc-gen-doc/CHANGELOG.md +++ b/plugins/api-docs-module-protoc-gen-doc/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/plugin-api-docs-module-protoc-gen-doc +## 0.1.5 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. + ## 0.1.5-next.0 ### Patch Changes diff --git a/plugins/api-docs-module-protoc-gen-doc/package.json b/plugins/api-docs-module-protoc-gen-doc/package.json index 4f038aaaec..3adf16d6ff 100644 --- a/plugins/api-docs-module-protoc-gen-doc/package.json +++ b/plugins/api-docs-module-protoc-gen-doc/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-api-docs-module-protoc-gen-doc", "description": "Additional functionalities for the api-docs plugin that renders the output of the protoc-gen-doc", - "version": "0.1.5-next.0", + "version": "0.1.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/api-docs/CHANGELOG.md b/plugins/api-docs/CHANGELOG.md index 42bb23bf2c..f801bf9ba2 100644 --- a/plugins/api-docs/CHANGELOG.md +++ b/plugins/api-docs/CHANGELOG.md @@ -1,5 +1,151 @@ # @backstage/plugin-api-docs +## 0.10.3 + +### Patch Changes + +- 8a69cc9: Fix custom http resolvers for AsyncAPI widget. +- 062b8f2: Add permission check to Register Existing API button +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/plugin-catalog@1.16.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.20 + +## 0.10.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.16.1-next.2 + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.10.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog@1.16.1-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + +## 0.10.3-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/plugin-catalog@1.16.1-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + +## 0.10.2 + +### Patch Changes + +- 816d331: Add dependency on `graphql-config` to compensate for `graphql-language-service` needing it but not shipping the dep properly +- 615159e: Updated dependency `graphiql` to `3.0.10`. +- e16e7ce: Updated dependency `@asyncapi/react-component` to `1.2.2`. +- 82fb18b: Updated dependency `@asyncapi/react-component` to `1.2.6`. +- 53e2c06: Updated dependency `@asyncapi/react-component` to `1.1.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/plugin-catalog@1.16.0 + - @backstage/catalog-model@1.4.3 + +## 0.10.2-next.4 + +### Patch Changes + +- 82fb18b: Updated dependency `@asyncapi/react-component` to `1.2.6`. +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog@1.16.0-next.4 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## 0.10.2-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog@1.16.0-next.3 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## 0.10.2-next.2 + +### Patch Changes + +- e16e7ce6a5: Updated dependency `@asyncapi/react-component` to `1.2.2`. +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-catalog@1.16.0-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## 0.10.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.16.0-next.1 + +## 0.10.2-next.0 + +### Patch Changes + +- 816d331d16: Add dependency on `graphql-config` to compensate for `graphql-language-service` needing it but not shipping the dep properly +- 615159e536: Updated dependency `graphiql` to `3.0.10`. +- 53e2c06f41: Updated dependency `@asyncapi/react-component` to `1.1.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/plugin-catalog@1.16.0-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + +## 0.10.0 + +### Minor Changes + +- 0ac0e10822: Replace GraphiQL playground with DocExplorer +- 62310404b7: Define a default for oauth2RedirectUrl option of swagger-ui-react to match documentation + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- 613a55911f: Updated dependency `graphiql` to `3.0.9`. +- 4ad15278e6: Updated dependency `@graphiql/react` to `^0.20.0`. +- 62b5922916: Internal theme type updates +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/plugin-catalog@1.15.0 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + ## 0.10.0-next.2 ### Minor Changes diff --git a/plugins/api-docs/README.md b/plugins/api-docs/README.md index 79c4581e79..4d4342de61 100644 --- a/plugins/api-docs/README.md +++ b/plugins/api-docs/README.md @@ -13,7 +13,7 @@ The plugin provides a standalone list of APIs, as well as an integration into th Right now, the following API formats are supported: - [OpenAPI](https://swagger.io/specification/) 2 & 3 -- [AsyncAPI](https://www.asyncapi.com/docs/specifications/latest/) +- [AsyncAPI](https://www.asyncapi.com/docs/reference/specification/latest) - [GraphQL](https://graphql.org/learn/schema/) Other formats are displayed as plain text, but this can easily be extended. diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index 8ee15550ed..1819d80208 100644 --- a/plugins/api-docs/package.json +++ b/plugins/api-docs/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-api-docs", "description": "A Backstage plugin that helps represent API entities in the frontend", - "version": "0.10.0-next.2", + "version": "0.10.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,23 +33,24 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@asyncapi/react-component": "1.0.0-next.48", + "@asyncapi/react-component": "1.2.6", "@backstage/catalog-model": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/plugin-catalog": "workspace:^", + "@backstage/plugin-catalog-common": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", - "@backstage/theme": "workspace:^", + "@backstage/plugin-permission-react": "workspace:^", "@graphiql/react": "^0.20.0", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", "@types/react": "^16.13.1 || ^17.0.0", - "graphiql": "3.0.9", + "graphiql": "3.0.10", "graphql": "^16.0.0", + "graphql-config": "^5.0.2", "graphql-ws": "^5.4.1", "isomorphic-form-data": "^2.0.0", - "react-use": "^17.2.4", "swagger-ui-react": "^5.0.0" }, "peerDependencies": { @@ -66,9 +67,7 @@ "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", - "@types/swagger-ui-react": "^4.18.0", - "cross-fetch": "^4.0.0", - "msw": "^1.0.0" + "@types/swagger-ui-react": "^4.18.0" }, "files": [ "dist" diff --git a/plugins/api-docs/src/components/ApiDefinitionDialog/ApiDefinitionDialog.tsx b/plugins/api-docs/src/components/ApiDefinitionDialog/ApiDefinitionDialog.tsx index 2f82a0cc5a..6673420732 100644 --- a/plugins/api-docs/src/components/ApiDefinitionDialog/ApiDefinitionDialog.tsx +++ b/plugins/api-docs/src/components/ApiDefinitionDialog/ApiDefinitionDialog.tsx @@ -16,7 +16,6 @@ import { ApiEntity } from '@backstage/catalog-model'; import { useApi } from '@backstage/core-plugin-api'; -import { BackstageTheme } from '@backstage/theme'; import { Box, Button, @@ -33,7 +32,7 @@ import React, { useEffect } from 'react'; import { apiDocsConfigRef } from '../../config'; import { PlainApiDefinitionWidget } from '../PlainApiDefinitionWidget'; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles(theme => ({ fullHeightDialog: { height: 'calc(100% - 64px)', }, diff --git a/plugins/api-docs/src/components/ApiExplorerPage/DefaultApiExplorerPage.test.tsx b/plugins/api-docs/src/components/ApiExplorerPage/DefaultApiExplorerPage.test.tsx index 6d0b191d68..7938770c4c 100644 --- a/plugins/api-docs/src/components/ApiExplorerPage/DefaultApiExplorerPage.test.tsx +++ b/plugins/api-docs/src/components/ApiExplorerPage/DefaultApiExplorerPage.test.tsx @@ -32,6 +32,7 @@ import { starredEntitiesApiRef, } from '@backstage/plugin-catalog-react'; import { + MockPermissionApi, MockStorageApi, TestApiProvider, renderInTestApp, @@ -41,6 +42,7 @@ import { screen, waitFor } from '@testing-library/react'; import React from 'react'; import { apiDocsConfigRef } from '../../config'; import { DefaultApiExplorerPage } from './DefaultApiExplorerPage'; +import { permissionApiRef } from '@backstage/plugin-permission-react'; describe('DefaultApiExplorerPage', () => { const catalogApi: Partial = { @@ -98,6 +100,7 @@ describe('DefaultApiExplorerPage', () => { new DefaultStarredEntitiesApi({ storageApi }), ], [apiDocsConfigRef, apiDocsConfig], + [permissionApiRef, new MockPermissionApi()], ]} > {children} diff --git a/plugins/api-docs/src/components/ApiExplorerPage/DefaultApiExplorerPage.tsx b/plugins/api-docs/src/components/ApiExplorerPage/DefaultApiExplorerPage.tsx index ad43205c5f..dc83c2528d 100644 --- a/plugins/api-docs/src/components/ApiExplorerPage/DefaultApiExplorerPage.tsx +++ b/plugins/api-docs/src/components/ApiExplorerPage/DefaultApiExplorerPage.tsx @@ -38,6 +38,8 @@ import { } from '@backstage/plugin-catalog-react'; import React from 'react'; import { registerComponentRouteRef } from '../../routes'; +import { usePermission } from '@backstage/plugin-permission-react'; +import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common/alpha'; const defaultColumns: TableColumn[] = [ CatalogTable.columns.createTitleColumn({ hidden: true }), @@ -72,6 +74,9 @@ export const DefaultApiExplorerPage = (props: DefaultApiExplorerPageProps) => { configApi.getOptionalString('organization.name') ?? 'Backstage' } API Explorer`; const registerComponentLink = useRouteRef(registerComponentRouteRef); + const { allowed } = usePermission({ + permission: catalogEntityCreatePermission, + }); return ( { > - + {allowed && ( + + )} All your APIs diff --git a/plugins/api-docs/src/components/AsyncApiDefinitionWidget/AsyncApiDefinition.test.tsx b/plugins/api-docs/src/components/AsyncApiDefinitionWidget/AsyncApiDefinition.test.tsx index c9f979edad..ed3a3e98ce 100644 --- a/plugins/api-docs/src/components/AsyncApiDefinitionWidget/AsyncApiDefinition.test.tsx +++ b/plugins/api-docs/src/components/AsyncApiDefinitionWidget/AsyncApiDefinition.test.tsx @@ -54,7 +54,7 @@ components: expect(getByText(/Account Service/i)).toBeInTheDocument(); expect(getByText(/user\/signedup/i)).toBeInTheDocument(); - expect(getAllByText(/UserSignedUp/i)).toHaveLength(2); + expect(getAllByText(/UserSignedUp/i)).toHaveLength(4); expect(getAllByText(/displayName/i)).toHaveLength(3); }); }); diff --git a/plugins/api-docs/src/components/AsyncApiDefinitionWidget/AsyncApiDefinition.tsx b/plugins/api-docs/src/components/AsyncApiDefinitionWidget/AsyncApiDefinition.tsx index 3e2fbd1078..461e466b4f 100644 --- a/plugins/api-docs/src/components/AsyncApiDefinitionWidget/AsyncApiDefinition.tsx +++ b/plugins/api-docs/src/components/AsyncApiDefinitionWidget/AsyncApiDefinition.tsx @@ -143,18 +143,33 @@ const useStyles = makeStyles(theme => ({ }, })); -const fetchResolver = { - order: 199, // Use 199 as the built-in http resolver is 200 - canRead: /^https?:\/\//, - async read(file: any) { - const response = await fetch(file.url); +const httpsFetchResolver = { + schema: 'https', + order: 1, + canRead: true, + async read(uri: any) { + const response = await fetch(uri.toString()); + return response.text(); + }, +}; + +const httpFetchResolver = { + schema: 'http', + order: 1, + canRead: true, + async read(uri: any) { + const response = await fetch(uri.toString()); return response.text(); }, }; const config = { parserOptions: { - resolve: { fetch: fetchResolver }, + __unstable: { + resolver: { + resolvers: [httpsFetchResolver, httpFetchResolver], + }, + }, }, }; diff --git a/plugins/api-docs/src/components/GraphQlDefinitionWidget/GraphQlDefinition.tsx b/plugins/api-docs/src/components/GraphQlDefinitionWidget/GraphQlDefinition.tsx index 6ad8643111..bf45a0e637 100644 --- a/plugins/api-docs/src/components/GraphQlDefinitionWidget/GraphQlDefinition.tsx +++ b/plugins/api-docs/src/components/GraphQlDefinitionWidget/GraphQlDefinition.tsx @@ -14,7 +14,6 @@ * limitations under the License. */ -import { BackstageTheme } from '@backstage/theme'; import { makeStyles } from '@material-ui/core/styles'; import { DocExplorer, @@ -26,7 +25,7 @@ import 'graphiql/graphiql.css'; import { buildSchema } from 'graphql'; import React from 'react'; -const useStyles = makeStyles(() => ({ +const useStyles = makeStyles({ root: { height: '100%', display: 'flex', @@ -46,7 +45,7 @@ const useStyles = makeStyles(() => ({ }, }, }, -})); +}); type Props = { definition: string; diff --git a/plugins/api-docs/src/components/GrpcApiDefinitionWidget/GrpcApiDefinitionWidget.tsx b/plugins/api-docs/src/components/GrpcApiDefinitionWidget/GrpcApiDefinitionWidget.tsx index b6bf317099..8363ebaedc 100644 --- a/plugins/api-docs/src/components/GrpcApiDefinitionWidget/GrpcApiDefinitionWidget.tsx +++ b/plugins/api-docs/src/components/GrpcApiDefinitionWidget/GrpcApiDefinitionWidget.tsx @@ -17,7 +17,6 @@ import React from 'react'; import { CodeSnippet } from '@backstage/core-components'; import { useTheme } from '@material-ui/core/styles'; -import { BackstageTheme } from '@backstage/theme'; /** @public */ export type GrpcApiDefinitionWidgetProps = { @@ -28,7 +27,7 @@ export type GrpcApiDefinitionWidgetProps = { export const GrpcApiDefinitionWidget = ( props: GrpcApiDefinitionWidgetProps, ) => { - const theme = useTheme(); + const theme = useTheme(); return ( { const { definition } = props; - const theme = useTheme(); + const theme = useTheme(); return ( (theme => ({ +const useStyles = makeStyles(theme => ({ tabs: { background: theme.palette.background.paper, }, diff --git a/plugins/app-backend/CHANGELOG.md b/plugins/app-backend/CHANGELOG.md index f9e98e031e..8550264a15 100644 --- a/plugins/app-backend/CHANGELOG.md +++ b/plugins/app-backend/CHANGELOG.md @@ -1,5 +1,126 @@ # @backstage/plugin-app-backend +## 0.3.57 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/config-loader@1.6.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.9 + +## 0.3.57-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-app-node@0.1.9-next.2 + - @backstage/config-loader@1.6.1-next.0 + +## 0.3.57-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.6.1-next.0 + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.9-next.1 + +## 0.3.57-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.6.0 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.9-next.0 + +## 0.3.56 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/config-loader@1.6.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.8 + +## 0.3.56-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.6.0-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.8-next.3 + +## 0.3.56-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.6.0-next.0 + - @backstage/backend-common@0.20.0-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.8-next.2 + +## 0.3.56-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.5.3 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.8-next.1 + +## 0.3.56-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.5.3 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.8-next.0 + +## 0.3.55 + +### Patch Changes + +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. +- Updated dependencies + - @backstage/config-loader@1.5.3 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.7 + ## 0.3.55-next.2 ### Patch Changes diff --git a/plugins/app-backend/alpha-api-report.md b/plugins/app-backend/api-report-alpha.md similarity index 100% rename from plugins/app-backend/alpha-api-report.md rename to plugins/app-backend/api-report-alpha.md diff --git a/plugins/app-backend/package.json b/plugins/app-backend/package.json index 1699ac7f31..0aecbec7f0 100644 --- a/plugins/app-backend/package.json +++ b/plugins/app-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-app-backend", "description": "A Backstage backend plugin that serves the Backstage frontend app", - "version": "0.3.55-next.2", + "version": "0.3.57", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -69,7 +69,6 @@ "@backstage/cli": "workspace:^", "@backstage/types": "workspace:^", "@types/supertest": "^2.0.8", - "msw": "^1.0.0", "node-fetch": "^2.6.7", "supertest": "^6.1.3" }, diff --git a/plugins/app-backend/src/lib/assets/StaticAssetsStore.test.ts b/plugins/app-backend/src/lib/assets/StaticAssetsStore.test.ts index f14349a55b..e18d136b9d 100644 --- a/plugins/app-backend/src/lib/assets/StaticAssetsStore.test.ts +++ b/plugins/app-backend/src/lib/assets/StaticAssetsStore.test.ts @@ -37,7 +37,7 @@ jest.setTimeout(60_000); describe('StaticAssetsStore', () => { const databases = TestDatabases.create({ - ids: ['MYSQL_8', 'POSTGRES_13', 'POSTGRES_9', 'SQLITE_3'], + ids: ['MYSQL_8', 'POSTGRES_16', 'POSTGRES_12', 'SQLITE_3'], }); it.each(databases.eachSupportedId())( diff --git a/plugins/app-node/CHANGELOG.md b/plugins/app-node/CHANGELOG.md index 13f0920921..d396e40aba 100644 --- a/plugins/app-node/CHANGELOG.md +++ b/plugins/app-node/CHANGELOG.md @@ -1,5 +1,75 @@ # @backstage/plugin-app-node +## 0.1.9 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + +## 0.1.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + +## 0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.1 + +## 0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + +## 0.1.8 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8 + +## 0.1.8-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.3 + +## 0.1.8-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.2 + +## 0.1.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + +## 0.1.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.0 + +## 0.1.7 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.7 + ## 0.1.7-next.2 ### Patch Changes diff --git a/plugins/app-node/package.json b/plugins/app-node/package.json index f781002c6c..38c5eadacf 100644 --- a/plugins/app-node/package.json +++ b/plugins/app-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-app-node", "description": "Node.js library for the app plugin", - "version": "0.1.7-next.2", + "version": "0.1.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/graphql-backend/.eslintrc.js b/plugins/app-visualizer/.eslintrc.js similarity index 100% rename from plugins/graphql-backend/.eslintrc.js rename to plugins/app-visualizer/.eslintrc.js diff --git a/plugins/app-visualizer/CHANGELOG.md b/plugins/app-visualizer/CHANGELOG.md new file mode 100644 index 0000000000..a4ddea2590 --- /dev/null +++ b/plugins/app-visualizer/CHANGELOG.md @@ -0,0 +1,14 @@ +# @backstage/plugin-app-visualizer + +## 0.1.0 + +### Minor Changes + +- e57cc9f: Initial release of the app visualizer plugin. + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 diff --git a/plugins/app-visualizer/README.md b/plugins/app-visualizer/README.md new file mode 100644 index 0000000000..865cd66746 --- /dev/null +++ b/plugins/app-visualizer/README.md @@ -0,0 +1,10 @@ +# @backstage/plugin-app-visualizer + +A plugin to help explore the structure of your Backstage app. + +This plugin provides the following extensions: + +| ID | Type | Description | Default Config | +| ------------------------- | --------- | ------------------------------------ | ------------------------- | +| `page:app-visualizer` | `Page` | The app visualizer page | `{ path: '/visualizer' }` | +| `nav-item:app-visualizer` | `NavItem` | Nav item for the app visualizer page | | diff --git a/plugins/app-visualizer/api-report.md b/plugins/app-visualizer/api-report.md new file mode 100644 index 0000000000..764caa7190 --- /dev/null +++ b/plugins/app-visualizer/api-report.md @@ -0,0 +1,13 @@ +## API Report File for "@backstage/plugin-app-visualizer" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { BackstagePlugin } from '@backstage/frontend-plugin-api'; + +// @public (undocumented) +const visualizerPlugin: BackstagePlugin<{}, {}>; +export default visualizerPlugin; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/app-visualizer/catalog-info.yaml b/plugins/app-visualizer/catalog-info.yaml new file mode 100644 index 0000000000..cb444af524 --- /dev/null +++ b/plugins/app-visualizer/catalog-info.yaml @@ -0,0 +1,10 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: backstage-plugin-app-visualizer + title: '@backstage/plugin-app-visualizer' + description: Visualizes the Backstage app structure +spec: + lifecycle: experimental + type: backstage-frontend-plugin + owner: maintainers diff --git a/plugins/app-visualizer/package.json b/plugins/app-visualizer/package.json new file mode 100644 index 0000000000..197e97c464 --- /dev/null +++ b/plugins/app-visualizer/package.json @@ -0,0 +1,43 @@ +{ + "name": "@backstage/plugin-app-visualizer", + "description": "Visualizes the Backstage app structure", + "version": "0.1.0", + "publishConfig": { + "access": "public" + }, + "backstage": { + "role": "frontend-plugin" + }, + "license": "Apache-2.0", + "main": "src/index.ts", + "types": "src/index.ts", + "sideEffects": false, + "scripts": { + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "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" + }, + "dependencies": { + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/frontend-plugin-api": "workspace:^", + "@material-ui/core": "^4.12.2", + "@material-ui/icons": "^4.9.1" + }, + "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/cli": "workspace:^", + "@types/react": "^16.13.1 || ^17.0.0" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/app-visualizer/src/components/AppVisualizerPage/AppVisualizerPage.tsx b/plugins/app-visualizer/src/components/AppVisualizerPage/AppVisualizerPage.tsx new file mode 100644 index 0000000000..b984f8ac59 --- /dev/null +++ b/plugins/app-visualizer/src/components/AppVisualizerPage/AppVisualizerPage.tsx @@ -0,0 +1,100 @@ +/* + * 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 { Content, Header, HeaderTabs, Page } from '@backstage/core-components'; +import { useApi } from '@backstage/core-plugin-api'; +import { appTreeApiRef } from '@backstage/frontend-plugin-api'; +import Box from '@material-ui/core/Box'; +import React, { useCallback, useEffect, useMemo } from 'react'; +import { DetailedVisualizer } from './DetailedVisualizer'; +import { TextVisualizer } from './TextVisualizer'; +import { TreeVisualizer } from './TreeVisualizer'; +import { + matchRoutes, + useLocation, + useNavigate, + useParams, + useRoutes, +} from 'react-router-dom'; + +export function AppVisualizerPage() { + const appTreeApi = useApi(appTreeApiRef); + const { tree } = appTreeApi.getTree(); + + const tabs = useMemo( + () => [ + { + id: 'tree', + path: 'tree', + label: 'Tree', + element: , + }, + { + id: 'detailed', + path: 'detailed', + label: 'Detailed', + element: , + }, + { + id: 'text', + path: 'text', + label: 'Text', + element: , + }, + ], + [tree], + ); + + const location = useLocation(); + const element = useRoutes(tabs, location); + + const currentPath = `/${useParams()['*']}`; + const [matchedRoute] = matchRoutes(tabs, currentPath) ?? []; + + const currentTabIndex = matchedRoute + ? tabs.findIndex(t => t.path === matchedRoute.route.path) + : 0; + + const navigate = useNavigate(); + const handleTabChange = useCallback( + (index: number) => { + navigate(tabs[index].id); + }, + [navigate, tabs], + ); + + useEffect(() => { + if (!element) { + navigate(tabs[0].path); + } + }, [element, navigate, tabs]); + + return ( + +
    + + + + {element} + + + + ); +} diff --git a/plugins/app-visualizer/src/components/AppVisualizerPage/DetailedVisualizer.tsx b/plugins/app-visualizer/src/components/AppVisualizerPage/DetailedVisualizer.tsx new file mode 100644 index 0000000000..2356f38cfa --- /dev/null +++ b/plugins/app-visualizer/src/components/AppVisualizerPage/DetailedVisualizer.tsx @@ -0,0 +1,377 @@ +/* + * 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 { + AppNode, + AppTree, + ExtensionDataRef, + RouteRef, + coreExtensionData, + createApiExtension, + createNavItemExtension, + createThemeExtension, + useRouteRef, +} from '@backstage/frontend-plugin-api'; +import Box from '@material-ui/core/Box'; +import Paper from '@material-ui/core/Paper'; +import Tooltip from '@material-ui/core/Tooltip'; +import Typography from '@material-ui/core/Typography'; +import * as colors from '@material-ui/core/colors'; +import { makeStyles } from '@material-ui/core/styles'; +import InputIcon from '@material-ui/icons/InputSharp'; +import DisabledIcon from '@material-ui/icons/NotInterestedSharp'; +import React from 'react'; +import { Link } from 'react-router-dom'; + +function createOutputColorGenerator( + colorMap: { [extDataId: string]: string }, + availableColors: string[], +) { + const map = new Map(); + let i = 0; + + return function getOutputColor(id: string) { + if (id in colorMap) { + return colorMap[id]; + } + let color = map.get(id); + if (color) { + return color; + } + color = availableColors[i]; + i += 1; + if (i >= availableColors.length) { + i = 0; + } + map.set(id, color); + return color; + }; +} + +const getOutputColor = createOutputColorGenerator( + { + [coreExtensionData.reactElement.id]: colors.green[500], + [coreExtensionData.routePath.id]: colors.yellow[500], + [coreExtensionData.routeRef.id]: colors.purple[500], + [createApiExtension.factoryDataRef.id]: colors.blue[500], + [createThemeExtension.themeDataRef.id]: colors.lime[500], + [createNavItemExtension.targetDataRef.id]: colors.orange[500], + }, + + [ + colors.blue[200], + colors.orange[200], + colors.green[200], + colors.red[200], + colors.yellow[200], + colors.purple[200], + colors.lime[200], + ], +); + +interface StyleProps { + enabled: boolean; + depth: number; +} + +const config = { + borderWidth: 0.75, +}; + +const useStyles = makeStyles(theme => ({ + extension: { + borderLeftWidth: theme.spacing(config.borderWidth), + borderLeftStyle: 'solid', + borderLeftColor: ({ depth }: StyleProps) => + colors.grey[(700 - (depth % 6) * 100) as keyof typeof colors.grey], + cursor: 'pointer', + + '&:hover $extensionHeader': { + color: ({ enabled }: StyleProps) => + enabled ? theme.palette.primary.main : theme.palette.text.secondary, + }, + }, + extensionHeader: { + display: 'flex', + alignItems: 'center', + width: 'fit-content', + + padding: theme.spacing(0.5, 1), + color: ({ enabled }: StyleProps) => + enabled ? theme.palette.text.primary : theme.palette.text.disabled, + background: theme.palette.background.paper, + + borderTopRightRadius: theme.shape.borderRadius, + borderBottomRightRadius: theme.shape.borderRadius, + }, + extensionHeaderId: { + userSelect: 'all', + }, + extensionHeaderOutputs: { + display: 'flex', + alignItems: 'center', + marginLeft: theme.spacing(1), + gap: theme.spacing(1), + }, + attachments: { + gap: theme.spacing(2), + display: 'flex', + flexDirection: 'column', + }, + attachmentsInput: { + '&:first-child $attachmentsInputTitle': { + borderTop: 0, + }, + }, + attachmentsInputTitle: { + display: 'flex', + alignItems: 'center', + width: 'fit-content', + padding: theme.spacing(1), + + borderTopWidth: theme.spacing(config.borderWidth), + borderTopStyle: 'solid', + borderTopColor: ({ depth }: StyleProps) => + colors.grey[(700 - (depth % 6) * 100) as keyof typeof colors.grey], + }, + attachmentsInputName: { + marginLeft: theme.spacing(1), + }, + attachmentsInputChildren: { + display: 'flex', + flexDirection: 'column', + alignItems: 'flex-start', + gap: theme.spacing(0.5), + marginLeft: theme.spacing(1), + marginBottom: theme.spacing(1), + }, +})); + +const useOutputStyles = makeStyles(theme => ({ + output: ({ color }: { color: string }) => ({ + padding: `0 10px`, + height: 20, + borderRadius: 10, + color: theme.palette.getContrastText(color), + backgroundColor: color, + }), +})); + +function getFullPath(node?: AppNode): string { + if (!node) { + return ''; + } + const parent = node.edges.attachedTo?.node; + const part = node.instance?.getData(coreExtensionData.routePath); + if (!part) { + return getFullPath(parent); + } + return getFullPath(parent) + part; +} + +function OutputLink(props: { + dataRef: ExtensionDataRef; + node?: AppNode; + className: string; +}) { + const routeRef = props.node?.instance?.getData(coreExtensionData.routeRef); + + let link: string | undefined = undefined; + try { + // eslint-disable-next-line react-hooks/rules-of-hooks + link = useRouteRef(routeRef as RouteRef)(); + } catch { + /* ignore */ + } + + return ( + {props.dataRef.id}}> + + {link ? link : null} + + + ); +} + +function Output(props: { dataRef: ExtensionDataRef; node?: AppNode }) { + const { dataRef, node } = props; + const { id } = dataRef; + const instance = node?.instance; + + const classes = useOutputStyles({ color: getOutputColor(id) }); + + if (id === coreExtensionData.routePath.id) { + return ( + {getFullPath(node)}}> + + {String(instance?.getData(dataRef) ?? '')} + + + ); + } + + if (id === coreExtensionData.routeRef.id) { + return ; + } + + return ( + {id}}> + + + ); +} + +function Attachments(props: { + node: AppNode; + enabled: boolean; + depth: number; +}) { + const { node, enabled, depth } = props; + const { attachments } = node.edges; + + const classes = useStyles({ enabled, depth }); + + if (attachments.size === 0) { + return null; + } + + return ( + + {[...attachments.entries()] + .sort(([a], [b]) => a.localeCompare(b)) + .map(([key, children]) => { + return ( + + + + + {key} + + + + {children.map(childNode => ( + + ))} + + + ); + })} + + ); +} + +function ExtensionTooltip(props: { node: AppNode }) { + const parts = []; + let node = props.node; + parts.push(node.spec.id); + while (node.edges.attachedTo) { + const input = node.edges.attachedTo.input; + node = node.edges.attachedTo.node; + parts.push(`${node.spec.id} [${input}]`); + } + parts.reverse(); + + return ( + <> + {parts.map(part => ( + {part} + ))} + + ); +} + +function Extension(props: { node: AppNode; depth: number }) { + const { node, depth } = props; + + const enabled = Boolean(node.instance); + const classes = useStyles({ enabled, depth }); + + const dataRefs = node.instance && [...node.instance.getDataRefs()]; + + return ( + + + }> + + {node.spec.id} + + + + {dataRefs && + dataRefs.length > 0 && + dataRefs + .sort((a, b) => a.id.localeCompare(b.id)) + .map(ref => )} + {!enabled && } + + + + + ); +} + +const legendMap = { + 'React Element': coreExtensionData.reactElement, + 'Utility API': createApiExtension.factoryDataRef, + 'Route Path': coreExtensionData.routePath, + 'Route Ref': coreExtensionData.routeRef, + 'Nav Target': createNavItemExtension.targetDataRef, + Theme: createThemeExtension.themeDataRef, +}; + +function Legend() { + return ( + + {Object.entries(legendMap).map(([label, dataRef]) => ( + + + {label} + + ))} + + ); +} + +export function DetailedVisualizer({ tree }: { tree: AppTree }) { + return ( + + + + + + + + + + ); +} diff --git a/plugins/app-visualizer/src/components/AppVisualizerPage/TextVisualizer.tsx b/plugins/app-visualizer/src/components/AppVisualizerPage/TextVisualizer.tsx new file mode 100644 index 0000000000..50b1f61484 --- /dev/null +++ b/plugins/app-visualizer/src/components/AppVisualizerPage/TextVisualizer.tsx @@ -0,0 +1,116 @@ +/* + * 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 { AppNode, AppTree } from '@backstage/frontend-plugin-api'; +import Box from '@material-ui/core/Box'; +import Checkbox from '@material-ui/core/Checkbox'; +import FormControlLabel from '@material-ui/core/FormControlLabel'; +import Paper from '@material-ui/core/Paper'; +import React, { ReactNode, useState } from 'react'; + +function mkDiv( + children: ReactNode, + options?: { indent?: boolean; key?: string | number; color?: string }, +) { + return ( +
    + {children} +
    + ); +} + +function nodeToText( + node: AppNode, + options?: { showOutputs?: boolean; showDisabled?: boolean }, +): ReactNode { + const dataRefIds = + node.instance && [...node.instance.getDataRefs()].map(r => r.id); + const out = + options?.showOutputs && dataRefIds && dataRefIds.length > 0 + ? ` out="${[...dataRefIds].sort().join(', ')}"` + : ''; + const color = node.instance ? undefined : 'gray'; + + if (node.edges.attachments.size === 0) { + return mkDiv(`<${node.spec.id}${out}/>`, { color }); + } + + return mkDiv([ + mkDiv(`<${node.spec.id}${out}>`, { key: 'start', color }), + ...[...node.edges.attachments.entries()] + .sort(([a], [b]) => a.localeCompare(b)) + .map(([key, v]) => { + const children = v + .filter(e => options?.showDisabled || e.instance) + .sort((a, b) => a.spec.id.localeCompare(b.spec.id)); + if (children.length === 0) { + return mkDiv(`${key} []`, { indent: true }); + } + return mkDiv( + [ + mkDiv(`${key} [`), + ...children.map(e => + mkDiv(nodeToText(e, options), { indent: true }), + ), + mkDiv(']'), + ], + { key, indent: true }, + ); + }), + mkDiv(``, { key: 'end', color }), + ]); +} + +export function TextVisualizer({ tree }: { tree: AppTree }) { + const [showOutputs, setShowOutputs] = useState(false); + const [showDisabled, setShowDisabled] = useState(false); + + return ( + <> + +
    + {nodeToText(tree.root, { showOutputs, showDisabled })} +
    +
    + + setShowOutputs(value)} + /> + } + label="Show Outputs" + /> + setShowDisabled(value)} + /> + } + label="Show Disabled" + /> + + + ); +} diff --git a/plugins/app-visualizer/src/components/AppVisualizerPage/TreeVisualizer.tsx b/plugins/app-visualizer/src/components/AppVisualizerPage/TreeVisualizer.tsx new file mode 100644 index 0000000000..eac7c4e203 --- /dev/null +++ b/plugins/app-visualizer/src/components/AppVisualizerPage/TreeVisualizer.tsx @@ -0,0 +1,172 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { + DependencyGraph, + DependencyGraphTypes, +} from '@backstage/core-components'; +import { AppNode, AppTree } from '@backstage/frontend-plugin-api'; +import Box from '@material-ui/core/Box'; +import { makeStyles } from '@material-ui/core/styles'; +import { useLayoutEffect, useMemo, useRef, useState } from 'react'; + +type NodeType = + | ({ type: 'node'; id: string } & AppNode) + | { type: 'input'; id: string; name: string }; + +function inputId({ node, input }: { node: AppNode; input: string }) { + return `${node.spec.id}$$${input}`; +} + +function trimNodeId(id: string) { + let newId = id; + if (newId.startsWith('apis.')) { + newId = newId.slice('apis.'.length); + } + if (newId.startsWith('plugin.')) { + newId = newId.slice('plugin.'.length); + } + if (newId.startsWith('catalog.filter.entity.')) { + newId = newId.slice('catalog.filter.entity.'.length); + } + if (newId.endsWith('.nav.index')) { + newId = newId.slice(0, -'.nav.index'.length); + } + return newId; +} + +function resolveGraphData(tree: AppTree): { + nodes: NodeType[]; + edges: { from: string; to: string }[]; +} { + const nodes = [...tree.nodes.values()] + .filter(node => node.instance) + .map(node => ({ ...node, id: node.spec.id, type: 'node' as const })); + + return { + nodes: [ + ...nodes, + ...nodes.flatMap(node => + [...node.edges.attachments.keys()].map(input => ({ + id: inputId({ node, input }), + type: 'input' as const, + name: input, + })), + ), + ], + edges: [ + ...nodes + .filter(node => node.edges.attachedTo) + .map(node => ({ + from: inputId(node.edges.attachedTo!), + to: node.spec.id, + })), + ...nodes.flatMap(node => + [...node.edges.attachments.keys()].map(input => ({ + from: node.spec.id, + to: inputId({ node, input }), + })), + ), + ], + }; +} + +const useStyles = makeStyles(theme => ({ + node: { + fill: (node: NodeType) => + node.type === 'node' + ? theme.palette.primary.light + : theme.palette.grey[500], + stroke: (node: NodeType) => + node.type === 'node' + ? theme.palette.primary.main + : theme.palette.grey[600], + }, + text: { + fill: theme.palette.primary.contrastText, + }, +})); + +/** @public */ +export function Node(props: { node: NodeType }) { + const { node } = props; + const classes = useStyles(node); + const [width, setWidth] = useState(0); + const [height, setHeight] = useState(0); + const idRef = useRef(null); + + useLayoutEffect(() => { + // set the width to the length of the ID + if (idRef.current) { + let { height: renderedHeight, width: renderedWidth } = + idRef.current.getBBox(); + renderedHeight = Math.round(renderedHeight); + renderedWidth = Math.round(renderedWidth); + + if (renderedHeight !== height || renderedWidth !== width) { + setWidth(renderedWidth); + setHeight(renderedHeight); + } + } + }, [width, height]); + + const padding = 10; + const paddedWidth = width + padding * 2; + const paddedHeight = height + padding * 2; + + return ( + + + + {node.type === 'node' ? trimNodeId(node.id) : node.name} + + + ); +} + +export function TreeVisualizer({ tree }: { tree: AppTree }) { + const graphData = useMemo(() => resolveGraphData(tree), [tree]); + + return ( + + + + ); +} diff --git a/plugins/app-visualizer/src/components/AppVisualizerPage/index.ts b/plugins/app-visualizer/src/components/AppVisualizerPage/index.ts new file mode 100644 index 0000000000..971bc6ccb2 --- /dev/null +++ b/plugins/app-visualizer/src/components/AppVisualizerPage/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 { AppVisualizerPage } from './AppVisualizerPage'; diff --git a/plugins/app-visualizer/src/index.ts b/plugins/app-visualizer/src/index.ts new file mode 100644 index 0000000000..b91a06c569 --- /dev/null +++ b/plugins/app-visualizer/src/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 { visualizerPlugin as default } from './plugin'; diff --git a/plugins/app-visualizer/src/plugin.tsx b/plugins/app-visualizer/src/plugin.tsx new file mode 100644 index 0000000000..9a726ecc99 --- /dev/null +++ b/plugins/app-visualizer/src/plugin.tsx @@ -0,0 +1,45 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + createNavItemExtension, + createPageExtension, + createPlugin, + createRouteRef, +} from '@backstage/frontend-plugin-api'; +import VisualizerIcon from '@material-ui/icons/Visibility'; +import React from 'react'; + +const rootRouteRef = createRouteRef(); + +const appVisualizerPage = createPageExtension({ + defaultPath: '/visualizer', + routeRef: rootRouteRef, + loader: () => + import('./components/AppVisualizerPage').then(m => ), +}); + +export const appVisualizerNavItem = createNavItemExtension({ + title: 'Visualizer', + icon: VisualizerIcon, + routeRef: rootRouteRef, +}); + +/** @public */ +export const visualizerPlugin = createPlugin({ + id: 'app-visualizer', + extensions: [appVisualizerPage, appVisualizerNavItem], +}); diff --git a/plugins/auth-backend-module-atlassian-provider/.eslintrc.js b/plugins/auth-backend-module-atlassian-provider/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/auth-backend-module-atlassian-provider/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md b/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md new file mode 100644 index 0000000000..22f61ff088 --- /dev/null +++ b/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md @@ -0,0 +1,90 @@ +# @backstage/plugin-auth-backend-module-atlassian-provider + +## 0.1.1 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + +## 0.1.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## 0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + +## 0.1.1-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/plugin-auth-node@0.4.3-next.0 + +## 0.1.0 + +### Minor Changes + +- 2a5891e: New module for `@backstage/plugin-auth-backend` that adds an atlassian auth provider + +### Patch Changes + +- a62764b: Updated dependency `passport` to `^0.7.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + +## 0.1.0-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + +## 0.1.0-next.2 + +### Patch Changes + +- a62764b: Updated dependency `passport` to `^0.7.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + +## 0.1.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## 0.1.0-next.0 + +### Minor Changes + +- 2a5891e816: New module for `@backstage/plugin-auth-backend` that adds an atlassian auth provider + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 diff --git a/plugins/auth-backend-module-atlassian-provider/README.md b/plugins/auth-backend-module-atlassian-provider/README.md new file mode 100644 index 0000000000..fb326f68be --- /dev/null +++ b/plugins/auth-backend-module-atlassian-provider/README.md @@ -0,0 +1,8 @@ +# Auth Module: Atlassian Provider + +This module provides an Atlassian auth provider implementation for `@backstage/plugin-auth-backend`. + +## Links + +- [Repository](https://atlassian.com/backstage/backstage/tree/master/plugins/auth-backend-module-atlassian-provider) +- [Backstage Project Homepage](https://backstage.io) diff --git a/plugins/auth-backend-module-atlassian-provider/api-report.md b/plugins/auth-backend-module-atlassian-provider/api-report.md new file mode 100644 index 0000000000..8a30e6b493 --- /dev/null +++ b/plugins/auth-backend-module-atlassian-provider/api-report.md @@ -0,0 +1,30 @@ +## API Report File for "@backstage/plugin-auth-backend-module-atlassian-provider" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { BackendFeature } from '@backstage/backend-plugin-api'; +import { OAuthAuthenticator } from '@backstage/plugin-auth-node'; +import { OAuthAuthenticatorResult } from '@backstage/plugin-auth-node'; +import { PassportOAuthAuthenticatorHelper } from '@backstage/plugin-auth-node'; +import { PassportProfile } from '@backstage/plugin-auth-node'; +import { SignInResolverFactory } from '@backstage/plugin-auth-node'; + +// @public (undocumented) +export const atlassianAuthenticator: OAuthAuthenticator< + PassportOAuthAuthenticatorHelper, + PassportProfile +>; + +// @public +export namespace atlassianSignInResolvers { + const usernameMatchingUserEntityName: SignInResolverFactory< + OAuthAuthenticatorResult, + unknown + >; +} + +// @public (undocumented) +const authModuleAtlassianProvider: () => BackendFeature; +export default authModuleAtlassianProvider; +``` diff --git a/plugins/auth-backend-module-atlassian-provider/catalog-info.yaml b/plugins/auth-backend-module-atlassian-provider/catalog-info.yaml new file mode 100644 index 0000000000..d3e2c11c17 --- /dev/null +++ b/plugins/auth-backend-module-atlassian-provider/catalog-info.yaml @@ -0,0 +1,10 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: backstage-plugin-auth-backend-module-atlassian-provider + title: '@backstage/plugin-auth-backend-module-atlassian-provider' + description: The atlassian-provider backend module for the auth plugin. +spec: + lifecycle: experimental + type: backstage-backend-plugin-module + owner: maintainers diff --git a/plugins/auth-backend-module-atlassian-provider/config.d.ts b/plugins/auth-backend-module-atlassian-provider/config.d.ts new file mode 100644 index 0000000000..999bf1b304 --- /dev/null +++ b/plugins/auth-backend-module-atlassian-provider/config.d.ts @@ -0,0 +1,34 @@ +/* + * 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 { + auth?: { + providers?: { + /** @visibility frontend */ + atlassian?: { + [authEnv: string]: { + clientId: string; + /** + * @visibility secret + */ + clientSecret: string; + audience?: string; + callbackUrl?: string; + }; + }; + }; + }; +} diff --git a/plugins/auth-backend-module-atlassian-provider/dev/index.ts b/plugins/auth-backend-module-atlassian-provider/dev/index.ts new file mode 100644 index 0000000000..d3c18c1d48 --- /dev/null +++ b/plugins/auth-backend-module-atlassian-provider/dev/index.ts @@ -0,0 +1,24 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createBackend } from '@backstage/backend-defaults'; + +const backend = createBackend(); + +backend.add(import('@backstage/plugin-auth-backend')); +backend.add(import('../src')); + +backend.start(); diff --git a/plugins/auth-backend-module-atlassian-provider/package.json b/plugins/auth-backend-module-atlassian-provider/package.json new file mode 100644 index 0000000000..3d73de88fc --- /dev/null +++ b/plugins/auth-backend-module-atlassian-provider/package.json @@ -0,0 +1,44 @@ +{ + "name": "@backstage/plugin-auth-backend-module-atlassian-provider", + "description": "The atlassian-provider backend module for the auth plugin.", + "version": "0.1.1", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "backend-plugin-module" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/backend-plugin-api": "workspace:^", + "@backstage/plugin-auth-node": "workspace:^", + "express": "^4.18.2", + "passport": "^0.7.0", + "passport-atlassian-oauth2": "^2.1.0" + }, + "devDependencies": { + "@backstage/backend-defaults": "workspace:^", + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", + "@backstage/plugin-auth-backend": "workspace:^", + "supertest": "^6.3.3" + }, + "configSchema": "config.d.ts", + "files": [ + "dist", + "config.d.ts" + ] +} diff --git a/plugins/auth-backend-module-atlassian-provider/src/authenticator.ts b/plugins/auth-backend-module-atlassian-provider/src/authenticator.ts new file mode 100644 index 0000000000..3e5ed50246 --- /dev/null +++ b/plugins/auth-backend-module-atlassian-provider/src/authenticator.ts @@ -0,0 +1,77 @@ +/* + * 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 { Strategy as AtlassianStrategy } from 'passport-atlassian-oauth2'; +import { + createOAuthAuthenticator, + PassportOAuthAuthenticatorHelper, + PassportOAuthDoneCallback, + PassportProfile, +} from '@backstage/plugin-auth-node'; + +/** @public */ +export const atlassianAuthenticator = createOAuthAuthenticator({ + defaultProfileTransform: + PassportOAuthAuthenticatorHelper.defaultProfileTransform, + initialize({ callbackUrl, config }) { + const clientId = config.getString('clientId'); + const clientSecret = config.getString('clientSecret'); + const baseUrl = + config.getOptionalString('audience') || 'https://atlassian.com'; + + return PassportOAuthAuthenticatorHelper.from( + new AtlassianStrategy( + { + clientID: clientId, + clientSecret: clientSecret, + callbackURL: callbackUrl, + baseURL: baseUrl, + authorizationURL: `${baseUrl}/oauth/authorize`, + tokenURL: `${baseUrl}/oauth/token`, + profileURL: `${baseUrl}/api/v4/user`, + }, + ( + accessToken: string, + refreshToken: string, + params: any, + fullProfile: PassportProfile, + done: PassportOAuthDoneCallback, + ) => { + done( + undefined, + { fullProfile, params, accessToken }, + { refreshToken }, + ); + }, + ), + ); + }, + + async start(input, helper) { + return helper.start(input, { + accessType: 'offline', + prompt: 'consent', + }); + }, + + async authenticate(input, helper) { + return helper.authenticate(input); + }, + + async refresh(input, helper) { + return helper.refresh(input); + }, +}); diff --git a/plugins/auth-backend-module-atlassian-provider/src/index.ts b/plugins/auth-backend-module-atlassian-provider/src/index.ts new file mode 100644 index 0000000000..cc71c9b7e3 --- /dev/null +++ b/plugins/auth-backend-module-atlassian-provider/src/index.ts @@ -0,0 +1,25 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * The atlassian-provider backend module for the auth plugin. + * + * @packageDocumentation + */ + +export { atlassianAuthenticator } from './authenticator'; +export { authModuleAtlassianProvider as default } from './module'; +export { atlassianSignInResolvers } from './resolvers'; diff --git a/plugins/auth-backend-module-atlassian-provider/src/module.test.ts b/plugins/auth-backend-module-atlassian-provider/src/module.test.ts new file mode 100644 index 0000000000..8d02b0b7a5 --- /dev/null +++ b/plugins/auth-backend-module-atlassian-provider/src/module.test.ts @@ -0,0 +1,77 @@ +/* + * 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 { mockServices, startTestBackend } from '@backstage/backend-test-utils'; +import { authModuleAtlassianProvider } from './module'; +import request from 'supertest'; +import { decodeOAuthState } from '@backstage/plugin-auth-node'; + +describe('authModuleAtlassianProvider', () => { + it('should start', async () => { + const { server } = await startTestBackend({ + features: [ + import('@backstage/plugin-auth-backend'), + authModuleAtlassianProvider, + mockServices.rootConfig.factory({ + data: { + app: { + baseUrl: 'http://localhost:3000', + }, + auth: { + providers: { + atlassian: { + development: { + clientId: 'my-client-id', + clientSecret: 'my-client-secret', + }, + }, + }, + }, + }, + }), + ], + }); + + const agent = request.agent(server); + + const res = await agent.get('/api/auth/atlassian/start?env=development'); + + expect(res.status).toEqual(302); + + const nonceCookie = agent.jar.getCookie('atlassian-nonce', { + domain: 'localhost', + path: '/api/auth/atlassian/handler', + script: false, + secure: false, + }); + expect(nonceCookie).toBeDefined(); + + const startUrl = new URL(res.get('location')); + expect(startUrl.origin).toBe('https://atlassian.com'); + expect(startUrl.pathname).toBe('/oauth/authorize'); + expect(Object.fromEntries(startUrl.searchParams)).toEqual({ + response_type: 'code', + client_id: 'my-client-id', + redirect_uri: `http://localhost:${server.port()}/api/auth/atlassian/handler/frame`, + state: expect.any(String), + }); + + expect(decodeOAuthState(startUrl.searchParams.get('state')!)).toEqual({ + env: 'development', + nonce: decodeURIComponent(nonceCookie.value), + }); + }); +}); diff --git a/plugins/auth-backend-module-atlassian-provider/src/module.ts b/plugins/auth-backend-module-atlassian-provider/src/module.ts new file mode 100644 index 0000000000..9acb665ede --- /dev/null +++ b/plugins/auth-backend-module-atlassian-provider/src/module.ts @@ -0,0 +1,48 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { createBackendModule } from '@backstage/backend-plugin-api'; +import { + authProvidersExtensionPoint, + commonSignInResolvers, + createOAuthProviderFactory, +} from '@backstage/plugin-auth-node'; +import { atlassianAuthenticator } from './authenticator'; +import { atlassianSignInResolvers } from './resolvers'; + +/** @public */ +export const authModuleAtlassianProvider = createBackendModule({ + pluginId: 'auth', + moduleId: 'atlassian-provider', + register(reg) { + reg.registerInit({ + deps: { + providers: authProvidersExtensionPoint, + }, + async init({ providers }) { + providers.registerProvider({ + providerId: 'atlassian', + factory: createOAuthProviderFactory({ + authenticator: atlassianAuthenticator, + signInResolverFactories: { + ...atlassianSignInResolvers, + ...commonSignInResolvers, + }, + }), + }); + }, + }); + }, +}); diff --git a/plugins/auth-backend-module-atlassian-provider/src/resolvers.ts b/plugins/auth-backend-module-atlassian-provider/src/resolvers.ts new file mode 100644 index 0000000000..1f3090bfdd --- /dev/null +++ b/plugins/auth-backend-module-atlassian-provider/src/resolvers.ts @@ -0,0 +1,50 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + createSignInResolverFactory, + OAuthAuthenticatorResult, + PassportProfile, + SignInInfo, +} from '@backstage/plugin-auth-node'; + +/** + * Available sign-in resolvers for the Atlassian auth provider. + * + * @public + */ +export namespace atlassianSignInResolvers { + /** + * Looks up the user by matching their Atlassian username to the entity name. + */ + export const usernameMatchingUserEntityName = createSignInResolverFactory({ + create() { + return async ( + info: SignInInfo>, + ctx, + ) => { + const { result } = info; + + const id = result.fullProfile.username; + if (!id) { + throw new Error(`Atlassian user profile does not contain a username`); + } + + return ctx.signInWithCatalogUser({ entityRef: { name: id } }); + }; + }, + }); +} diff --git a/plugins/auth-backend-module-atlassian-provider/src/types.d.ts b/plugins/auth-backend-module-atlassian-provider/src/types.d.ts new file mode 100644 index 0000000000..5fd47bf885 --- /dev/null +++ b/plugins/auth-backend-module-atlassian-provider/src/types.d.ts @@ -0,0 +1,25 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +declare module 'passport-atlassian-oauth2' { + import { Request } from 'express'; + import { StrategyCreated } from 'passport'; + + export class Strategy { + constructor(options: any, verify: any); + authenticate(this: StrategyCreated, req: Request, options?: any): any; + } +} diff --git a/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md b/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md index b4624b7614..e9e5d99224 100644 --- a/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md @@ -1,5 +1,107 @@ # @backstage/plugin-auth-backend-module-gcp-iap-provider +## 0.2.3 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.2.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## 0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.2.3-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.0 + +## 0.2.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.2.2-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.3 + +## 0.2.2-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.2.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## 0.2.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.2.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.7 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.1 + ## 0.2.1-next.2 ### Patch Changes diff --git a/plugins/auth-backend-module-gcp-iap-provider/package.json b/plugins/auth-backend-module-gcp-iap-provider/package.json index 22cb9afc12..d167389b20 100644 --- a/plugins/auth-backend-module-gcp-iap-provider/package.json +++ b/plugins/auth-backend-module-gcp-iap-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-gcp-iap-provider", "description": "A GCP IAP auth provider module for the Backstage auth backend", - "version": "0.2.1-next.2", + "version": "0.2.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -41,9 +41,7 @@ "devDependencies": { "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", - "express": "^4.18.2", - "msw": "^1.0.0", - "supertest": "^6.1.3" + "express": "^4.18.2" }, "files": [ "dist", diff --git a/plugins/auth-backend-module-gcp-iap-provider/src/module.ts b/plugins/auth-backend-module-gcp-iap-provider/src/module.ts index 90771eecb9..23c503c317 100644 --- a/plugins/auth-backend-module-gcp-iap-provider/src/module.ts +++ b/plugins/auth-backend-module-gcp-iap-provider/src/module.ts @@ -26,7 +26,7 @@ import { gcpIapSignInResolvers } from './resolvers'; /** @public */ export const authModuleGcpIapProvider = createBackendModule({ pluginId: 'auth', - moduleId: 'gcpIapProvider', + moduleId: 'gcp-iap-provider', register(reg) { reg.registerInit({ deps: { diff --git a/plugins/auth-backend-module-github-provider/CHANGELOG.md b/plugins/auth-backend-module-github-provider/CHANGELOG.md index 0ff80a1600..ee59a1e269 100644 --- a/plugins/auth-backend-module-github-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-github-provider/CHANGELOG.md @@ -1,5 +1,93 @@ # @backstage/plugin-auth-backend-module-github-provider +## 0.1.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + +## 0.1.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## 0.1.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + +## 0.1.6-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/plugin-auth-node@0.4.3-next.0 + +## 0.1.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + +## 0.1.5-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + +## 0.1.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + +## 0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## 0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + +## 0.1.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/plugin-auth-node@0.4.1 + ## 0.1.4-next.2 ### Patch Changes diff --git a/plugins/auth-backend-module-github-provider/package.json b/plugins/auth-backend-module-github-provider/package.json index e84723147a..bf84dc5ec7 100644 --- a/plugins/auth-backend-module-github-provider/package.json +++ b/plugins/auth-backend-module-github-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-github-provider", "description": "The github-provider backend module for the auth plugin.", - "version": "0.1.4-next.2", + "version": "0.1.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,7 +23,6 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/backend-common": "workspace:^", "@backstage/backend-plugin-api": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", "passport-github2": "^0.1.12" diff --git a/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md b/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md index 29d6733090..92acc636c1 100644 --- a/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md @@ -1,5 +1,96 @@ # @backstage/plugin-auth-backend-module-gitlab-provider +## 0.1.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + +## 0.1.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## 0.1.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + +## 0.1.6-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/plugin-auth-node@0.4.3-next.0 + +## 0.1.5 + +### Patch Changes + +- a62764b: Updated dependency `passport` to `^0.7.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + +## 0.1.5-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + +## 0.1.5-next.2 + +### Patch Changes + +- a62764b: Updated dependency `passport` to `^0.7.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + +## 0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## 0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + +## 0.1.4 + +### Patch Changes + +- a3236ad0ca: Fix link to the repository in `README.md`. +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/plugin-auth-node@0.4.1 + ## 0.1.4-next.2 ### Patch Changes diff --git a/plugins/auth-backend-module-gitlab-provider/package.json b/plugins/auth-backend-module-gitlab-provider/package.json index 087cbcb3ce..c7f4d5ef04 100644 --- a/plugins/auth-backend-module-gitlab-provider/package.json +++ b/plugins/auth-backend-module-gitlab-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-gitlab-provider", "description": "The gitlab-provider backend module for the auth plugin.", - "version": "0.1.4-next.2", + "version": "0.1.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,11 +23,10 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/backend-common": "workspace:^", "@backstage/backend-plugin-api": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", "express": "^4.18.2", - "passport": "^0.6.0", + "passport": "^0.7.0", "passport-gitlab2": "^5.0.0" }, "devDependencies": { diff --git a/plugins/auth-backend-module-google-provider/CHANGELOG.md b/plugins/auth-backend-module-google-provider/CHANGELOG.md index 92ee0e10c9..b43722644b 100644 --- a/plugins/auth-backend-module-google-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-google-provider/CHANGELOG.md @@ -1,5 +1,89 @@ # @backstage/plugin-auth-backend-module-google-provider +## 0.1.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + +## 0.1.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## 0.1.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + +## 0.1.6-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/plugin-auth-node@0.4.3-next.0 + +## 0.1.5 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + +## 0.1.5-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + +## 0.1.5-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + +## 0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## 0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + +## 0.1.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.7 + - @backstage/plugin-auth-node@0.4.1 + ## 0.1.4-next.2 ### Patch Changes diff --git a/plugins/auth-backend-module-google-provider/package.json b/plugins/auth-backend-module-google-provider/package.json index f13b82ffc7..7528d9f8b6 100644 --- a/plugins/auth-backend-module-google-provider/package.json +++ b/plugins/auth-backend-module-google-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-google-provider", "description": "A Google auth provider module for the Backstage auth backend", - "version": "0.1.4-next.2", + "version": "0.1.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -42,7 +42,6 @@ "@backstage/cli": "workspace:^", "@backstage/plugin-auth-backend": "workspace:^", "@types/passport-google-oauth20": "^2.0.3", - "msw": "^1.0.0", "supertest": "^6.1.3" }, "files": [ diff --git a/plugins/auth-backend-module-google-provider/src/module.ts b/plugins/auth-backend-module-google-provider/src/module.ts index 0354f99880..d0f8020b92 100644 --- a/plugins/auth-backend-module-google-provider/src/module.ts +++ b/plugins/auth-backend-module-google-provider/src/module.ts @@ -26,7 +26,7 @@ import { googleSignInResolvers } from './resolvers'; /** @public */ export const authModuleGoogleProvider = createBackendModule({ pluginId: 'auth', - moduleId: 'googleProvider', + moduleId: 'google-provider', register(reg) { reg.registerInit({ deps: { diff --git a/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md b/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md index 04fe350cf6..496538fdf0 100644 --- a/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md @@ -1,5 +1,106 @@ # @backstage/plugin-auth-backend-module-microsoft-provider +## 0.1.4 + +### Patch Changes + +- 928efbc: Deprecated the `authModuleMicrosoftProvider` export. A default export is now available and should be used like this in your backend: `backend.add(import('@backstage/plugin-auth-backend-module-microsoft-provider'));` +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + +## 0.1.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## 0.1.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + +## 0.1.4-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/plugin-auth-node@0.4.3-next.0 + +## 0.1.3 + +### Patch Changes + +- a62764b: Updated dependency `passport` to `^0.7.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + +## 0.1.3-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + +## 0.1.3-next.2 + +### Patch Changes + +- a62764b: Updated dependency `passport` to `^0.7.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + +## 0.1.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## 0.1.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + +## 0.1.2 + +### Patch Changes + +- a3236ad0ca: Fix link to the repository in `README.md`. +- 3979524c74: Added support for specifying a domain hint on the Microsoft authentication provider configuration. +- fde212dd10: Re-add the missing profile photo + as well as access token retrieval for foreign scopes. + + Additionally, we switch from previously 48x48 to 96x96 + which is the size used at the profile card. + +- 5aeb14f035: Correctly mark the client secret in configuration as secret +- 2817115d09: Removed `prompt=consent` from start method to fix #20641 +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/plugin-auth-node@0.4.1 + ## 0.1.2-next.2 ### Patch Changes diff --git a/plugins/auth-backend-module-microsoft-provider/api-report.md b/plugins/auth-backend-module-microsoft-provider/api-report.md index 21bf77d545..33600c10d8 100644 --- a/plugins/auth-backend-module-microsoft-provider/api-report.md +++ b/plugins/auth-backend-module-microsoft-provider/api-report.md @@ -10,9 +10,13 @@ import { PassportOAuthAuthenticatorHelper } from '@backstage/plugin-auth-node'; import { PassportProfile } from '@backstage/plugin-auth-node'; import { SignInResolverFactory } from '@backstage/plugin-auth-node'; -// @public (undocumented) +// @public @deprecated (undocumented) export const authModuleMicrosoftProvider: () => BackendFeature; +// @public (undocumented) +const authModuleMicrosoftProvider_2: () => BackendFeature; +export default authModuleMicrosoftProvider_2; + // @public (undocumented) export const microsoftAuthenticator: OAuthAuthenticator< { diff --git a/plugins/auth-backend-module-microsoft-provider/package.json b/plugins/auth-backend-module-microsoft-provider/package.json index 8ed7533463..94dddfc7ac 100644 --- a/plugins/auth-backend-module-microsoft-provider/package.json +++ b/plugins/auth-backend-module-microsoft-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-microsoft-provider", "description": "The microsoft-provider backend module for the auth plugin.", - "version": "0.1.2-next.2", + "version": "0.1.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,14 +23,13 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/backend-common": "workspace:^", "@backstage/backend-plugin-api": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", "express": "^4.18.2", "jose": "^4.6.0", "lodash": "^4.17.21", "node-fetch": "^2.6.7", - "passport": "^0.6.0", + "passport": "^0.7.0", "passport-microsoft": "^1.0.0" }, "devDependencies": { diff --git a/plugins/auth-backend-module-microsoft-provider/src/deprecated.ts b/plugins/auth-backend-module-microsoft-provider/src/deprecated.ts new file mode 100644 index 0000000000..3c671b6c25 --- /dev/null +++ b/plugins/auth-backend-module-microsoft-provider/src/deprecated.ts @@ -0,0 +1,24 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { authModuleMicrosoftProvider as deprecatedAuthModuleMicrosoftProvider } from './module'; + +/** + * @public + * @deprecated Use default import instead + */ +export const authModuleMicrosoftProvider = + deprecatedAuthModuleMicrosoftProvider; diff --git a/plugins/auth-backend-module-microsoft-provider/src/index.ts b/plugins/auth-backend-module-microsoft-provider/src/index.ts index ae4fbf5926..45b7b719cd 100644 --- a/plugins/auth-backend-module-microsoft-provider/src/index.ts +++ b/plugins/auth-backend-module-microsoft-provider/src/index.ts @@ -21,5 +21,6 @@ */ export { microsoftAuthenticator } from './authenticator'; -export { authModuleMicrosoftProvider } from './module'; +export { authModuleMicrosoftProvider as default } from './module'; export { microsoftSignInResolvers } from './resolvers'; +export * from './deprecated'; diff --git a/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md b/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md index dc2863709d..44cb96b97d 100644 --- a/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md @@ -1,5 +1,95 @@ # @backstage/plugin-auth-backend-module-oauth2-provider +## 0.1.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + +## 0.1.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## 0.1.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + +## 0.1.6-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/plugin-auth-node@0.4.3-next.0 + +## 0.1.5 + +### Patch Changes + +- a62764b: Updated dependency `passport` to `^0.7.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + +## 0.1.5-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + +## 0.1.5-next.2 + +### Patch Changes + +- a62764b: Updated dependency `passport` to `^0.7.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + +## 0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## 0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + +## 0.1.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/plugin-auth-node@0.4.1 + ## 0.1.4-next.2 ### Patch Changes diff --git a/plugins/auth-backend-module-oauth2-provider/package.json b/plugins/auth-backend-module-oauth2-provider/package.json index 24aab9ea73..5edc0be4b8 100644 --- a/plugins/auth-backend-module-oauth2-provider/package.json +++ b/plugins/auth-backend-module-oauth2-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-oauth2-provider", "description": "The oauth2-provider backend module for the auth plugin.", - "version": "0.1.4-next.2", + "version": "0.1.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,11 +23,9 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/backend-common": "workspace:^", "@backstage/backend-plugin-api": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", - "express": "^4.18.2", - "passport": "^0.6.0", + "passport": "^0.7.0", "passport-oauth2": "^1.6.1" }, "devDependencies": { diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/.eslintrc.js b/plugins/auth-backend-module-oauth2-proxy-provider/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/auth-backend-module-oauth2-proxy-provider/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md b/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md new file mode 100644 index 0000000000..71c14a75e2 --- /dev/null +++ b/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md @@ -0,0 +1,92 @@ +# @backstage/plugin-auth-backend-module-oauth2-proxy-provider + +## 0.1.1 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/errors@1.2.3 + +## 0.1.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## 0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/errors@1.2.3 + +## 0.1.1-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.3-next.0 + +## 0.1.0 + +### Minor Changes + +- 271aa12: Release of `oauth2-proxy-provider` plugin + +### Patch Changes + +- a6be465: Exported the provider as default so it gets discovered when using `featureDiscoveryServiceFactory()` +- 510dab4: Change provider id from `oauth2ProxyProvider` to `oauth2Proxy` +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/errors@1.2.3 + +## 0.1.0-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + +## 0.1.0-next.1 + +### Patch Changes + +- a6be465: Exported the provider as default so it gets discovered when using `featureDiscoveryServiceFactory()` +- 510dab4: Change provider id from `oauth2ProxyProvider` to `oauth2Proxy` +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/errors@1.2.3 + +## 0.1.0-next.0 + +### Minor Changes + +- 271aa12c7c: Release of `oauth2-proxy-provider` plugin + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.1 diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/README.md b/plugins/auth-backend-module-oauth2-proxy-provider/README.md new file mode 100644 index 0000000000..edec8fb3c2 --- /dev/null +++ b/plugins/auth-backend-module-oauth2-proxy-provider/README.md @@ -0,0 +1,5 @@ +# @backstage/plugin-auth-backend-module-oauth2-proxy-provider + +The oauth2-proxy-provider backend module for the auth plugin. + +_This plugin was created through the Backstage CLI_ diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/api-report.md b/plugins/auth-backend-module-oauth2-proxy-provider/api-report.md new file mode 100644 index 0000000000..1a4c1ee6d6 --- /dev/null +++ b/plugins/auth-backend-module-oauth2-proxy-provider/api-report.md @@ -0,0 +1,32 @@ +## API Report File for "@backstage/plugin-auth-backend-module-oauth2-proxy-provider" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +/// + +import { BackendFeature } from '@backstage/backend-plugin-api'; +import { IncomingHttpHeaders } from 'http'; +import { ProxyAuthenticator } from '@backstage/plugin-auth-node'; + +// @public (undocumented) +const authModuleOauth2ProxyProvider: () => BackendFeature; +export default authModuleOauth2ProxyProvider; + +// @public +export const OAUTH2_PROXY_JWT_HEADER = 'X-OAUTH2-PROXY-ID-TOKEN'; + +// @public (undocumented) +export const oauth2ProxyAuthenticator: ProxyAuthenticator< + unknown, + OAuth2ProxyResult +>; + +// @public +export type OAuth2ProxyResult = { + fullProfile: JWTPayload; + accessToken: string; + headers: IncomingHttpHeaders; + getHeader(name: string): string | undefined; +}; +``` diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/catalog-info.yaml b/plugins/auth-backend-module-oauth2-proxy-provider/catalog-info.yaml new file mode 100644 index 0000000000..c26202c97d --- /dev/null +++ b/plugins/auth-backend-module-oauth2-proxy-provider/catalog-info.yaml @@ -0,0 +1,10 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: backstage-plugin-auth-backend-module-oauth2-proxy-provider + title: '@backstage/plugin-auth-backend-module-oauth2-proxy-provider' + description: The oauth2-proxy-provider backend module for the auth plugin. +spec: + lifecycle: experimental + type: backstage-backend-plugin-module + owner: maintainers diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/package.json b/plugins/auth-backend-module-oauth2-proxy-provider/package.json new file mode 100644 index 0000000000..c3d49bfcd0 --- /dev/null +++ b/plugins/auth-backend-module-oauth2-proxy-provider/package.json @@ -0,0 +1,38 @@ +{ + "name": "@backstage/plugin-auth-backend-module-oauth2-proxy-provider", + "description": "The oauth2-proxy-provider backend module for the auth plugin.", + "version": "0.1.1", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "backend-plugin-module" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/backend-plugin-api": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/plugin-auth-node": "workspace:^", + "jose": "^4.6.0" + }, + "devDependencies": { + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/src/authenticator.ts b/plugins/auth-backend-module-oauth2-proxy-provider/src/authenticator.ts new file mode 100644 index 0000000000..a3da83791a --- /dev/null +++ b/plugins/auth-backend-module-oauth2-proxy-provider/src/authenticator.ts @@ -0,0 +1,71 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { AuthenticationError } from '@backstage/errors'; +import { + createProxyAuthenticator, + getBearerTokenFromAuthorizationHeader, +} from '@backstage/plugin-auth-node'; +import { decodeJwt } from 'jose'; +import { OAuth2ProxyResult } from './types'; + +/** + * NOTE: This may come in handy if you're doing work on this provider: + * plugins/auth-backend/examples/docker-compose.oauth2-proxy.yaml + * + * @public + */ +export const OAUTH2_PROXY_JWT_HEADER = 'X-OAUTH2-PROXY-ID-TOKEN'; + +/** @public */ +export const oauth2ProxyAuthenticator = createProxyAuthenticator< + unknown, + OAuth2ProxyResult +>({ + defaultProfileTransform: async (result: OAuth2ProxyResult) => { + return { + profile: { + email: result.getHeader('x-forwarded-email'), + displayName: + result.getHeader('x-forwarded-preferred-username') || + result.getHeader('x-forwarded-user'), + }, + }; + }, + async initialize() {}, + async authenticate({ req }) { + try { + const authHeader = req.header(OAUTH2_PROXY_JWT_HEADER); + const jwt = getBearerTokenFromAuthorizationHeader(authHeader); + const decodedJWT = jwt && decodeJwt(jwt); + + const result = { + fullProfile: decodedJWT || {}, + accessToken: jwt || '', + headers: req.headers, + getHeader(name: string) { + if (name.toLocaleLowerCase('en-US') === 'set-cookie') { + throw new Error('Access Set-Cookie via the headers object instead'); + } + return req.get(name); + }, + }; + return { result }; + } catch (e) { + throw new AuthenticationError('Authentication failed', e); + } + }, +}); diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/src/index.ts b/plugins/auth-backend-module-oauth2-proxy-provider/src/index.ts new file mode 100644 index 0000000000..b804f666c7 --- /dev/null +++ b/plugins/auth-backend-module-oauth2-proxy-provider/src/index.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * The oauth2-proxy-provider backend module for the auth plugin. + * + * @packageDocumentation + */ +export { authModuleOauth2ProxyProvider as default } from './module'; +export { + oauth2ProxyAuthenticator, + OAUTH2_PROXY_JWT_HEADER, +} from './authenticator'; +export type { OAuth2ProxyResult } from './types'; diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/src/module.ts b/plugins/auth-backend-module-oauth2-proxy-provider/src/module.ts new file mode 100644 index 0000000000..70ce506d73 --- /dev/null +++ b/plugins/auth-backend-module-oauth2-proxy-provider/src/module.ts @@ -0,0 +1,49 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createBackendModule } from '@backstage/backend-plugin-api'; +import { + authProvidersExtensionPoint, + createProxyAuthProviderFactory, + commonSignInResolvers, +} from '@backstage/plugin-auth-node'; +import { oauth2ProxyAuthenticator } from './authenticator'; +import { oauth2ProxySignInResolvers } from './resolvers'; + +/** @public */ +export const authModuleOauth2ProxyProvider = createBackendModule({ + pluginId: 'auth', + moduleId: 'oauth2-proxy-provider', + register(reg) { + reg.registerInit({ + deps: { + providers: authProvidersExtensionPoint, + }, + async init({ providers }) { + providers.registerProvider({ + providerId: 'oauth2Proxy', + factory: createProxyAuthProviderFactory({ + authenticator: oauth2ProxyAuthenticator, + signInResolverFactories: { + ...commonSignInResolvers, + ...oauth2ProxySignInResolvers, + }, + }), + }); + }, + }); + }, +}); diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/src/resolvers.ts b/plugins/auth-backend-module-oauth2-proxy-provider/src/resolvers.ts new file mode 100644 index 0000000000..99ca8bc156 --- /dev/null +++ b/plugins/auth-backend-module-oauth2-proxy-provider/src/resolvers.ts @@ -0,0 +1,41 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + createSignInResolverFactory, + SignInInfo, +} from '@backstage/plugin-auth-node'; +import { OAuth2ProxyResult } from './types'; + +/** + * @public + */ +export namespace oauth2ProxySignInResolvers { + export const forwardedUserMatchingUserEntityName = + createSignInResolverFactory({ + create() { + return async (info: SignInInfo, ctx) => { + const name = info.result.getHeader('x-forwarded-user'); + if (!name) { + throw new Error('Request did not contain a user'); + } + return ctx.signInWithCatalogUser({ + entityRef: { name }, + }); + }; + }, + }); +} diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/src/types.ts b/plugins/auth-backend-module-oauth2-proxy-provider/src/types.ts new file mode 100644 index 0000000000..5b9e97ab05 --- /dev/null +++ b/plugins/auth-backend-module-oauth2-proxy-provider/src/types.ts @@ -0,0 +1,60 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { IncomingHttpHeaders } from 'http'; + +/** + * JWT header extraction result, containing the raw value and the parsed JWT + * payload. + * + * @public + */ +export type OAuth2ProxyResult = { + /** + * The parsed payload of the `accessToken`. The token is only parsed, not verified. + * + * @deprecated Access through the `headers` instead. This will be removed in a future release. + */ + fullProfile: JWTPayload; + + /** + * The token received via the X-OAUTH2-PROXY-ID-TOKEN header. Will be an empty string + * if the header is not set. Note the this is typically an OpenID Connect token. + * + * @deprecated Access through the `headers` instead. This will be removed in a future release. + */ + accessToken: string; + + /** + * The headers of the incoming request from the OAuth2 proxy. This will include + * both the headers set by the client as well as the ones added by the OAuth2 proxy. + * You should only trust the headers that are injected by the OAuth2 proxy. + * + * Useful headers to use to complete the sign-in are for example `x-forwarded-user` + * and `x-forwarded-email`. See the OAuth2 proxy documentation for more information + * about the available headers and how to enable them. In particular it is possible + * to forward access and identity tokens, which can be user for additional verification + * and lookups. + */ + headers: IncomingHttpHeaders; + + /** + * Provides convenient access to the request headers. + * + * This call is simply forwarded to `req.get(name)`. + */ + getHeader(name: string): string | undefined; +}; diff --git a/plugins/auth-backend-module-okta-provider/.eslintrc.js b/plugins/auth-backend-module-okta-provider/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/auth-backend-module-okta-provider/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/auth-backend-module-okta-provider/CHANGELOG.md b/plugins/auth-backend-module-okta-provider/CHANGELOG.md new file mode 100644 index 0000000000..b059fa0bb4 --- /dev/null +++ b/plugins/auth-backend-module-okta-provider/CHANGELOG.md @@ -0,0 +1,84 @@ +# @backstage/plugin-auth-backend-module-okta-provider + +## 0.0.2 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + +## 0.0.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## 0.0.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + +## 0.0.2-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/plugin-auth-node@0.4.3-next.0 + +## 0.0.1 + +### Patch Changes + +- e1c189b: Adds okta-provider backend module for the auth plugin +- a62764b: Updated dependency `passport` to `^0.7.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + +## 0.0.1-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + +## 0.0.1-next.2 + +### Patch Changes + +- a62764b: Updated dependency `passport` to `^0.7.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + +## 0.0.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## 0.0.1-next.0 + +### Patch Changes + +- e1c189b524: Adds okta-provider backend module for the auth plugin +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 diff --git a/plugins/auth-backend-module-okta-provider/README.md b/plugins/auth-backend-module-okta-provider/README.md new file mode 100644 index 0000000000..3a320a9b1a --- /dev/null +++ b/plugins/auth-backend-module-okta-provider/README.md @@ -0,0 +1,30 @@ +# Auth Module: Okta Provider + +This module provides an Okta auth provider implementation for `@backstage/plugin-auth-backend`. + +## Utilization + +This module is used in `auth-backend/src/providers/okta` + +```ts +import { oktaAuthenticator } from '@backstage/plugin-auth-backend-module-okta-provider'; + +export const okta = createAuthProviderIntegration({ + create({ + authHandler?: AuthHandler, + + signIn?: { + resolver: SignInResolver, + }, + }) { + return createOAuthProviderFactory({ + authenticator: oktaAuthenticator, + }); + }, +}); +``` + +## Links + +- [Repository](https://okta.com/backstage/backstage/tree/master/plugins/auth-backend-module-okta-provider) +- [Backstage Project Homepage](https://backstage.io) diff --git a/plugins/auth-backend-module-okta-provider/api-report.md b/plugins/auth-backend-module-okta-provider/api-report.md new file mode 100644 index 0000000000..e04c762fe2 --- /dev/null +++ b/plugins/auth-backend-module-okta-provider/api-report.md @@ -0,0 +1,30 @@ +## API Report File for "@backstage/plugin-auth-backend-module-okta-provider" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { BackendFeature } from '@backstage/backend-plugin-api'; +import { OAuthAuthenticator } from '@backstage/plugin-auth-node'; +import { OAuthAuthenticatorResult } from '@backstage/plugin-auth-node'; +import { PassportOAuthAuthenticatorHelper } from '@backstage/plugin-auth-node'; +import { PassportProfile } from '@backstage/plugin-auth-node'; +import { SignInResolverFactory } from '@backstage/plugin-auth-node'; + +// @public (undocumented) +const authModuleOktaProvider: () => BackendFeature; +export default authModuleOktaProvider; + +// @public (undocumented) +export const oktaAuthenticator: OAuthAuthenticator< + PassportOAuthAuthenticatorHelper, + PassportProfile +>; + +// @public +export namespace oktaSignInResolvers { + const emailMatchingUserEntityAnnotation: SignInResolverFactory< + OAuthAuthenticatorResult, + unknown + >; +} +``` diff --git a/plugins/auth-backend-module-okta-provider/catalog-info.yaml b/plugins/auth-backend-module-okta-provider/catalog-info.yaml new file mode 100644 index 0000000000..7a5536edcf --- /dev/null +++ b/plugins/auth-backend-module-okta-provider/catalog-info.yaml @@ -0,0 +1,10 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: backstage-plugin-auth-backend-module-okta-provider + title: '@backstage/plugin-auth-backend-module-okta-provider' + description: The okta-provider backend module for the auth plugin. +spec: + lifecycle: experimental + type: backstage-backend-plugin-module + owner: maintainers diff --git a/plugins/auth-backend-module-okta-provider/config.d.ts b/plugins/auth-backend-module-okta-provider/config.d.ts new file mode 100644 index 0000000000..f047c96739 --- /dev/null +++ b/plugins/auth-backend-module-okta-provider/config.d.ts @@ -0,0 +1,36 @@ +/* + * 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 { + auth?: { + providers?: { + /** @visibility frontend */ + okta?: { + [authEnv: string]: { + clientId: string; + /** + * @visibility secret + */ + clientSecret: string; + audience?: string; + authServerId?: string; + idp?: string; + callbackUrl?: string; + }; + }; + }; + }; +} diff --git a/plugins/auth-backend-module-okta-provider/dev/index.ts b/plugins/auth-backend-module-okta-provider/dev/index.ts new file mode 100644 index 0000000000..d3c18c1d48 --- /dev/null +++ b/plugins/auth-backend-module-okta-provider/dev/index.ts @@ -0,0 +1,24 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createBackend } from '@backstage/backend-defaults'; + +const backend = createBackend(); + +backend.add(import('@backstage/plugin-auth-backend')); +backend.add(import('../src')); + +backend.start(); diff --git a/plugins/auth-backend-module-okta-provider/package.json b/plugins/auth-backend-module-okta-provider/package.json new file mode 100644 index 0000000000..7159ab1292 --- /dev/null +++ b/plugins/auth-backend-module-okta-provider/package.json @@ -0,0 +1,44 @@ +{ + "name": "@backstage/plugin-auth-backend-module-okta-provider", + "description": "The okta-provider backend module for the auth plugin.", + "version": "0.0.2", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "backend-plugin-module" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/backend-plugin-api": "workspace:^", + "@backstage/plugin-auth-node": "workspace:^", + "@davidzemon/passport-okta-oauth": "^0.0.5", + "express": "^4.18.2", + "passport": "^0.7.0" + }, + "devDependencies": { + "@backstage/backend-defaults": "workspace:^", + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", + "@backstage/plugin-auth-backend": "workspace:^", + "supertest": "^6.3.3" + }, + "configSchema": "config.d.ts", + "files": [ + "dist", + "config.d.ts" + ] +} diff --git a/plugins/auth-backend-module-okta-provider/src/authenticator.ts b/plugins/auth-backend-module-okta-provider/src/authenticator.ts new file mode 100644 index 0000000000..42201232f1 --- /dev/null +++ b/plugins/auth-backend-module-okta-provider/src/authenticator.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 { Strategy as OktaStrategy } from '@davidzemon/passport-okta-oauth'; +import { + createOAuthAuthenticator, + PassportOAuthAuthenticatorHelper, + PassportOAuthDoneCallback, + PassportProfile, +} from '@backstage/plugin-auth-node'; + +/** @public */ +export const oktaAuthenticator = createOAuthAuthenticator({ + defaultProfileTransform: + PassportOAuthAuthenticatorHelper.defaultProfileTransform, + initialize({ callbackUrl, config }) { + const clientId = config.getString('clientId'); + const clientSecret = config.getString('clientSecret'); + const audience = config.getOptionalString('audience') || 'https://okta.com'; + const authServerId = config.getOptionalString('authServerId'); + const idp = config.getOptionalString('idp'); + // default scopes are taken from + // https://developer.okta.com/docs/reference/api/oidc/#response-example-success-refresh-token + const defaultScopes = 'openid profile email'; + // additional scopes can be configured in the config as a space separated string + const additionalScopes = config.getOptionalString('additionalScopes') || ''; + // combine default and additional scopes and remove duplicates + const combineScopeStrings = (scopesA: string, scopesB: string) => { + const scopesAArray = scopesA.split(' '); + const scopesBArray = scopesB.split(' '); + const combinedScopes = new Set([...scopesAArray, ...scopesBArray]); + return Array.from(combinedScopes).join(' '); + }; + const scope = combineScopeStrings(defaultScopes, additionalScopes); + + return PassportOAuthAuthenticatorHelper.from( + new OktaStrategy( + { + clientID: clientId, + clientSecret: clientSecret, + callbackURL: callbackUrl, + audience: audience, + authServerID: authServerId, + idp: idp, + passReqToCallback: false, + response_type: 'code', + scope, + }, + ( + accessToken: string, + refreshToken: string, + params: any, + fullProfile: PassportProfile, + done: PassportOAuthDoneCallback, + ) => { + done( + undefined, + { fullProfile, params, accessToken }, + { refreshToken }, + ); + }, + ), + ); + }, + + async start(input, helper) { + return helper.start(input, { + accessType: 'offline', + prompt: 'consent', + }); + }, + + async authenticate(input, helper) { + return helper.authenticate(input); + }, + + async refresh(input, helper) { + return helper.refresh(input); + }, +}); diff --git a/plugins/auth-backend-module-okta-provider/src/index.ts b/plugins/auth-backend-module-okta-provider/src/index.ts new file mode 100644 index 0000000000..43a075d56f --- /dev/null +++ b/plugins/auth-backend-module-okta-provider/src/index.ts @@ -0,0 +1,25 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * The okta-provider backend module for the auth plugin. + * + * @packageDocumentation + */ + +export { oktaAuthenticator } from './authenticator'; +export { authModuleOktaProvider as default } from './module'; +export { oktaSignInResolvers } from './resolvers'; diff --git a/plugins/auth-backend-module-okta-provider/src/module.test.ts b/plugins/auth-backend-module-okta-provider/src/module.test.ts new file mode 100644 index 0000000000..e469067b3f --- /dev/null +++ b/plugins/auth-backend-module-okta-provider/src/module.test.ts @@ -0,0 +1,82 @@ +/* + * 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 { mockServices, startTestBackend } from '@backstage/backend-test-utils'; +import { authModuleOktaProvider } from './module'; +import request from 'supertest'; +import { decodeOAuthState } from '@backstage/plugin-auth-node'; + +describe('authModuleOktaProvider', () => { + it('should start', async () => { + const defaultScopes = 'openid profile email'; + const additionalScopes = 'groups phone'; + const combinedScopes = `${defaultScopes} ${additionalScopes}`; + const { server } = await startTestBackend({ + features: [ + import('@backstage/plugin-auth-backend'), + authModuleOktaProvider, + mockServices.rootConfig.factory({ + data: { + app: { + baseUrl: 'http://localhost:3000', + }, + auth: { + providers: { + okta: { + development: { + clientId: 'my-client-id', + clientSecret: 'my-client-secret', + additionalScopes, + }, + }, + }, + }, + }, + }), + ], + }); + + const agent = request.agent(server); + + const res = await agent.get('/api/auth/okta/start?env=development'); + + expect(res.status).toEqual(302); + + const nonceCookie = agent.jar.getCookie('okta-nonce', { + domain: 'localhost', + path: '/api/auth/okta/handler', + script: false, + secure: false, + }); + expect(nonceCookie).toBeDefined(); + + const startUrl = new URL(res.get('location')); + expect(startUrl.origin).toBe('https://okta.com'); + expect(startUrl.pathname).toBe('/oauth2/v1/authorize'); + expect(Object.fromEntries(startUrl.searchParams)).toEqual({ + response_type: 'code', + scope: combinedScopes, + client_id: 'my-client-id', + redirect_uri: `http://localhost:${server.port()}/api/auth/okta/handler/frame`, + state: expect.any(String), + }); + + expect(decodeOAuthState(startUrl.searchParams.get('state')!)).toEqual({ + env: 'development', + nonce: decodeURIComponent(nonceCookie.value), + }); + }); +}); diff --git a/plugins/auth-backend-module-okta-provider/src/module.ts b/plugins/auth-backend-module-okta-provider/src/module.ts new file mode 100644 index 0000000000..35cb6634d5 --- /dev/null +++ b/plugins/auth-backend-module-okta-provider/src/module.ts @@ -0,0 +1,48 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { createBackendModule } from '@backstage/backend-plugin-api'; +import { + authProvidersExtensionPoint, + commonSignInResolvers, + createOAuthProviderFactory, +} from '@backstage/plugin-auth-node'; +import { oktaAuthenticator } from './authenticator'; +import { oktaSignInResolvers } from './resolvers'; + +/** @public */ +export const authModuleOktaProvider = createBackendModule({ + pluginId: 'auth', + moduleId: 'okta-provider', + register(reg) { + reg.registerInit({ + deps: { + providers: authProvidersExtensionPoint, + }, + async init({ providers }) { + providers.registerProvider({ + providerId: 'okta', + factory: createOAuthProviderFactory({ + authenticator: oktaAuthenticator, + signInResolverFactories: { + ...oktaSignInResolvers, + ...commonSignInResolvers, + }, + }), + }); + }, + }); + }, +}); diff --git a/plugins/auth-backend-module-okta-provider/src/resolvers.ts b/plugins/auth-backend-module-okta-provider/src/resolvers.ts new file mode 100644 index 0000000000..8bc3f38f17 --- /dev/null +++ b/plugins/auth-backend-module-okta-provider/src/resolvers.ts @@ -0,0 +1,54 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + createSignInResolverFactory, + OAuthAuthenticatorResult, + PassportProfile, + SignInInfo, +} from '@backstage/plugin-auth-node'; + +/** + * Available sign-in resolvers for the Okta auth provider. + * + * @public + */ +export namespace oktaSignInResolvers { + /** + * Looks up the user by matching their Okta email to the entity email. + */ + + export const emailMatchingUserEntityAnnotation = createSignInResolverFactory({ + create() { + return async ( + info: SignInInfo>, + ctx, + ) => { + const { profile } = info; + + if (!profile.email) { + throw new Error('Okta profile contained no email'); + } + + return ctx.signInWithCatalogUser({ + annotations: { + 'okta.com/email': profile.email, + }, + }); + }; + }, + }); +} diff --git a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/eks.ts b/plugins/auth-backend-module-okta-provider/src/types.d.ts similarity index 69% rename from plugins/kubernetes-react/src/utils/clusterLinks/formatters/eks.ts rename to plugins/auth-backend-module-okta-provider/src/types.d.ts index 975c39797c..58cfb74173 100644 --- a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/eks.ts +++ b/plugins/auth-backend-module-okta-provider/src/types.d.ts @@ -13,8 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { ClusterLinksFormatterOptions } from '../../../types/types'; -export function eksFormatter(_options: ClusterLinksFormatterOptions): URL { - throw new Error('EKS formatter is not yet implemented. Please, contribute!'); +declare module 'passport-okta2' { + import { Request } from 'express'; + import { StrategyCreated } from 'passport'; + + export class Strategy { + constructor(options: any, verify: any); + authenticate(this: StrategyCreated, req: Request, options?: any): any; + } } diff --git a/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md b/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md index c04460a935..147a13b97d 100644 --- a/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md @@ -1,5 +1,106 @@ # @backstage/plugin-auth-backend-module-pinniped-provider +## 0.1.3 + +### Patch Changes + +- 928efbc: Deprecated the `authModulePinnipedProvider` export. A default export is now available and should be used like this in your backend: `backend.add(import('@backstage/plugin-auth-backend-module-pinniped-provider'));` +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/config@1.1.1 + +## 0.1.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## 0.1.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + +## 0.1.3-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.0 + +## 0.1.2 + +### Patch Changes + +- a62764b: Updated dependency `passport` to `^0.7.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + +## 0.1.2-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.3 + +## 0.1.2-next.2 + +### Patch Changes + +- a62764b: Updated dependency `passport` to `^0.7.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/config@1.1.1 + +## 0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## 0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + +## 0.1.1 + +### Patch Changes + +- a8f6afda4a: Introduced metadata cache for the `pinniped` provider. +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.1 + ## 0.1.1-next.2 ### Patch Changes diff --git a/plugins/auth-backend-module-pinniped-provider/api-report.md b/plugins/auth-backend-module-pinniped-provider/api-report.md index b9b993bd1e..182ea8ba21 100644 --- a/plugins/auth-backend-module-pinniped-provider/api-report.md +++ b/plugins/auth-backend-module-pinniped-provider/api-report.md @@ -5,16 +5,29 @@ ```ts import { BackendFeature } from '@backstage/backend-plugin-api'; import { BaseClient } from 'openid-client'; +import { Config } from '@backstage/config'; import { OAuthAuthenticator } from '@backstage/plugin-auth-node'; import { Strategy } from 'openid-client'; import { TokenSet } from 'openid-client'; -// @public (undocumented) +// @public @deprecated (undocumented) export const authModulePinnipedProvider: () => BackendFeature; +// @public (undocumented) +const authModulePinnipedProvider_2: () => BackendFeature; +export default authModulePinnipedProvider_2; + // @public (undocumented) export const pinnipedAuthenticator: OAuthAuthenticator< - Promise<{ + PinnipedStrategyCache, + unknown +>; + +// @public (undocumented) +export class PinnipedStrategyCache { + constructor(callbackUrl: string, config: Config); + // (undocumented) + getStrategy(): Promise<{ providerStrategy: Strategy< { tokenset: TokenSet; @@ -22,7 +35,6 @@ export const pinnipedAuthenticator: OAuthAuthenticator< BaseClient >; client: BaseClient; - }>, - unknown ->; + }>; +} ``` diff --git a/plugins/auth-backend-module-pinniped-provider/package.json b/plugins/auth-backend-module-pinniped-provider/package.json index 087a90cdbb..bda4cd9751 100644 --- a/plugins/auth-backend-module-pinniped-provider/package.json +++ b/plugins/auth-backend-module-pinniped-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-pinniped-provider", "description": "The pinniped-provider backend module for the auth plugin.", - "version": "0.1.1-next.2", + "version": "0.1.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,24 +23,23 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/backend-common": "workspace:^", "@backstage/backend-plugin-api": "workspace:^", + "@backstage/config": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", + "luxon": "^3.4.3", "openid-client": "^5.4.3" }, "devDependencies": { "@backstage/backend-defaults": "workspace:^", "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", - "@backstage/config": "workspace:^", "@backstage/plugin-auth-backend": "workspace:^", "cookie-parser": "^1.4.6", "express": "^4.18.2", - "express-promise-router": "^4.1.1", "express-session": "^1.17.3", "jose": "^4.14.6", "msw": "^1.3.0", - "passport": "^0.6.0", + "passport": "^0.7.0", "supertest": "^6.3.3" }, "files": [ diff --git a/plugins/auth-backend-module-pinniped-provider/src/authenticator.test.ts b/plugins/auth-backend-module-pinniped-provider/src/authenticator.test.ts index f908c1ea13..2ecd54e80a 100644 --- a/plugins/auth-backend-module-pinniped-provider/src/authenticator.test.ts +++ b/plugins/auth-backend-module-pinniped-provider/src/authenticator.test.ts @@ -28,9 +28,10 @@ import { ConfigReader } from '@backstage/config'; import { JWK, SignJWT, exportJWK, generateKeyPair } from 'jose'; import { rest } from 'msw'; import express from 'express'; +import { DateTime } from 'luxon'; describe('pinnipedAuthenticator', () => { - let implementation: any; + let authCtx: any; let oauthState: OAuthState; let idToken: string; let publicKey: JWK; @@ -85,6 +86,7 @@ describe('pinnipedAuthenticator', () => { beforeEach(() => { jest.clearAllMocks(); + jest.restoreAllMocks(); mswServer.use( rest.get( @@ -128,7 +130,7 @@ describe('pinnipedAuthenticator', () => { }), ); - implementation = pinnipedAuthenticator.initialize({ + authCtx = pinnipedAuthenticator.initialize({ callbackUrl: 'https://backstage.test/callback', config: new ConfigReader({ federationDomain: 'https://federationDomain.test', @@ -143,6 +145,17 @@ describe('pinnipedAuthenticator', () => { }; }); + describe('#initialize', () => { + it('always returns a PinnipedStrategyCache', async () => { + const { providerStrategy, client } = await authCtx.getStrategy(); + + expect(providerStrategy).toBeDefined(); + expect(client.issuer.authorization_endpoint).toMatch( + 'https://pinniped.test/oauth2/authorize', + ); + }); + }); + describe('#start', () => { let fakeSession: Record; let startRequest: OAuthAuthenticatorStartInput; @@ -162,7 +175,7 @@ describe('pinnipedAuthenticator', () => { it('redirects to authorization endpoint returned from OIDC metadata endpoint', async () => { const startResponse = await pinnipedAuthenticator.start( startRequest, - implementation, + authCtx, ); const url = new URL(startResponse.url); @@ -174,7 +187,7 @@ describe('pinnipedAuthenticator', () => { it('initiates authorization code grant', async () => { const startResponse = await pinnipedAuthenticator.start( startRequest, - implementation, + authCtx, ); const { searchParams } = new URL(startResponse.url); @@ -185,7 +198,7 @@ describe('pinnipedAuthenticator', () => { startRequest.req.query = { audience: 'test-cluster' }; const startResponse = await pinnipedAuthenticator.start( startRequest, - implementation, + authCtx, ); const { searchParams } = new URL(startResponse.url); const stateParam = searchParams.get('state'); @@ -201,7 +214,7 @@ describe('pinnipedAuthenticator', () => { it('passes client ID from config', async () => { const startResponse = await pinnipedAuthenticator.start( startRequest, - implementation, + authCtx, ); const { searchParams } = new URL(startResponse.url); @@ -211,7 +224,7 @@ describe('pinnipedAuthenticator', () => { it('passes callback URL from config', async () => { const startResponse = await pinnipedAuthenticator.start( startRequest, - implementation, + authCtx, ); const { searchParams } = new URL(startResponse.url); @@ -223,7 +236,7 @@ describe('pinnipedAuthenticator', () => { it('generates PKCE challenge', async () => { const startResponse = await pinnipedAuthenticator.start( startRequest, - implementation, + authCtx, ); const { searchParams } = new URL(startResponse.url); @@ -232,14 +245,14 @@ describe('pinnipedAuthenticator', () => { }); it('stores PKCE verifier in session', async () => { - await pinnipedAuthenticator.start(startRequest, implementation); + await pinnipedAuthenticator.start(startRequest, authCtx); expect(fakeSession['oidc:pinniped.test'].code_verifier).toBeDefined(); }); it('requests sufficient scopes for token exchange by default', async () => { const startResponse = await pinnipedAuthenticator.start( startRequest, - implementation, + authCtx, ); const { searchParams } = new URL(startResponse.url); const scopes = searchParams.get('scope')?.split(' ') ?? []; @@ -257,7 +270,7 @@ describe('pinnipedAuthenticator', () => { it('encodes OAuth state in query param', async () => { const startResponse = await pinnipedAuthenticator.start( startRequest, - implementation, + authCtx, ); const { searchParams } = new URL(startResponse.url); const stateParam = searchParams.get('state'); @@ -276,10 +289,103 @@ describe('pinnipedAuthenticator', () => { url: 'test', }, } as unknown as OAuthAuthenticatorStartInput, - implementation, + authCtx, ), ).rejects.toThrow('authentication requires session support'); }); + + it('refreshes oidc metadata after a failed fetch', async () => { + mswServer.use( + rest.get( + 'https://federationDomain.test/.well-known/openid-configuration', + (_req, res, _ctx) => res.networkError('Timeout'), + ), + ); + + const authCtxCreatedWhileSupervisorUnavailable = + pinnipedAuthenticator.initialize({ + callbackUrl: 'https://backstage.test/callback', + config: new ConfigReader({ + federationDomain: 'https://federationDomain.test', + clientId: 'clientId', + clientSecret: 'clientSecret', + }), + }); + + mswServer.use( + rest.get( + 'https://federationDomain.test/.well-known/openid-configuration', + (_req, res, ctx) => + res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json(issuerMetadata), + ), + ), + ); + + const response = await pinnipedAuthenticator.start( + startRequest, + authCtxCreatedWhileSupervisorUnavailable, + ); + + expect(response.url).toMatch('https://pinniped.test/oauth2/authorize'); + }); + + it('caches oidc metadata after a success', async () => { + // we start with 1 because the supervisor was called once already when we initialize. + let supervisorCalls: number = 1; + + mswServer.use( + rest.get( + 'https://federationDomain.test/.well-known/openid-configuration', + (_req, res, ctx) => { + supervisorCalls += 1; + return res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json(issuerMetadata), + ); + }, + ), + ); + + await pinnipedAuthenticator.start(startRequest, authCtx); + await pinnipedAuthenticator.start(startRequest, authCtx); + + expect(supervisorCalls).toEqual(1); + }); + + it('refreshes oidc metadata when current one in cache expires', async () => { + // we start with 1 because the supervisor was called once already when we initialize. + let supervisorCalls: number = 1; + const fixedTime = DateTime.local(); + jest.spyOn(DateTime, 'local').mockImplementation(() => fixedTime); + + mswServer.use( + rest.get( + 'https://federationDomain.test/.well-known/openid-configuration', + (_req, res, ctx) => { + supervisorCalls += 1; + return res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json(issuerMetadata), + ); + }, + ), + ); + + await pinnipedAuthenticator.start(startRequest, authCtx); + + jest + .spyOn(DateTime, 'local') + .mockImplementation(() => fixedTime.plus({ seconds: 60000 })); + + await pinnipedAuthenticator.start(startRequest, authCtx); + + expect(supervisorCalls).toEqual(2); + }); }); describe('#authenticate', () => { @@ -304,7 +410,7 @@ describe('pinnipedAuthenticator', () => { it('exchanges authorization code for access token', async () => { const handlerResponse = await pinnipedAuthenticator.authenticate( handlerRequest, - implementation, + authCtx, ); const accessToken = handlerResponse.session.accessToken; @@ -314,7 +420,7 @@ describe('pinnipedAuthenticator', () => { it('exchanges authorization code for refresh token', async () => { const handlerResponse = await pinnipedAuthenticator.authenticate( handlerRequest, - implementation, + authCtx, ); const refreshToken = handlerResponse.session.refreshToken; @@ -324,7 +430,7 @@ describe('pinnipedAuthenticator', () => { it('returns granted scope', async () => { const handlerResponse = await pinnipedAuthenticator.authenticate( handlerRequest, - implementation, + authCtx, ); const responseScope = handlerResponse.session.scope; @@ -349,7 +455,7 @@ describe('pinnipedAuthenticator', () => { const handlerResponse = await pinnipedAuthenticator.authenticate( handlerRequest, - implementation, + authCtx, ); expect(handlerResponse.session.idToken).toEqual(clusterScopedIdToken); @@ -413,7 +519,7 @@ describe('pinnipedAuthenticator', () => { }; await expect( - pinnipedAuthenticator.authenticate(handlerRequest, implementation), + pinnipedAuthenticator.authenticate(handlerRequest, authCtx), ).rejects.toThrow( `Failed to get cluster specific ID token for "test_cluster": Error: RFC8693 token exchange failed with error: NetworkError: Connection timed out`, ); @@ -422,7 +528,7 @@ describe('pinnipedAuthenticator', () => { it('fails without authorization code', async () => { handlerRequest.req.url = 'https://test.com'; return expect( - pinnipedAuthenticator.authenticate(handlerRequest, implementation), + pinnipedAuthenticator.authenticate(handlerRequest, authCtx), ).rejects.toThrow('Unexpected redirect'); }); @@ -440,7 +546,7 @@ describe('pinnipedAuthenticator', () => { }, } as unknown as express.Request, }, - implementation, + authCtx, ), ).rejects.toThrow( 'Authentication rejected, state missing from the response', @@ -456,10 +562,140 @@ describe('pinnipedAuthenticator', () => { url: 'https://test.com', } as unknown as express.Request, }, - implementation, + authCtx, ), ).rejects.toThrow('authentication requires session support'); }); + + it('refreshes oidc metadata after a failed fetch', async () => { + mswServer.use( + rest.get( + 'https://federationDomain.test/.well-known/openid-configuration', + (_req, res, _ctx) => res.networkError('Timeout'), + ), + ); + + const authCtxCreatedWhileSupervisorUnavailable = + pinnipedAuthenticator.initialize({ + callbackUrl: 'https://backstage.test/callback', + config: new ConfigReader({ + federationDomain: 'https://federationDomain.test', + clientId: 'clientId', + clientSecret: 'clientSecret', + }), + }); + + mswServer.use( + rest.get( + 'https://federationDomain.test/.well-known/openid-configuration', + (_req, res, ctx) => + res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json(issuerMetadata), + ), + ), + ); + + const response = await pinnipedAuthenticator.authenticate( + handlerRequest, + authCtxCreatedWhileSupervisorUnavailable, + ); + expect(response.session.accessToken).toEqual('accessToken'); + }); + + it('caches oidc metadata after a success', async () => { + let supervisorCalls: number = 1; + + mswServer.use( + rest.get( + 'https://federationDomain.test/.well-known/openid-configuration', + (_req, res, ctx) => { + supervisorCalls += 1; + return res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json(issuerMetadata), + ); + }, + ), + ); + + await pinnipedAuthenticator.authenticate(handlerRequest, authCtx); + + await pinnipedAuthenticator.authenticate( + { + req: { + method: 'GET', + url: `https://test?code=authorization_code&state=${encodeOAuthState( + oauthState, + )}`, + session: { + 'oidc:pinniped.test': { + state: encodeOAuthState(oauthState), + }, + }, + } as unknown as express.Request, + }, + authCtx, + ); + + expect(supervisorCalls).toEqual(1); + }); + + it('refreshes oidc metadata when current one in cache expires', async () => { + let supervisorCalls: number = 0; + const fixedTime = DateTime.local(); + jest.spyOn(DateTime, 'local').mockImplementation(() => fixedTime); + + mswServer.use( + rest.get( + 'https://federationDomain.test/.well-known/openid-configuration', + (_req, res, ctx) => { + supervisorCalls += 1; + return res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json(issuerMetadata), + ); + }, + ), + ); + + authCtx = pinnipedAuthenticator.initialize({ + callbackUrl: 'https://backstage.test/callback', + config: new ConfigReader({ + federationDomain: 'https://federationDomain.test', + clientId: 'clientId', + clientSecret: 'clientSecret', + }), + }); + + await pinnipedAuthenticator.authenticate(handlerRequest, authCtx); + + jest + .spyOn(DateTime, 'local') + .mockImplementation(() => fixedTime.plus({ seconds: 60000 })); + + await pinnipedAuthenticator.authenticate( + { + req: { + method: 'GET', + url: `https://test?code=authorization_code&state=${encodeOAuthState( + oauthState, + )}`, + session: { + 'oidc:pinniped.test': { + state: encodeOAuthState(oauthState), + }, + }, + } as unknown as express.Request, + }, + authCtx, + ); + + expect(supervisorCalls).toEqual(2); + }); }); describe('#refresh', () => { @@ -476,7 +712,7 @@ describe('pinnipedAuthenticator', () => { it('gets new refresh token', async () => { const refreshResponse = await pinnipedAuthenticator.refresh( refreshRequest, - implementation, + authCtx, ); expect(refreshResponse.session.refreshToken).toBe('refreshToken'); @@ -485,7 +721,7 @@ describe('pinnipedAuthenticator', () => { it('gets access token', async () => { const refreshResponse = await pinnipedAuthenticator.refresh( refreshRequest, - implementation, + authCtx, ); expect(refreshResponse.session.accessToken).toBe('accessToken'); @@ -494,10 +730,100 @@ describe('pinnipedAuthenticator', () => { it('gets id token', async () => { const refreshResponse = await pinnipedAuthenticator.refresh( refreshRequest, - implementation, + authCtx, ); expect(refreshResponse.session.idToken).toBe(idToken); }); + + it('refreshes oidc metadata after a failed fetch', async () => { + mswServer.use( + rest.get( + 'https://federationDomain.test/.well-known/openid-configuration', + (_req, res, _ctx) => res.networkError('Timeout'), + ), + ); + + const authCtxCreatedWhileSupervisorUnavailable = + pinnipedAuthenticator.initialize({ + callbackUrl: 'https://backstage.test/callback', + config: new ConfigReader({ + federationDomain: 'https://federationDomain.test', + clientId: 'clientId', + clientSecret: 'clientSecret', + }), + }); + + mswServer.use( + rest.get( + 'https://federationDomain.test/.well-known/openid-configuration', + (_req, res, ctx) => + res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json(issuerMetadata), + ), + ), + ); + + const response = await pinnipedAuthenticator.refresh( + refreshRequest, + authCtxCreatedWhileSupervisorUnavailable, + ); + expect(response.session.accessToken).toEqual('accessToken'); + }); + + it('caches oidc metadata after a success', async () => { + let supervisorCalls: number = 1; + + mswServer.use( + rest.get( + 'https://federationDomain.test/.well-known/openid-configuration', + (_req, res, ctx) => { + supervisorCalls += 1; + return res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json(issuerMetadata), + ); + }, + ), + ); + + await pinnipedAuthenticator.refresh(refreshRequest, authCtx); + await pinnipedAuthenticator.refresh(refreshRequest, authCtx); + + expect(supervisorCalls).toEqual(1); + }); + + it('refreshes oidc metadata when current one in cache expires', async () => { + let supervisorCalls: number = 1; + const fixedTime = DateTime.local(); + jest.spyOn(DateTime, 'local').mockImplementation(() => fixedTime); + + mswServer.use( + rest.get( + 'https://federationDomain.test/.well-known/openid-configuration', + (_req, res, ctx) => { + supervisorCalls += 1; + return res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json(issuerMetadata), + ); + }, + ), + ); + + await pinnipedAuthenticator.refresh(refreshRequest, authCtx); + + jest + .spyOn(DateTime, 'local') + .mockImplementation(() => fixedTime.plus({ seconds: 60000 })); + + await pinnipedAuthenticator.refresh(refreshRequest, authCtx); + + expect(supervisorCalls).toEqual(2); + }); }); }); diff --git a/plugins/auth-backend-module-pinniped-provider/src/authenticator.ts b/plugins/auth-backend-module-pinniped-provider/src/authenticator.ts index 83c4204ad0..e07eaba759 100644 --- a/plugins/auth-backend-module-pinniped-provider/src/authenticator.ts +++ b/plugins/auth-backend-module-pinniped-provider/src/authenticator.ts @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { Config } from '@backstage/config'; import { PassportDoneCallback } from '@backstage/plugin-auth-node'; import { createOAuthAuthenticator, @@ -24,7 +25,9 @@ import { Issuer, TokenSet, Strategy as OidcStrategy, + BaseClient, } from 'openid-client'; +import { DateTime } from 'luxon'; const rfc8693TokenExchange = async ({ subject_token, @@ -53,22 +56,78 @@ const rfc8693TokenExchange = async ({ }); }; +const OIDC_METADATA_TTL_SECONDS = 3600; + /** @public */ -export const pinnipedAuthenticator = createOAuthAuthenticator({ - defaultProfileTransform: async (_r, _c) => ({ profile: {} }), - async initialize({ callbackUrl, config }) { +export class PinnipedStrategyCache { + private readonly callbackUrl: string; + private readonly config: Config; + private strategyPromise: Promise<{ + providerStrategy: OidcStrategy<{ tokenset: TokenSet }, BaseClient>; + client: BaseClient; + }>; + + private cachedPromise?: Promise<{ + providerStrategy: OidcStrategy<{ tokenset: TokenSet }, BaseClient>; + client: BaseClient; + }>; + private cachedPromiseExpiry?: Date; + + constructor(callbackUrl: string, config: Config) { + this.callbackUrl = callbackUrl; + this.config = config; + this.strategyPromise = this.buildStrategy(); + } + + public async getStrategy(): Promise<{ + providerStrategy: OidcStrategy<{ tokenset: TokenSet }, BaseClient>; + client: BaseClient; + }> { + if (this.cachedPromise) { + if ( + this.cachedPromiseExpiry && + DateTime.fromJSDate(this.cachedPromiseExpiry) > DateTime.local() + ) { + return this.cachedPromise; + } + // cachedPromise has expired, remove promise from cache and regenerate strategy + this.strategyPromise = this.buildStrategy(); + delete this.cachedPromise; + } + + try { + // if strategy is generated successfully, save it to cache + await this.strategyPromise; + this.cachedPromise = this.strategyPromise; + this.cachedPromiseExpiry = DateTime.utc() + .plus({ seconds: OIDC_METADATA_TTL_SECONDS }) + .toJSDate(); + } catch (error) { + // if we fail to generate a strategy, retry and overwrite strategy + this.strategyPromise = this.buildStrategy(); + delete this.cachedPromise; + delete this.cachedPromiseExpiry; + } + + return this.strategyPromise; + } + + private async buildStrategy(): Promise<{ + providerStrategy: OidcStrategy<{ tokenset: TokenSet }, BaseClient>; + client: BaseClient; + }> { const issuer = await Issuer.discover( - `${config.getString( + `${this.config.getString( 'federationDomain', )}/.well-known/openid-configuration`, ); const client = new issuer.Client({ - access_type: 'offline', // this option must be passed to provider to receive a refresh token - client_id: config.getString('clientId'), - client_secret: config.getString('clientSecret'), - redirect_uris: [callbackUrl], + access_type: 'offline', + client_id: this.config.getString('clientId'), + client_secret: this.config.getString('clientSecret'), + redirect_uris: [this.callbackUrl], response_types: ['code'], - scope: config.getOptionalString('scope') || '', + scope: this.config.getOptionalString('scope') || '', id_token_signed_response_alg: 'ES256', }); const providerStrategy = new OidcStrategy( @@ -88,12 +147,18 @@ export const pinnipedAuthenticator = createOAuthAuthenticator({ done(undefined, { tokenset }, {}); }, ); - return { providerStrategy, client }; - }, + } +} - async start(input, ctx) { - const { providerStrategy } = await ctx; +/** @public */ +export const pinnipedAuthenticator = createOAuthAuthenticator({ + defaultProfileTransform: async (_r, _c) => ({ profile: {} }), + initialize({ callbackUrl, config }) { + return new PinnipedStrategyCache(callbackUrl, config); + }, + async start(input, ctx): Promise<{ url: string; status?: number }> { + const { providerStrategy } = await ctx.getStrategy(); const stringifiedAudience = input.req.query?.audience as string; const decodedState = decodeOAuthState(input.state); const state = { ...decodedState, audience: stringifiedAudience }; @@ -117,7 +182,7 @@ export const pinnipedAuthenticator = createOAuthAuthenticator({ }, async authenticate(input, ctx) { - const { providerStrategy } = await ctx; + const { providerStrategy } = await ctx.getStrategy(); const { req } = input; const { searchParams } = new URL(req.url, 'https://pinniped.com'); const stateParam = searchParams.get('state'); @@ -132,7 +197,7 @@ export const pinnipedAuthenticator = createOAuthAuthenticator({ ? rfc8693TokenExchange({ subject_token: user.tokenset.access_token, target_audience: audience, - ctx, + ctx: ctx.getStrategy(), }).catch(err => reject( new Error( @@ -172,7 +237,7 @@ export const pinnipedAuthenticator = createOAuthAuthenticator({ }, async refresh(input, ctx) { - const { client } = await ctx; + const { client } = await ctx.getStrategy(); const tokenset = await client.refresh(input.refreshToken); return new Promise((resolve, reject) => { diff --git a/plugins/auth-backend-module-pinniped-provider/src/deprecated.ts b/plugins/auth-backend-module-pinniped-provider/src/deprecated.ts new file mode 100644 index 0000000000..0dd2ed36bd --- /dev/null +++ b/plugins/auth-backend-module-pinniped-provider/src/deprecated.ts @@ -0,0 +1,23 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { authModulePinnipedProvider as deprecatedAuthModulePinnipedProvider } from './module'; + +/** + * @public + * @deprecated Use default import instead + */ +export const authModulePinnipedProvider = deprecatedAuthModulePinnipedProvider; diff --git a/plugins/auth-backend-module-pinniped-provider/src/index.ts b/plugins/auth-backend-module-pinniped-provider/src/index.ts index 9a2ca6727e..f4b789644d 100644 --- a/plugins/auth-backend-module-pinniped-provider/src/index.ts +++ b/plugins/auth-backend-module-pinniped-provider/src/index.ts @@ -20,5 +20,6 @@ * @packageDocumentation */ -export { pinnipedAuthenticator } from './authenticator'; -export { authModulePinnipedProvider } from './module'; +export { pinnipedAuthenticator, PinnipedStrategyCache } from './authenticator'; +export { authModulePinnipedProvider as default } from './module'; +export * from './deprecated'; diff --git a/plugins/auth-backend-module-pinniped-provider/src/module.test.ts b/plugins/auth-backend-module-pinniped-provider/src/module.test.ts index ed285cff86..a5c8fb4599 100644 --- a/plugins/auth-backend-module-pinniped-provider/src/module.test.ts +++ b/plugins/auth-backend-module-pinniped-provider/src/module.test.ts @@ -13,30 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; -import request from 'supertest'; -import { setupServer } from 'msw/node'; -import { rest } from 'msw'; -import { Server } from 'http'; -import express from 'express'; -import cookieParser from 'cookie-parser'; -import session from 'express-session'; -import passport from 'passport'; -import { AddressInfo } from 'net'; import { - AuthProviderRouteHandlers, - createOAuthRouteHandlers, -} from '@backstage/plugin-auth-node'; -import Router from 'express-promise-router'; -import { pinnipedAuthenticator } from './authenticator'; -import { ConfigReader } from '@backstage/config'; + mockServices, + setupRequestMockHandlers, + startTestBackend, +} from '@backstage/backend-test-utils'; +import { Server } from 'http'; import { JWK, SignJWT, exportJWK, generateKeyPair } from 'jose'; +import { rest } from 'msw'; +import { setupServer } from 'msw/node'; +import request from 'supertest'; +import { authModulePinnipedProvider } from './module'; describe('authModulePinnipedProvider', () => { - let app: express.Express; - let backstageServer: Server; - let appUrl: string; - let providerRouteHandler: AuthProviderRouteHandlers; + let server: Server; + let port: number; let idToken: string; let publicKey: JWK; @@ -151,73 +142,38 @@ describe('authModulePinnipedProvider', () => { }), ); - const secret = 'secret'; - app = express() - .use(cookieParser(secret)) - .use( - session({ - secret, - saveUninitialized: false, - resave: false, - cookie: { secure: false }, - }), - ) - .use(passport.initialize()) - .use(passport.session()); - await new Promise(resolve => { - backstageServer = app.listen(0, '0.0.0.0', () => { - appUrl = `http://127.0.0.1:${ - (backstageServer.address() as AddressInfo).port - }`; - resolve(null); - }); - }); - - mswServer.use(rest.all(`${appUrl}/*`, req => req.passthrough())); - - providerRouteHandler = createOAuthRouteHandlers({ - authenticator: pinnipedAuthenticator, - appUrl, - baseUrl: `${appUrl}/api/auth`, - isOriginAllowed: _ => true, - providerId: 'pinniped', - config: new ConfigReader({ - federationDomain: 'https://federationDomain.test', - clientId: 'clientId', - clientSecret: 'clientSecret', - }), - resolverContext: { - issueToken: async _ => ({ token: '' }), - findCatalogUser: async _ => ({ - entity: { - apiVersion: '', - kind: '', - metadata: { name: '' }, + const backend = await startTestBackend({ + features: [ + authModulePinnipedProvider, + import('@backstage/plugin-auth-backend'), + mockServices.rootConfig.factory({ + data: { + app: { baseUrl: 'http://localhost' }, + auth: { + session: { secret: 'test' }, + providers: { + pinniped: { + development: { + federationDomain: 'https://federationDomain.test', + clientId: 'clientId', + clientSecret: 'clientSecret', + }, + }, + }, + }, }, }), - signInWithCatalogUser: async _ => ({ token: '' }), - }, + ], }); - const router = Router(); - router - .use( - '/api/auth/pinniped/start', - providerRouteHandler.start.bind(providerRouteHandler), - ) - .use( - '/api/auth/pinniped/handler/frame', - providerRouteHandler.frameHandler.bind(providerRouteHandler), - ); - app.use(router); - }); + server = backend.server; + port = backend.server.port(); - afterEach(() => { - backstageServer.close(); + mswServer.use(rest.all(`http://*:${port}/*`, req => req.passthrough())); }); it('should start', async () => { - const agent = request.agent(backstageServer); + const agent = request.agent(server); const startResponse = await agent.get( `/api/auth/pinniped/start?env=development&audience=test_cluster`, ); @@ -230,15 +186,20 @@ describe('authModulePinnipedProvider', () => { // make /start request with audience parameter const startResponse = await agent.get( - `${appUrl}/api/auth/pinniped/start?env=development&audience=test_cluster`, + `http://localhost:${port}/api/auth/pinniped/start?env=development&audience=test_cluster`, ); - // follow redirect to authorization endpoint - const authorizationResponse = await agent.get( - startResponse.header.location, + + // Emulate user interaction with the Pinniped login page + const authResponse = await agent.get(startResponse.header.location); + expect(authResponse.status).toBe(302); + const callbackUrl = new URL(authResponse.header.location); + + // follow redirect from the login page back to the callback URL to the Backstage auth backend + const relativeCallbackUrl = String(callbackUrl).slice( + callbackUrl.origin.length, ); - // follow redirect to token_endpoint const handlerResponse = await agent.get( - authorizationResponse.header.location, + `http://localhost:${port}${relativeCallbackUrl}`, ); expect(handlerResponse.text).toContain( diff --git a/plugins/auth-backend-module-vmware-cloud-provider/.eslintrc.js b/plugins/auth-backend-module-vmware-cloud-provider/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/auth-backend-module-vmware-cloud-provider/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md b/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md new file mode 100644 index 0000000000..8beb4ed11c --- /dev/null +++ b/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md @@ -0,0 +1,86 @@ +# @backstage/plugin-auth-backend-module-vmware-cloud-provider + +## 0.1.1 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + +## 0.1.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## 0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-model@1.4.3 + +## 0.1.1-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-auth-node@0.4.3-next.0 + +## 0.1.0 + +### Minor Changes + +- ed02c69: Add VMware Cloud auth backend module provider + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + +## 0.1.0-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + +## 0.1.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + +## 0.1.0-next.0 + +### Minor Changes + +- ed02c69a3c: Add VMware Cloud auth backend module provider + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-auth-node@0.4.2-next.1 diff --git a/plugins/auth-backend-module-vmware-cloud-provider/README.md b/plugins/auth-backend-module-vmware-cloud-provider/README.md new file mode 100644 index 0000000000..d06a0d84ab --- /dev/null +++ b/plugins/auth-backend-module-vmware-cloud-provider/README.md @@ -0,0 +1,7 @@ +# Auth Module: VMware Cloud Provider + +This module provides an VMware Cloud auth provider implementation for `@backstage/plugin-auth-backend`. + +## Links + +- [Backstage](https://backstage.io) diff --git a/plugins/auth-backend-module-vmware-cloud-provider/api-report.md b/plugins/auth-backend-module-vmware-cloud-provider/api-report.md new file mode 100644 index 0000000000..ff9e82dd45 --- /dev/null +++ b/plugins/auth-backend-module-vmware-cloud-provider/api-report.md @@ -0,0 +1,46 @@ +## API Report File for "@backstage/plugin-auth-backend-module-vmware-cloud-provider" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { BackendFeature } from '@backstage/backend-plugin-api'; +import { OAuthAuthenticator } from '@backstage/plugin-auth-node'; +import { OAuthAuthenticatorResult } from '@backstage/plugin-auth-node'; +import { PassportOAuthAuthenticatorHelper } from '@backstage/plugin-auth-node'; +import { PassportProfile } from '@backstage/plugin-auth-node'; +import { SignInResolverFactory } from '@backstage/plugin-auth-node'; +import { Strategy } from 'passport-oauth2'; + +// @public +const authModuleVmwareCloudProvider: () => BackendFeature; +export default authModuleVmwareCloudProvider; + +// @public +export const vmwareCloudAuthenticator: OAuthAuthenticator< + VMwareCloudAuthenticatorContext, + VMwarePassportProfile +>; + +// @public (undocumented) +export interface VMwareCloudAuthenticatorContext { + // (undocumented) + helper: PassportOAuthAuthenticatorHelper; + // (undocumented) + organizationId?: string; + // (undocumented) + providerStrategy: Strategy; +} + +// @public +export namespace vmwareCloudSignInResolvers { + const profileEmailMatchingUserEntityEmail: SignInResolverFactory< + OAuthAuthenticatorResult, + unknown + >; +} + +// @public (undocumented) +export type VMwarePassportProfile = PassportProfile & { + organizationId?: string; +}; +``` diff --git a/plugins/auth-backend-module-vmware-cloud-provider/catalog-info.yaml b/plugins/auth-backend-module-vmware-cloud-provider/catalog-info.yaml new file mode 100644 index 0000000000..d40b1e4308 --- /dev/null +++ b/plugins/auth-backend-module-vmware-cloud-provider/catalog-info.yaml @@ -0,0 +1,10 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: backstage-plugin-auth-backend-module-vmware-cloud-provider + title: '@backstage/plugin-auth-backend-module-vmware-cloud-provider' + description: The vmware-cloud-provider backend module for the auth plugin. +spec: + lifecycle: experimental + type: backstage-backend-plugin-module + owner: maintainers diff --git a/plugins/auth-backend-module-vmware-cloud-provider/config.d.ts b/plugins/auth-backend-module-vmware-cloud-provider/config.d.ts new file mode 100644 index 0000000000..10b3566899 --- /dev/null +++ b/plugins/auth-backend-module-vmware-cloud-provider/config.d.ts @@ -0,0 +1,31 @@ +/* + * 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 { + auth?: { + providers?: { + /** @visibility frontend */ + vmwareCloudServices?: { + [authEnv: string]: { + clientId: string; + organizationId: string; + scope?: string; + consoleEndpoint?: string; + }; + }; + }; + }; +} diff --git a/plugins/auth-backend-module-vmware-cloud-provider/dev/index.ts b/plugins/auth-backend-module-vmware-cloud-provider/dev/index.ts new file mode 100644 index 0000000000..d3c18c1d48 --- /dev/null +++ b/plugins/auth-backend-module-vmware-cloud-provider/dev/index.ts @@ -0,0 +1,24 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createBackend } from '@backstage/backend-defaults'; + +const backend = createBackend(); + +backend.add(import('@backstage/plugin-auth-backend')); +backend.add(import('../src')); + +backend.start(); diff --git a/plugins/auth-backend-module-vmware-cloud-provider/package.json b/plugins/auth-backend-module-vmware-cloud-provider/package.json new file mode 100644 index 0000000000..b9b6a3cdaf --- /dev/null +++ b/plugins/auth-backend-module-vmware-cloud-provider/package.json @@ -0,0 +1,46 @@ +{ + "name": "@backstage/plugin-auth-backend-module-vmware-cloud-provider", + "description": "The vmware-cloud-provider backend module for the auth plugin.", + "version": "0.1.1", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "backend-plugin-module" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/backend-plugin-api": "workspace:^", + "@backstage/catalog-model": "workspace:^", + "@backstage/plugin-auth-node": "workspace:^", + "@types/passport-oauth2": "^1.4.15", + "jose": "^4.6.0", + "passport-oauth2": "^1.6.1" + }, + "devDependencies": { + "@backstage/backend-defaults": "workspace:^", + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/plugin-auth-backend": "workspace:^", + "msw": "^2.0.8", + "supertest": "^6.3.3" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/auth-backend-module-vmware-cloud-provider/src/authenticator.test.ts b/plugins/auth-backend-module-vmware-cloud-provider/src/authenticator.test.ts new file mode 100644 index 0000000000..f38ceeb462 --- /dev/null +++ b/plugins/auth-backend-module-vmware-cloud-provider/src/authenticator.test.ts @@ -0,0 +1,477 @@ +/* + * 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 { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { ConfigReader } from '@backstage/config'; +import { + AuthResolverContext, + encodeOAuthState, + OAuthAuthenticatorAuthenticateInput, + OAuthAuthenticatorRefreshInput, + OAuthAuthenticatorStartInput, + OAuthState, +} from '@backstage/plugin-auth-node'; +import { SignJWT } from 'jose'; +import { http, HttpResponse } from 'msw'; +import { setupServer } from 'msw/node'; + +import { + vmwareCloudAuthenticator, + VMwareCloudAuthenticatorContext, +} from './authenticator'; + +jest.mock('uid2', () => jest.fn().mockReturnValue('sessionid')); + +describe('vmwareCloudAuthenticator', () => { + const server = setupServer(); + setupRequestMockHandlers(server); + + let oAuthState: OAuthState = { + nonce: 'nonce', + env: 'env', + }; + + const signInInfo: Record = { + given_name: 'Givenname', + family_name: 'Familyname', + context_name: 'orgId', + email: 'user@example.com', + }; + + let idToken: string; + + let authResponse: { + access_token: string; + refresh_token: string; + id_token: typeof idToken; + }; + + let fakeSession: Record; + let authenticatorCtx: VMwareCloudAuthenticatorContext; + + beforeAll(async () => { + idToken = await new SignJWT(signInInfo) + .setProtectedHeader({ alg: 'HS256' }) + .sign(Buffer.from('signing key')); + + authResponse = { + access_token: 'accessToken', + refresh_token: 'refreshToken', + id_token: idToken, + }; + }); + + beforeEach(() => { + server.use( + http.post( + 'https://console.cloud.vmware.com/csp/gateway/am/api/auth/token', + ({ request }) => + request.headers.get('Authorization') + ? HttpResponse.json(authResponse) + : HttpResponse.json(null, { status: 500 }), + ), + ); + + authenticatorCtx = vmwareCloudAuthenticator.initialize({ + callbackUrl: 'http://callbackUrl', + config: new ConfigReader({ + clientId: 'placeholderClientId', + organizationId: 'orgId', + }), + }); + }); + + describe('#initialize', () => { + it('fails when organizationId is not configured', () => { + return expect(() => + vmwareCloudAuthenticator.initialize({ + callbackUrl: 'http://callbackUrl', + config: new ConfigReader({ + clientId: 'placeholderClientId', + }), + }), + ).toThrow(`Missing required config value at 'organizationId'`); + }); + }); + + describe('#start', () => { + let startRequest: OAuthAuthenticatorStartInput; + + beforeEach(() => { + fakeSession = {}; + startRequest = { + state: encodeOAuthState(oAuthState), + req: { + query: {}, + session: fakeSession, + }, + } as OAuthAuthenticatorStartInput; + }); + + it('redirects to the Cloud Services Console consent page', async () => { + const startResponse = await vmwareCloudAuthenticator.start( + startRequest, + authenticatorCtx, + ); + const url = new URL(startResponse.url); + + expect(url.protocol).toBe('https:'); + expect(url.hostname).toBe('console.cloud.vmware.com'); + expect(url.pathname).toBe('/csp/gateway/discovery'); + }); + + it('passes client ID from config', async () => { + const startResponse = await vmwareCloudAuthenticator.start( + startRequest, + authenticatorCtx, + ); + const { searchParams } = new URL(startResponse.url); + + expect(searchParams.get('client_id')).toBe('placeholderClientId'); + }); + + it('passes organizationId from config', async () => { + const startResponse = await vmwareCloudAuthenticator.start( + startRequest, + authenticatorCtx, + ); + const { searchParams } = new URL(startResponse.url); + + expect(searchParams.get('orgId')).toBe('orgId'); + }); + + it('passes callback URL', async () => { + const startResponse = await vmwareCloudAuthenticator.start( + startRequest, + authenticatorCtx, + ); + const { searchParams } = new URL(startResponse.url); + + expect(searchParams.get('redirect_uri')).toBe('http://callbackUrl'); + }); + + it('requests scopes for ID and refresh token', async () => { + const startResponse = await vmwareCloudAuthenticator.start( + startRequest, + authenticatorCtx, + ); + const { searchParams } = new URL(startResponse.url); + + expect(searchParams.get('scope')).toBe('openid offline_access'); + }); + + it('generates PKCE challenge', async () => { + const startResponse = await vmwareCloudAuthenticator.start( + startRequest, + authenticatorCtx, + ); + const { searchParams } = new URL(startResponse.url); + + expect(searchParams.get('code_challenge_method')).toBe('S256'); + expect(searchParams.get('code_challenge')).not.toBeNull(); + }); + + it('stores PKCE verifier in session', async () => { + await vmwareCloudAuthenticator.start(startRequest, authenticatorCtx); + + expect( + fakeSession['oauth2:console.cloud.vmware.com'].state.code_verifier, + ).toBeDefined(); + }); + + it('fails when request has no session', () => { + return expect( + vmwareCloudAuthenticator.start( + { + state: encodeOAuthState(oAuthState), + req: { + query: {}, + }, + } as OAuthAuthenticatorStartInput, + authenticatorCtx, + ), + ).rejects.toThrow('requires session support'); + }); + + it('adds session ID handle to state param', async () => { + const startResponse = await vmwareCloudAuthenticator.start( + startRequest, + authenticatorCtx, + ); + const stateParam = new URL(startResponse.url).searchParams.get('state'); + + const state = Object.fromEntries( + new URLSearchParams(Buffer.from(stateParam!, 'hex').toString('utf-8')), + ); + + const { handle } = fakeSession['oauth2:console.cloud.vmware.com'].state; + expect(state.handle).toBe(handle); + }); + }); + + describe('#authenticate', () => { + let resolverContext: jest.Mocked; + let authenticateRequest: OAuthAuthenticatorAuthenticateInput; + + beforeEach(() => { + resolverContext = { + issueToken: jest.fn().mockResolvedValue({ + token: 'defaultBackstageToken', + }), + findCatalogUser: jest.fn(), + signInWithCatalogUser: jest.fn().mockResolvedValue({ + token: 'backstageToken', + }), + }; + + oAuthState = { + code_verifier: 'foo', + handle: 'sessionid', + nonce: 'nonce', + env: 'development', + } as OAuthState; + + fakeSession = { + ['oauth2:console.cloud.vmware.com']: { + state: oAuthState, + }, + }; + + authenticateRequest = { + req: { + query: { + code: 'foo', + state: encodeOAuthState(oAuthState), + } as unknown, + session: fakeSession, + }, + } as OAuthAuthenticatorAuthenticateInput; + }); + + it('stores refresh token in cookie', async () => { + const { + session: { refreshToken }, + } = await vmwareCloudAuthenticator.authenticate( + authenticateRequest, + authenticatorCtx, + ); + + expect(refreshToken).toBe('refreshToken'); + }); + + it('responds with ID token', async () => { + const { session } = await vmwareCloudAuthenticator.authenticate( + authenticateRequest, + authenticatorCtx, + ); + + expect(session.idToken).toBe(idToken); + }); + + it('default transform decodes ID token', async () => { + const result = await vmwareCloudAuthenticator.authenticate( + authenticateRequest, + authenticatorCtx, + ); + + const { profile } = + await vmwareCloudAuthenticator.defaultProfileTransform( + result, + resolverContext, + ); + + expect(profile).toStrictEqual({ + email: signInInfo.email, + displayName: `${signInInfo.given_name} ${signInInfo.family_name}`, + }); + }); + + it('default transform fails if claims are missing', async () => { + authenticatorCtx = vmwareCloudAuthenticator.initialize({ + callbackUrl: 'http://callbackUrl', + config: new ConfigReader({ + clientId: 'placeholderClientId', + organizationId: 'myOrgId', + }), + }); + + const result = await vmwareCloudAuthenticator.authenticate( + authenticateRequest, + authenticatorCtx, + ); + + return expect( + vmwareCloudAuthenticator.defaultProfileTransform( + result, + resolverContext, + ), + ).rejects.toThrow('ID token organizationId mismatch'); + }); + + it('default transform fails if organizationId mismatch', async () => { + const inadequateIdToken: string = await new SignJWT({ sub: 'unusual' }) + .setProtectedHeader({ alg: 'HS256' }) + .sign(Buffer.from('signing key')); + + server.use( + http.post( + 'https://console.cloud.vmware.com/csp/gateway/am/api/auth/token', + () => + HttpResponse.json({ + access_token: 'accessToken', + id_token: inadequateIdToken, + }), + ), + ); + + const result = await vmwareCloudAuthenticator.authenticate( + authenticateRequest, + authenticatorCtx, + ); + + return expect( + vmwareCloudAuthenticator.defaultProfileTransform( + result, + resolverContext, + ), + ).rejects.toThrow( + 'ID token missing required claims: email, given_name, family_name', + ); + }); + + it('fails when request has no session', () => { + return expect( + vmwareCloudAuthenticator.authenticate( + { + req: { + query: {}, + }, + } as OAuthAuthenticatorStartInput, + authenticatorCtx, + ), + ).rejects.toThrow('requires session support'); + }); + + it('fails when request has no authorization code', () => { + return expect( + vmwareCloudAuthenticator.authenticate( + { + req: { + query: {}, + session: fakeSession, + }, + } as OAuthAuthenticatorStartInput, + authenticatorCtx, + ), + ).rejects.toThrow('Unexpected redirect'); + }); + }); + + describe('integration between #start and #authenticate', () => { + beforeEach(() => { + fakeSession = { + ['oauth2:console.cloud.vmware.com']: { + state: oAuthState, + }, + }; + }); + + it('state param is compatible', async () => { + const startResponse = await vmwareCloudAuthenticator.start( + { + req: { + query: {}, + session: {}, + }, + state: encodeOAuthState(oAuthState), + } as OAuthAuthenticatorStartInput, + authenticatorCtx, + ); + const { searchParams } = new URL(startResponse.url); + const { session } = await vmwareCloudAuthenticator.authenticate( + { + req: { + query: { + code: 'authorization_code', + state: searchParams.get('state'), + } as unknown, + session: fakeSession, + }, + } as OAuthAuthenticatorAuthenticateInput, + authenticatorCtx, + ); + + expect(session).toBeDefined(); + expect(session.idToken).toBe(idToken); + }); + }); + + describe('#refresh', () => { + let refreshRequest: OAuthAuthenticatorRefreshInput; + let resolverContext: jest.Mocked; + + beforeEach(() => { + resolverContext = { + issueToken: jest.fn().mockResolvedValue({ + token: 'defaultBackstageToken', + }), + findCatalogUser: jest.fn(), + signInWithCatalogUser: jest.fn().mockResolvedValue({ + token: 'backstageToken', + }), + }; + + refreshRequest = { + req: { + query: { + code: 'foo', + state: 'sessionid', + } as unknown, + session: fakeSession, + }, + } as OAuthAuthenticatorRefreshInput; + }); + + it('gets new refresh token', async () => { + const { + session: { refreshToken }, + } = await vmwareCloudAuthenticator.refresh( + refreshRequest, + authenticatorCtx, + ); + + expect(refreshToken).toBe('refreshToken'); + }); + + it('default transform decodes ID token', async () => { + const result = await vmwareCloudAuthenticator.refresh( + refreshRequest, + authenticatorCtx, + ); + + const { profile } = + await vmwareCloudAuthenticator.defaultProfileTransform( + result, + resolverContext, + ); + + expect(profile).toStrictEqual({ + email: signInInfo.email, + displayName: `${signInInfo.given_name} ${signInInfo.family_name}`, + }); + }); + }); +}); diff --git a/plugins/auth-backend-module-vmware-cloud-provider/src/authenticator.ts b/plugins/auth-backend-module-vmware-cloud-provider/src/authenticator.ts new file mode 100644 index 0000000000..4db4836f13 --- /dev/null +++ b/plugins/auth-backend-module-vmware-cloud-provider/src/authenticator.ts @@ -0,0 +1,238 @@ +/* + * 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 { + createOAuthAuthenticator, + decodeOAuthState, + encodeOAuthState, + OAuthState, + PassportOAuthAuthenticatorHelper, + PassportOAuthDoneCallback, + PassportProfile, +} from '@backstage/plugin-auth-node'; +import { decodeJwt } from 'jose'; +import { + Metadata, + StateStoreStoreCallback, + StateStoreVerifyCallback, + Strategy as OAuth2Strategy, +} from 'passport-oauth2'; + +/** @public */ +export interface VMwareCloudAuthenticatorContext { + organizationId?: string; + providerStrategy: OAuth2Strategy; + helper: PassportOAuthAuthenticatorHelper; +} + +/** @public */ +export type VMwarePassportProfile = PassportProfile & { + organizationId?: string; +}; + +/** + * VMware Cloud Authenticator to be used by `createOAuthProviderFactory` + * + * @public + */ +export const vmwareCloudAuthenticator = createOAuthAuthenticator< + VMwareCloudAuthenticatorContext, + VMwarePassportProfile +>({ + defaultProfileTransform: async input => { + if (!input.session.idToken) { + throw new Error( + `Failed to parse id token and get profile info, missing token from session`, + ); + } + + const vmwareClaims = ['email', 'given_name', 'family_name', 'context_name']; + + const identity = decodeJwt(input.session.idToken); + const missingClaims = vmwareClaims.filter(key => !(key in identity)); + + if (missingClaims.length > 0) { + throw new Error( + `ID token missing required claims: ${missingClaims.join(', ')}`, + ); + } + + const typeMismatchClaims = vmwareClaims.filter( + key => typeof identity[key] !== 'string', + ); + + if (typeMismatchClaims.length > 0) { + throw new Error( + `ID token claims type mismatch: ${typeMismatchClaims.join(', ')}`, + ); + } + + // These claims were checked for presence & type + const { email, given_name, family_name, context_name } = identity as Record< + string, + string + >; + + if (context_name !== input.fullProfile.organizationId) { + throw new Error(`ID token organizationId mismatch`); + } + + return { + profile: { + displayName: `${given_name} ${family_name}`, + email, + }, + }; + }, + initialize({ callbackUrl, config }) { + const consoleEndpoint = + config.getOptionalString('consoleEndpoint') ?? + 'https://console.cloud.vmware.com'; + const organizationId = config.getString('organizationId'); + + const clientId = config.getString('clientId'); + const clientSecret = ''; + const authorizationUrl = `${consoleEndpoint}/csp/gateway/discovery`; + const tokenUrl = `${consoleEndpoint}/csp/gateway/am/api/auth/token`; + const scope = config.getOptionalString('scope') ?? 'openid offline_access'; + + const providerStrategy = new OAuth2Strategy( + { + clientID: clientId, + clientSecret: clientSecret, + callbackURL: callbackUrl, + authorizationURL: authorizationUrl, + tokenURL: tokenUrl, + passReqToCallback: false, + pkce: true, + state: true, + scope: scope, + customHeaders: { + Authorization: `Basic ${encodeClientCredentials( + clientId, + clientSecret, + )}`, + }, + }, + ( + accessToken: any, + refreshToken: any, + params: any, + fullProfile: PassportProfile, + done: PassportOAuthDoneCallback, + ) => { + done(undefined, { fullProfile, params, accessToken }, { refreshToken }); + }, + ); + + // Both VMware & OAuth2Strategy fight over control of the state when PKCE is on, thus this hack + const pkceSessionStore = Object.create( + (providerStrategy as any)._stateStore, + ); + (providerStrategy as any)._stateStore = { + verify(req: Request, state: string, callback: StateStoreVerifyCallback) { + pkceSessionStore.verify( + req, + (decodeOAuthState(state) as any).handle, + callback, + ); + }, + store( + req: Request & { + scope: string; + state: OAuthState; + }, + verifier: string, + state: any, + meta: Metadata, + callback: StateStoreStoreCallback, + ) { + pkceSessionStore.store( + req, + verifier, + state, + meta, + (err: Error, handle: string) => { + callback( + err, + encodeOAuthState({ + handle, + ...state, + ...req.state, + } as OAuthState), + ); + }, + ); + }, + }; + + return { + organizationId, + providerStrategy, + helper: PassportOAuthAuthenticatorHelper.from(providerStrategy), + }; + }, + + async start(input, ctx) { + return new Promise((resolve, reject) => { + const strategy: OAuth2Strategy = Object.create(ctx.providerStrategy); + + strategy.redirect = (url: string, status?: number) => { + const parsed = new URL(url); + if (ctx.organizationId) { + parsed.searchParams.set('orgId', ctx.organizationId); + } + resolve({ url: parsed.toString(), status: status ?? undefined }); + }; + strategy.error = (error: Error) => { + reject(error); + }; + strategy.authenticate(input.req, { + scope: input.scope, + state: decodeOAuthState(input.state), + accessType: 'offline', + prompt: 'consent', + }); + }); + }, + + async authenticate(input, ctx) { + return ctx.helper.authenticate(input).then(result => ({ + ...result, + fullProfile: { + ...result.fullProfile, + organizationId: ctx.organizationId, + } as VMwarePassportProfile, + })); + }, + + async refresh(input, ctx) { + return ctx.helper.refresh(input).then(result => ({ + ...result, + fullProfile: { + ...result.fullProfile, + organizationId: ctx.organizationId, + } as VMwarePassportProfile, + })); + }, +}); + +/** @private */ +function encodeClientCredentials( + clientID: string, + clientSecret: string, +): string { + return Buffer.from(`${clientID}:${clientSecret}`).toString('base64'); +} diff --git a/plugins/auth-backend-module-vmware-cloud-provider/src/index.ts b/plugins/auth-backend-module-vmware-cloud-provider/src/index.ts new file mode 100644 index 0000000000..1d7bb14b63 --- /dev/null +++ b/plugins/auth-backend-module-vmware-cloud-provider/src/index.ts @@ -0,0 +1,29 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * The vmware-cloud-provider backend module for the auth plugin. + * + * @packageDocumentation + */ + +export { + vmwareCloudAuthenticator, + type VMwareCloudAuthenticatorContext, + type VMwarePassportProfile, +} from './authenticator'; +export { authModuleVmwareCloudProvider as default } from './module'; +export { vmwareCloudSignInResolvers } from './resolvers'; diff --git a/plugins/auth-backend-module-vmware-cloud-provider/src/module.test.ts b/plugins/auth-backend-module-vmware-cloud-provider/src/module.test.ts new file mode 100644 index 0000000000..9bed931da1 --- /dev/null +++ b/plugins/auth-backend-module-vmware-cloud-provider/src/module.test.ts @@ -0,0 +1,90 @@ +/* + * 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 { mockServices, startTestBackend } from '@backstage/backend-test-utils'; +import { decodeOAuthState } from '@backstage/plugin-auth-node'; +import request from 'supertest'; + +import { Config } from '../config'; +import { authModuleVmwareCloudProvider } from './module'; + +describe('authModuleVmwareCloudProvider', () => { + it('should start', async () => { + const backend = await startTestBackend({ + features: [ + import('@backstage/plugin-auth-backend'), + authModuleVmwareCloudProvider, + mockServices.rootConfig.factory({ + data: { + app: { + baseUrl: 'http://localhost:3000', + }, + auth: { + session: { secret: 'test' }, + providers: { + vmwareCloudServices: { + development: { + clientId: 'placeholderClientId', + organizationId: 'orgId', + }, + }, + }, + } as Config['auth'], + }, + }), + ], + }); + + const { server } = backend; + + const agent = request.agent(server); + + const res = await agent.get( + '/api/auth/vmwareCloudServices/start?env=development', + ); + + expect(res.status).toEqual(302); + + const nonceCookie = agent.jar.getCookie('vmwareCloudServices-nonce', { + domain: 'localhost', + path: '/api/auth/vmwareCloudServices/handler', + script: false, + secure: false, + }); + expect(nonceCookie).toBeDefined(); + + const startUrl = new URL(res.get('location')); + expect(startUrl.origin).toBe('https://console.cloud.vmware.com'); + expect(startUrl.pathname).toBe('/csp/gateway/discovery'); + expect(Object.fromEntries(startUrl.searchParams)).toEqual({ + response_type: 'code', + client_id: 'placeholderClientId', + redirect_uri: `http://localhost:${server.port()}/api/auth/vmwareCloudServices/handler/frame`, + code_challenge: expect.any(String), + state: expect.any(String), + scope: 'openid offline_access', + orgId: 'orgId', + code_challenge_method: 'S256', + }); + + expect(decodeOAuthState(startUrl.searchParams.get('state')!)).toEqual({ + env: 'development', + handle: expect.any(String), + nonce: decodeURIComponent(nonceCookie.value), + }); + + backend.stop(); + }); +}); diff --git a/plugins/auth-backend-module-vmware-cloud-provider/src/module.ts b/plugins/auth-backend-module-vmware-cloud-provider/src/module.ts new file mode 100644 index 0000000000..5ef79654a3 --- /dev/null +++ b/plugins/auth-backend-module-vmware-cloud-provider/src/module.ts @@ -0,0 +1,51 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { createBackendModule } from '@backstage/backend-plugin-api'; +import { + authProvidersExtensionPoint, + commonSignInResolvers, + createOAuthProviderFactory, +} from '@backstage/plugin-auth-node'; + +import { vmwareCloudAuthenticator } from './authenticator'; +import { vmwareCloudSignInResolvers } from './resolvers'; + +/** + * VMware Cloud Provider backend module for the auth plugin + * + * @public + */ +export const authModuleVmwareCloudProvider = createBackendModule({ + pluginId: 'auth', + moduleId: 'vmware-cloud-provider', + register(reg) { + reg.registerInit({ + deps: { providers: authProvidersExtensionPoint }, + async init({ providers }) { + providers.registerProvider({ + providerId: 'vmwareCloudServices', + factory: createOAuthProviderFactory({ + authenticator: vmwareCloudAuthenticator, + signInResolverFactories: { + ...vmwareCloudSignInResolvers, + ...commonSignInResolvers, + }, + }), + }); + }, + }); + }, +}); diff --git a/plugins/auth-backend-module-vmware-cloud-provider/src/resolvers.test.ts b/plugins/auth-backend-module-vmware-cloud-provider/src/resolvers.test.ts new file mode 100644 index 0000000000..250fd430c7 --- /dev/null +++ b/plugins/auth-backend-module-vmware-cloud-provider/src/resolvers.test.ts @@ -0,0 +1,90 @@ +/* + * 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 { NotFoundError } from '@backstage/errors'; +import { + AuthResolverContext, + OAuthAuthenticatorResult, + PassportProfile, + SignInInfo, + SignInResolver, +} from '@backstage/plugin-auth-node'; + +import { vmwareCloudSignInResolvers } from './resolvers'; + +describe('vmwareCloudResolver', () => { + let resolverContext: jest.Mocked; + let signInInfo: SignInInfo>; + let signInResolver: SignInResolver>; + + beforeEach(() => { + resolverContext = { + issueToken: jest.fn().mockResolvedValue({ + token: 'defaultBackstageToken', + }), + findCatalogUser: jest.fn(), + signInWithCatalogUser: jest.fn().mockResolvedValue({ + token: 'backstageToken', + }), + }; + + signInInfo = { + result: {} as any, // Resolver doesn't care about the result object + profile: { + displayName: 'TestName', + email: 'user@example.com', + }, + }; + + signInResolver = + vmwareCloudSignInResolvers.profileEmailMatchingUserEntityEmail(); + }); + + it('looks up backstage identity by email', async () => { + const backstageIdentity = await signInResolver(signInInfo, resolverContext); + + expect(backstageIdentity.token).toBe('backstageToken'); + expect(resolverContext.signInWithCatalogUser).toHaveBeenCalledWith({ + filter: { + 'spec.profile.email': 'user@example.com', + }, + }); + }); + + it('returns "fake" backstage identity when no entity matches', async () => { + resolverContext.signInWithCatalogUser.mockRejectedValue( + new NotFoundError('User not found'), + ); + + const backstageIdentity = await signInResolver(signInInfo, resolverContext); + + expect(backstageIdentity.token).toBe('defaultBackstageToken'); + expect(resolverContext.issueToken).toHaveBeenCalledWith({ + claims: { + sub: 'user:default/user@example.com', + ent: ['user:default/user@example.com'], + }, + }); + }); + + it('fails when resolver context throws other error', () => { + const error = new Error('bizarre'); + resolverContext.signInWithCatalogUser.mockRejectedValue(error); + + return expect(signInResolver(signInInfo, resolverContext)).rejects.toThrow( + error, + ); + }); +}); diff --git a/plugins/auth-backend-module-vmware-cloud-provider/src/resolvers.ts b/plugins/auth-backend-module-vmware-cloud-provider/src/resolvers.ts new file mode 100644 index 0000000000..2b3a78842b --- /dev/null +++ b/plugins/auth-backend-module-vmware-cloud-provider/src/resolvers.ts @@ -0,0 +1,75 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { stringifyEntityRef } from '@backstage/catalog-model'; +import { + createSignInResolverFactory, + OAuthAuthenticatorResult, + PassportProfile, + SignInInfo, +} from '@backstage/plugin-auth-node'; + +/** + * Available sign-in resolvers for the VMware Cloud auth provider. + * + * @public + */ +export namespace vmwareCloudSignInResolvers { + /** + * Looks up the user by matching their profile email to the entity's profile email. + * If that fails, sign in the user without associating with a catalog user. + */ + export const profileEmailMatchingUserEntityEmail = + createSignInResolverFactory({ + create() { + return async ( + info: SignInInfo>, + ctx, + ) => { + const email = info.profile.email; + + if (!email) { + throw new Error( + 'VMware login failed, user profile does not contain an email', + ); + } + + const userEntityRef = stringifyEntityRef({ + kind: 'User', + name: email, + }); + + try { + // we await here so that signInWithCatalogUser throws in the current `try` + return await ctx.signInWithCatalogUser({ + filter: { + 'spec.profile.email': email, + }, + }); + } catch (e) { + if (e.name !== 'NotFoundError') { + throw e; + } + return ctx.issueToken({ + claims: { + sub: userEntityRef, + ent: [userEntityRef], + }, + }); + } + }; + }, + }); +} diff --git a/plugins/auth-backend/CHANGELOG.md b/plugins/auth-backend/CHANGELOG.md index 57c9c1aac2..a65f0bdb61 100644 --- a/plugins/auth-backend/CHANGELOG.md +++ b/plugins/auth-backend/CHANGELOG.md @@ -1,5 +1,247 @@ # @backstage/plugin-auth-backend +## 0.20.3 + +### Patch Changes + +- 004499c: Fixed an issue where some Okta's resolvers were missing +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.1 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.1.1 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.3 + - @backstage/plugin-auth-backend-module-github-provider@0.1.6 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.6 + - @backstage/plugin-auth-backend-module-google-provider@0.1.6 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.1.6 + - @backstage/plugin-auth-backend-module-okta-provider@0.0.2 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.20.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.1.1-next.2 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.3-next.2 + - @backstage/plugin-auth-backend-module-github-provider@0.1.6-next.2 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.6-next.2 + - @backstage/plugin-auth-backend-module-google-provider@0.1.6-next.2 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.1.6-next.2 + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.1-next.2 + - @backstage/plugin-auth-backend-module-okta-provider@0.0.2-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + +## 0.20.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.1.1-next.1 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.3-next.1 + - @backstage/plugin-auth-backend-module-github-provider@0.1.6-next.1 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.6-next.1 + - @backstage/plugin-auth-backend-module-google-provider@0.1.6-next.1 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.1.6-next.1 + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.1-next.1 + - @backstage/plugin-auth-backend-module-okta-provider@0.0.2-next.1 + - @backstage/plugin-catalog-node@1.6.1-next.1 + +## 0.20.3-next.0 + +### Patch Changes + +- 004499c: Fixed an issue where some Okta's resolvers were missing +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.1-next.0 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.1.1-next.0 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.3-next.0 + - @backstage/plugin-auth-backend-module-github-provider@0.1.6-next.0 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.6-next.0 + - @backstage/plugin-auth-backend-module-google-provider@0.1.6-next.0 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.1.6-next.0 + - @backstage/plugin-auth-backend-module-okta-provider@0.0.2-next.0 + - @backstage/plugin-catalog-node@1.6.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.3-next.0 + +## 0.20.1 + +### Patch Changes + +- 7ac2575: `oauth2-proxy` auth implementation has been moved to `@backstage/plugin-auth-backend-module-oauth2-proxy-provider` +- 2a5891e: Migrate the atlassian auth provider to be implemented using the new `@backstage/plugin-auth-backend-module-atlassian-provider` module +- 783797a: fix static token issuer not being able to initialize +- e1c189b: The Okta provider implementation is moved to the new module +- a62764b: Updated dependency `passport` to `^0.7.0`. +- bcbbf8e: Updated dependency `@google-cloud/firestore` to `^7.0.0`. +- Updated dependencies + - @backstage/plugin-auth-backend-module-atlassian-provider@0.1.0 + - @backstage/backend-common@0.20.0 + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/catalog-client@1.5.0 + - @backstage/plugin-auth-backend-module-okta-provider@0.0.1 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.5 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.1.5 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.2 + - @backstage/plugin-auth-backend-module-google-provider@0.1.5 + - @backstage/plugin-auth-backend-module-github-provider@0.1.5 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.20.1-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.1.0-next.3 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.2-next.3 + - @backstage/plugin-auth-backend-module-github-provider@0.1.5-next.3 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.5-next.3 + - @backstage/plugin-auth-backend-module-google-provider@0.1.5-next.3 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.1.5-next.3 + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.0-next.2 + - @backstage/plugin-auth-backend-module-okta-provider@0.0.1-next.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + - @backstage/plugin-catalog-node@1.6.0-next.3 + +## 0.20.1-next.2 + +### Patch Changes + +- 783797a: fix static token issuer not being able to initialize +- a62764b: Updated dependency `passport` to `^0.7.0`. +- Updated dependencies + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.0-next.1 + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.1.0-next.2 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.5-next.2 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.1.5-next.2 + - @backstage/plugin-auth-backend-module-okta-provider@0.0.1-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.2-next.2 + - @backstage/plugin-auth-backend-module-google-provider@0.1.5-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-backend-module-github-provider@0.1.5-next.2 + +## 0.20.1-next.1 + +### Patch Changes + +- 7ac25759a5: `oauth2-proxy` auth implementation has been moved to `@backstage/plugin-auth-backend-module-oauth2-proxy-provider` +- bcbbf8e042: Updated dependency `@google-cloud/firestore` to `^7.0.0`. +- Updated dependencies + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.0-next.0 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.1.0-next.1 + - @backstage/plugin-auth-backend-module-github-provider@0.1.5-next.1 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.5-next.1 + - @backstage/plugin-auth-backend-module-google-provider@0.1.5-next.1 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.1.5-next.1 + - @backstage/plugin-auth-backend-module-okta-provider@0.0.1-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.2-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## 0.20.1-next.0 + +### Patch Changes + +- 2a5891e816: Migrate the atlassian auth provider to be implemented using the new `@backstage/plugin-auth-backend-module-atlassian-provider` module +- e1c189b524: The Okta provider implementation is moved to the new module +- Updated dependencies + - @backstage/plugin-auth-backend-module-atlassian-provider@0.1.0-next.0 + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-backend-module-okta-provider@0.0.1-next.0 + - @backstage/plugin-auth-backend-module-github-provider@0.1.5-next.0 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.5-next.0 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.1.5-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/plugin-auth-backend-module-google-provider@0.1.5-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.2-next.0 + +## 0.20.0 + +### Minor Changes + +- bdf08ad04a: Adds the StaticTokenIssuer and StaticKeyStore, an alternative token issuer that can be used to sign the Authorization header using a predefined public/private key pair. + +### Patch Changes + +- 243c655a68: JSDoc and Error message updates to handle `Azure Active Directory` re-brand to `Entra ID` +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. +- f2fc5acca6: Added an optional `additionalScopes` configuration parameter to `okta` providers, that lets you add additional scopes on top of the default ones. +- 96c4f54bf6: Reverted the Microsoft auth provider to the previous implementation. +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.4 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.1 + - @backstage/plugin-auth-backend-module-github-provider@0.1.4 + - @backstage/plugin-auth-backend-module-google-provider@0.1.4 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.1.4 + - @backstage/plugin-auth-node@0.4.1 + ## 0.20.0-next.2 ### Patch Changes diff --git a/plugins/auth-backend/api-report.md b/plugins/auth-backend/api-report.md index 6372c2ee60..d80648a10f 100644 --- a/plugins/auth-backend/api-report.md +++ b/plugins/auth-backend/api-report.md @@ -3,8 +3,6 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts -/// - import { AuthProviderConfig as AuthProviderConfig_2 } from '@backstage/plugin-auth-node'; import { AuthProviderFactory as AuthProviderFactory_2 } from '@backstage/plugin-auth-node'; import { AuthProviderRouteHandlers as AuthProviderRouteHandlers_2 } from '@backstage/plugin-auth-node'; @@ -23,8 +21,8 @@ import { Entity } from '@backstage/catalog-model'; import express from 'express'; import { GcpIapResult as GcpIapResult_2 } from '@backstage/plugin-auth-backend-module-gcp-iap-provider'; import { GcpIapTokenInfo as GcpIapTokenInfo_2 } from '@backstage/plugin-auth-backend-module-gcp-iap-provider'; -import { IncomingHttpHeaders } from 'http'; import { LoggerService } from '@backstage/backend-plugin-api'; +import { OAuth2ProxyResult as OAuth2ProxyResult_2 } from '@backstage/plugin-auth-backend-module-oauth2-proxy-provider'; import { OAuthEnvironmentHandler as OAuthEnvironmentHandler_2 } from '@backstage/plugin-auth-node'; import { OAuthState as OAuthState_2 } from '@backstage/plugin-auth-node'; import { PluginDatabaseManager } from '@backstage/backend-common'; @@ -228,13 +226,8 @@ export type GithubOAuthResult = { refreshToken?: string; }; -// @public -export type OAuth2ProxyResult = { - fullProfile: JWTPayload; - accessToken: string; - headers: IncomingHttpHeaders; - getHeader(name: string): string | undefined; -}; +// @public @deprecated (undocumented) +export type OAuth2ProxyResult = OAuth2ProxyResult_2; // @public @deprecated (undocumented) export class OAuthAdapter implements AuthProviderRouteHandlers { @@ -560,9 +553,9 @@ export const providers: Readonly<{ }>; oauth2Proxy: Readonly<{ create: (options: { - authHandler?: AuthHandler> | undefined; + authHandler?: AuthHandler | undefined; signIn: { - resolver: SignInResolver>; + resolver: SignInResolver; }; }) => AuthProviderFactory_2; resolvers: never; diff --git a/plugins/auth-backend/config.d.ts b/plugins/auth-backend/config.d.ts index 54fad12939..34139593d3 100644 --- a/plugins/auth-backend/config.d.ts +++ b/plugins/auth-backend/config.d.ts @@ -135,20 +135,6 @@ export interface Config { acceptedClockSkewMs?: number; }; /** @visibility frontend */ - okta?: { - [authEnv: string]: { - clientId: string; - /** - * @visibility secret - */ - clientSecret: string; - audience: string; - authServerId?: string; - idp?: string; - callbackUrl?: string; - }; - }; - /** @visibility frontend */ oauth2?: { [authEnv: string]: { clientId: string; diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index 08336ae6fe..a2b4d01b6c 100644 --- a/plugins/auth-backend/package.json +++ b/plugins/auth-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend", "description": "A Backstage backend plugin that handles authentication", - "version": "0.20.0-next.2", + "version": "0.20.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -38,16 +38,17 @@ "@backstage/catalog-model": "workspace:^", "@backstage/config": "workspace:^", "@backstage/errors": "workspace:^", + "@backstage/plugin-auth-backend-module-atlassian-provider": "workspace:^", "@backstage/plugin-auth-backend-module-gcp-iap-provider": "workspace:^", "@backstage/plugin-auth-backend-module-github-provider": "workspace:^", "@backstage/plugin-auth-backend-module-gitlab-provider": "workspace:^", "@backstage/plugin-auth-backend-module-google-provider": "workspace:^", "@backstage/plugin-auth-backend-module-oauth2-provider": "workspace:^", + "@backstage/plugin-auth-backend-module-oauth2-proxy-provider": "workspace:^", + "@backstage/plugin-auth-backend-module-okta-provider": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", "@backstage/plugin-catalog-node": "workspace:^", - "@backstage/types": "workspace:^", - "@davidzemon/passport-okta-oauth": "^0.0.5", - "@google-cloud/firestore": "^6.0.0", + "@google-cloud/firestore": "^7.0.0", "@types/express": "^4.17.6", "@types/passport": "^1.0.3", "compression": "^1.7.4", @@ -69,7 +70,7 @@ "node-cache": "^5.1.2", "node-fetch": "^2.6.7", "openid-client": "^5.2.1", - "passport": "^0.6.0", + "passport": "^0.7.0", "passport-auth0": "^1.4.3", "passport-bitbucket-oauth2": "^0.1.2", "passport-github2": "^0.1.12", diff --git a/plugins/auth-backend/src/identity/DatabaseKeyStore.test.ts b/plugins/auth-backend/src/identity/DatabaseKeyStore.test.ts index cf415c7e13..f86c4a400b 100644 --- a/plugins/auth-backend/src/identity/DatabaseKeyStore.test.ts +++ b/plugins/auth-backend/src/identity/DatabaseKeyStore.test.ts @@ -28,9 +28,7 @@ const keyBase = { jest.setTimeout(60_000); describe('DatabaseKeyStore', () => { - const databases = TestDatabases.create({ - ids: ['MYSQL_8', 'POSTGRES_13', 'POSTGRES_9', 'SQLITE_3'], - }); + const databases = TestDatabases.create(); it.each(databases.eachSupportedId())( 'should store a key, %p', diff --git a/plugins/auth-backend/src/identity/KeyStores.ts b/plugins/auth-backend/src/identity/KeyStores.ts index 7242530c57..16f25817a9 100644 --- a/plugins/auth-backend/src/identity/KeyStores.ts +++ b/plugins/auth-backend/src/identity/KeyStores.ts @@ -76,7 +76,7 @@ export class KeyStores { } if (provider === 'static') { - await StaticKeyStore.fromConfig(config); + return await StaticKeyStore.fromConfig(config); } throw new Error(`Unknown KeyStore provider: ${provider}`); diff --git a/plugins/auth-backend/src/migrations.test.ts b/plugins/auth-backend/src/migrations.test.ts index 194bbbf44c..f80b729975 100644 --- a/plugins/auth-backend/src/migrations.test.ts +++ b/plugins/auth-backend/src/migrations.test.ts @@ -42,9 +42,7 @@ async function migrateUntilBefore(knex: Knex, target: string): Promise { jest.setTimeout(60_000); describe('migrations', () => { - const databases = TestDatabases.create({ - ids: ['MYSQL_8', 'POSTGRES_13', 'POSTGRES_9', 'SQLITE_3'], - }); + const databases = TestDatabases.create(); it.each(databases.eachSupportedId())( '20230428155633_sessions.js, %p', diff --git a/plugins/auth-backend/src/providers/atlassian/provider.test.ts b/plugins/auth-backend/src/providers/atlassian/provider.test.ts deleted file mode 100644 index 1fb987d3b0..0000000000 --- a/plugins/auth-backend/src/providers/atlassian/provider.test.ts +++ /dev/null @@ -1,145 +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 { AtlassianAuthProvider } from './provider'; -import * as helpers from '../../lib/passport/PassportStrategyHelper'; -import { OAuthResult } from '../../lib/oauth'; -import { PassportProfile } from '../../lib/passport/types'; -import { AuthResolverContext } from '../types'; - -jest.mock('../../lib/passport/PassportStrategyHelper', () => { - return { - executeFrameHandlerStrategy: jest.fn(), - executeRefreshTokenStrategy: jest.fn(), - executeFetchUserProfileStrategy: jest.fn(), - }; -}); - -const mockFrameHandler = jest.spyOn( - helpers, - 'executeFrameHandlerStrategy', -) as unknown as jest.MockedFunction<() => Promise<{ result: OAuthResult }>>; - -describe('createAtlassianProvider', () => { - const provider = new AtlassianAuthProvider({ - resolverContext: {} as AuthResolverContext, - authHandler: async ({ fullProfile }) => ({ - profile: { - email: fullProfile.emails![0]!.value, - displayName: fullProfile.displayName, - picture: 'http://google.com/lols', - }, - }), - clientId: 'mock', - clientSecret: 'mock', - callbackUrl: 'mock', - scopes: 'scope', - }); - - it('should auth', async () => { - mockFrameHandler.mockResolvedValueOnce({ - result: { - fullProfile: { - photos: [ - { - value: - 'https://a1cf74336522e87f135f-2f21ace9a6cf0052456644b80fa06d4f.ssl.cf2.rackcdn.com/images/characters_opt/p-mystic-river-sean-penn.jpg', - }, - ], - emails: [{ value: 'conrad@example.com' }], - displayName: 'Conrad', - id: 'conrad', - provider: 'google', - }, - params: { - id_token: 'idToken', - scope: 'scope', - expires_in: 123, - }, - accessToken: 'accessToken', - refreshToken: 'wacka', - }, - }); - const result = await provider.handler({} as any); - expect(result).toEqual({ - response: { - providerInfo: { - accessToken: 'accessToken', - expiresInSeconds: 123, - idToken: 'idToken', - scope: 'scope', - }, - profile: { - email: 'conrad@example.com', - displayName: 'Conrad', - picture: 'http://google.com/lols', - }, - }, - refreshToken: 'wacka', - }); - }); - - it('should forward a new refresh token on refresh', async () => { - const mockRefreshToken = jest.spyOn( - helpers, - 'executeRefreshTokenStrategy', - ) as unknown as jest.MockedFunction<() => Promise<{}>>; - - mockRefreshToken.mockResolvedValueOnce({ - accessToken: 'a.b.c', - refreshToken: 'dont-forget-to-send-refresh', - params: { - id_token: 'my-id', - scope: 'read_user', - }, - }); - - const mockUserProfile = jest.spyOn( - helpers, - 'executeFetchUserProfileStrategy', - ) as unknown as jest.MockedFunction<() => Promise>; - - mockUserProfile.mockResolvedValueOnce({ - id: 'uid-my-id', - username: 'mockuser', - provider: 'atlassian', - displayName: 'Mocked User', - emails: [ - { - value: 'mockuser@gmail.com', - }, - ], - }); - - const result = await provider.refresh({} as any); - - expect(result).toEqual({ - response: { - profile: { - displayName: 'Mocked User', - email: 'mockuser@gmail.com', - picture: 'http://google.com/lols', - }, - providerInfo: { - accessToken: 'a.b.c', - idToken: 'my-id', - scope: 'read_user', - }, - }, - refreshToken: 'dont-forget-to-send-refresh', - }); - }); -}); diff --git a/plugins/auth-backend/src/providers/atlassian/provider.ts b/plugins/auth-backend/src/providers/atlassian/provider.ts index e02d899fb1..a142d1de90 100644 --- a/plugins/auth-backend/src/providers/atlassian/provider.ts +++ b/plugins/auth-backend/src/providers/atlassian/provider.ts @@ -14,156 +14,18 @@ * limitations under the License. */ -import AtlassianStrategy from './strategy'; -import { - encodeState, - OAuthAdapter, - OAuthEnvironmentHandler, - OAuthHandlers, - OAuthProviderOptions, - OAuthRefreshRequest, - OAuthResponse, - OAuthResult, - OAuthStartRequest, -} from '../../lib/oauth'; -import passport from 'passport'; -import { - executeFetchUserProfileStrategy, - executeFrameHandlerStrategy, - executeRedirectStrategy, - executeRefreshTokenStrategy, - makeProfileInfo, - PassportDoneCallback, -} from '../../lib/passport'; -import { - AuthHandler, - AuthResolverContext, - OAuthStartResponse, - SignInResolver, -} from '../types'; -import express from 'express'; +import { SignInResolver, AuthHandler } from '../types'; +import { OAuthResult } from '../../lib/oauth'; import { createAuthProviderIntegration } from '../createAuthProviderIntegration'; - -/** @public */ -export type AtlassianAuthProviderOptions = OAuthProviderOptions & { - scopes: string; - signInResolver?: SignInResolver; - authHandler: AuthHandler; - resolverContext: AuthResolverContext; -}; - -export const atlassianDefaultAuthHandler: AuthHandler = async ({ - fullProfile, - params, -}) => ({ - profile: makeProfileInfo(fullProfile, params.id_token), -}); - -export class AtlassianAuthProvider implements OAuthHandlers { - private readonly _strategy: AtlassianStrategy; - private readonly signInResolver?: SignInResolver; - private readonly authHandler: AuthHandler; - private readonly resolverContext: AuthResolverContext; - - constructor(options: AtlassianAuthProviderOptions) { - this.resolverContext = options.resolverContext; - this.authHandler = options.authHandler; - this.signInResolver = options.signInResolver; - - this._strategy = new AtlassianStrategy( - { - clientID: options.clientId, - clientSecret: options.clientSecret, - callbackURL: options.callbackUrl, - scope: options.scopes, - }, - ( - accessToken: any, - refreshToken: any, - params: any, - fullProfile: passport.Profile, - done: PassportDoneCallback, - ) => { - done(undefined, { - fullProfile, - accessToken, - refreshToken, - params, - }); - }, - ); - } - - async start(req: OAuthStartRequest): Promise { - return await executeRedirectStrategy(req, this._strategy, { - state: encodeState(req.state), - }); - } - - async handler(req: express.Request) { - const { result } = await executeFrameHandlerStrategy( - req, - this._strategy, - ); - - return { - response: await this.handleResult(result), - refreshToken: result.refreshToken, - }; - } - - private async handleResult(result: OAuthResult): Promise { - const { profile } = await this.authHandler(result, this.resolverContext); - - const response: OAuthResponse = { - providerInfo: { - idToken: result.params.id_token, - accessToken: result.accessToken, - scope: result.params.scope, - expiresInSeconds: result.params.expires_in, - }, - profile, - }; - - if (this.signInResolver) { - response.backstageIdentity = await this.signInResolver( - { - result, - profile, - }, - this.resolverContext, - ); - } - - return response; - } - - async refresh(req: OAuthRefreshRequest) { - const { accessToken, params, refreshToken } = - await executeRefreshTokenStrategy( - this._strategy, - req.refreshToken, - req.scope, - ); - - const fullProfile = await executeFetchUserProfileStrategy( - this._strategy, - accessToken, - ); - - return { - response: await this.handleResult({ - fullProfile, - params, - accessToken, - }), - refreshToken, - }; - } -} +import { createOAuthProviderFactory } from '@backstage/plugin-auth-node'; +import { + adaptLegacyOAuthHandler, + adaptLegacyOAuthSignInResolver, +} from '../../lib/legacy'; +import { atlassianAuthenticator } from '@backstage/plugin-auth-backend-module-atlassian-provider'; /** - * Auth provider integration for atlassian auth + * Auth provider integration for Atlassian auth * * @public */ @@ -182,33 +44,10 @@ export const atlassian = createAuthProviderIntegration({ resolver: SignInResolver; }; }) { - return ({ providerId, globalConfig, config, resolverContext }) => - OAuthEnvironmentHandler.mapConfig(config, envConfig => { - const clientId = envConfig.getString('clientId'); - const clientSecret = envConfig.getString('clientSecret'); - const scopes = envConfig.getString('scopes'); - const customCallbackUrl = envConfig.getOptionalString('callbackUrl'); - const callbackUrl = - customCallbackUrl || - `${globalConfig.baseUrl}/${providerId}/handler/frame`; - - const authHandler: AuthHandler = - options?.authHandler ?? atlassianDefaultAuthHandler; - - const provider = new AtlassianAuthProvider({ - clientId, - clientSecret, - scopes, - callbackUrl, - authHandler, - signInResolver: options?.signIn?.resolver, - resolverContext, - }); - - return OAuthAdapter.fromConfig(globalConfig, provider, { - providerId, - callbackUrl, - }); - }); + return createOAuthProviderFactory({ + authenticator: atlassianAuthenticator, + profileTransform: adaptLegacyOAuthHandler(options?.authHandler), + signInResolver: adaptLegacyOAuthSignInResolver(options?.signIn?.resolver), + }); }, }); diff --git a/plugins/auth-backend/src/providers/oauth2-proxy/index.ts b/plugins/auth-backend/src/providers/oauth2-proxy/index.ts index d3004f31e4..2e4e7d016f 100644 --- a/plugins/auth-backend/src/providers/oauth2-proxy/index.ts +++ b/plugins/auth-backend/src/providers/oauth2-proxy/index.ts @@ -15,4 +15,10 @@ */ export { oauth2Proxy } from './provider'; -export type { OAuth2ProxyResult } from './provider'; +import { OAuth2ProxyResult as _OAuth2ProxyResult } from '@backstage/plugin-auth-backend-module-oauth2-proxy-provider'; + +/** + * @public + * @deprecated import from `@backstage/plugin-auth-backend-module-oauth2-proxy-provider` instead + */ +export type OAuth2ProxyResult = _OAuth2ProxyResult; diff --git a/plugins/auth-backend/src/providers/oauth2-proxy/provider.test.ts b/plugins/auth-backend/src/providers/oauth2-proxy/provider.test.ts deleted file mode 100644 index f585d4831f..0000000000 --- a/plugins/auth-backend/src/providers/oauth2-proxy/provider.test.ts +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright 2021 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -jest.mock('jose', () => ({ - decodeJwt: jest.fn(), -})); -jest.mock('@backstage/catalog-client'); - -import { AuthenticationError } from '@backstage/errors'; -import express from 'express'; -import * as jose from 'jose'; -import { LoggerService } from '@backstage/backend-plugin-api'; -import { AuthHandler, AuthResolverContext, SignInResolver } from '../types'; -import { - oauth2Proxy, - Oauth2ProxyAuthProvider, - OAuth2ProxyResult, - OAUTH2_PROXY_JWT_HEADER, -} from './provider'; - -describe('Oauth2ProxyAuthProvider', () => { - const mockToken = - 'eyblob.eyJzdWIiOiJ1c2VyOmRlZmF1bHQvamltbXltYXJrdW0iLCJlbnQiOlsidXNlcjpkZWZhdWx0L2ppbW15bWFya3VtIl19.eyblob'; - - let provider: Oauth2ProxyAuthProvider; - let logger: jest.Mocked; - let signInResolver: jest.MockedFunction< - SignInResolver> - >; - let authHandler: jest.MockedFunction>>; - let mockResponse: jest.Mocked; - let mockRequest: jest.Mocked; - let mockJwtDecode: jest.MockedFunction; - - beforeEach(() => { - jest.resetAllMocks(); - - mockJwtDecode = jose.decodeJwt as jest.MockedFunction< - typeof jose.decodeJwt - >; - authHandler = jest.fn(); - signInResolver = jest.fn(); - logger = { error: jest.fn() } as unknown as jest.Mocked; - - mockResponse = { - status: jest.fn(), - end: jest.fn(), - json: jest.fn(), - } as unknown as jest.Mocked; - - mockRequest = { - body: {}, - header: jest.fn(), - headers: { - 'x-mock': 'mock', - }, - } as unknown as jest.Mocked; - - provider = new Oauth2ProxyAuthProvider({ - authHandler, - signInResolver, - resolverContext: { - _: 'resolver-context', - } as unknown as AuthResolverContext, - }); - }); - - describe('frameHandler()', () => { - it('should do nothing and return undefined', async () => { - const result = await provider.frameHandler(); - - expect(result).toBeUndefined(); - }); - }); - - describe('start()', () => { - it('should do nothing and return undefined', async () => { - const result = await provider.start(); - - expect(result).toBeUndefined(); - }); - }); - - describe('refresh()', () => { - it('should throw an error when auth header is missing', async () => { - mockRequest.header.mockReturnValue(undefined); - - await expect(provider.refresh(mockRequest, mockResponse)).rejects.toThrow( - AuthenticationError, - ); - }); - - it('should throw an error if the bearer token is invalid', async () => { - mockRequest.header.mockReturnValue('Basic asdf='); - - await expect(provider.refresh(mockRequest, mockResponse)).rejects.toThrow( - AuthenticationError, - ); - }); - - it('should return if auth header is set and valid', async () => { - mockRequest.header.mockReturnValue(`Bearer token`); - authHandler.mockResolvedValue({ - profile: {}, - }); - signInResolver.mockResolvedValue({ - token: mockToken, - }); - - await provider.refresh(mockRequest, mockResponse); - - expect(mockRequest.header).toHaveBeenCalledWith(OAUTH2_PROXY_JWT_HEADER); - expect(mockJwtDecode).toHaveBeenCalledWith('token'); - expect(mockResponse.json).toHaveBeenCalled(); - }); - - it('should load profile from authHandler and backstage identity from signInResolver', async () => { - const decodedToken = { - oid: 'oid', - name: 'name', - upn: 'john.doe@example.com', - }; - const profile = { displayName: 'some value' }; - mockRequest.header.mockReturnValue(`Bearer token`); - signInResolver.mockResolvedValue({ - token: mockToken, - }); - authHandler.mockResolvedValue({ profile: profile }); - mockJwtDecode.mockReturnValue(decodedToken as any); - - await provider.refresh(mockRequest, mockResponse); - - expect(signInResolver).toHaveBeenCalledWith( - { - profile: profile, - result: { - accessToken: 'token', - fullProfile: decodedToken, - getHeader: expect.any(Function), - headers: { - 'x-mock': 'mock', - }, - }, - }, - { _: 'resolver-context' }, - ); - expect(mockResponse.json).toHaveBeenCalledWith({ - backstageIdentity: { - identity: { - type: 'user', - userEntityRef: 'user:default/jimmymarkum', - ownershipEntityRefs: ['user:default/jimmymarkum'], - }, - token: mockToken, - }, - profile: { displayName: 'some value' }, - providerInfo: { - accessToken: 'token', - }, - }); - }); - }); - - describe('oauth2Proxy.create()', () => { - beforeEach(() => { - mockRequest.header.mockReturnValue(`Bearer token`); - authHandler.mockResolvedValue({ - profile: {}, - }); - signInResolver.mockResolvedValue({ - token: mockToken, - }); - }); - - it('should create a valid provider', async () => { - const factory = oauth2Proxy.create({ - authHandler, - signIn: { resolver: signInResolver }, - }); - const handler = factory({ - logger, - catalogApi: {}, - tokenIssuer: {}, - } as any); - await handler.refresh!(mockRequest, mockResponse); - - expect(mockRequest.header).toHaveBeenCalledWith(OAUTH2_PROXY_JWT_HEADER); - expect(mockJwtDecode).toHaveBeenCalledWith('token'); - expect(mockResponse.json).toHaveBeenCalled(); - }); - }); -}); diff --git a/plugins/auth-backend/src/providers/oauth2-proxy/provider.ts b/plugins/auth-backend/src/providers/oauth2-proxy/provider.ts index 3ac7d09000..5d75167e84 100644 --- a/plugins/auth-backend/src/providers/oauth2-proxy/provider.ts +++ b/plugins/auth-backend/src/providers/oauth2-proxy/provider.ts @@ -14,164 +14,13 @@ * limitations under the License. */ -import express from 'express'; -import { AuthenticationError } from '@backstage/errors'; -import { getBearerTokenFromAuthorizationHeader } from '@backstage/plugin-auth-node'; -import { - AuthHandler, - SignInResolver, - AuthProviderRouteHandlers, - AuthResponse, - AuthResolverContext, - AuthHandlerResult, -} from '../types'; -import { decodeJwt } from 'jose'; -import { prepareBackstageIdentityResponse } from '../prepareBackstageIdentityResponse'; +import { createProxyAuthProviderFactory } from '@backstage/plugin-auth-node'; +import { AuthHandler, SignInResolver } from '../types'; import { createAuthProviderIntegration } from '../createAuthProviderIntegration'; -import { IncomingHttpHeaders } from 'http'; - -// NOTE: This may come in handy if you're doing work on this provider: -// -// plugins/auth-backend/examples/docker-compose.oauth2-proxy.yaml -// - -export const OAUTH2_PROXY_JWT_HEADER = 'X-OAUTH2-PROXY-ID-TOKEN'; - -/** - * JWT header extraction result, containing the raw value and the parsed JWT - * payload. - * - * @public - */ -export type OAuth2ProxyResult = { - /** - * The parsed payload of the `accessToken`. The token is only parsed, not verified. - * - * @deprecated Access through the `headers` instead. This will be removed in a future release. - */ - fullProfile: JWTPayload; - - /** - * The token received via the X-OAUTH2-PROXY-ID-TOKEN header. Will be an empty string - * if the header is not set. Note the this is typically an OpenID Connect token. - * - * @deprecated Access through the `headers` instead. This will be removed in a future release. - */ - accessToken: string; - - /** - * The headers of the incoming request from the OAuth2 proxy. This will include - * both the headers set by the client as well as the ones added by the OAuth2 proxy. - * You should only trust the headers that are injected by the OAuth2 proxy. - * - * Useful headers to use to complete the sign-in are for example `x-forwarded-user` - * and `x-forwarded-email`. See the OAuth2 proxy documentation for more information - * about the available headers and how to enable them. In particular it is possible - * to forward access and identity tokens, which can be user for additional verification - * and lookups. - */ - headers: IncomingHttpHeaders; - - /** - * Provides convenient access to the request headers. - * - * This call is simply forwarded to `req.get(name)`. - */ - getHeader(name: string): string | undefined; -}; - -interface Options { - resolverContext: AuthResolverContext; - signInResolver: SignInResolver>; - authHandler: AuthHandler>; -} - -export class Oauth2ProxyAuthProvider - implements AuthProviderRouteHandlers -{ - private readonly resolverContext: AuthResolverContext; - private readonly signInResolver: SignInResolver< - OAuth2ProxyResult - >; - private readonly authHandler: AuthHandler>; - - constructor(options: Options) { - this.resolverContext = options.resolverContext; - this.signInResolver = options.signInResolver; - this.authHandler = options.authHandler; - } - - frameHandler(): Promise { - return Promise.resolve(undefined); - } - - async refresh(req: express.Request, res: express.Response): Promise { - try { - // TODO(Rugvip): This parsing was deprecated in 1.2 and should be removed in a future release. - const authHeader = req.header(OAUTH2_PROXY_JWT_HEADER); - const jwt = getBearerTokenFromAuthorizationHeader(authHeader); - const decodedJWT = jwt && (decodeJwt(jwt) as unknown as JWTPayload); - - const result = { - fullProfile: decodedJWT || ({} as JWTPayload), - accessToken: jwt || '', - headers: req.headers, - getHeader(name: string) { - if (name.toLocaleLowerCase('en-US') === 'set-cookie') { - throw new Error('Access Set-Cookie via the headers object instead'); - } - return req.get(name); - }, - }; - - const response = await this.handleResult(result); - res.json(response); - } catch (e) { - throw new AuthenticationError('Refresh failed', e); - } - } - - start(): Promise { - return Promise.resolve(undefined); - } - - private async handleResult( - result: OAuth2ProxyResult, - ): Promise> { - const { profile } = await this.authHandler(result, this.resolverContext); - - const backstageSignInResult = await this.signInResolver( - { - result, - profile, - }, - this.resolverContext, - ); - - return { - providerInfo: { - accessToken: result.accessToken, - }, - backstageIdentity: prepareBackstageIdentityResponse( - backstageSignInResult, - ), - profile, - }; - } -} - -async function defaultAuthHandler( - result: OAuth2ProxyResult, -): Promise { - return { - profile: { - email: result.getHeader('x-forwarded-email'), - displayName: - result.getHeader('x-forwarded-preferred-username') || - result.getHeader('x-forwarded-user'), - }, - }; -} +import { + type OAuth2ProxyResult, + oauth2ProxyAuthenticator, +} from '@backstage/plugin-auth-backend-module-oauth2-proxy-provider'; /** * Auth provider integration for oauth2-proxy auth @@ -179,7 +28,7 @@ async function defaultAuthHandler( * @public */ export const oauth2Proxy = createAuthProviderIntegration({ - create(options: { + create(options: { /** * Configure an auth handler to generate a profile for the user. * @@ -187,7 +36,7 @@ export const oauth2Proxy = createAuthProviderIntegration({ * header as the display name, falling back to `X-Forwarded-User`, and the value of * the `X-Forwarded-Email` header as the email address. */ - authHandler?: AuthHandler>; + authHandler?: AuthHandler; /** * Configure sign-in for this provider, without it the provider can not be used to sign users in. @@ -196,17 +45,13 @@ export const oauth2Proxy = createAuthProviderIntegration({ /** * Maps an auth result to a Backstage identity for the user. */ - resolver: SignInResolver>; + resolver: SignInResolver; }; }) { - return ({ resolverContext }) => { - const signInResolver = options.signIn.resolver; - const authHandler = options.authHandler; - return new Oauth2ProxyAuthProvider({ - resolverContext, - signInResolver, - authHandler: authHandler ?? defaultAuthHandler, - }); - }; + return createProxyAuthProviderFactory({ + authenticator: oauth2ProxyAuthenticator, + profileTransform: options?.authHandler, + signInResolver: options?.signIn?.resolver, + }); }, }); diff --git a/plugins/auth-backend/src/providers/okta/provider.test.ts b/plugins/auth-backend/src/providers/okta/provider.test.ts deleted file mode 100644 index bc27129300..0000000000 --- a/plugins/auth-backend/src/providers/okta/provider.test.ts +++ /dev/null @@ -1,100 +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 { OktaAuthProvider } from './provider'; -import * as helpers from '../../lib/passport/PassportStrategyHelper'; -import { OAuthResult } from '../../lib/oauth'; -import { AuthResolverContext } from '../types'; - -jest.mock('../../lib/passport/PassportStrategyHelper', () => { - return { - executeFrameHandlerStrategy: jest.fn(), - executeRefreshTokenStrategy: jest.fn(), - executeFetchUserProfileStrategy: jest.fn(), - }; -}); - -const mockFrameHandler = jest.spyOn( - helpers, - 'executeFrameHandlerStrategy', -) as unknown as jest.MockedFunction< - () => Promise<{ result: OAuthResult; privateInfo: any }> ->; - -describe('createOktaProvider', () => { - it('should auth', async () => { - const provider = new OktaAuthProvider({ - resolverContext: {} as AuthResolverContext, - authHandler: async ({ fullProfile }) => ({ - profile: { - email: fullProfile.emails![0]!.value, - displayName: fullProfile.displayName, - }, - }), - audience: 'http://example.com', - clientId: 'mock', - clientSecret: 'mock', - callbackUrl: 'mock', - }); - - mockFrameHandler.mockResolvedValueOnce({ - result: { - fullProfile: { - emails: [ - { - type: 'work', - value: 'conrad@example.com', - }, - ], - displayName: 'Conrad', - name: { - familyName: 'Ribas', - givenName: 'Francisco', - }, - id: 'conrad', - provider: 'okta', - photos: [ - { - value: 'some-data', - }, - ], - }, - params: { - id_token: 'idToken', - scope: 'scope', - expires_in: 123, - }, - accessToken: 'accessToken', - }, - privateInfo: { - refreshToken: 'wacka', - }, - }); - const { response } = await provider.handler({} as any); - expect(response).toEqual({ - providerInfo: { - accessToken: 'accessToken', - expiresInSeconds: 123, - idToken: 'idToken', - scope: 'scope', - }, - profile: { - email: 'conrad@example.com', - displayName: 'Conrad', - }, - }); - }); -}); diff --git a/plugins/auth-backend/src/providers/okta/provider.ts b/plugins/auth-backend/src/providers/okta/provider.ts index 05e0451bdb..669914e7fc 100644 --- a/plugins/auth-backend/src/providers/okta/provider.ts +++ b/plugins/auth-backend/src/providers/okta/provider.ts @@ -14,187 +14,20 @@ * limitations under the License. */ -import express from 'express'; -import { - OAuthAdapter, - OAuthProviderOptions, - OAuthHandlers, - OAuthResponse, - OAuthEnvironmentHandler, - OAuthStartRequest, - encodeState, - OAuthRefreshRequest, - OAuthResult, -} from '../../lib/oauth'; -import { Strategy as OktaStrategy } from '@davidzemon/passport-okta-oauth'; -import passport from 'passport'; -import { - executeFrameHandlerStrategy, - executeRedirectStrategy, - executeRefreshTokenStrategy, - makeProfileInfo, - executeFetchUserProfileStrategy, - PassportDoneCallback, -} from '../../lib/passport'; -import { - AuthHandler, - OAuthStartResponse, - SignInResolver, - AuthResolverContext, -} from '../types'; +import { AuthHandler, SignInResolver } from '../types'; +import { OAuthResult } from '../../lib/oauth'; + import { createAuthProviderIntegration } from '../createAuthProviderIntegration'; +import { createOAuthProviderFactory } from '@backstage/plugin-auth-node'; +import { + adaptLegacyOAuthHandler, + adaptLegacyOAuthSignInResolver, +} from '../../lib/legacy'; +import { oktaAuthenticator } from '@backstage/plugin-auth-backend-module-okta-provider'; import { commonByEmailLocalPartResolver, commonByEmailResolver, } from '../resolvers'; -import { StateStore } from 'passport-oauth2'; - -type PrivateInfo = { - refreshToken: string; -}; - -export type OktaAuthProviderOptions = OAuthProviderOptions & { - audience: string; - authServerId?: string; - idp?: string; - signInResolver?: SignInResolver; - authHandler: AuthHandler; - resolverContext: AuthResolverContext; -}; - -export class OktaAuthProvider implements OAuthHandlers { - private readonly strategy: any; - private readonly signInResolver?: SignInResolver; - private readonly authHandler: AuthHandler; - private readonly resolverContext: AuthResolverContext; - - /** - * Due to passport-okta-oauth forcing options.state = true, - * passport-oauth2 requires express-session to be installed - * so that the 'state' parameter of the oauth2 flow can be stored. - * This implementation of StateStore matches the NullStore found within - * passport-oauth2, which is the StateStore implementation used when options.state = false, - * allowing us to avoid using express-session in order to integrate with Okta. - */ - private store: StateStore = { - store(_req: express.Request, cb: any) { - cb(null, null); - }, - verify(_req: express.Request, _state: string, cb: any) { - cb(null, true); - }, - }; - - constructor(options: OktaAuthProviderOptions) { - this.signInResolver = options.signInResolver; - this.authHandler = options.authHandler; - this.resolverContext = options.resolverContext; - - this.strategy = new OktaStrategy( - { - clientID: options.clientId, - clientSecret: options.clientSecret, - callbackURL: options.callbackUrl, - audience: options.audience, - authServerID: options.authServerId, - idp: options.idp, - passReqToCallback: false, - store: this.store, - response_type: 'code', - }, - ( - accessToken: any, - refreshToken: any, - params: any, - fullProfile: passport.Profile, - done: PassportDoneCallback, - ) => { - done( - undefined, - { - accessToken, - refreshToken, - params, - fullProfile, - }, - { - refreshToken, - }, - ); - }, - ); - } - - async start(req: OAuthStartRequest): Promise { - return await executeRedirectStrategy(req, this.strategy, { - accessType: 'offline', - prompt: 'consent', - scope: req.scope, - state: encodeState(req.state), - }); - } - - async handler(req: express.Request) { - const { result, privateInfo } = await executeFrameHandlerStrategy< - OAuthResult, - PrivateInfo - >(req, this.strategy); - - return { - response: await this.handleResult(result), - refreshToken: privateInfo.refreshToken, - }; - } - - async refresh(req: OAuthRefreshRequest) { - const { accessToken, refreshToken, params } = - await executeRefreshTokenStrategy( - this.strategy, - req.refreshToken, - req.scope, - ); - - const fullProfile = await executeFetchUserProfileStrategy( - this.strategy, - accessToken, - ); - - return { - response: await this.handleResult({ - fullProfile, - params, - accessToken, - }), - refreshToken, - }; - } - - private async handleResult(result: OAuthResult) { - const { profile } = await this.authHandler(result, this.resolverContext); - - const response: OAuthResponse = { - providerInfo: { - idToken: result.params.id_token, - accessToken: result.accessToken, - scope: result.params.scope, - expiresInSeconds: result.params.expires_in, - }, - profile, - }; - - if (this.signInResolver) { - response.backstageIdentity = await this.signInResolver( - { - result, - profile, - }, - this.resolverContext, - ); - } - - return response; - } -} /** * Auth provider integration for Okta auth @@ -208,59 +41,18 @@ export const okta = createAuthProviderIntegration({ * into the profile that will be presented to the user. */ authHandler?: AuthHandler; - /** * Configure sign-in for this provider, without it the provider can not be used to sign users in. */ signIn?: { - /** - * Maps an auth result to a Backstage identity for the user. - */ resolver: SignInResolver; }; }) { - return ({ providerId, globalConfig, config, resolverContext }) => - OAuthEnvironmentHandler.mapConfig(config, envConfig => { - const clientId = envConfig.getString('clientId'); - const clientSecret = envConfig.getString('clientSecret'); - const audience = envConfig.getString('audience'); - const authServerId = envConfig.getOptionalString('authServerId'); - const idp = envConfig.getOptionalString('idp'); - const customCallbackUrl = envConfig.getOptionalString('callbackUrl'); - const callbackUrl = - customCallbackUrl || - `${globalConfig.baseUrl}/${providerId}/handler/frame`; - - // This is a safe assumption as `passport-okta-oauth` uses the audience - // as the base for building the authorization, token, and user info URLs. - // https://github.com/fischerdan/passport-okta-oauth/blob/ea9ac42d/lib/passport-okta-oauth/oauth2.js#L12-L14 - if (!audience.startsWith('https://')) { - throw new Error("URL for 'audience' must start with 'https://'."); - } - - const authHandler: AuthHandler = options?.authHandler - ? options.authHandler - : async ({ fullProfile, params }) => ({ - profile: makeProfileInfo(fullProfile, params.id_token), - }); - - const provider = new OktaAuthProvider({ - audience, - authServerId, - idp, - clientId, - clientSecret, - callbackUrl, - authHandler, - signInResolver: options?.signIn?.resolver, - resolverContext, - }); - - return OAuthAdapter.fromConfig(globalConfig, provider, { - providerId, - callbackUrl, - }); - }); + return createOAuthProviderFactory({ + authenticator: oktaAuthenticator, + profileTransform: adaptLegacyOAuthHandler(options?.authHandler), + signInResolver: adaptLegacyOAuthSignInResolver(options?.signIn?.resolver), + }); }, resolvers: { /** diff --git a/plugins/auth-backend/src/setupTests.ts b/plugins/auth-backend/src/setupTests.ts index d3232290a7..f7c56ef27d 100644 --- a/plugins/auth-backend/src/setupTests.ts +++ b/plugins/auth-backend/src/setupTests.ts @@ -14,4 +14,10 @@ * limitations under the License. */ +import { TestDatabases } from '@backstage/backend-test-utils'; + export {}; + +TestDatabases.setDefaults({ + ids: ['MYSQL_8', 'POSTGRES_16', 'POSTGRES_12', 'SQLITE_3'], +}); diff --git a/plugins/auth-node/CHANGELOG.md b/plugins/auth-node/CHANGELOG.md index 65fe3b962e..36d65e9fa3 100644 --- a/plugins/auth-node/CHANGELOG.md +++ b/plugins/auth-node/CHANGELOG.md @@ -1,5 +1,133 @@ # @backstage/plugin-auth-node +## 0.4.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.4.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + +## 0.4.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.4.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.4.2 + +### Patch Changes + +- a62764b: Updated dependency `passport` to `^0.7.0`. +- 0cbb03b: Fixing regular expression ReDoS with zod packages. Upgrading to latest. ref: https://security.snyk.io/vuln/SNYK-JS-ZOD-5925617 +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/catalog-client@1.5.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.4.2-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.4.2-next.2 + +### Patch Changes + +- a62764b: Updated dependency `passport` to `^0.7.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.4.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.4.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.4.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + ## 0.4.1-next.2 ### Patch Changes diff --git a/plugins/auth-node/package.json b/plugins/auth-node/package.json index ebabd6903d..fc8fb5b25c 100644 --- a/plugins/auth-node/package.json +++ b/plugins/auth-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-node", - "version": "0.4.1-next.2", + "version": "0.4.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -41,9 +41,9 @@ "jose": "^4.6.0", "lodash": "^4.17.21", "node-fetch": "^2.6.7", - "passport": "^0.6.0", + "passport": "^0.7.0", "winston": "^3.2.1", - "zod": "^3.21.4", + "zod": "^3.22.4", "zod-to-json-schema": "^3.21.4" }, "devDependencies": { diff --git a/plugins/azure-devops-backend/CHANGELOG.md b/plugins/azure-devops-backend/CHANGELOG.md index c5de0432ec..7b0a081b34 100644 --- a/plugins/azure-devops-backend/CHANGELOG.md +++ b/plugins/azure-devops-backend/CHANGELOG.md @@ -1,5 +1,154 @@ # @backstage/plugin-azure-devops-backend +## 0.5.1 + +### Patch Changes + +- d076ee4: Updated dependency `azure-devops-node-api` to `^12.0.0`. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + - @backstage/plugin-azure-devops-common@0.3.2 + - @backstage/plugin-catalog-common@1.0.20 + +## 0.5.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + +## 0.5.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-azure-devops-common@0.3.2 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-catalog-node@1.6.1-next.1 + +## 0.5.1-next.0 + +### Patch Changes + +- d076ee4: Updated dependency `azure-devops-node-api` to `^12.0.0`. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/plugin-catalog-node@1.6.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + - @backstage/plugin-azure-devops-common@0.3.2 + - @backstage/plugin-catalog-common@1.0.19 + +## 0.5.0 + +### Minor Changes + +- 844969c: **BREAKING** New `fromConfig` static method must be used now when creating an instance of the `AzureDevOpsApi` + + Added support for using the `AzureDevOpsCredentialsProvider` + +### Patch Changes + +- c70e4f5: Added multi-org support +- 646db72: Updated encoding of Org to use `encodeURIComponent` when building URL used to get credentials from credential provider +- 043b724: Introduced new `AzureDevOpsAnnotatorProcessor` that adds the needed annotations automatically. Also, moved constants to common package so they can be shared more easily +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/plugin-azure-devops-common@0.3.2 + - @backstage/integration@1.8.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + +## 0.5.0-next.3 + +### Patch Changes + +- c70e4f5: Added multi-org support +- 646db72: Updated encoding of Org to use `encodeURIComponent` when building URL used to get credentials from credential provider +- Updated dependencies + - @backstage/plugin-azure-devops-common@0.3.2-next.1 + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.6.0-next.3 + +## 0.5.0-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/backend-common@0.20.0-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/plugin-azure-devops-common@0.3.2-next.0 + - @backstage/plugin-catalog-common@1.0.18 + +## 0.5.0-next.1 + +### Minor Changes + +- 844969cd97: **BREAKING** New `fromConfig` static method must be used now when creating an instance of the `AzureDevOpsApi` + + Added support for using the `AzureDevOpsCredentialsProvider` + +### Patch Changes + +- 043b724c56: Introduced new `AzureDevOpsAnnotatorProcessor` that adds the needed annotations automatically. Also, moved constants to common package so they can be shared more easily +- Updated dependencies + - @backstage/plugin-azure-devops-common@0.3.2-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## 0.4.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + - @backstage/plugin-azure-devops-common@0.3.1 + +## 0.4.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/config@1.1.1 + - @backstage/plugin-azure-devops-common@0.3.1 + ## 0.4.4-next.2 ### Patch Changes diff --git a/plugins/azure-devops-backend/README.md b/plugins/azure-devops-backend/README.md index e892b84dd1..0066e43856 100644 --- a/plugins/azure-devops-backend/README.md +++ b/plugins/azure-devops-backend/README.md @@ -8,7 +8,7 @@ The following sections will help you get the Azure DevOps Backend plugin setup a ### Configuration -The Azure DevOps plugin requires the following YAML to be added to your app-config.yaml: +The Azure DevOps plugin requires the following YAML to be added to your `app-config.yaml`: ```yaml azureDevOps: @@ -23,6 +23,12 @@ Configuration Details: - `AZURE_TOKEN` environment variable must be set to a [Personal Access Token](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=preview-page) with read access to both Code and Build - `organization` is your Azure DevOps Services (cloud) Organization name or for Azure DevOps Server (on-premise) this will be your Collection name +#### Multi Organization & Service Principals + +To support cases where you have multiple Azure DevOps organizations and/or you want to use a Service Principal you will want to make sure to configure them in the `integrations.azure` section of your `app-config.yaml` as detailed in the [Azure DevOps Locations](https://backstage.io/docs/integrations/azure/locations) documentation. + +**Note:** You will still need to define the [configuration above](#configuration). + ### Up and Running Here's how to get the backend up and running: @@ -89,6 +95,62 @@ In your `packages/backend/src/index.ts` make the following changes: backend.start(); ``` +## Processor + +The Azure DevOps backend plugin includes the `AzureDevOpsAnnotatorProcessor` which will automatically add the needed annotations for you. Here's how to install it: + +```diff + import { CatalogBuilder } from '@backstage/plugin-catalog-backend'; + import { ScaffolderEntitiesProcessor } from '@backstage/plugin-catalog-backend-module-scaffolder-entity-model'; + import { Router } from 'express'; + import { PluginEnvironment } from '../types'; ++ import { AzureDevOpsAnnotatorProcessor } from '@backstage/plugin-azure-devops-backend'; + + export default async function createPlugin( + env: PluginEnvironment, + ): Promise { + const builder = await CatalogBuilder.create(env); + builder.addProcessor(new ScaffolderEntitiesProcessor()); ++ builder.addProcessor(AzureDevOpsAnnotatorProcessor.fromConfig(env.config)); + const { processingEngine, router } = await builder.build(); + await processingEngine.start(); + return router; + } +``` + +To use this with the New Backend System you'll want to create a [backend module extension for the Catalog](https://backstage.io/docs/backend-system/building-backends/migrating#other-catalog-extensions) if you haven't already. Here's a basic example of this assuming you are only adding the `AzureDevOpsAnnotatorProcessor`, this would go in your `packages/backend/index.ts`: + +```diff + import { createBackend } from '@backstage/backend-defaults'; ++ import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; ++ import { coreServices, createBackendModule } from '@backstage/backend-plugin-api'; ++ import { AzureDevOpsAnnotatorProcessor } from '@backstage/plugin-azure-devops-backend'; + ++ const catalogModuleCustomExtensions = createBackendModule({ ++ pluginId: 'catalog', // name of the plugin that the module is targeting ++ moduleId: 'custom-extensions', ++ register(env) { ++ env.registerInit({ ++ deps: { ++ catalog: catalogProcessingExtensionPoint, ++ config: coreServices.rootConfig, ++ }, ++ async init({ catalog, config }) { ++ catalog.addProcessor(AzureDevOpsAnnotatorProcessor.fromConfig(config)); ++ }, ++ }); ++ }, ++ }); + + const backend = createBackend(); + + // ... other feature additions + ++ backend.add(catalogModuleCustomExtensions()); + + backend.start(); +``` + ## Links - [Frontend part of the plugin](https://github.com/backstage/backstage/tree/master/plugins/azure-devops) diff --git a/plugins/azure-devops-backend/api-report.md b/plugins/azure-devops-backend/api-report.md index 8c916a1495..6dead7f11b 100644 --- a/plugins/azure-devops-backend/api-report.md +++ b/plugins/azure-devops-backend/api-report.md @@ -7,36 +7,69 @@ import { BackendFeature } from '@backstage/backend-plugin-api'; import { Build } from 'azure-devops-node-api/interfaces/BuildInterfaces'; import { BuildDefinitionReference } from 'azure-devops-node-api/interfaces/BuildInterfaces'; import { BuildRun } from '@backstage/plugin-azure-devops-common'; +import { CatalogProcessor } from '@backstage/plugin-catalog-node'; import { Config } from '@backstage/config'; import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common'; +import { Entity } from '@backstage/catalog-model'; import express from 'express'; import { GitRepository } from 'azure-devops-node-api/interfaces/GitInterfaces'; import { GitTag } from '@backstage/plugin-azure-devops-common'; +import { LocationSpec } from '@backstage/plugin-catalog-common'; import { Logger } from 'winston'; import { Project } from '@backstage/plugin-azure-devops-common'; import { PullRequest } from '@backstage/plugin-azure-devops-common'; import { PullRequestOptions } from '@backstage/plugin-azure-devops-common'; import { RepoBuild } from '@backstage/plugin-azure-devops-common'; +import { ScmIntegrationRegistry } from '@backstage/integration'; import { Team } from '@backstage/plugin-azure-devops-common'; import { TeamMember } from '@backstage/plugin-azure-devops-common'; import { UrlReader } from '@backstage/backend-common'; -import { WebApi } from 'azure-devops-node-api'; + +// @public (undocumented) +export class AzureDevOpsAnnotatorProcessor implements CatalogProcessor { + constructor(opts: { + scmIntegrationRegistry: ScmIntegrationRegistry; + kinds?: string[]; + }); + // (undocumented) + static fromConfig( + config: Config, + options?: { + kinds?: string[]; + }, + ): AzureDevOpsAnnotatorProcessor; + // (undocumented) + getProcessorName(): string; + // (undocumented) + preProcessEntity(entity: Entity, location: LocationSpec): Promise; +} // @public (undocumented) export class AzureDevOpsApi { - constructor(logger: Logger, webApi: WebApi, urlReader: UrlReader); + // (undocumented) + static fromConfig( + config: Config, + options: { + logger: Logger; + urlReader: UrlReader; + }, + ): AzureDevOpsApi; // (undocumented) getAllTeams(): Promise; // (undocumented) getBuildDefinitions( projectName: string, definitionName: string, + host?: string, + org?: string, ): Promise; // (undocumented) getBuildList( projectName: string, repoId: string, top: number, + host?: string, + org?: string, ): Promise; // (undocumented) getBuildRuns( @@ -44,6 +77,8 @@ export class AzureDevOpsApi { top: number, repoName?: string, definitionName?: string, + host?: string, + org?: string, ): Promise; // (undocumented) getBuilds( @@ -51,6 +86,8 @@ export class AzureDevOpsApi { top: number, repoId?: string, definitions?: number[], + host?: string, + org?: string, ): Promise; // (undocumented) getDashboardPullRequests( @@ -61,16 +98,25 @@ export class AzureDevOpsApi { getGitRepository( projectName: string, repoName: string, + host?: string, + org?: string, ): Promise; // (undocumented) - getGitTags(projectName: string, repoName: string): Promise; + getGitTags( + projectName: string, + repoName: string, + host?: string, + org?: string, + ): Promise; // (undocumented) - getProjects(): Promise; + getProjects(host?: string, org?: string): Promise; // (undocumented) getPullRequests( projectName: string, repoName: string, options: PullRequestOptions, + host?: string, + org?: string, ): Promise; // (undocumented) getReadme( @@ -87,6 +133,8 @@ export class AzureDevOpsApi { projectName: string, repoName: string, top: number, + host?: string, + org?: string, ): Promise; // (undocumented) getTeamMembers(options: { diff --git a/plugins/azure-devops-backend/config.d.ts b/plugins/azure-devops-backend/config.d.ts index 433e4df22f..86fefeeef9 100644 --- a/plugins/azure-devops-backend/config.d.ts +++ b/plugins/azure-devops-backend/config.d.ts @@ -15,7 +15,9 @@ */ export interface Config { - /** Configuration options for the azure-devops-backend plugin */ + /** + * Configuration options for the azure-devops-backend plugin + */ azureDevOps: { /** * The hostname of the given Azure instance diff --git a/plugins/azure-devops-backend/package.json b/plugins/azure-devops-backend/package.json index e675ec316f..12b598f7e9 100644 --- a/plugins/azure-devops-backend/package.json +++ b/plugins/azure-devops-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-azure-devops-backend", - "version": "0.4.4-next.2", + "version": "0.5.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,12 +30,17 @@ "dependencies": { "@backstage/backend-common": "workspace:^", "@backstage/backend-plugin-api": "workspace:^", + "@backstage/catalog-model": "workspace:^", "@backstage/config": "workspace:^", + "@backstage/integration": "workspace:^", "@backstage/plugin-azure-devops-common": "workspace:^", + "@backstage/plugin-catalog-common": "workspace:^", + "@backstage/plugin-catalog-node": "workspace:^", "@types/express": "^4.17.6", - "azure-devops-node-api": "^11.0.1", + "azure-devops-node-api": "^12.0.0", "express": "^4.17.1", "express-promise-router": "^4.1.0", + "lodash": "^4.17.21", "mime-types": "^2.1.27", "p-limit": "^3.1.0", "winston": "^3.2.1", @@ -44,7 +49,6 @@ "devDependencies": { "@backstage/cli": "workspace:^", "@types/supertest": "^2.0.8", - "msw": "^1.0.0", "supertest": "^6.1.6" }, "files": [ diff --git a/plugins/azure-devops-backend/src/api/AzureDevOpsApi.test.ts b/plugins/azure-devops-backend/src/api/AzureDevOpsApi.test.ts index dade60f1ed..174c5ff6cd 100644 --- a/plugins/azure-devops-backend/src/api/AzureDevOpsApi.test.ts +++ b/plugins/azure-devops-backend/src/api/AzureDevOpsApi.test.ts @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Backstage Authors + * 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. @@ -14,560 +14,751 @@ * limitations under the License. */ +jest.mock('azure-devops-node-api', () => ({ + WebApi: jest.fn(), + getHandlerFromToken: jest.fn().mockReturnValue(() => {}), +})); + +import { UrlReader, getVoidLogger } from '@backstage/backend-common'; +import { ConfigReader } from '@backstage/config'; +import { AzureDevOpsApi } from './AzureDevOpsApi'; +import { WebApi } from 'azure-devops-node-api'; +import { TeamProjectReference } from 'azure-devops-node-api/interfaces/CoreInterfaces'; +import { GitRepository } from 'azure-devops-node-api/interfaces/TfvcInterfaces'; import { Build, - DefinitionReference, -} from 'azure-devops-node-api/interfaces/BuildInterfaces'; -import { BuildResult, BuildStatus, - GitTag, - PullRequest, - PullRequestStatus, - RepoBuild, -} from '@backstage/plugin-azure-devops-common'; +} from 'azure-devops-node-api/interfaces/BuildInterfaces'; import { GitPullRequest, GitRef, - GitRepository, + PullRequestStatus, } from 'azure-devops-node-api/interfaces/GitInterfaces'; -import { - mappedBuildRun, - mappedGitTag, - mappedPullRequest, - mappedRepoBuild, -} from './AzureDevOpsApi'; - -import { IdentityRef } from 'azure-devops-node-api/interfaces/common/VSSInterfaces'; +import { PullRequestOptions } from '@backstage/plugin-azure-devops-common'; describe('AzureDevOpsApi', () => { - describe('mappedRepoBuild', () => { - describe('mappedRepoBuild happy path', () => { - it('should return RepoBuild from Build', () => { - const inputBuildDefinition: DefinitionReference = { - name: 'My Build Definition', - }; - - const inputLinks: any = { - web: { - href: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', - }, - }; - - const inputIdentityRef: IdentityRef = { - displayName: 'Jane Doe', - uniqueName: 'DOMAIN\\jdoe', - }; - - const inputBuild: Build = { - id: 1, - buildNumber: 'Build-1', - status: BuildStatus.Completed, - result: BuildResult.Succeeded, - queueTime: new Date('2020-09-12T06:10:23.932Z'), - startTime: new Date('2020-09-12T06:15:23.932Z'), - finishTime: new Date('2020-09-12T06:20:23.932Z'), - sourceBranch: 'refs/heads/develop', - sourceVersion: 'f4f78b3100b2923982bdf60c89c57ce6fd2d9a1c', - definition: inputBuildDefinition, - _links: inputLinks, - requestedFor: inputIdentityRef, - }; - - const outputRepoBuild: RepoBuild = { - id: 1, - title: 'My Build Definition - Build-1', - link: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', - status: BuildStatus.Completed, - result: BuildResult.Succeeded, - queueTime: '2020-09-12T06:10:23.932Z', - startTime: '2020-09-12T06:15:23.932Z', - finishTime: '2020-09-12T06:20:23.932Z', - source: 'refs/heads/develop (f4f78b31)', - uniqueName: 'DOMAIN\\jdoe', - }; - - expect(mappedRepoBuild(inputBuild)).toEqual(outputRepoBuild); - }); - }); - - describe('mappedRepoBuild with no Build definition name', () => { - it('should return RepoBuild with only Build Number for title', () => { - const inputLinks: any = { - web: { - href: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', - }, - }; - - const inputIdentityRef: IdentityRef = { - displayName: 'Jane Doe', - uniqueName: 'DOMAIN\\jdoe', - }; - - const inputBuild: Build = { - id: 1, - buildNumber: 'Build-1', - status: BuildStatus.Completed, - result: BuildResult.Succeeded, - queueTime: new Date('2020-09-12T06:10:23.932Z'), - startTime: new Date('2020-09-12T06:15:23.932Z'), - finishTime: new Date('2020-09-12T06:20:23.932Z'), - sourceBranch: 'refs/heads/develop', - sourceVersion: 'f4f78b3100b2923982bdf60c89c57ce6fd2d9a1c', - definition: undefined, - _links: inputLinks, - requestedFor: inputIdentityRef, - }; - - const outputRepoBuild: RepoBuild = { - id: 1, - title: 'Build-1', - link: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', - status: BuildStatus.Completed, - result: BuildResult.Succeeded, - queueTime: '2020-09-12T06:10:23.932Z', - startTime: '2020-09-12T06:15:23.932Z', - finishTime: '2020-09-12T06:20:23.932Z', - source: 'refs/heads/develop (f4f78b31)', - uniqueName: 'DOMAIN\\jdoe', - }; - - expect(mappedRepoBuild(inputBuild)).toEqual(outputRepoBuild); - }); - }); - - describe('mappedRepoBuild with undefined status', () => { - it('should return BuildStatus of None for status', () => { - const inputLinks: any = { - web: { - href: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', - }, - }; - - const inputIdentityRef: IdentityRef = { - displayName: 'Jane Doe', - uniqueName: 'DOMAIN\\jdoe', - }; - - const inputBuild: Build = { - id: 1, - buildNumber: 'Build-1', - status: undefined, - result: BuildResult.Succeeded, - queueTime: new Date('2020-09-12T06:10:23.932Z'), - startTime: new Date('2020-09-12T06:15:23.932Z'), - finishTime: new Date('2020-09-12T06:20:23.932Z'), - sourceBranch: 'refs/heads/develop', - sourceVersion: 'f4f78b3100b2923982bdf60c89c57ce6fd2d9a1c', - definition: undefined, - _links: inputLinks, - requestedFor: inputIdentityRef, - }; - - const outputRepoBuild: RepoBuild = { - id: 1, - title: 'Build-1', - link: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', - status: BuildStatus.None, - result: BuildResult.Succeeded, - queueTime: '2020-09-12T06:10:23.932Z', - startTime: '2020-09-12T06:15:23.932Z', - finishTime: '2020-09-12T06:20:23.932Z', - source: 'refs/heads/develop (f4f78b31)', - uniqueName: 'DOMAIN\\jdoe', - }; - - expect(mappedRepoBuild(inputBuild)).toEqual(outputRepoBuild); - }); - }); - - describe('mappedRepoBuild with undefined result', () => { - it('should return BuildResult of None for result', () => { - const inputLinks: any = { - web: { - href: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', - }, - }; - - const inputIdentityRef: IdentityRef = { - displayName: 'Jane Doe', - uniqueName: 'DOMAIN\\jdoe', - }; - - const inputBuild: Build = { - id: 1, - buildNumber: 'Build-1', - status: BuildStatus.InProgress, - result: undefined, - queueTime: new Date('2020-09-12T06:10:23.932Z'), - startTime: new Date('2020-09-12T06:15:23.932Z'), - finishTime: new Date('2020-09-12T06:20:23.932Z'), - sourceBranch: 'refs/heads/develop', - sourceVersion: 'f4f78b3100b2923982bdf60c89c57ce6fd2d9a1c', - definition: undefined, - _links: inputLinks, - requestedFor: inputIdentityRef, - }; - - const outputRepoBuild: RepoBuild = { - id: 1, - title: 'Build-1', - link: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', - status: BuildStatus.InProgress, - result: BuildResult.None, - queueTime: '2020-09-12T06:10:23.932Z', - startTime: '2020-09-12T06:15:23.932Z', - finishTime: '2020-09-12T06:20:23.932Z', - source: 'refs/heads/develop (f4f78b31)', - uniqueName: 'DOMAIN\\jdoe', - }; - - expect(mappedRepoBuild(inputBuild)).toEqual(outputRepoBuild); - }); - }); - - describe('mappedRepoBuild with undefined link', () => { - it('should return empty string for link', () => { - const inputIdentityRef: IdentityRef = { - displayName: 'Jane Doe', - uniqueName: 'DOMAIN\\jdoe', - }; - - const inputBuild: Build = { - id: 1, - buildNumber: 'Build-1', - status: BuildStatus.InProgress, - result: undefined, - queueTime: new Date('2020-09-12T06:10:23.932Z'), - startTime: new Date('2020-09-12T06:15:23.932Z'), - finishTime: new Date('2020-09-12T06:20:23.932Z'), - sourceBranch: 'refs/heads/develop', - sourceVersion: 'f4f78b3100b2923982bdf60c89c57ce6fd2d9a1c', - definition: undefined, - _links: undefined, - requestedFor: inputIdentityRef, - }; - - const outputRepoBuild: RepoBuild = { - id: 1, - title: 'Build-1', - link: '', - status: BuildStatus.InProgress, - result: BuildResult.None, - queueTime: '2020-09-12T06:10:23.932Z', - startTime: '2020-09-12T06:15:23.932Z', - finishTime: '2020-09-12T06:20:23.932Z', - source: 'refs/heads/develop (f4f78b31)', - uniqueName: 'DOMAIN\\jdoe', - }; - - expect(mappedRepoBuild(inputBuild)).toEqual(outputRepoBuild); - }); - }); + beforeEach(() => { + jest.clearAllMocks(); }); - describe('mappedGitTag', () => { - describe('mappedGitTag happy path', () => { - it('should return GitTag from GitRef', () => { - const inputIdentityRef: IdentityRef = { - displayName: 'Jane Doe', - }; - const inputGitRef: GitRef = { - name: 'refs/tags/v1.1.2', - creator: inputIdentityRef, - objectId: '1111aaaa2222bbbb3333cccc4444dddd5555eeee', - peeledObjectId: '1234567890abcdef1234567890abcdef12345678', - }; - const inputLinkBaseUrl = - 'https://host.com/myOrg/_git/super-feature-repo?version=GT'; - const inputCommitBaseUrl = - 'https://host.com/myOrg/_git/super-feature-repo/commit'; - const outputGitTag: GitTag = { - name: 'v1.1.2', - createdBy: 'Jane Doe', - commitLink: - 'https://host.com/myOrg/_git/super-feature-repo/commit/1234567890abcdef1234567890abcdef12345678', - objectId: '1111aaaa2222bbbb3333cccc4444dddd5555eeee', - peeledObjectId: '1234567890abcdef1234567890abcdef12345678', - link: 'https://host.com/myOrg/_git/super-feature-repo?version=GTv1.1.2', - }; - expect( - mappedGitTag(inputGitRef, inputLinkBaseUrl, inputCommitBaseUrl), - ).toEqual(outputGitTag); - }); - }); + const mockConfig = new ConfigReader({ + azureDevOps: { + host: 'dev.azure.com', + token: 'token', + organization: 'org', + }, + integrations: { + azure: [ + { + host: 'dev.azure.com', + credentials: [ + { + personalAccessToken: 'pat', + }, + ], + }, + ], + }, }); - describe('mappedPullRequest', () => { - describe('mappedPullRequest happy path', () => { - it('should return PullRequest from GitPullRequest', () => { - const inputGitRepository: GitRepository = { - name: 'super-feature-repo', - }; + const mockLogger = getVoidLogger(); - const inputIdentityRef: IdentityRef = { - displayName: 'Jane Doe', - uniqueName: 'DOMAIN\\jdoe', - }; + const mockUrlReader: UrlReader = { + readUrl: url => + Promise.resolve({ + buffer: async () => Buffer.from(url), + etag: 'buffer', + stream: jest.fn(), + }), + readTree: jest.fn(), + search: jest.fn(), + }; - const inputPullRequest: GitPullRequest = { - pullRequestId: 7181, - repository: inputGitRepository, - title: 'My Awesome New Feature', - createdBy: inputIdentityRef, - creationDate: new Date('2020-09-12T06:10:23.932Z'), - sourceRefName: 'refs/heads/topic/super-awesome-feature', - targetRefName: 'refs/heads/main', - status: PullRequestStatus.Active, - isDraft: false, - }; + it('should get projects', async () => { + const mockProjects: TeamProjectReference[] = [ + { + id: 'one', + name: 'one', + description: 'one', + }, + { + id: 'two', + name: 'two', + description: 'two', + }, + { + id: 'three', + name: 'three', + description: 'three', + }, + ]; - const inputBaseUrl = - 'https://host.com/myOrg/_git/super-feature-repo/pullrequest'; + const mockCoreApiClient = { + getProjects: jest.fn().mockResolvedValue(mockProjects), + }; - const outputPullRequest: PullRequest = { - pullRequestId: 7181, - repoName: 'super-feature-repo', - title: 'My Awesome New Feature', - uniqueName: 'DOMAIN\\jdoe', - createdBy: 'Jane Doe', - creationDate: '2020-09-12T06:10:23.932Z', - sourceRefName: 'refs/heads/topic/super-awesome-feature', - targetRefName: 'refs/heads/main', - status: PullRequestStatus.Active, - isDraft: false, - link: 'https://host.com/myOrg/_git/super-feature-repo/pullrequest/7181', - }; + const mockCoreApi = { + getCoreApi: jest.fn().mockResolvedValue(mockCoreApiClient), + }; - expect(mappedPullRequest(inputPullRequest, inputBaseUrl)).toEqual( - outputPullRequest, - ); - }); + (WebApi as unknown as jest.Mock).mockImplementation(() => mockCoreApi); + + const api = AzureDevOpsApi.fromConfig(mockConfig, { + logger: mockLogger, + urlReader: mockUrlReader, }); + + const result = await api.getProjects(); + + expect(result).toEqual([ + { + id: 'one', + name: 'one', + description: 'one', + }, + { + id: 'three', + name: 'three', + description: 'three', + }, + { + id: 'two', + name: 'two', + description: 'two', + }, + ]); }); - describe('mappedBuildRun', () => { - describe('mappedBuildRun happy path', () => { - it('should return RepoBuild from Build', () => { - const inputBuildDefinition: DefinitionReference = { - name: 'My Build Definition', - }; + it('should get git repository', async () => { + const mockGitRepository: GitRepository = { + id: 'repo', + }; - const inputLinks: any = { - web: { - href: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', - }, - }; + const mockGitClient = { + getRepository: jest.fn().mockResolvedValue(mockGitRepository), + }; + const mockGitApi = { + getGitApi: jest.fn().mockReturnValue(mockGitClient), + }; - const inputIdentityRef: IdentityRef = { - displayName: 'Jane Doe', - uniqueName: 'DOMAIN\\jdoe', - }; + (WebApi as unknown as jest.Mock).mockImplementation(() => mockGitApi); - const inputBuild: Build = { - id: 1, - buildNumber: 'Build-1', - status: BuildStatus.Completed, - result: BuildResult.Succeeded, - queueTime: new Date('2020-09-12T06:10:23.932Z'), - startTime: new Date('2020-09-12T06:15:23.932Z'), - finishTime: new Date('2020-09-12T06:20:23.932Z'), - sourceBranch: 'refs/heads/develop', - sourceVersion: 'f4f78b3100b2923982bdf60c89c57ce6fd2d9a1c', - definition: inputBuildDefinition, - _links: inputLinks, - requestedFor: inputIdentityRef, - }; - - const outputRepoBuild: RepoBuild = { - id: 1, - title: 'My Build Definition - Build-1', - link: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', - status: BuildStatus.Completed, - result: BuildResult.Succeeded, - queueTime: '2020-09-12T06:10:23.932Z', - startTime: '2020-09-12T06:15:23.932Z', - finishTime: '2020-09-12T06:20:23.932Z', - source: 'refs/heads/develop (f4f78b31)', - uniqueName: 'DOMAIN\\jdoe', - }; - - expect(mappedBuildRun(inputBuild)).toEqual(outputRepoBuild); - }); + const api = AzureDevOpsApi.fromConfig(mockConfig, { + logger: mockLogger, + urlReader: mockUrlReader, }); - describe('mappedBuildRun with no Build definition name', () => { - it('should return RepoBuild with only Build Number for title', () => { - const inputLinks: any = { - web: { - href: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', - }, - }; + const result = await api.getGitRepository('project', 'repo'); - const inputIdentityRef: IdentityRef = { - displayName: 'Jane Doe', - uniqueName: 'DOMAIN\\jdoe', - }; + expect(result).toEqual({ id: 'repo' }); + }); - const inputBuild: Build = { - id: 1, - buildNumber: 'Build-1', - status: BuildStatus.Completed, - result: BuildResult.Succeeded, - queueTime: new Date('2020-09-12T06:10:23.932Z'), - startTime: new Date('2020-09-12T06:15:23.932Z'), - finishTime: new Date('2020-09-12T06:20:23.932Z'), - sourceBranch: 'refs/heads/develop', - sourceVersion: 'f4f78b3100b2923982bdf60c89c57ce6fd2d9a1c', - definition: undefined, - _links: inputLinks, - requestedFor: inputIdentityRef, - }; + it('should get build list', async () => { + const mockBuilds: Build[] = [ + { + id: 1, + }, + { + id: 2, + }, + { + id: 3, + }, + ]; - const outputRepoBuild: RepoBuild = { - id: 1, - title: 'Build-1', - link: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', - status: BuildStatus.Completed, - result: BuildResult.Succeeded, - queueTime: '2020-09-12T06:10:23.932Z', - startTime: '2020-09-12T06:15:23.932Z', - finishTime: '2020-09-12T06:20:23.932Z', - source: 'refs/heads/develop (f4f78b31)', - uniqueName: 'DOMAIN\\jdoe', - }; + const mockBuildClient = { + getBuilds: jest.fn().mockResolvedValue(mockBuilds), + }; + const mockBuildApi = { + getBuildApi: jest.fn().mockReturnValue(mockBuildClient), + }; - expect(mappedBuildRun(inputBuild)).toEqual(outputRepoBuild); - }); + (WebApi as unknown as jest.Mock).mockImplementation(() => mockBuildApi); + + const api = AzureDevOpsApi.fromConfig(mockConfig, { + logger: mockLogger, + urlReader: mockUrlReader, }); - describe('mappedBuildRun with undefined status', () => { - it('should return BuildStatus of None for status', () => { - const inputLinks: any = { - web: { - href: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', - }, - }; + const result = await api.getBuildList('project', 'repo', 10); - const inputIdentityRef: IdentityRef = { - displayName: 'Jane Doe', - uniqueName: 'DOMAIN\\jdoe', - }; + expect(result).toEqual([{ id: 1 }, { id: 2 }, { id: 3 }]); + }); - const inputBuild: Build = { - id: 1, - buildNumber: 'Build-1', - status: undefined, - result: BuildResult.Succeeded, - queueTime: new Date('2020-09-12T06:10:23.932Z'), - startTime: new Date('2020-09-12T06:15:23.932Z'), - finishTime: new Date('2020-09-12T06:20:23.932Z'), - sourceBranch: 'refs/heads/develop', - sourceVersion: 'f4f78b3100b2923982bdf60c89c57ce6fd2d9a1c', - definition: undefined, - _links: inputLinks, - requestedFor: inputIdentityRef, - }; + it('should get repo builds', async () => { + const mockGitRepository: GitRepository = { + id: 'repo', + }; - const outputRepoBuild: RepoBuild = { - id: 1, - title: 'Build-1', - link: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', - status: BuildStatus.None, - result: BuildResult.Succeeded, - queueTime: '2020-09-12T06:10:23.932Z', - startTime: '2020-09-12T06:15:23.932Z', - finishTime: '2020-09-12T06:20:23.932Z', - source: 'refs/heads/develop (f4f78b31)', - uniqueName: 'DOMAIN\\jdoe', - }; + const mockBuilds: Build[] = [ + { + id: 1, + buildNumber: 'Build-1', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'main', + sourceVersion: 'abcd', + }, + { + id: 2, + buildNumber: 'Build-2', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'main', + sourceVersion: 'abcd', + }, + { + id: 3, + buildNumber: 'Build-3', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'main', + sourceVersion: 'abcd', + }, + ]; - expect(mappedBuildRun(inputBuild)).toEqual(outputRepoBuild); - }); + const mockBuildClient = { + getBuilds: jest.fn().mockResolvedValue(mockBuilds), + }; + const mockGitClient = { + getRepository: jest.fn().mockResolvedValue(mockGitRepository), + }; + const mockApi = { + getGitApi: jest.fn().mockReturnValue(mockGitClient), + getBuildApi: jest.fn().mockReturnValue(mockBuildClient), + }; + + (WebApi as unknown as jest.Mock).mockImplementation(() => mockApi); + + const api = AzureDevOpsApi.fromConfig(mockConfig, { + logger: mockLogger, + urlReader: mockUrlReader, }); - describe('mappedBuildRun with undefined result', () => { - it('should return BuildResult of None for result', () => { - const inputLinks: any = { - web: { - href: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', - }, - }; + const result = await api.getRepoBuilds('project', 'repo', 10); - const inputIdentityRef: IdentityRef = { - displayName: 'Jane Doe', - uniqueName: 'DOMAIN\\jdoe', - }; + expect(result).toEqual([ + { + id: 1, + title: 'Build-1', + link: '', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'main (abcd)', + uniqueName: 'N/A', + }, + { + id: 2, + title: 'Build-2', + link: '', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'main (abcd)', + uniqueName: 'N/A', + }, + { + id: 3, + title: 'Build-3', + link: '', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'main (abcd)', + uniqueName: 'N/A', + }, + ]); + }); - const inputBuild: Build = { - id: 1, - buildNumber: 'Build-1', - status: BuildStatus.InProgress, - result: undefined, - queueTime: new Date('2020-09-12T06:10:23.932Z'), - startTime: new Date('2020-09-12T06:15:23.932Z'), - finishTime: new Date('2020-09-12T06:20:23.932Z'), - sourceBranch: 'refs/heads/develop', - sourceVersion: 'f4f78b3100b2923982bdf60c89c57ce6fd2d9a1c', - definition: undefined, - _links: inputLinks, - requestedFor: inputIdentityRef, - }; + it('should get git tags', async () => { + const mockGitRepository: GitRepository = { + id: 'repo', + }; - const outputRepoBuild: RepoBuild = { - id: 1, - title: 'Build-1', - link: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', - status: BuildStatus.InProgress, - result: BuildResult.None, - queueTime: '2020-09-12T06:10:23.932Z', - startTime: '2020-09-12T06:15:23.932Z', - finishTime: '2020-09-12T06:20:23.932Z', - source: 'refs/heads/develop (f4f78b31)', - uniqueName: 'DOMAIN\\jdoe', - }; + const mockGitRefs: GitRef[] = [ + { + objectId: '1.0', + peeledObjectId: '1.0', + name: 'v1.0', + }, + { + objectId: '2.0', + peeledObjectId: '2.0', + name: 'v2.0', + }, + { + objectId: '3.0', + peeledObjectId: '3.0', + name: 'v3.0', + }, + ]; - expect(mappedBuildRun(inputBuild)).toEqual(outputRepoBuild); - }); + const mockGitClient = { + getRepository: jest.fn().mockResolvedValue(mockGitRepository), + getRefs: jest.fn().mockResolvedValue(mockGitRefs), + }; + const mockApi = { + getGitApi: jest.fn().mockReturnValue(mockGitClient), + serverUrl: 'serverUrl', + }; + + (WebApi as unknown as jest.Mock).mockImplementation(() => mockApi); + + const api = AzureDevOpsApi.fromConfig(mockConfig, { + logger: mockLogger, + urlReader: mockUrlReader, }); - describe('mappedBuildRun with undefined link', () => { - it('should return empty string for link', () => { - const inputIdentityRef: IdentityRef = { - displayName: 'Jane Doe', - uniqueName: 'DOMAIN\\jdoe', - }; + const result = await api.getGitTags('project', 'repo'); - const inputBuild: Build = { - id: 1, - buildNumber: 'Build-1', - status: BuildStatus.InProgress, - result: undefined, - queueTime: new Date('2020-09-12T06:10:23.932Z'), - startTime: new Date('2020-09-12T06:15:23.932Z'), - finishTime: new Date('2020-09-12T06:20:23.932Z'), - sourceBranch: 'refs/heads/develop', - sourceVersion: 'f4f78b3100b2923982bdf60c89c57ce6fd2d9a1c', - definition: undefined, - _links: undefined, - requestedFor: inputIdentityRef, - }; + expect(result).toEqual([ + { + objectId: '1.0', + peeledObjectId: '1.0', + name: 'v1.0', + commitLink: 'serverUrl/project/_git/repo/commit/1.0', + createdBy: 'N/A', + link: 'serverUrl/project/_git/repo?version=GTv1.0', + }, + { + objectId: '2.0', + peeledObjectId: '2.0', + name: 'v2.0', + commitLink: 'serverUrl/project/_git/repo/commit/2.0', + createdBy: 'N/A', + link: 'serverUrl/project/_git/repo?version=GTv2.0', + }, + { + objectId: '3.0', + peeledObjectId: '3.0', + name: 'v3.0', + commitLink: 'serverUrl/project/_git/repo/commit/3.0', + createdBy: 'N/A', + link: 'serverUrl/project/_git/repo?version=GTv3.0', + }, + ]); + }); - const outputRepoBuild: RepoBuild = { - id: 1, - title: 'Build-1', - link: '', - status: BuildStatus.InProgress, - result: BuildResult.None, - queueTime: '2020-09-12T06:10:23.932Z', - startTime: '2020-09-12T06:15:23.932Z', - finishTime: '2020-09-12T06:20:23.932Z', - source: 'refs/heads/develop (f4f78b31)', - uniqueName: 'DOMAIN\\jdoe', - }; + it('should get pull requests', async () => { + const mockGitRepository: GitRepository = { + id: 'repo', + name: 'repo', + }; - expect(mappedBuildRun(inputBuild)).toEqual(outputRepoBuild); - }); + const mockGitPullRequests: GitPullRequest[] = [ + { + pullRequestId: 1, + repository: mockGitRepository, + title: 'PR1', + creationDate: new Date('2020-09-12T06:10:23.932Z'), + sourceRefName: 'refs/heads/topic/pr1', + targetRefName: 'refs/heads/main', + status: PullRequestStatus.Active, + isDraft: false, + }, + { + pullRequestId: 2, + repository: mockGitRepository, + title: 'PR2', + creationDate: new Date('2020-09-12T06:10:23.932Z'), + sourceRefName: 'refs/heads/topic/pr2', + targetRefName: 'refs/heads/main', + status: PullRequestStatus.Active, + isDraft: false, + }, + { + pullRequestId: 3, + repository: mockGitRepository, + title: 'PR3', + creationDate: new Date('2020-09-12T06:10:23.932Z'), + sourceRefName: 'refs/heads/topic/pr3', + targetRefName: 'refs/heads/main', + status: PullRequestStatus.Active, + isDraft: false, + }, + ]; + + const mockGitClient = { + getRepository: jest.fn().mockResolvedValue(mockGitRepository), + getPullRequests: jest.fn().mockResolvedValue(mockGitPullRequests), + }; + const mockApi = { + getGitApi: jest.fn().mockReturnValue(mockGitClient), + serverUrl: 'serverUrl', + }; + + (WebApi as unknown as jest.Mock).mockImplementation(() => mockApi); + + const api = AzureDevOpsApi.fromConfig(mockConfig, { + logger: mockLogger, + urlReader: mockUrlReader, }); + + const pullRequestOptions: PullRequestOptions = { + top: 10, + status: PullRequestStatus.Active, + }; + + const result = await api.getPullRequests( + 'project', + 'repo', + pullRequestOptions, + ); + + expect(result).toEqual([ + { + pullRequestId: 1, + repoName: 'repo', + title: 'PR1', + uniqueName: 'N/A', + createdBy: 'N/A', + creationDate: '2020-09-12T06:10:23.932Z', + sourceRefName: 'refs/heads/topic/pr1', + targetRefName: 'refs/heads/main', + status: PullRequestStatus.Active, + isDraft: false, + link: 'serverUrl/project/_git/repo/pullrequest/1', + }, + { + pullRequestId: 2, + repoName: 'repo', + title: 'PR2', + uniqueName: 'N/A', + createdBy: 'N/A', + creationDate: '2020-09-12T06:10:23.932Z', + sourceRefName: 'refs/heads/topic/pr2', + targetRefName: 'refs/heads/main', + status: PullRequestStatus.Active, + isDraft: false, + link: 'serverUrl/project/_git/repo/pullrequest/2', + }, + { + pullRequestId: 3, + repoName: 'repo', + title: 'PR3', + uniqueName: 'N/A', + createdBy: 'N/A', + creationDate: '2020-09-12T06:10:23.932Z', + sourceRefName: 'refs/heads/topic/pr3', + targetRefName: 'refs/heads/main', + status: PullRequestStatus.Active, + isDraft: false, + link: 'serverUrl/project/_git/repo/pullrequest/3', + }, + ]); + }); + + it('should get build definitions', async () => { + const mockBuilds: Build[] = [ + { + id: 1, + }, + { + id: 2, + }, + { + id: 3, + }, + ]; + + const mockBuildClient = { + getDefinitions: jest.fn().mockResolvedValue(mockBuilds), + }; + const mockBuildApi = { + getBuildApi: jest.fn().mockReturnValue(mockBuildClient), + }; + + (WebApi as unknown as jest.Mock).mockImplementation(() => mockBuildApi); + + const api = AzureDevOpsApi.fromConfig(mockConfig, { + logger: mockLogger, + urlReader: mockUrlReader, + }); + + const result = await api.getBuildDefinitions('project', 'definition'); + + expect(result).toEqual([{ id: 1 }, { id: 2 }, { id: 3 }]); + }); + + it('should get build builds with repoId', async () => { + const mockBuilds: Build[] = [ + { + id: 1, + }, + { + id: 2, + }, + { + id: 3, + }, + ]; + + const mockBuildClient = { + getBuilds: jest.fn().mockResolvedValue(mockBuilds), + }; + const mockBuildApi = { + getBuildApi: jest.fn().mockReturnValue(mockBuildClient), + }; + + (WebApi as unknown as jest.Mock).mockImplementation(() => mockBuildApi); + + const api = AzureDevOpsApi.fromConfig(mockConfig, { + logger: mockLogger, + urlReader: mockUrlReader, + }); + + const result = await api.getBuilds('project', 10, 'repo', undefined); + + expect(result).toEqual([{ id: 1 }, { id: 2 }, { id: 3 }]); + }); + + it('should get build builds with definitions', async () => { + const mockBuilds: Build[] = [ + { + id: 1, + }, + { + id: 2, + }, + { + id: 3, + }, + ]; + + const mockBuildClient = { + getBuilds: jest.fn().mockResolvedValue(mockBuilds), + }; + const mockBuildApi = { + getBuildApi: jest.fn().mockReturnValue(mockBuildClient), + }; + + (WebApi as unknown as jest.Mock).mockImplementation(() => mockBuildApi); + + const api = AzureDevOpsApi.fromConfig(mockConfig, { + logger: mockLogger, + urlReader: mockUrlReader, + }); + + const result = await api.getBuilds('project', 10, undefined, [1, 2, 3]); + + expect(result).toEqual([{ id: 1 }, { id: 2 }, { id: 3 }]); + }); + + it('should get build runs with repoName', async () => { + const mockGitRepository: GitRepository = { + id: 'repo', + }; + + const mockBuilds: Build[] = [ + { + id: 1, + buildNumber: 'Build-1', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'main', + sourceVersion: 'abcd', + }, + { + id: 2, + buildNumber: 'Build-2', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'main', + sourceVersion: 'abcd', + }, + { + id: 3, + buildNumber: 'Build-3', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'main', + sourceVersion: 'abcd', + }, + ]; + + const mockBuildClient = { + getBuilds: jest.fn().mockResolvedValue(mockBuilds), + }; + const mockGitClient = { + getRepository: jest.fn().mockResolvedValue(mockGitRepository), + }; + const mockApi = { + getGitApi: jest.fn().mockReturnValue(mockGitClient), + getBuildApi: jest.fn().mockReturnValue(mockBuildClient), + }; + + (WebApi as unknown as jest.Mock).mockImplementation(() => mockApi); + + const api = AzureDevOpsApi.fromConfig(mockConfig, { + logger: mockLogger, + urlReader: mockUrlReader, + }); + + const result = await api.getBuildRuns('project', 10, 'repo', undefined); + + expect(result).toEqual([ + { + id: 1, + title: 'Build-1', + link: '', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'main (abcd)', + uniqueName: 'N/A', + }, + { + id: 2, + title: 'Build-2', + link: '', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'main (abcd)', + uniqueName: 'N/A', + }, + { + id: 3, + title: 'Build-3', + link: '', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'main (abcd)', + uniqueName: 'N/A', + }, + ]); + }); + + it('should get build runs with definitionName', async () => { + const mockBuilds: Build[] = [ + { + id: 1, + buildNumber: 'Build-1', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'main', + sourceVersion: 'abcd', + }, + { + id: 2, + buildNumber: 'Build-2', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'main', + sourceVersion: 'abcd', + }, + { + id: 3, + buildNumber: 'Build-3', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'main', + sourceVersion: 'abcd', + }, + ]; + + const mockBuildClient = { + getBuilds: jest.fn().mockResolvedValue(mockBuilds), + getDefinitions: jest.fn().mockResolvedValue(mockBuilds), + }; + + const mockApi = { + getBuildApi: jest.fn().mockReturnValue(mockBuildClient), + }; + + (WebApi as unknown as jest.Mock).mockImplementation(() => mockApi); + + const api = AzureDevOpsApi.fromConfig(mockConfig, { + logger: mockLogger, + urlReader: mockUrlReader, + }); + + const result = await api.getBuildRuns( + 'project', + 10, + undefined, + 'definition', + ); + + expect(result).toEqual([ + { + id: 1, + title: 'Build-1', + link: '', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'main (abcd)', + uniqueName: 'N/A', + }, + { + id: 2, + title: 'Build-2', + link: '', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'main (abcd)', + uniqueName: 'N/A', + }, + { + id: 3, + title: 'Build-3', + link: '', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'main (abcd)', + uniqueName: 'N/A', + }, + ]); }); }); diff --git a/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts b/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts index 87ded2f0e9..d50888006b 100644 --- a/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts +++ b/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts @@ -19,9 +19,7 @@ import { BuildDefinitionReference, } from 'azure-devops-node-api/interfaces/BuildInterfaces'; import { - BuildResult, BuildRun, - BuildStatus, DashboardPullRequest, GitTag, Policy, @@ -49,23 +47,92 @@ import { import { TeamMember as AdoTeamMember } from 'azure-devops-node-api/interfaces/common/VSSInterfaces'; import { Logger } from 'winston'; import { PolicyEvaluationRecord } from 'azure-devops-node-api/interfaces/PolicyInterfaces'; -import { WebApi } from 'azure-devops-node-api'; +import { + WebApi, + getHandlerFromToken, + getPersonalAccessTokenHandler, +} from 'azure-devops-node-api'; import { TeamProjectReference, WebApiTeam, } from 'azure-devops-node-api/interfaces/CoreInterfaces'; import { UrlReader } from '@backstage/backend-common'; +import { Config } from '@backstage/config'; +import { + AzureDevOpsCredentialsProvider, + DefaultAzureDevOpsCredentialsProvider, + ScmIntegrations, +} from '@backstage/integration'; +import { + mappedBuildRun, + mappedGitTag, + mappedPullRequest, + mappedRepoBuild, +} from './mappers'; /** @public */ export class AzureDevOpsApi { - public constructor( - private readonly logger: Logger, - private readonly webApi: WebApi, - private readonly urlReader: UrlReader, - ) {} + private readonly logger: Logger; + private readonly urlReader: UrlReader; + private readonly config: Config; + private readonly credentialsProvider: AzureDevOpsCredentialsProvider; - public async getProjects(): Promise { - const client = await this.webApi.getCoreApi(); + private constructor( + logger: Logger, + urlReader: UrlReader, + config: Config, + credentialsProvider: AzureDevOpsCredentialsProvider, + ) { + this.logger = logger; + this.urlReader = urlReader; + this.config = config; + this.credentialsProvider = credentialsProvider; + } + + static fromConfig( + config: Config, + options: { logger: Logger; urlReader: UrlReader }, + ) { + const scmIntegrations = ScmIntegrations.fromConfig(config); + const credentialsProvider = + DefaultAzureDevOpsCredentialsProvider.fromIntegrations(scmIntegrations); + return new AzureDevOpsApi( + options.logger, + options.urlReader, + config, + credentialsProvider, + ); + } + + private async getWebApi(host?: string, org?: string): Promise { + // If no host or org is provided we fall back to the values from the `azureDevOps` config section + // these may have been setup in the `integrations.azure` config section + // which is why use them here and not just falling back on them entirely + const validHost = host ?? this.config.getString('azureDevOps.host'); + const validOrg = org ?? this.config.getString('azureDevOps.organization'); + const url = `https://${validHost}/${encodeURIComponent(validOrg)}`; + + const credentials = await this.credentialsProvider.getCredentials({ + url, + }); + + let authHandler; + if (!credentials) { + // No credentials found for the provided host and org in the `integrations.azure` config section + // use the fall back personal access token from `azureDevOps.token` + const token = this.config.getString('azureDevOps.token'); + authHandler = getPersonalAccessTokenHandler(token); + } else { + authHandler = getHandlerFromToken(credentials.token); + } + + const webApi = new WebApi(url, authHandler); + return webApi; + } + + public async getProjects(host?: string, org?: string): Promise { + const webApi = await this.getWebApi(host, org); + const client = await webApi.getCoreApi(); const projectList: TeamProjectReference[] = await client.getProjects(); const projects: Project[] = projectList.map(project => ({ @@ -82,12 +149,15 @@ export class AzureDevOpsApi { public async getGitRepository( projectName: string, repoName: string, + host?: string, + org?: string, ): Promise { this.logger?.debug( `Calling Azure DevOps REST API, getting Repository ${repoName} for Project ${projectName}`, ); - const client = await this.webApi.getGitApi(); + const webApi = await this.getWebApi(host, org); + const client = await webApi.getGitApi(); return client.getRepository(repoName, projectName); } @@ -95,12 +165,15 @@ export class AzureDevOpsApi { projectName: string, repoId: string, top: number, + host?: string, + org?: string, ): Promise { this.logger?.debug( `Calling Azure DevOps REST API, getting up to ${top} Builds for Repository Id ${repoId} for Project ${projectName}`, ); - const client = await this.webApi.getBuildApi(); + const webApi = await this.getWebApi(host, org); + const client = await webApi.getBuildApi(); return client.getBuilds( projectName, undefined, @@ -130,16 +203,25 @@ export class AzureDevOpsApi { projectName: string, repoName: string, top: number, + host?: string, + org?: string, ) { this.logger?.debug( `Calling Azure DevOps REST API, getting up to ${top} Builds for Repository ${repoName} for Project ${projectName}`, ); - const gitRepository = await this.getGitRepository(projectName, repoName); + const gitRepository = await this.getGitRepository( + projectName, + repoName, + host, + org, + ); const buildList = await this.getBuildList( projectName, gitRepository.id as string, top, + host, + org, ); const repoBuilds: RepoBuild[] = buildList.map(build => { @@ -152,13 +234,21 @@ export class AzureDevOpsApi { public async getGitTags( projectName: string, repoName: string, + host?: string, + org?: string, ): Promise { this.logger?.debug( `Calling Azure DevOps REST API, getting Git Tags for Repository ${repoName} for Project ${projectName}`, ); - const gitRepository = await this.getGitRepository(projectName, repoName); - const client = await this.webApi.getGitApi(); + const gitRepository = await this.getGitRepository( + projectName, + repoName, + host, + org, + ); + const webApi = await this.getWebApi(host, org); + const client = await webApi.getGitApi(); const tagRefs: GitRef[] = await client.getRefs( gitRepository.id as string, projectName, @@ -169,10 +259,10 @@ export class AzureDevOpsApi { false, true, ); - const linkBaseUrl = `${this.webApi.serverUrl}/${encodeURIComponent( + const linkBaseUrl = `${webApi.serverUrl}/${encodeURIComponent( projectName, )}/_git/${encodeURIComponent(repoName)}?version=GT`; - const commitBaseUrl = `${this.webApi.serverUrl}/${encodeURIComponent( + const commitBaseUrl = `${webApi.serverUrl}/${encodeURIComponent( projectName, )}/_git/${encodeURIComponent(repoName)}/commit`; const gitTags: GitTag[] = tagRefs.map(tagRef => { @@ -186,13 +276,21 @@ export class AzureDevOpsApi { projectName: string, repoName: string, options: PullRequestOptions, + host?: string, + org?: string, ): Promise { this.logger?.debug( `Calling Azure DevOps REST API, getting up to ${options.top} Pull Requests for Repository ${repoName} for Project ${projectName}`, ); - const gitRepository = await this.getGitRepository(projectName, repoName); - const client = await this.webApi.getGitApi(); + const gitRepository = await this.getGitRepository( + projectName, + repoName, + host, + org, + ); + const webApi = await this.getWebApi(host, org); + const client = await webApi.getGitApi(); const searchCriteria: GitPullRequestSearchCriteria = { status: options.status, }; @@ -204,7 +302,7 @@ export class AzureDevOpsApi { undefined, options.top, ); - const linkBaseUrl = `${this.webApi.serverUrl}/${encodeURIComponent( + const linkBaseUrl = `${webApi.serverUrl}/${encodeURIComponent( projectName, )}/_git/${encodeURIComponent(repoName)}/pullrequest`; const pullRequests: PullRequest[] = gitPullRequests.map(gitPullRequest => { @@ -222,7 +320,8 @@ export class AzureDevOpsApi { `Getting dashboard pull requests for project '${projectName}'.`, ); - const client = await this.webApi.getGitApi(); + const webApi = await this.getWebApi(); + const client = await webApi.getGitApi(); const searchCriteria: GitPullRequestSearchCriteria = { status: options.status, @@ -254,7 +353,7 @@ export class AzureDevOpsApi { return convertDashboardPullRequest( gitPullRequest, - this.webApi.serverUrl, + webApi.serverUrl, policies, ); }), @@ -270,7 +369,8 @@ export class AzureDevOpsApi { `Getting pull request policies for pull request id '${pullRequestId}'.`, ); - const client = await this.webApi.getPolicyApi(); + const webApi = await this.getWebApi(); + const client = await webApi.getPolicyApi(); const artifactId = getArtifactId(projectId, pullRequestId); @@ -285,7 +385,8 @@ export class AzureDevOpsApi { public async getAllTeams(): Promise { this.logger?.debug('Getting all teams.'); - const client = await this.webApi.getCoreApi(); + const webApi = await this.getWebApi(); + const client = await webApi.getCoreApi(); const webApiTeams: WebApiTeam[] = await client.getAllTeams(); const teams: Team[] = webApiTeams.map(team => ({ @@ -307,7 +408,8 @@ export class AzureDevOpsApi { const { projectId, teamId } = options; this.logger?.debug(`Getting team member ids for team '${teamId}'.`); - const client = await this.webApi.getCoreApi(); + const webApi = await this.getWebApi(); + const client = await webApi.getCoreApi(); const teamMembers: AdoTeamMember[] = await client.getTeamMembersWithExtendedProperties(projectId, teamId); @@ -322,12 +424,15 @@ export class AzureDevOpsApi { public async getBuildDefinitions( projectName: string, definitionName: string, + host?: string, + org?: string, ): Promise { this.logger?.debug( `Calling Azure DevOps REST API, getting Build Definitions for ${definitionName} in Project ${projectName}`, ); - const client = await this.webApi.getBuildApi(); + const webApi = await this.getWebApi(host, org); + const client = await webApi.getBuildApi(); return client.getDefinitions(projectName, definitionName); } @@ -336,12 +441,15 @@ export class AzureDevOpsApi { top: number, repoId?: string, definitions?: number[], + host?: string, + org?: string, ): Promise { this.logger?.debug( `Calling Azure DevOps REST API, getting up to ${top} Builds for Repository Id ${repoId} for Project ${projectName}`, ); - const client = await this.webApi.getBuildApi(); + const webApi = await this.getWebApi(host, org); + const client = await webApi.getBuildApi(); return client.getBuilds( projectName, definitions, @@ -372,12 +480,19 @@ export class AzureDevOpsApi { top: number, repoName?: string, definitionName?: string, + host?: string, + org?: string, ) { let repoId: string | undefined; let definitions: number[] | undefined; if (repoName) { - const gitRepository = await this.getGitRepository(projectName, repoName); + const gitRepository = await this.getGitRepository( + projectName, + repoName, + host, + org, + ); repoId = gitRepository.id; } @@ -385,13 +500,22 @@ export class AzureDevOpsApi { const buildDefinitions = await this.getBuildDefinitions( projectName, definitionName, + host, + org, ); definitions = buildDefinitions .map(bd => bd.id) .filter((bd): bd is number => Boolean(bd)); } - const builds = await this.getBuilds(projectName, top, repoId, definitions); + const builds = await this.getBuilds( + projectName, + top, + repoId, + definitions, + host, + org, + ); const buildRuns: BuildRun[] = builds.map(mappedBuildRun); @@ -421,75 +545,3 @@ export class AzureDevOpsApi { return { url, content }; } } - -export function mappedRepoBuild(build: Build): RepoBuild { - return { - id: build.id, - title: [build.definition?.name, build.buildNumber] - .filter(Boolean) - .join(' - '), - link: build._links?.web.href ?? '', - status: build.status ?? BuildStatus.None, - result: build.result ?? BuildResult.None, - queueTime: build.queueTime?.toISOString(), - startTime: build.startTime?.toISOString(), - finishTime: build.finishTime?.toISOString(), - source: `${build.sourceBranch} (${build.sourceVersion?.slice(0, 8)})`, - uniqueName: build.requestedFor?.uniqueName ?? 'N/A', - }; -} - -export function mappedGitTag( - gitRef: GitRef, - linkBaseUrl: string, - commitBaseUrl: string, -): GitTag { - return { - objectId: gitRef.objectId, - peeledObjectId: gitRef.peeledObjectId, - name: gitRef.name?.replace('refs/tags/', ''), - createdBy: gitRef.creator?.displayName ?? 'N/A', - link: `${linkBaseUrl}${encodeURIComponent( - gitRef.name?.replace('refs/tags/', '') ?? '', - )}`, - commitLink: `${commitBaseUrl}/${encodeURIComponent( - gitRef.peeledObjectId ?? '', - )}`, - }; -} - -export function mappedPullRequest( - pullRequest: GitPullRequest, - linkBaseUrl: string, -): PullRequest { - return { - pullRequestId: pullRequest.pullRequestId, - repoName: pullRequest.repository?.name, - title: pullRequest.title, - uniqueName: pullRequest.createdBy?.uniqueName ?? 'N/A', - createdBy: pullRequest.createdBy?.displayName ?? 'N/A', - creationDate: pullRequest.creationDate?.toISOString(), - sourceRefName: pullRequest.sourceRefName, - targetRefName: pullRequest.targetRefName, - status: pullRequest.status, - isDraft: pullRequest.isDraft, - link: `${linkBaseUrl}/${pullRequest.pullRequestId}`, - }; -} - -export function mappedBuildRun(build: Build): BuildRun { - return { - id: build.id, - title: [build.definition?.name, build.buildNumber] - .filter(Boolean) - .join(' - '), - link: build._links?.web.href ?? '', - status: build.status ?? BuildStatus.None, - result: build.result ?? BuildResult.None, - queueTime: build.queueTime?.toISOString(), - startTime: build.startTime?.toISOString(), - finishTime: build.finishTime?.toISOString(), - source: `${build.sourceBranch} (${build.sourceVersion?.slice(0, 8)})`, - uniqueName: build.requestedFor?.uniqueName ?? 'N/A', - }; -} diff --git a/plugins/azure-devops-backend/src/api/mappers.test.ts b/plugins/azure-devops-backend/src/api/mappers.test.ts new file mode 100644 index 0000000000..5f7fe5eb28 --- /dev/null +++ b/plugins/azure-devops-backend/src/api/mappers.test.ts @@ -0,0 +1,573 @@ +/* + * 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 { + Build, + DefinitionReference, +} from 'azure-devops-node-api/interfaces/BuildInterfaces'; +import { + BuildResult, + BuildStatus, + GitTag, + PullRequest, + PullRequestStatus, + RepoBuild, +} from '@backstage/plugin-azure-devops-common'; +import { + GitPullRequest, + GitRef, + GitRepository, +} from 'azure-devops-node-api/interfaces/GitInterfaces'; +import { + mappedBuildRun, + mappedGitTag, + mappedPullRequest, + mappedRepoBuild, +} from './mappers'; + +import { IdentityRef } from 'azure-devops-node-api/interfaces/common/VSSInterfaces'; + +describe('mappers', () => { + describe('mappedRepoBuild', () => { + describe('mappedRepoBuild happy path', () => { + it('should return RepoBuild from Build', () => { + const inputBuildDefinition: DefinitionReference = { + name: 'My Build Definition', + }; + + const inputLinks: any = { + web: { + href: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', + }, + }; + + const inputIdentityRef: IdentityRef = { + displayName: 'Jane Doe', + uniqueName: 'DOMAIN\\jdoe', + }; + + const inputBuild: Build = { + id: 1, + buildNumber: 'Build-1', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'refs/heads/develop', + sourceVersion: 'f4f78b3100b2923982bdf60c89c57ce6fd2d9a1c', + definition: inputBuildDefinition, + _links: inputLinks, + requestedFor: inputIdentityRef, + }; + + const outputRepoBuild: RepoBuild = { + id: 1, + title: 'My Build Definition - Build-1', + link: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'refs/heads/develop (f4f78b31)', + uniqueName: 'DOMAIN\\jdoe', + }; + + expect(mappedRepoBuild(inputBuild)).toEqual(outputRepoBuild); + }); + }); + + describe('mappedRepoBuild with no Build definition name', () => { + it('should return RepoBuild with only Build Number for title', () => { + const inputLinks: any = { + web: { + href: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', + }, + }; + + const inputIdentityRef: IdentityRef = { + displayName: 'Jane Doe', + uniqueName: 'DOMAIN\\jdoe', + }; + + const inputBuild: Build = { + id: 1, + buildNumber: 'Build-1', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'refs/heads/develop', + sourceVersion: 'f4f78b3100b2923982bdf60c89c57ce6fd2d9a1c', + definition: undefined, + _links: inputLinks, + requestedFor: inputIdentityRef, + }; + + const outputRepoBuild: RepoBuild = { + id: 1, + title: 'Build-1', + link: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'refs/heads/develop (f4f78b31)', + uniqueName: 'DOMAIN\\jdoe', + }; + + expect(mappedRepoBuild(inputBuild)).toEqual(outputRepoBuild); + }); + }); + + describe('mappedRepoBuild with undefined status', () => { + it('should return BuildStatus of None for status', () => { + const inputLinks: any = { + web: { + href: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', + }, + }; + + const inputIdentityRef: IdentityRef = { + displayName: 'Jane Doe', + uniqueName: 'DOMAIN\\jdoe', + }; + + const inputBuild: Build = { + id: 1, + buildNumber: 'Build-1', + status: undefined, + result: BuildResult.Succeeded, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'refs/heads/develop', + sourceVersion: 'f4f78b3100b2923982bdf60c89c57ce6fd2d9a1c', + definition: undefined, + _links: inputLinks, + requestedFor: inputIdentityRef, + }; + + const outputRepoBuild: RepoBuild = { + id: 1, + title: 'Build-1', + link: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', + status: BuildStatus.None, + result: BuildResult.Succeeded, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'refs/heads/develop (f4f78b31)', + uniqueName: 'DOMAIN\\jdoe', + }; + + expect(mappedRepoBuild(inputBuild)).toEqual(outputRepoBuild); + }); + }); + + describe('mappedRepoBuild with undefined result', () => { + it('should return BuildResult of None for result', () => { + const inputLinks: any = { + web: { + href: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', + }, + }; + + const inputIdentityRef: IdentityRef = { + displayName: 'Jane Doe', + uniqueName: 'DOMAIN\\jdoe', + }; + + const inputBuild: Build = { + id: 1, + buildNumber: 'Build-1', + status: BuildStatus.InProgress, + result: undefined, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'refs/heads/develop', + sourceVersion: 'f4f78b3100b2923982bdf60c89c57ce6fd2d9a1c', + definition: undefined, + _links: inputLinks, + requestedFor: inputIdentityRef, + }; + + const outputRepoBuild: RepoBuild = { + id: 1, + title: 'Build-1', + link: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', + status: BuildStatus.InProgress, + result: BuildResult.None, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'refs/heads/develop (f4f78b31)', + uniqueName: 'DOMAIN\\jdoe', + }; + + expect(mappedRepoBuild(inputBuild)).toEqual(outputRepoBuild); + }); + }); + + describe('mappedRepoBuild with undefined link', () => { + it('should return empty string for link', () => { + const inputIdentityRef: IdentityRef = { + displayName: 'Jane Doe', + uniqueName: 'DOMAIN\\jdoe', + }; + + const inputBuild: Build = { + id: 1, + buildNumber: 'Build-1', + status: BuildStatus.InProgress, + result: undefined, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'refs/heads/develop', + sourceVersion: 'f4f78b3100b2923982bdf60c89c57ce6fd2d9a1c', + definition: undefined, + _links: undefined, + requestedFor: inputIdentityRef, + }; + + const outputRepoBuild: RepoBuild = { + id: 1, + title: 'Build-1', + link: '', + status: BuildStatus.InProgress, + result: BuildResult.None, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'refs/heads/develop (f4f78b31)', + uniqueName: 'DOMAIN\\jdoe', + }; + + expect(mappedRepoBuild(inputBuild)).toEqual(outputRepoBuild); + }); + }); + }); + + describe('mappedGitTag', () => { + describe('mappedGitTag happy path', () => { + it('should return GitTag from GitRef', () => { + const inputIdentityRef: IdentityRef = { + displayName: 'Jane Doe', + }; + const inputGitRef: GitRef = { + name: 'refs/tags/v1.1.2', + creator: inputIdentityRef, + objectId: '1111aaaa2222bbbb3333cccc4444dddd5555eeee', + peeledObjectId: '1234567890abcdef1234567890abcdef12345678', + }; + const inputLinkBaseUrl = + 'https://host.com/myOrg/_git/super-feature-repo?version=GT'; + const inputCommitBaseUrl = + 'https://host.com/myOrg/_git/super-feature-repo/commit'; + const outputGitTag: GitTag = { + name: 'v1.1.2', + createdBy: 'Jane Doe', + commitLink: + 'https://host.com/myOrg/_git/super-feature-repo/commit/1234567890abcdef1234567890abcdef12345678', + objectId: '1111aaaa2222bbbb3333cccc4444dddd5555eeee', + peeledObjectId: '1234567890abcdef1234567890abcdef12345678', + link: 'https://host.com/myOrg/_git/super-feature-repo?version=GTv1.1.2', + }; + expect( + mappedGitTag(inputGitRef, inputLinkBaseUrl, inputCommitBaseUrl), + ).toEqual(outputGitTag); + }); + }); + }); + + describe('mappedPullRequest', () => { + describe('mappedPullRequest happy path', () => { + it('should return PullRequest from GitPullRequest', () => { + const inputGitRepository: GitRepository = { + name: 'super-feature-repo', + }; + + const inputIdentityRef: IdentityRef = { + displayName: 'Jane Doe', + uniqueName: 'DOMAIN\\jdoe', + }; + + const inputPullRequest: GitPullRequest = { + pullRequestId: 7181, + repository: inputGitRepository, + title: 'My Awesome New Feature', + createdBy: inputIdentityRef, + creationDate: new Date('2020-09-12T06:10:23.932Z'), + sourceRefName: 'refs/heads/topic/super-awesome-feature', + targetRefName: 'refs/heads/main', + status: PullRequestStatus.Active, + isDraft: false, + }; + + const inputBaseUrl = + 'https://host.com/myOrg/_git/super-feature-repo/pullrequest'; + + const outputPullRequest: PullRequest = { + pullRequestId: 7181, + repoName: 'super-feature-repo', + title: 'My Awesome New Feature', + uniqueName: 'DOMAIN\\jdoe', + createdBy: 'Jane Doe', + creationDate: '2020-09-12T06:10:23.932Z', + sourceRefName: 'refs/heads/topic/super-awesome-feature', + targetRefName: 'refs/heads/main', + status: PullRequestStatus.Active, + isDraft: false, + link: 'https://host.com/myOrg/_git/super-feature-repo/pullrequest/7181', + }; + + expect(mappedPullRequest(inputPullRequest, inputBaseUrl)).toEqual( + outputPullRequest, + ); + }); + }); + }); + + describe('mappedBuildRun', () => { + describe('mappedBuildRun happy path', () => { + it('should return RepoBuild from Build', () => { + const inputBuildDefinition: DefinitionReference = { + name: 'My Build Definition', + }; + + const inputLinks: any = { + web: { + href: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', + }, + }; + + const inputIdentityRef: IdentityRef = { + displayName: 'Jane Doe', + uniqueName: 'DOMAIN\\jdoe', + }; + + const inputBuild: Build = { + id: 1, + buildNumber: 'Build-1', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'refs/heads/develop', + sourceVersion: 'f4f78b3100b2923982bdf60c89c57ce6fd2d9a1c', + definition: inputBuildDefinition, + _links: inputLinks, + requestedFor: inputIdentityRef, + }; + + const outputRepoBuild: RepoBuild = { + id: 1, + title: 'My Build Definition - Build-1', + link: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'refs/heads/develop (f4f78b31)', + uniqueName: 'DOMAIN\\jdoe', + }; + + expect(mappedBuildRun(inputBuild)).toEqual(outputRepoBuild); + }); + }); + + describe('mappedBuildRun with no Build definition name', () => { + it('should return RepoBuild with only Build Number for title', () => { + const inputLinks: any = { + web: { + href: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', + }, + }; + + const inputIdentityRef: IdentityRef = { + displayName: 'Jane Doe', + uniqueName: 'DOMAIN\\jdoe', + }; + + const inputBuild: Build = { + id: 1, + buildNumber: 'Build-1', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'refs/heads/develop', + sourceVersion: 'f4f78b3100b2923982bdf60c89c57ce6fd2d9a1c', + definition: undefined, + _links: inputLinks, + requestedFor: inputIdentityRef, + }; + + const outputRepoBuild: RepoBuild = { + id: 1, + title: 'Build-1', + link: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'refs/heads/develop (f4f78b31)', + uniqueName: 'DOMAIN\\jdoe', + }; + + expect(mappedBuildRun(inputBuild)).toEqual(outputRepoBuild); + }); + }); + + describe('mappedBuildRun with undefined status', () => { + it('should return BuildStatus of None for status', () => { + const inputLinks: any = { + web: { + href: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', + }, + }; + + const inputIdentityRef: IdentityRef = { + displayName: 'Jane Doe', + uniqueName: 'DOMAIN\\jdoe', + }; + + const inputBuild: Build = { + id: 1, + buildNumber: 'Build-1', + status: undefined, + result: BuildResult.Succeeded, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'refs/heads/develop', + sourceVersion: 'f4f78b3100b2923982bdf60c89c57ce6fd2d9a1c', + definition: undefined, + _links: inputLinks, + requestedFor: inputIdentityRef, + }; + + const outputRepoBuild: RepoBuild = { + id: 1, + title: 'Build-1', + link: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', + status: BuildStatus.None, + result: BuildResult.Succeeded, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'refs/heads/develop (f4f78b31)', + uniqueName: 'DOMAIN\\jdoe', + }; + + expect(mappedBuildRun(inputBuild)).toEqual(outputRepoBuild); + }); + }); + + describe('mappedBuildRun with undefined result', () => { + it('should return BuildResult of None for result', () => { + const inputLinks: any = { + web: { + href: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', + }, + }; + + const inputIdentityRef: IdentityRef = { + displayName: 'Jane Doe', + uniqueName: 'DOMAIN\\jdoe', + }; + + const inputBuild: Build = { + id: 1, + buildNumber: 'Build-1', + status: BuildStatus.InProgress, + result: undefined, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'refs/heads/develop', + sourceVersion: 'f4f78b3100b2923982bdf60c89c57ce6fd2d9a1c', + definition: undefined, + _links: inputLinks, + requestedFor: inputIdentityRef, + }; + + const outputRepoBuild: RepoBuild = { + id: 1, + title: 'Build-1', + link: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', + status: BuildStatus.InProgress, + result: BuildResult.None, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'refs/heads/develop (f4f78b31)', + uniqueName: 'DOMAIN\\jdoe', + }; + + expect(mappedBuildRun(inputBuild)).toEqual(outputRepoBuild); + }); + }); + + describe('mappedBuildRun with undefined link', () => { + it('should return empty string for link', () => { + const inputIdentityRef: IdentityRef = { + displayName: 'Jane Doe', + uniqueName: 'DOMAIN\\jdoe', + }; + + const inputBuild: Build = { + id: 1, + buildNumber: 'Build-1', + status: BuildStatus.InProgress, + result: undefined, + queueTime: new Date('2020-09-12T06:10:23.932Z'), + startTime: new Date('2020-09-12T06:15:23.932Z'), + finishTime: new Date('2020-09-12T06:20:23.932Z'), + sourceBranch: 'refs/heads/develop', + sourceVersion: 'f4f78b3100b2923982bdf60c89c57ce6fd2d9a1c', + definition: undefined, + _links: undefined, + requestedFor: inputIdentityRef, + }; + + const outputRepoBuild: RepoBuild = { + id: 1, + title: 'Build-1', + link: '', + status: BuildStatus.InProgress, + result: BuildResult.None, + queueTime: '2020-09-12T06:10:23.932Z', + startTime: '2020-09-12T06:15:23.932Z', + finishTime: '2020-09-12T06:20:23.932Z', + source: 'refs/heads/develop (f4f78b31)', + uniqueName: 'DOMAIN\\jdoe', + }; + + expect(mappedBuildRun(inputBuild)).toEqual(outputRepoBuild); + }); + }); + }); +}); diff --git a/plugins/azure-devops-backend/src/api/mappers.ts b/plugins/azure-devops-backend/src/api/mappers.ts new file mode 100644 index 0000000000..72097a25b8 --- /dev/null +++ b/plugins/azure-devops-backend/src/api/mappers.ts @@ -0,0 +1,101 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + RepoBuild, + BuildStatus, + BuildResult, + GitTag, + PullRequest, + BuildRun, +} from '@backstage/plugin-azure-devops-common'; +import { Build } from 'azure-devops-node-api/interfaces/BuildInterfaces'; +import { + GitRef, + GitPullRequest, +} from 'azure-devops-node-api/interfaces/GitInterfaces'; + +export function mappedRepoBuild(build: Build): RepoBuild { + return { + id: build.id, + title: [build.definition?.name, build.buildNumber] + .filter(Boolean) + .join(' - '), + link: build._links?.web.href ?? '', + status: build.status ?? BuildStatus.None, + result: build.result ?? BuildResult.None, + queueTime: build.queueTime?.toISOString(), + startTime: build.startTime?.toISOString(), + finishTime: build.finishTime?.toISOString(), + source: `${build.sourceBranch} (${build.sourceVersion?.slice(0, 8)})`, + uniqueName: build.requestedFor?.uniqueName ?? 'N/A', + }; +} + +export function mappedGitTag( + gitRef: GitRef, + linkBaseUrl: string, + commitBaseUrl: string, +): GitTag { + return { + objectId: gitRef.objectId, + peeledObjectId: gitRef.peeledObjectId, + name: gitRef.name?.replace('refs/tags/', ''), + createdBy: gitRef.creator?.displayName ?? 'N/A', + link: `${linkBaseUrl}${encodeURIComponent( + gitRef.name?.replace('refs/tags/', '') ?? '', + )}`, + commitLink: `${commitBaseUrl}/${encodeURIComponent( + gitRef.peeledObjectId ?? '', + )}`, + }; +} + +export function mappedPullRequest( + pullRequest: GitPullRequest, + linkBaseUrl: string, +): PullRequest { + return { + pullRequestId: pullRequest.pullRequestId, + repoName: pullRequest.repository?.name, + title: pullRequest.title, + uniqueName: pullRequest.createdBy?.uniqueName ?? 'N/A', + createdBy: pullRequest.createdBy?.displayName ?? 'N/A', + creationDate: pullRequest.creationDate?.toISOString(), + sourceRefName: pullRequest.sourceRefName, + targetRefName: pullRequest.targetRefName, + status: pullRequest.status, + isDraft: pullRequest.isDraft, + link: `${linkBaseUrl}/${pullRequest.pullRequestId}`, + }; +} + +export function mappedBuildRun(build: Build): BuildRun { + return { + id: build.id, + title: [build.definition?.name, build.buildNumber] + .filter(Boolean) + .join(' - '), + link: build._links?.web.href ?? '', + status: build.status ?? BuildStatus.None, + result: build.result ?? BuildResult.None, + queueTime: build.queueTime?.toISOString(), + startTime: build.startTime?.toISOString(), + finishTime: build.finishTime?.toISOString(), + source: `${build.sourceBranch} (${build.sourceVersion?.slice(0, 8)})`, + uniqueName: build.requestedFor?.uniqueName ?? 'N/A', + }; +} diff --git a/plugins/azure-devops-backend/src/index.ts b/plugins/azure-devops-backend/src/index.ts index 3c802e7144..61cf7c7a6f 100644 --- a/plugins/azure-devops-backend/src/index.ts +++ b/plugins/azure-devops-backend/src/index.ts @@ -23,3 +23,4 @@ export { AzureDevOpsApi } from './api'; export * from './service/router'; export { azureDevOpsPlugin as default } from './plugin'; +export { AzureDevOpsAnnotatorProcessor } from './processor'; diff --git a/plugins/azure-devops-backend/src/processor/AzureDevOpsAnnotatorProcessor.test.ts b/plugins/azure-devops-backend/src/processor/AzureDevOpsAnnotatorProcessor.test.ts new file mode 100644 index 0000000000..dd83c56f70 --- /dev/null +++ b/plugins/azure-devops-backend/src/processor/AzureDevOpsAnnotatorProcessor.test.ts @@ -0,0 +1,271 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { Entity } from '@backstage/catalog-model'; +import { ConfigReader } from '@backstage/config'; +import { AzureDevOpsAnnotatorProcessor } from './AzureDevOpsAnnotatorProcessor'; +import { LocationSpec } from '@backstage/plugin-catalog-common'; + +describe('AzureDevOpsAnnotatorProcessor', () => { + it('adds annotation', async () => { + const entity: Entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'my-component', + }, + }; + const location: LocationSpec = { + type: 'url', + target: + 'https://dev.azure.com/organization/project/_git/repository?path=%2Fcatalog-info.yaml', + }; + + const processor = AzureDevOpsAnnotatorProcessor.fromConfig( + new ConfigReader({}), + ); + + expect(await processor.preProcessEntity(entity, location)).toEqual({ + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'my-component', + annotations: { + 'dev.azure.com/host-org': 'dev.azure.com/organization', + 'dev.azure.com/project-repo': 'project/repository', + }, + }, + }); + }); + + it('adds annotation for Azure DevOps Server url', async () => { + const entity: Entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'my-component', + }, + }; + const location: LocationSpec = { + type: 'url', + target: + 'https://example.com/organization/project/_git/repository?path=%2Fcatalog-info.yaml', + }; + + const processor = AzureDevOpsAnnotatorProcessor.fromConfig( + new ConfigReader({ + integrations: { + azure: [ + { + host: 'example.com', + credentials: [ + { + personalAccessToken: 'pat', + }, + ], + }, + ], + }, + }), + ); + + expect(await processor.preProcessEntity(entity, location)).toEqual({ + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'my-component', + annotations: { + 'dev.azure.com/host-org': 'example.com/organization', + 'dev.azure.com/project-repo': 'project/repository', + }, + }, + }); + }); + + it('adds annotation for TFS subpath url', async () => { + const entity: Entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'my-component', + }, + }; + const location: LocationSpec = { + type: 'url', + target: + 'https://example.com/tfs/organization/project/_git/repository?path=%2Fcatalog-info.yaml', + }; + + const processor = AzureDevOpsAnnotatorProcessor.fromConfig( + new ConfigReader({ + integrations: { + azure: [ + { + host: 'example.com', + credentials: [ + { + personalAccessToken: 'pat', + }, + ], + }, + ], + }, + }), + ); + + expect(await processor.preProcessEntity(entity, location)).toEqual({ + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'my-component', + annotations: { + 'dev.azure.com/host-org': 'example.com/tfs/organization', + 'dev.azure.com/project-repo': 'project/repository', + }, + }, + }); + }); + + it('does not override existing annotation', async () => { + const entity: Entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'my-component', + annotations: { + 'dev.azure.com/host-org': 'myhost/myorg', + 'dev.azure.com/project-repo': 'myproj/myrepo', + }, + }, + }; + const location: LocationSpec = { + type: 'url', + target: + 'https://dev.azure.com/organization/project/_git/repository?path=%2Fcatalog-info.yaml', + }; + + const processor = AzureDevOpsAnnotatorProcessor.fromConfig( + new ConfigReader({}), + ); + + expect(await processor.preProcessEntity(entity, location)).toEqual({ + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'my-component', + annotations: { + 'dev.azure.com/host-org': 'myhost/myorg', + 'dev.azure.com/project-repo': 'myproj/myrepo', + }, + }, + }); + }); + + it('should not add annotation for other providers', async () => { + const entity: Entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'my-component', + }, + }; + const location: LocationSpec = { + type: 'url', + target: + 'https://not-in-mock-config.example.com/backstage/backstage/-/blob/master/catalog-info.yaml', + }; + + const processor = AzureDevOpsAnnotatorProcessor.fromConfig( + new ConfigReader({}), + ); + + expect(await processor.preProcessEntity(entity, location)).toEqual({ + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'my-component', + }, + }); + }); + + it('should only process applicable kinds', async () => { + const component: Entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'my-component', + }, + }; + + const api: Entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'API', + metadata: { + name: 'my-component', + }, + }; + + const system: Entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'System', + metadata: { + name: 'my-component', + }, + }; + + const location: LocationSpec = { + type: 'url', + target: + 'https://dev.azure.com/organization/project/_git/repository?path=%2Fcatalog-info.yaml', + }; + + const processor = AzureDevOpsAnnotatorProcessor.fromConfig( + new ConfigReader({}), + { kinds: ['API', 'Component'] }, + ); + + expect(await processor.preProcessEntity(component, location)).toEqual({ + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'my-component', + annotations: { + 'dev.azure.com/host-org': 'dev.azure.com/organization', + 'dev.azure.com/project-repo': 'project/repository', + }, + }, + }); + + expect(await processor.preProcessEntity(api, location)).toEqual({ + apiVersion: 'backstage.io/v1alpha1', + kind: 'API', + metadata: { + name: 'my-component', + annotations: { + 'dev.azure.com/host-org': 'dev.azure.com/organization', + 'dev.azure.com/project-repo': 'project/repository', + }, + }, + }); + + expect(await processor.preProcessEntity(system, location)).toEqual({ + apiVersion: 'backstage.io/v1alpha1', + kind: 'System', + metadata: { + name: 'my-component', + }, + }); + }); +}); diff --git a/plugins/azure-devops-backend/src/processor/AzureDevOpsAnnotatorProcessor.ts b/plugins/azure-devops-backend/src/processor/AzureDevOpsAnnotatorProcessor.ts new file mode 100644 index 0000000000..c27195b8ac --- /dev/null +++ b/plugins/azure-devops-backend/src/processor/AzureDevOpsAnnotatorProcessor.ts @@ -0,0 +1,127 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Entity } from '@backstage/catalog-model'; +import { Config } from '@backstage/config'; +import { + ScmIntegrationRegistry, + ScmIntegrations, +} from '@backstage/integration'; +import { identity, merge, pickBy } from 'lodash'; +import { LocationSpec } from '@backstage/plugin-catalog-common'; +import { CatalogProcessor } from '@backstage/plugin-catalog-node'; +import { + AZURE_DEVOPS_HOST_ORG_ANNOTATION, + AZURE_DEVOPS_REPO_ANNOTATION, +} from '@backstage/plugin-azure-devops-common'; +import { parseAzureDevOpsUrl } from '../utils'; + +/** @public */ +export class AzureDevOpsAnnotatorProcessor implements CatalogProcessor { + constructor( + private readonly opts: { + scmIntegrationRegistry: ScmIntegrationRegistry; + kinds?: string[]; + }, + ) {} + + getProcessorName(): string { + return 'AzureDevOpsAnnotatorProcessor'; + } + + static fromConfig( + config: Config, + options?: { kinds?: string[] }, + ): AzureDevOpsAnnotatorProcessor { + return new AzureDevOpsAnnotatorProcessor({ + scmIntegrationRegistry: ScmIntegrations.fromConfig(config), + kinds: options?.kinds, + }); + } + + async preProcessEntity( + entity: Entity, + location: LocationSpec, + ): Promise { + const applicableKinds = (this.opts.kinds ?? ['Component']).map(k => + k.toLocaleLowerCase('en-US'), + ); + if ( + !applicableKinds.includes(entity.kind.toLocaleLowerCase('en-US')) || + location.type !== 'url' + ) { + return entity; + } + + const scmIntegration = this.opts.scmIntegrationRegistry.byUrl( + location.target, + ); + + if (!scmIntegration) { + return entity; + } + + if (scmIntegration.type !== 'azure') { + return entity; + } + + const { host, org, project, repo } = parseAzureDevOpsUrl(location.target); + + if (!org || !project || !repo) { + return entity; + } + + const hostOrgAnnotation = AZURE_DEVOPS_HOST_ORG_ANNOTATION; + let hostOrgValue = entity.metadata.annotations?.[hostOrgAnnotation]; + if (!hostOrgValue) { + hostOrgValue = `${host}/${org}`; + } + + const projectRepoAnnotation = AZURE_DEVOPS_REPO_ANNOTATION; + let projectRepoValue = entity.metadata.annotations?.[projectRepoAnnotation]; + if (!projectRepoValue) { + projectRepoValue = `${project}/${repo}`; + } + + const result = merge( + { + metadata: { + annotations: pickBy( + { + [hostOrgAnnotation]: hostOrgValue, + }, + identity, + ), + }, + }, + entity, + ); + + return merge( + { + metadata: { + annotations: pickBy( + { + [projectRepoAnnotation]: projectRepoValue, + }, + identity, + ), + }, + }, + result, + ); + } +} diff --git a/plugins/azure-devops-backend/src/processor/index.ts b/plugins/azure-devops-backend/src/processor/index.ts new file mode 100644 index 0000000000..46747c4802 --- /dev/null +++ b/plugins/azure-devops-backend/src/processor/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { AzureDevOpsAnnotatorProcessor } from './AzureDevOpsAnnotatorProcessor'; diff --git a/plugins/azure-devops-backend/src/service/router.test.ts b/plugins/azure-devops-backend/src/service/router.test.ts index a77600feb0..65cb27271e 100644 --- a/plugins/azure-devops-backend/src/service/router.test.ts +++ b/plugins/azure-devops-backend/src/service/router.test.ts @@ -161,6 +161,8 @@ describe('createRouter', () => { 'myProject', 'af4ae3af-e747-4129-9bbc-d1329f6b0998', 40, + undefined, + undefined, ); expect(response.status).toEqual(200); expect(response.body).toEqual(builds); @@ -215,6 +217,8 @@ describe('createRouter', () => { 'myProject', 'myRepo', 50, + undefined, + undefined, ); expect(response.status).toEqual(200); expect(response.body).toEqual(repoBuilds); @@ -252,6 +256,8 @@ describe('createRouter', () => { expect(azureDevOpsApi.getGitTags).toHaveBeenCalledWith( 'myProject', 'myRepo', + undefined, + undefined, ); expect(response.status).toEqual(200); expect(response.body).toEqual(gitTags); @@ -315,6 +321,8 @@ describe('createRouter', () => { 'myProject', 'myRepo', { status: 1, top: 50 }, + undefined, + undefined, ); expect(response.status).toEqual(200); expect(response.body).toEqual(pullRequests); @@ -341,6 +349,8 @@ describe('createRouter', () => { expect(azureDevOpsApi.getBuildDefinitions).toHaveBeenCalledWith( 'myProject', 'myBuildDefinition', + undefined, + undefined, ); expect(response.status).toEqual(200); expect(response.body).toEqual(inputDefinitions); @@ -397,6 +407,8 @@ describe('createRouter', () => { 50, 'myRepo', undefined, + undefined, + undefined, ); expect(response.status).toEqual(200); expect(response.body).toEqual(buildRuns); @@ -452,6 +464,8 @@ describe('createRouter', () => { 50, undefined, 'myDefinition', + undefined, + undefined, ); expect(response.status).toEqual(200); expect(response.body).toEqual(buildRuns); diff --git a/plugins/azure-devops-backend/src/service/router.ts b/plugins/azure-devops-backend/src/service/router.ts index b6b8a6fdea..9a71c8f03d 100644 --- a/plugins/azure-devops-backend/src/service/router.ts +++ b/plugins/azure-devops-backend/src/service/router.ts @@ -19,7 +19,6 @@ import { PullRequestOptions, PullRequestStatus, } from '@backstage/plugin-azure-devops-common'; -import { WebApi, getPersonalAccessTokenHandler } from 'azure-devops-node-api'; import { AzureDevOpsApi } from '../api'; import { Config } from '@backstage/config'; @@ -43,18 +42,11 @@ export interface RouterOptions { export async function createRouter( options: RouterOptions, ): Promise { - const { logger, reader } = options; - const config = options.config.getConfig('azureDevOps'); - - const token = config.getString('token'); - const host = config.getString('host'); - const organization = config.getString('organization'); - - const authHandler = getPersonalAccessTokenHandler(token); - const webApi = new WebApi(`https://${host}/${organization}`, authHandler); + const { logger, reader, config } = options; const azureDevOpsApi = - options.azureDevOpsApi || new AzureDevOpsApi(logger, webApi, reader); + options.azureDevOpsApi || + AzureDevOpsApi.fromConfig(config, { logger, urlReader: reader }); const pullRequestsDashboardProvider = await PullRequestsDashboardProvider.create(logger, azureDevOpsApi); @@ -83,10 +75,14 @@ export async function createRouter( router.get('/builds/:projectName/:repoId', async (req, res) => { const { projectName, repoId } = req.params; const top = req.query.top ? Number(req.query.top) : DEFAULT_TOP; + const host = req.query.host?.toString(); + const org = req.query.org?.toString(); const buildList = await azureDevOpsApi.getBuildList( projectName, repoId, top, + host, + org, ); res.status(200).json(buildList); }); @@ -95,11 +91,14 @@ export async function createRouter( const { projectName, repoName } = req.params; const top = req.query.top ? Number(req.query.top) : DEFAULT_TOP; - + const host = req.query.host?.toString(); + const org = req.query.org?.toString(); const gitRepository = await azureDevOpsApi.getRepoBuilds( projectName, repoName, top, + host, + org, ); res.status(200).json(gitRepository); @@ -107,7 +106,14 @@ export async function createRouter( router.get('/git-tags/:projectName/:repoName', async (req, res) => { const { projectName, repoName } = req.params; - const gitTags = await azureDevOpsApi.getGitTags(projectName, repoName); + const host = req.query.host?.toString(); + const org = req.query.org?.toString(); + const gitTags = await azureDevOpsApi.getGitTags( + projectName, + repoName, + host, + org, + ); res.status(200).json(gitTags); }); @@ -115,7 +121,8 @@ export async function createRouter( const { projectName, repoName } = req.params; const top = req.query.top ? Number(req.query.top) : DEFAULT_TOP; - + const host = req.query.host?.toString(); + const org = req.query.org?.toString(); const status = req.query.status ? Number(req.query.status) : PullRequestStatus.Active; @@ -129,6 +136,8 @@ export async function createRouter( projectName, repoName, pullRequestOptions, + host, + org, ); res.status(200).json(gitPullRequest); @@ -166,9 +175,13 @@ export async function createRouter( '/build-definitions/:projectName/:definitionName', async (req, res) => { const { projectName, definitionName } = req.params; + const host = req.query.host?.toString(); + const org = req.query.org?.toString(); const buildDefinitionList = await azureDevOpsApi.getBuildDefinitions( projectName, definitionName, + host, + org, ); res.status(200).json(buildDefinitionList); }, @@ -179,11 +192,15 @@ export async function createRouter( const repoName = req.query.repoName?.toString(); const definitionName = req.query.definitionName?.toString(); const top = req.query.top ? Number(req.query.top) : DEFAULT_TOP; + const host = req.query.host?.toString(); + const org = req.query.org?.toString(); const builds = await azureDevOpsApi.getBuildRuns( projectName, top, repoName, definitionName, + host, + org, ); res.status(200).json(builds); }); @@ -195,10 +212,14 @@ export async function createRouter( }); router.get('/readme/:projectName/:repoName', async (req, res) => { + const host = + req.query.host?.toString() ?? config.getString('azureDevOps.host'); + const org = + req.query.org?.toString() ?? config.getString('azureDevOps.organization'); const { projectName, repoName } = req.params; const readme = await azureDevOpsApi.getReadme( host, - organization, + org, projectName, repoName, ); diff --git a/plugins/azure-devops-backend/src/utils/azure-devops-utils.test.ts b/plugins/azure-devops-backend/src/utils/azure-devops-utils.test.ts index 427980be14..86a06b7b0b 100644 --- a/plugins/azure-devops-backend/src/utils/azure-devops-utils.test.ts +++ b/plugins/azure-devops-backend/src/utils/azure-devops-utils.test.ts @@ -28,6 +28,7 @@ import { getPullRequestLink, replaceReadme, buildEncodedUrl, + parseAzureDevOpsUrl, } from './azure-devops-utils'; import { GitPullRequest } from 'azure-devops-node-api/interfaces/GitInterfaces'; import { UrlReader } from '@backstage/backend-common'; @@ -295,3 +296,38 @@ describe('buildEncodedUrl', () => { ); }); }); + +describe('parseAzureDevOpsUrl', () => { + it('parses Azure DevOps Cloud url', async () => { + const result = parseAzureDevOpsUrl( + 'https://dev.azure.com/organization/project/_git/repository?path=%2Fcatalog-info.yaml', + ); + + expect(result.host).toEqual('dev.azure.com'); + expect(result.org).toEqual('organization'); + expect(result.project).toEqual('project'); + expect(result.repo).toEqual('repository'); + }); + + it('parses Azure DevOps Server url', async () => { + const result = parseAzureDevOpsUrl( + 'https://server.com/organization/project/_git/repository?path=%2Fcatalog-info.yaml', + ); + + expect(result.host).toEqual('server.com'); + expect(result.org).toEqual('organization'); + expect(result.project).toEqual('project'); + expect(result.repo).toEqual('repository'); + }); + + it('parses TFS subpath Url', async () => { + const result = parseAzureDevOpsUrl( + 'https://server.com/tfs/organization/project/_git/repository?path=%2Fcatalog-info.yaml', + ); + + expect(result.host).toEqual('server.com/tfs'); + expect(result.org).toEqual('organization'); + expect(result.project).toEqual('project'); + expect(result.repo).toEqual('repository'); + }); +}); diff --git a/plugins/azure-devops-backend/src/utils/azure-devops-utils.ts b/plugins/azure-devops-backend/src/utils/azure-devops-utils.ts index aa946e7a74..7f5bf39ac4 100644 --- a/plugins/azure-devops-backend/src/utils/azure-devops-utils.ts +++ b/plugins/azure-devops-backend/src/utils/azure-devops-utils.ts @@ -328,3 +328,29 @@ export function extractPartsFromAsset(content: string): { path: path.startsWith('.') ? path.substring(1, path.length) : path, }; } + +export function parseAzureDevOpsUrl(sourceUrl: string) { + const url = new URL(sourceUrl); + + let host = url.host; + let org; + let project; + let repo; + + const parts = url.pathname.split('/').map(part => decodeURIComponent(part)); + if (parts[2] === '_git') { + org = parts[1]; + project = repo = parts[3]; + } else if (parts[3] === '_git') { + org = parts[1]; + project = parts[2]; + repo = parts[4]; + } else if (parts[4] === '_git') { + host = `${host}/${parts[1]}`; + org = parts[2]; + project = parts[3]; + repo = parts[5]; + } + + return { host, org, project, repo }; +} diff --git a/plugins/azure-devops-common/CHANGELOG.md b/plugins/azure-devops-common/CHANGELOG.md index e5637a9ff4..1709b96073 100644 --- a/plugins/azure-devops-common/CHANGELOG.md +++ b/plugins/azure-devops-common/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/plugin-azure-devops-common +## 0.3.2 + +### Patch Changes + +- c70e4f5: Added multi-org support +- 043b724: Introduced new `AzureDevOpsAnnotatorProcessor` that adds the needed annotations automatically. Also, moved constants to common package so they can be shared more easily + +## 0.3.2-next.1 + +### Patch Changes + +- c70e4f5: Added multi-org support + +## 0.3.2-next.0 + +### Patch Changes + +- 043b724c56: Introduced new `AzureDevOpsAnnotatorProcessor` that adds the needed annotations automatically. Also, moved constants to common package so they can be shared more easily + ## 0.3.1 ### Patch Changes diff --git a/plugins/azure-devops-common/api-report.md b/plugins/azure-devops-common/api-report.md index ea9f7130c0..5bd1674fc8 100644 --- a/plugins/azure-devops-common/api-report.md +++ b/plugins/azure-devops-common/api-report.md @@ -3,6 +3,22 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +// @public (undocumented) +export const AZURE_DEVOPS_BUILD_DEFINITION_ANNOTATION = + 'dev.azure.com/build-definition'; + +// @public (undocumented) +export const AZURE_DEVOPS_DEFAULT_TOP: number; + +// @public (undocumented) +export const AZURE_DEVOPS_HOST_ORG_ANNOTATION = 'dev.azure.com/host-org'; + +// @public (undocumented) +export const AZURE_DEVOPS_PROJECT_ANNOTATION = 'dev.azure.com/project'; + +// @public (undocumented) +export const AZURE_DEVOPS_REPO_ANNOTATION = 'dev.azure.com/project-repo'; + // @public (undocumented) export enum BuildResult { Canceled = 32, @@ -207,6 +223,10 @@ export interface Readme { // @public (undocumented) export interface ReadmeConfig { + // (undocumented) + host?: string; + // (undocumented) + org?: string; // (undocumented) project: string; // (undocumented) diff --git a/plugins/azure-devops-common/package.json b/plugins/azure-devops-common/package.json index 7648e39539..21e9245e38 100644 --- a/plugins/azure-devops-common/package.json +++ b/plugins/azure-devops-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-azure-devops-common", - "version": "0.3.1", + "version": "0.3.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/azure-devops/src/constants.ts b/plugins/azure-devops-common/src/constants.ts similarity index 92% rename from plugins/azure-devops/src/constants.ts rename to plugins/azure-devops-common/src/constants.ts index aba0ec093a..5cc6b54592 100644 --- a/plugins/azure-devops/src/constants.ts +++ b/plugins/azure-devops-common/src/constants.ts @@ -14,9 +14,14 @@ * limitations under the License. */ +/** @public */ export const AZURE_DEVOPS_BUILD_DEFINITION_ANNOTATION = 'dev.azure.com/build-definition'; +/** @public */ export const AZURE_DEVOPS_HOST_ORG_ANNOTATION = 'dev.azure.com/host-org'; +/** @public */ export const AZURE_DEVOPS_PROJECT_ANNOTATION = 'dev.azure.com/project'; +/** @public */ export const AZURE_DEVOPS_REPO_ANNOTATION = 'dev.azure.com/project-repo'; +/** @public */ export const AZURE_DEVOPS_DEFAULT_TOP: number = 10; diff --git a/plugins/azure-devops-common/src/index.ts b/plugins/azure-devops-common/src/index.ts index 26a854de89..9a4a007317 100644 --- a/plugins/azure-devops-common/src/index.ts +++ b/plugins/azure-devops-common/src/index.ts @@ -15,3 +15,4 @@ */ export * from './types'; +export * from './constants'; diff --git a/plugins/azure-devops-common/src/types.ts b/plugins/azure-devops-common/src/types.ts index 380cb3e585..afb6083867 100644 --- a/plugins/azure-devops-common/src/types.ts +++ b/plugins/azure-devops-common/src/types.ts @@ -210,6 +210,8 @@ export interface Team { export interface ReadmeConfig { project: string; repo: string; + host?: string; + org?: string; } /** @public */ diff --git a/plugins/azure-devops/.eslintrc.js b/plugins/azure-devops/.eslintrc.js index e2a53a6ad2..e487f765b2 100644 --- a/plugins/azure-devops/.eslintrc.js +++ b/plugins/azure-devops/.eslintrc.js @@ -1 +1,5 @@ -module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, { + rules: { + '@backstage/no-top-level-material-ui-4-imports': 'error', + }, +}); diff --git a/plugins/azure-devops/CHANGELOG.md b/plugins/azure-devops/CHANGELOG.md index beb0f0478e..8d851523f6 100644 --- a/plugins/azure-devops/CHANGELOG.md +++ b/plugins/azure-devops/CHANGELOG.md @@ -1,5 +1,137 @@ # @backstage/plugin-azure-devops +## 0.3.11 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-azure-devops-common@0.3.2 + +## 0.3.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.3.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-azure-devops-common@0.3.2 + +## 0.3.11-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-azure-devops-common@0.3.2 + +## 0.3.10 + +### Patch Changes + +- c70e4f5: Added multi-org support +- 7c9af0b: Added support for annotations that use a subpath for the host. Also validated that the annotations have the correct number of slashes. +- 043b724: Introduced new `AzureDevOpsAnnotatorProcessor` that adds the needed annotations automatically. Also, moved constants to common package so they can be shared more easily +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/plugin-azure-devops-common@0.3.2 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.3.10-next.3 + +### Patch Changes + +- c70e4f5: Added multi-org support +- 7c9af0b: Added support for annotations that use a subpath for the host. Also validated that the annotations have the correct number of slashes. +- Updated dependencies + - @backstage/plugin-azure-devops-common@0.3.2-next.1 + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## 0.3.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-azure-devops-common@0.3.2-next.0 + +## 0.3.10-next.1 + +### Patch Changes + +- 043b724c56: Introduced new `AzureDevOpsAnnotatorProcessor` that adds the needed annotations automatically. Also, moved constants to common package so they can be shared more easily +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-azure-devops-common@0.3.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## 0.3.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-azure-devops-common@0.3.1 + +## 0.3.8 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- ce9e59cbb3: Refactored the error handling for some of the hooks +- 361bb34d8e: Consolidated getting the annotation values into a single function to help with future changes +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-azure-devops-common@0.3.1 + ## 0.3.8-next.2 ### Patch Changes diff --git a/plugins/azure-devops/README.md b/plugins/azure-devops/README.md index 7eeae09813..d7335e54c8 100644 --- a/plugins/azure-devops/README.md +++ b/plugins/azure-devops/README.md @@ -72,6 +72,53 @@ dev.azure.com/build-definition: In this case `` will be the name of your Team Project and `` will be the name of the Build Definition you would like to see Builds for, and it's possible to add more Builds separated by a comma. If the Build Definition name has spaces in it make sure to put quotes around it. +#### Multiple Organizations + +If you have multiple organizations you'll need to also add this annotation: + +```yaml +dev.azure.com/host-org: / +``` + +For this annotation `` will match the `host` value in the `integrations.azure` section in your `app-config.yaml` and `` will be the name of the Organization that is part of the `host`. Let's break this down with an example: + +Say we have the following `integrations.azure` section: + +```yaml +integrations: + azure: + - host: dev.azure.com + credentials: + - organizations: + - my-org + - my-other-org + clientId: ${AZURE_CLIENT_ID} + clientSecret: ${AZURE_CLIENT_SECRET} + tenantId: ${AZURE_TENANT_ID} + - organizations: + - another-org + clientId: ${AZURE_CLIENT_ID} + - host: server.company.com + credentials: + - organizations: + - yet-another-org + personalAccessToken: ${PERSONAL_ACCESS_TOKEN} +``` + +If the entity we are viewing lives in the `my-other-org` organization then the `dev.azure.com/host-org` annotation would look like this: + +```yaml +dev.azure.com/host-org: dev.azure.com/my-other-org +``` + +And if the entity was from `yet-another-org` it would look like this: + +```yaml +dev.azure.com/host-org: server.company.com/yet-another-org +``` + +**Note:** To save you time, effort, and confusion setting up these annotations manually you can use the `AzureDevOpsAnnotatorProcessor` processor which will add the `dev.azure.com/host-org` and `dev.azure.com/project-repo` annotations for you with the correct values. The Azure DevOps backend plugin has details on how to [add this processor](https://github.com/backstage/backstage/tree/master/plugins/azure-devops-backend#processor). + ### Azure Pipelines Component To get the Azure Pipelines component working you'll need to do the following two steps: @@ -247,8 +294,3 @@ To get the README component working you'll need to do the following two steps: - You'll need to add the `EntitySwitch.Case` above from step 2 to all the entity sections you want to see Readme in. For example if you wanted to see Readme when looking at Website entities then you would need to add this to the `websiteEntityPage` section. - The `if` prop is optional on the `EntitySwitch.Case`, you can remove it if you always want to see the tab even if the entity being viewed does not have the needed annotation - The `maxHeight` property on the `EntityAzureReadmeCard` will set the maximum screen size you would like to see, if not set it will default to 100% - -## Limitations - -- Currently multiple organizations are not supported -- Mixing Azure DevOps Services (cloud) and Azure DevOps Server (on-premise) is not supported diff --git a/plugins/azure-devops/api-report.md b/plugins/azure-devops/api-report.md index 6b33762639..cfff4348ee 100644 --- a/plugins/azure-devops/api-report.md +++ b/plugins/azure-devops/api-report.md @@ -22,7 +22,7 @@ import { Readme } from '@backstage/plugin-azure-devops-common'; import { ReadmeConfig } from '@backstage/plugin-azure-devops-common'; import { RepoBuild } from '@backstage/plugin-azure-devops-common'; import { RepoBuildOptions } from '@backstage/plugin-azure-devops-common'; -import { SvgIconProps } from '@material-ui/core'; +import { SvgIconProps } from '@material-ui/core/SvgIcon'; import { Team } from '@backstage/plugin-azure-devops-common'; // @public (undocumented) @@ -71,6 +71,8 @@ export interface AzureDevOpsApi { projectName: string, repoName?: string, definitionName?: string, + host?: string, + org?: string, options?: BuildRunOptions, ): Promise<{ items: BuildRun[]; @@ -83,6 +85,8 @@ export interface AzureDevOpsApi { getGitTags( projectName: string, repoName: string, + host?: string, + org?: string, ): Promise<{ items: GitTag[]; }>; @@ -90,6 +94,8 @@ export interface AzureDevOpsApi { getPullRequests( projectName: string, repoName: string, + host?: string, + org?: string, options?: PullRequestOptions, ): Promise<{ items: PullRequest[]; @@ -100,6 +106,8 @@ export interface AzureDevOpsApi { getRepoBuilds( projectName: string, repoName: string, + host?: string, + org?: string, options?: RepoBuildOptions, ): Promise<{ items: RepoBuild[]; @@ -124,6 +132,8 @@ export class AzureDevOpsClient implements AzureDevOpsApi { projectName: string, repoName?: string, definitionName?: string, + host?: string, + org?: string, options?: BuildRunOptions, ): Promise<{ items: BuildRun[]; @@ -136,6 +146,8 @@ export class AzureDevOpsClient implements AzureDevOpsApi { getGitTags( projectName: string, repoName: string, + host?: string, + org?: string, ): Promise<{ items: GitTag[]; }>; @@ -143,6 +155,8 @@ export class AzureDevOpsClient implements AzureDevOpsApi { getPullRequests( projectName: string, repoName: string, + host?: string, + org?: string, options?: PullRequestOptions, ): Promise<{ items: PullRequest[]; @@ -153,6 +167,8 @@ export class AzureDevOpsClient implements AzureDevOpsApi { getRepoBuilds( projectName: string, repoName: string, + host?: string, + org?: string, options?: RepoBuildOptions, ): Promise<{ items: RepoBuild[]; diff --git a/plugins/azure-devops/package.json b/plugins/azure-devops/package.json index fbc049a860..db744139ee 100644 --- a/plugins/azure-devops/package.json +++ b/plugins/azure-devops/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-azure-devops", - "version": "0.3.8-next.2", + "version": "0.3.11", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,10 +35,8 @@ "@backstage/errors": "workspace:^", "@backstage/plugin-azure-devops-common": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.61", "@types/react": "^16.13.1 || ^17.0.0", "humanize-duration": "^3.27.0", "luxon": "^3.0.0", @@ -51,14 +49,11 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", "@backstage/dev-utils": "workspace:^", "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "msw": "^1.0.0" + "@testing-library/react": "^14.0.0" }, "files": [ "dist" diff --git a/plugins/azure-devops/src/api/AzureDevOpsApi.ts b/plugins/azure-devops/src/api/AzureDevOpsApi.ts index ce6a3cac39..89aa4b7d6e 100644 --- a/plugins/azure-devops/src/api/AzureDevOpsApi.ts +++ b/plugins/azure-devops/src/api/AzureDevOpsApi.ts @@ -40,17 +40,23 @@ export interface AzureDevOpsApi { getRepoBuilds( projectName: string, repoName: string, + host?: string, + org?: string, options?: RepoBuildOptions, ): Promise<{ items: RepoBuild[] }>; getGitTags( projectName: string, repoName: string, + host?: string, + org?: string, ): Promise<{ items: GitTag[] }>; getPullRequests( projectName: string, repoName: string, + host?: string, + org?: string, options?: PullRequestOptions, ): Promise<{ items: PullRequest[] }>; @@ -66,6 +72,8 @@ export interface AzureDevOpsApi { projectName: string, repoName?: string, definitionName?: string, + host?: string, + org?: string, options?: BuildRunOptions, ): Promise<{ items: BuildRun[] }>; diff --git a/plugins/azure-devops/src/api/AzureDevOpsClient.ts b/plugins/azure-devops/src/api/AzureDevOpsClient.ts index a202008798..76e38b064c 100644 --- a/plugins/azure-devops/src/api/AzureDevOpsClient.ts +++ b/plugins/azure-devops/src/api/AzureDevOpsClient.ts @@ -47,12 +47,20 @@ export class AzureDevOpsClient implements AzureDevOpsApi { public async getRepoBuilds( projectName: string, repoName: string, + host?: string, + org?: string, options?: RepoBuildOptions, ): Promise<{ items: RepoBuild[] }> { const queryString = new URLSearchParams(); if (options?.top) { queryString.append('top', options.top.toString()); } + if (host) { + queryString.append('host', host); + } + if (org) { + queryString.append('org', org); + } const urlSegment = `repo-builds/${encodeURIComponent( projectName, )}/${encodeURIComponent(repoName)}?${queryString}`; @@ -64,10 +72,19 @@ export class AzureDevOpsClient implements AzureDevOpsApi { public async getGitTags( projectName: string, repoName: string, + host?: string, + org?: string, ): Promise<{ items: GitTag[] }> { + const queryString = new URLSearchParams(); + if (host) { + queryString.append('host', host); + } + if (org) { + queryString.append('org', org); + } const urlSegment = `git-tags/${encodeURIComponent( projectName, - )}/${encodeURIComponent(repoName)}`; + )}/${encodeURIComponent(repoName)}?${queryString}`; const items = await this.get(urlSegment); return { items }; @@ -76,6 +93,8 @@ export class AzureDevOpsClient implements AzureDevOpsApi { public async getPullRequests( projectName: string, repoName: string, + host?: string, + org?: string, options?: PullRequestOptions, ): Promise<{ items: PullRequest[] }> { const queryString = new URLSearchParams(); @@ -85,6 +104,12 @@ export class AzureDevOpsClient implements AzureDevOpsApi { if (options?.status) { queryString.append('status', options.status.toString()); } + if (host) { + queryString.append('host', host); + } + if (org) { + queryString.append('org', org); + } const urlSegment = `pull-requests/${encodeURIComponent( projectName, )}/${encodeURIComponent(repoName)}?${queryString}`; @@ -113,12 +138,20 @@ export class AzureDevOpsClient implements AzureDevOpsApi { projectName: string, repoName?: string, definitionName?: string, + host?: string, + org?: string, options?: BuildRunOptions, ): Promise<{ items: BuildRun[] }> { const queryString = new URLSearchParams(); if (repoName) { queryString.append('repoName', repoName); } + if (host) { + queryString.append('host', host); + } + if (org) { + queryString.append('org', org); + } if (definitionName) { const definitionNames = definitionName.split(','); if (definitionNames.length > 1) { @@ -149,10 +182,17 @@ export class AzureDevOpsClient implements AzureDevOpsApi { } public async getReadme(opts: ReadmeConfig): Promise { + const queryString = new URLSearchParams(); + if (opts.host) { + queryString.append('host', opts.host); + } + if (opts.org) { + queryString.append('org', opts.org); + } return await this.get( `readme/${encodeURIComponent(opts.project)}/${encodeURIComponent( opts.repo, - )}`, + )}?${queryString}`, ); } diff --git a/plugins/azure-devops/src/components/AzureGitTagsIcon/AzureGitTagsIcon.tsx b/plugins/azure-devops/src/components/AzureGitTagsIcon/AzureGitTagsIcon.tsx index c8b63e3259..0d317e3ce1 100644 --- a/plugins/azure-devops/src/components/AzureGitTagsIcon/AzureGitTagsIcon.tsx +++ b/plugins/azure-devops/src/components/AzureGitTagsIcon/AzureGitTagsIcon.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { SvgIcon, SvgIconProps } from '@material-ui/core'; +import SvgIcon, { SvgIconProps } from '@material-ui/core/SvgIcon'; import React from 'react'; diff --git a/plugins/azure-devops/src/components/AzurePipelinesIcon/AzurePipelinesIcon.tsx b/plugins/azure-devops/src/components/AzurePipelinesIcon/AzurePipelinesIcon.tsx index bd19331f6e..10cdb3a905 100644 --- a/plugins/azure-devops/src/components/AzurePipelinesIcon/AzurePipelinesIcon.tsx +++ b/plugins/azure-devops/src/components/AzurePipelinesIcon/AzurePipelinesIcon.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { SvgIcon, SvgIconProps } from '@material-ui/core'; +import SvgIcon, { SvgIconProps } from '@material-ui/core/SvgIcon'; import React from 'react'; diff --git a/plugins/azure-devops/src/components/AzurePullRequestsIcon/AzurePullRequestsIcon.tsx b/plugins/azure-devops/src/components/AzurePullRequestsIcon/AzurePullRequestsIcon.tsx index 99e3f74e90..e298f8bc25 100644 --- a/plugins/azure-devops/src/components/AzurePullRequestsIcon/AzurePullRequestsIcon.tsx +++ b/plugins/azure-devops/src/components/AzurePullRequestsIcon/AzurePullRequestsIcon.tsx @@ -15,7 +15,7 @@ */ import React from 'react'; -import { SvgIcon, SvgIconProps } from '@material-ui/core'; +import SvgIcon, { SvgIconProps } from '@material-ui/core/SvgIcon'; /** @public */ export const AzurePullRequestsIcon = (props: SvgIconProps) => ( diff --git a/plugins/azure-devops/src/components/BuildTable/BuildTable.tsx b/plugins/azure-devops/src/components/BuildTable/BuildTable.tsx index 6707929a6c..09eba5f5a2 100644 --- a/plugins/azure-devops/src/components/BuildTable/BuildTable.tsx +++ b/plugins/azure-devops/src/components/BuildTable/BuildTable.tsx @@ -14,7 +14,8 @@ * limitations under the License. */ -import { Box, Typography } from '@material-ui/core'; +import Box from '@material-ui/core/Box'; +import Typography from '@material-ui/core/Typography'; import { BuildResult, BuildRun, diff --git a/plugins/azure-devops/src/components/EntityPageAzurePipelines/EntityPageAzurePipelines.tsx b/plugins/azure-devops/src/components/EntityPageAzurePipelines/EntityPageAzurePipelines.tsx index 02a61a9a9a..c33d849c24 100644 --- a/plugins/azure-devops/src/components/EntityPageAzurePipelines/EntityPageAzurePipelines.tsx +++ b/plugins/azure-devops/src/components/EntityPageAzurePipelines/EntityPageAzurePipelines.tsx @@ -16,21 +16,13 @@ import { BuildTable } from '../BuildTable/BuildTable'; import React from 'react'; -import { getAnnotationValuesFromEntity } from '../../utils/getAnnotationValuesFromEntity'; -import { useBuildRuns } from '../../hooks/useBuildRuns'; +import { useBuildRuns } from '../../hooks'; import { useEntity } from '@backstage/plugin-catalog-react'; export const EntityPageAzurePipelines = (props: { defaultLimit?: number }) => { const { entity } = useEntity(); - const { project, repo, definition } = getAnnotationValuesFromEntity(entity); - - const { items, loading, error } = useBuildRuns( - project, - props.defaultLimit, - repo, - definition, - ); + const { items, loading, error } = useBuildRuns(entity, props.defaultLimit); return ; }; diff --git a/plugins/azure-devops/src/components/GitTagTable/GitTagTable.tsx b/plugins/azure-devops/src/components/GitTagTable/GitTagTable.tsx index c6abba55e1..f34a1929fe 100644 --- a/plugins/azure-devops/src/components/GitTagTable/GitTagTable.tsx +++ b/plugins/azure-devops/src/components/GitTagTable/GitTagTable.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { Box } from '@material-ui/core'; +import Box from '@material-ui/core/Box'; import { Link, ResponseErrorPanel, diff --git a/plugins/azure-devops/src/components/PullRequestStatusButtonGroup/PullRequestStatusButtonGroup.tsx b/plugins/azure-devops/src/components/PullRequestStatusButtonGroup/PullRequestStatusButtonGroup.tsx index f516bfb0e5..1b0b9a8afe 100644 --- a/plugins/azure-devops/src/components/PullRequestStatusButtonGroup/PullRequestStatusButtonGroup.tsx +++ b/plugins/azure-devops/src/components/PullRequestStatusButtonGroup/PullRequestStatusButtonGroup.tsx @@ -14,7 +14,8 @@ * limitations under the License. */ -import { Button, ButtonGroup } from '@material-ui/core'; +import Button from '@material-ui/core/Button'; +import ButtonGroup from '@material-ui/core/ButtonGroup'; import { PullRequestStatus } from '@backstage/plugin-azure-devops-common'; import React from 'react'; diff --git a/plugins/azure-devops/src/components/PullRequestTable/PullRequestTable.tsx b/plugins/azure-devops/src/components/PullRequestTable/PullRequestTable.tsx index b37ba6e73c..d672102945 100644 --- a/plugins/azure-devops/src/components/PullRequestTable/PullRequestTable.tsx +++ b/plugins/azure-devops/src/components/PullRequestTable/PullRequestTable.tsx @@ -14,7 +14,8 @@ * limitations under the License. */ -import { Box, Chip } from '@material-ui/core'; +import Box from '@material-ui/core/Box'; +import Chip from '@material-ui/core/Chip'; import { Link, ResponseErrorPanel, diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/PullRequestCard/PullRequestCard.tsx b/plugins/azure-devops/src/components/PullRequestsPage/lib/PullRequestCard/PullRequestCard.tsx index 98237cb2a3..dd9fff86b5 100644 --- a/plugins/azure-devops/src/components/PullRequestsPage/lib/PullRequestCard/PullRequestCard.tsx +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/PullRequestCard/PullRequestCard.tsx @@ -15,7 +15,9 @@ */ import { Avatar, Link } from '@backstage/core-components'; -import { Card, CardContent, CardHeader } from '@material-ui/core'; +import Card from '@material-ui/core/Card'; +import CardContent from '@material-ui/core/CardContent'; +import CardHeader from '@material-ui/core/CardHeader'; import Typography from '@material-ui/core/Typography'; import { AutoCompleteIcon } from '../AutoCompleteIcon'; diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/PullRequestGrid/PullRequestGrid.tsx b/plugins/azure-devops/src/components/PullRequestsPage/lib/PullRequestGrid/PullRequestGrid.tsx index 8b9c49beb4..0244ea3bb1 100644 --- a/plugins/azure-devops/src/components/PullRequestsPage/lib/PullRequestGrid/PullRequestGrid.tsx +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/PullRequestGrid/PullRequestGrid.tsx @@ -17,7 +17,7 @@ import { PullRequestGridColumn } from '../PullRequestGridColumn'; import { PullRequestGroup } from '../types'; import React from 'react'; -import { styled } from '@material-ui/core'; +import { styled } from '@material-ui/core/styles'; const GridDiv = styled('div')(({ theme }) => ({ display: 'flex', diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/PullRequestGridColumn/PullRequestGridColumn.tsx b/plugins/azure-devops/src/components/PullRequestsPage/lib/PullRequestGridColumn/PullRequestGridColumn.tsx index 94a648188d..f06216ac76 100644 --- a/plugins/azure-devops/src/components/PullRequestsPage/lib/PullRequestGridColumn/PullRequestGridColumn.tsx +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/PullRequestGridColumn/PullRequestGridColumn.tsx @@ -14,7 +14,9 @@ * limitations under the License. */ -import { Paper, Typography, styled, withStyles } from '@material-ui/core'; +import Paper from '@material-ui/core/Paper'; +import Typography from '@material-ui/core/Typography'; +import { styled, withStyles } from '@material-ui/core/styles'; import { PullRequestCard } from '../PullRequestCard'; import { PullRequestGroup } from '../types'; diff --git a/plugins/azure-devops/src/components/ReadmeCard/ReadmeCard.tsx b/plugins/azure-devops/src/components/ReadmeCard/ReadmeCard.tsx index 420fe6ecf4..300c9e0d7c 100644 --- a/plugins/azure-devops/src/components/ReadmeCard/ReadmeCard.tsx +++ b/plugins/azure-devops/src/components/ReadmeCard/ReadmeCard.tsx @@ -14,7 +14,9 @@ * limitations under the License. */ -import { Box, Button, makeStyles } from '@material-ui/core'; +import Box from '@material-ui/core/Box'; +import Button from '@material-ui/core/Button'; +import { makeStyles } from '@material-ui/core/styles'; import { InfoCard, Progress, diff --git a/plugins/azure-devops/src/hooks/index.ts b/plugins/azure-devops/src/hooks/index.ts index ab1a3c9998..82ca86d055 100644 --- a/plugins/azure-devops/src/hooks/index.ts +++ b/plugins/azure-devops/src/hooks/index.ts @@ -17,7 +17,7 @@ export * from './useAllTeams'; export * from './useDashboardPullRequests'; export * from './usePullRequests'; -export * from './useRepoBuilds'; export * from './useUserEmail'; export * from './useUserTeamIds'; export * from './useReadme'; +export * from './useBuildRuns'; diff --git a/plugins/azure-devops/src/hooks/useRepoBuilds.test.tsx b/plugins/azure-devops/src/hooks/useBuildRuns.test.tsx similarity index 84% rename from plugins/azure-devops/src/hooks/useRepoBuilds.test.tsx rename to plugins/azure-devops/src/hooks/useBuildRuns.test.tsx index 99eaeb1ce3..409602eec4 100644 --- a/plugins/azure-devops/src/hooks/useRepoBuilds.test.tsx +++ b/plugins/azure-devops/src/hooks/useBuildRuns.test.tsx @@ -17,14 +17,14 @@ import React from 'react'; import { renderHook, waitFor } from '@testing-library/react'; import { Entity } from '@backstage/catalog-model'; -import { RepoBuild } from '@backstage/plugin-azure-devops-common'; +import { BuildRun } from '@backstage/plugin-azure-devops-common'; import { TestApiProvider } from '@backstage/test-utils'; import { AzureDevOpsApi, azureDevOpsApiRef } from '../api'; -import { useRepoBuilds } from './useRepoBuilds'; +import { useBuildRuns } from './useBuildRuns'; -describe('useRepoBuilds', () => { +describe('useBuildRuns', () => { const azureDevOpsApiMock = { - getRepoBuilds: jest.fn(), + getBuildRuns: jest.fn(), }; const azureDevOpsApi = azureDevOpsApiMock as Partial as AzureDevOpsApi; @@ -35,7 +35,7 @@ describe('useRepoBuilds', () => { ); - it('should provide an array of RepoBuild', async () => { + it('should provide an array of BuildRun', async () => { const entity: Entity = { apiVersion: 'backstage.io/v1alpha1', kind: 'Component', @@ -47,7 +47,7 @@ describe('useRepoBuilds', () => { }, }, }; - const repoBuilds: RepoBuild[] = [ + const buildRuns: BuildRun[] = [ { id: 1, title: 'title-1', @@ -67,10 +67,10 @@ describe('useRepoBuilds', () => { link: 'https://dev.azure.com/org/project/repo', }, ]; - azureDevOpsApiMock.getRepoBuilds.mockResolvedValue({ - items: repoBuilds, + azureDevOpsApiMock.getBuildRuns.mockResolvedValue({ + items: buildRuns, }); - const { result } = renderHook(() => useRepoBuilds(entity), { + const { result } = renderHook(() => useBuildRuns(entity), { wrapper: Wrapper, }); @@ -79,7 +79,7 @@ describe('useRepoBuilds', () => { await waitFor(() => { expect(result.current).toEqual({ error: undefined, - items: repoBuilds, + items: buildRuns, loading: false, }); }); @@ -96,7 +96,7 @@ describe('useRepoBuilds', () => { }; expect(() => - renderHook(() => useRepoBuilds(entity), { + renderHook(() => useBuildRuns(entity), { wrapper: Wrapper, }), ).toThrow('Value for annotation "dev.azure.com/project" was not found'); @@ -116,7 +116,7 @@ describe('useRepoBuilds', () => { }; expect(() => - renderHook(() => useRepoBuilds(entity), { + renderHook(() => useBuildRuns(entity), { wrapper: Wrapper, }), ).toThrow( diff --git a/plugins/azure-devops/src/hooks/useBuildRuns.ts b/plugins/azure-devops/src/hooks/useBuildRuns.ts index ae0273de44..e335d2ffaf 100644 --- a/plugins/azure-devops/src/hooks/useBuildRuns.ts +++ b/plugins/azure-devops/src/hooks/useBuildRuns.ts @@ -15,20 +15,20 @@ */ import { + AZURE_DEVOPS_DEFAULT_TOP, BuildRun, BuildRunOptions, } from '@backstage/plugin-azure-devops-common'; -import { AZURE_DEVOPS_DEFAULT_TOP } from '../constants'; import { azureDevOpsApiRef } from '../api'; import { useApi } from '@backstage/core-plugin-api'; import useAsync from 'react-use/lib/useAsync'; +import { getAnnotationValuesFromEntity } from '../utils'; +import { Entity } from '@backstage/catalog-model'; export function useBuildRuns( - projectName: string, + entity: Entity, defaultLimit?: number, - repoName?: string, - definitionName?: string, ): { items?: BuildRun[]; loading: boolean; @@ -42,8 +42,10 @@ export function useBuildRuns( const api = useApi(azureDevOpsApiRef); const { value, loading, error } = useAsync(() => { - return api.getBuildRuns(projectName, repoName, definitionName, options); - }, [api, projectName, repoName, definitionName]); + const { project, repo, definition, host, org } = + getAnnotationValuesFromEntity(entity); + return api.getBuildRuns(project, repo, definition, host, org, options); + }, [api]); return { items: value?.items, diff --git a/plugins/azure-devops/src/hooks/useGitTags.ts b/plugins/azure-devops/src/hooks/useGitTags.ts index 13c7118934..57489316da 100644 --- a/plugins/azure-devops/src/hooks/useGitTags.ts +++ b/plugins/azure-devops/src/hooks/useGitTags.ts @@ -28,11 +28,11 @@ export function useGitTags(entity: Entity): { error?: Error; } { const api = useApi(azureDevOpsApiRef); - const { project, repo } = getAnnotationValuesFromEntity(entity); - const { value, loading, error } = useAsync(async () => { - return await api.getGitTags(project, repo as string); - }, [api, project, repo]); + const { value, loading, error } = useAsync(() => { + const { project, repo, host, org } = getAnnotationValuesFromEntity(entity); + return api.getGitTags(project, repo as string, host, org); + }, [api]); return { items: value?.items, diff --git a/plugins/azure-devops/src/hooks/usePullRequests.ts b/plugins/azure-devops/src/hooks/usePullRequests.ts index c4223871f2..af2c4b1cc1 100644 --- a/plugins/azure-devops/src/hooks/usePullRequests.ts +++ b/plugins/azure-devops/src/hooks/usePullRequests.ts @@ -15,12 +15,12 @@ */ import { + AZURE_DEVOPS_DEFAULT_TOP, PullRequest, PullRequestOptions, PullRequestStatus, } from '@backstage/plugin-azure-devops-common'; -import { AZURE_DEVOPS_DEFAULT_TOP } from '../constants'; import { Entity } from '@backstage/catalog-model'; import { azureDevOpsApiRef } from '../api'; import { useApi } from '@backstage/core-plugin-api'; @@ -44,11 +44,11 @@ export function usePullRequests( }; const api = useApi(azureDevOpsApiRef); - const { project, repo } = getAnnotationValuesFromEntity(entity); - const { value, loading, error } = useAsync(async () => { - return await api.getPullRequests(project, repo as string, options); - }, [api, project, repo, top, status]); + const { value, loading, error } = useAsync(() => { + const { project, repo, host, org } = getAnnotationValuesFromEntity(entity); + return api.getPullRequests(project, repo as string, host, org, options); + }, [api, top, status]); return { items: value?.items, diff --git a/plugins/azure-devops/src/hooks/useReadme.ts b/plugins/azure-devops/src/hooks/useReadme.ts index 60b2e21990..348b4219f0 100644 --- a/plugins/azure-devops/src/hooks/useReadme.ts +++ b/plugins/azure-devops/src/hooks/useReadme.ts @@ -28,11 +28,11 @@ export function useReadme(entity: Entity): { error?: Error; } { const api = useApi(azureDevOpsApiRef); - const { project, repo } = getAnnotationValuesFromEntity(entity); - const { value, loading, error } = useAsync(async () => { - return await api.getReadme({ project, repo: repo as string }); - }, [api, project, repo]); + const { value, loading, error } = useAsync(() => { + const { project, repo, host, org } = getAnnotationValuesFromEntity(entity); + return api.getReadme({ project, repo: repo as string, host, org }); + }, [api]); return { item: value, diff --git a/plugins/azure-devops/src/hooks/useRepoBuilds.ts b/plugins/azure-devops/src/hooks/useRepoBuilds.ts deleted file mode 100644 index 9292a6e035..0000000000 --- a/plugins/azure-devops/src/hooks/useRepoBuilds.ts +++ /dev/null @@ -1,54 +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 { - RepoBuild, - RepoBuildOptions, -} from '@backstage/plugin-azure-devops-common'; - -import { AZURE_DEVOPS_DEFAULT_TOP } from '../constants'; -import { Entity } from '@backstage/catalog-model'; -import { azureDevOpsApiRef } from '../api'; -import { useApi } from '@backstage/core-plugin-api'; -import useAsync from 'react-use/lib/useAsync'; -import { getAnnotationValuesFromEntity } from '../utils'; - -export function useRepoBuilds( - entity: Entity, - defaultLimit?: number, -): { - items?: RepoBuild[]; - loading: boolean; - error?: Error; -} { - const top = defaultLimit ?? AZURE_DEVOPS_DEFAULT_TOP; - const options: RepoBuildOptions = { - top: top, - }; - - const api = useApi(azureDevOpsApiRef); - const { project, repo } = getAnnotationValuesFromEntity(entity); - - const { value, loading, error } = useAsync(async () => { - return await api.getRepoBuilds(project, repo as string, options); - }, [api, project, repo, entity]); - - return { - items: value?.items, - loading, - error, - }; -} diff --git a/plugins/azure-devops/src/plugin.ts b/plugins/azure-devops/src/plugin.ts index 4dd423f35a..1e76c9e53a 100644 --- a/plugins/azure-devops/src/plugin.ts +++ b/plugins/azure-devops/src/plugin.ts @@ -14,11 +14,6 @@ * limitations under the License. */ -import { - AZURE_DEVOPS_BUILD_DEFINITION_ANNOTATION, - AZURE_DEVOPS_PROJECT_ANNOTATION, - AZURE_DEVOPS_REPO_ANNOTATION, -} from './constants'; import { azurePipelinesEntityContentRouteRef, azurePullRequestDashboardRouteRef, @@ -37,6 +32,11 @@ import { import { AzureDevOpsClient } from './api/AzureDevOpsClient'; import { Entity } from '@backstage/catalog-model'; import { azureDevOpsApiRef } from './api/AzureDevOpsApi'; +import { + AZURE_DEVOPS_REPO_ANNOTATION, + AZURE_DEVOPS_PROJECT_ANNOTATION, + AZURE_DEVOPS_BUILD_DEFINITION_ANNOTATION, +} from '@backstage/plugin-azure-devops-common'; /** @public */ export const isAzureDevOpsAvailable = (entity: Entity) => diff --git a/plugins/azure-devops/src/utils/getAnnotationValuesFromEntity.test.ts b/plugins/azure-devops/src/utils/getAnnotationValuesFromEntity.test.ts index 67e46cee7b..c13dc526d8 100644 --- a/plugins/azure-devops/src/utils/getAnnotationValuesFromEntity.test.ts +++ b/plugins/azure-devops/src/utils/getAnnotationValuesFromEntity.test.ts @@ -67,7 +67,7 @@ describe('getAnnotationValuesFromEntity', () => { }); describe('with project-repo annotation missing project', () => { - it('should throw missing project error', () => { + it('should throw incorrect format error', () => { const entity: Entity = { apiVersion: 'backstage.io/v1alpha1', kind: 'Component', @@ -91,7 +91,7 @@ describe('getAnnotationValuesFromEntity', () => { }); describe('with project-repo annotation missing repo', () => { - it('should throw missing repo error', () => { + it('should throw incorrect format error', () => { const entity: Entity = { apiVersion: 'backstage.io/v1alpha1', kind: 'Component', @@ -261,7 +261,7 @@ describe('getAnnotationValuesFromEntity', () => { }); describe('with host-org annotation missing host', () => { - it('should throw missing project error', () => { + it('should throw incorrect format error', () => { const entity: Entity = { apiVersion: 'backstage.io/v1alpha1', kind: 'Component', @@ -285,7 +285,7 @@ describe('getAnnotationValuesFromEntity', () => { }); describe('with host-org annotation missing org', () => { - it('should throw missing repo error', () => { + it('should throw incorrect format error', () => { const entity: Entity = { apiVersion: 'backstage.io/v1alpha1', kind: 'Component', @@ -307,4 +307,78 @@ describe('getAnnotationValuesFromEntity', () => { ); }); }); + + describe('with tfs subpath for org', () => { + it('should return host and org', () => { + const entity: Entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + namespace: 'default', + name: 'tfs-subpath', + annotations: { + 'dev.azure.com/project-repo': 'projectName/repoName', + 'dev.azure.com/host-org': 'company.com/tfs/organizationName', + }, + }, + }; + + const values = getAnnotationValuesFromEntity(entity); + expect(values).toEqual({ + project: 'projectName', + repo: 'repoName', + definition: undefined, + host: 'company.com/tfs', + org: 'organizationName', + }); + }); + }); + + describe('host-org with more then expected slashes', () => { + it('should throw incorrect format error', () => { + const entity: Entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + namespace: 'default', + name: 'host-org', + annotations: { + 'dev.azure.com/host-org': 'host/subpath/another-path/org/project', + }, + }, + }; + + const test = () => { + return getAnnotationValuesFromEntity(entity); + }; + + expect(test).toThrow( + 'Invalid value for annotation "dev.azure.com/host-org"; expected format is: /, found: "host/subpath/another-path/org/project"', + ); + }); + }); + + describe('project-repo with more then expected slashes', () => { + it('should throw incorrect format error', () => { + const entity: Entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + namespace: 'default', + name: 'project-repo', + annotations: { + 'dev.azure.com/project-repo': 'project/another/repo/final', + }, + }, + }; + + const test = () => { + return getAnnotationValuesFromEntity(entity); + }; + + expect(test).toThrow( + 'Invalid value for annotation "dev.azure.com/project-repo"; expected format is: /, found: "project/another/repo/final"', + ); + }); + }); }); diff --git a/plugins/azure-devops/src/utils/getAnnotationValuesFromEntity.ts b/plugins/azure-devops/src/utils/getAnnotationValuesFromEntity.ts index 9feec8bf95..83091fb155 100644 --- a/plugins/azure-devops/src/utils/getAnnotationValuesFromEntity.ts +++ b/plugins/azure-devops/src/utils/getAnnotationValuesFromEntity.ts @@ -14,14 +14,13 @@ * limitations under the License. */ -import { - AZURE_DEVOPS_BUILD_DEFINITION_ANNOTATION, - AZURE_DEVOPS_HOST_ORG_ANNOTATION, - AZURE_DEVOPS_PROJECT_ANNOTATION, - AZURE_DEVOPS_REPO_ANNOTATION, -} from '../constants'; - import { Entity } from '@backstage/catalog-model'; +import { + AZURE_DEVOPS_PROJECT_ANNOTATION, + AZURE_DEVOPS_BUILD_DEFINITION_ANNOTATION, + AZURE_DEVOPS_REPO_ANNOTATION, + AZURE_DEVOPS_HOST_ORG_ANNOTATION, +} from '@backstage/plugin-azure-devops-common'; export function getAnnotationValuesFromEntity(entity: Entity): { project: string; @@ -69,7 +68,7 @@ function getProjectRepo(annotations?: Record): { return { project: undefined, repo: undefined }; } - if (annotation.includes('/')) { + if (annotation.split('/').length === 2) { const [project, repo] = annotation.split('/'); if (project && repo) { return { project, repo }; @@ -90,11 +89,15 @@ function getHostOrg(annotations?: Record): { return { host: undefined, org: undefined }; } - if (annotation.includes('/')) { - const [host, org] = annotation.split('/'); + const segments = annotation.split('/'); + if (segments.length === 2) { + const [host, org] = segments; if (host && org) { return { host, org }; } + } else if (segments.length === 3) { + const [host, subpath, org] = segments; + return { host: `${host}/${subpath}`, org }; } throw new Error( diff --git a/plugins/azure-sites-backend/CHANGELOG.md b/plugins/azure-sites-backend/CHANGELOG.md index b981cb0b66..c806c46925 100644 --- a/plugins/azure-sites-backend/CHANGELOG.md +++ b/plugins/azure-sites-backend/CHANGELOG.md @@ -1,5 +1,99 @@ # @backstage/plugin-azure-sites-backend +## 0.1.19 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/config@1.1.1 + - @backstage/plugin-azure-sites-common@0.1.1 + +## 0.1.19-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.2 + +## 0.1.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-azure-sites-common@0.1.1 + +## 0.1.19-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/config@1.1.1 + - @backstage/plugin-azure-sites-common@0.1.1 + +## 0.1.18 + +### Patch Changes + +- 99fb541: Updated dependency `@azure/identity` to `^4.0.0`. +- b7a13ed: Updated dependency `@azure/arm-appservice` to `^14.0.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/config@1.1.1 + - @backstage/plugin-azure-sites-common@0.1.1 + +## 0.1.18-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/config@1.1.1 + - @backstage/plugin-azure-sites-common@0.1.1 + +## 0.1.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/config@1.1.1 + - @backstage/plugin-azure-sites-common@0.1.1 + +## 0.1.18-next.1 + +### Patch Changes + +- 99fb54183b: Updated dependency `@azure/identity` to `^4.0.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-azure-sites-common@0.1.1 + +## 0.1.18-next.0 + +### Patch Changes + +- b7a13edf6d: Updated dependency `@azure/arm-appservice` to `^14.0.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/config@1.1.1 + - @backstage/plugin-azure-sites-common@0.1.1 + +## 0.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/config@1.1.1 + - @backstage/plugin-azure-sites-common@0.1.1 + ## 0.1.17-next.2 ### Patch Changes diff --git a/plugins/azure-sites-backend/package.json b/plugins/azure-sites-backend/package.json index 975ad2fee2..ae3a849810 100644 --- a/plugins/azure-sites-backend/package.json +++ b/plugins/azure-sites-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-azure-sites-backend", - "version": "0.1.17-next.2", + "version": "0.1.19", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,9 +32,9 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@azure/arm-appservice": "^13.0.1", + "@azure/arm-appservice": "^14.0.0", "@azure/arm-resourcegraph": "^4.2.1", - "@azure/identity": "^3.2.1", + "@azure/identity": "^4.0.0", "@backstage/backend-common": "workspace:^", "@backstage/config": "workspace:^", "@backstage/plugin-azure-sites-common": "workspace:^", @@ -47,8 +47,7 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@types/supertest": "^2.0.8", - "msw": "^1.0.0" + "@types/supertest": "^2.0.8" }, "files": [ "dist" diff --git a/plugins/azure-sites/CHANGELOG.md b/plugins/azure-sites/CHANGELOG.md index 5c6cf6529f..dd706132a6 100644 --- a/plugins/azure-sites/CHANGELOG.md +++ b/plugins/azure-sites/CHANGELOG.md @@ -1,5 +1,123 @@ # @backstage/plugin-azure-sites +## 0.1.18 + +### Patch Changes + +- a31f688: Show Azure site tags in `EntityAzureSitesOverviewWidget`. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-azure-sites-common@0.1.1 + +## 0.1.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.1.18-next.1 + +### Patch Changes + +- a31f688: Show Azure site tags in `EntityAzureSitesOverviewWidget`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-azure-sites-common@0.1.1 + +## 0.1.18-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-azure-sites-common@0.1.1 + +## 0.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-azure-sites-common@0.1.1 + +## 0.1.17-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-azure-sites-common@0.1.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## 0.1.17-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-azure-sites-common@0.1.1 + +## 0.1.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-azure-sites-common@0.1.1 + +## 0.1.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-azure-sites-common@0.1.1 + +## 0.1.15 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-azure-sites-common@0.1.1 + ## 0.1.15-next.2 ### Patch Changes diff --git a/plugins/azure-sites/package.json b/plugins/azure-sites/package.json index 3be71efd11..cc16ab9e47 100644 --- a/plugins/azure-sites/package.json +++ b/plugins/azure-sites/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-azure-sites", - "version": "0.1.15-next.2", + "version": "0.1.18", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -38,7 +38,6 @@ "@backstage/core-plugin-api": "workspace:^", "@backstage/plugin-azure-sites-common": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", @@ -53,13 +52,11 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", "@backstage/dev-utils": "workspace:^", "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, "files": [ diff --git a/plugins/azure-sites/src/components/AzureSitesOverviewTableComponent/AzureSitesOverviewTable.tsx b/plugins/azure-sites/src/components/AzureSitesOverviewTableComponent/AzureSitesOverviewTable.tsx index 16321cd464..c7f8befedb 100644 --- a/plugins/azure-sites/src/components/AzureSitesOverviewTableComponent/AzureSitesOverviewTable.tsx +++ b/plugins/azure-sites/src/components/AzureSitesOverviewTableComponent/AzureSitesOverviewTable.tsx @@ -18,6 +18,7 @@ import React, { Dispatch, useEffect, useState } from 'react'; import { Box, Card, + Chip, IconButton, LinearProgress, Menu, @@ -39,7 +40,6 @@ import OpenInNewIcon from '@material-ui/icons/OpenInNew'; import { DateTime } from 'luxon'; import { useApi } from '@backstage/core-plugin-api'; import { azureSiteApiRef } from '../../api'; -import { BackstageTheme } from '@backstage/theme'; type States = 'Waiting' | 'Running' | 'Paused' | 'Failed' | 'Stopped'; type Kinds = 'app' | 'functionapp'; @@ -50,7 +50,7 @@ const State = ({ value }: { value: States }) => { common: { black }, status: { ok, error }, }, - } = useTheme(); + } = useTheme(); const colorMap = { Waiting: '#dcbc21', @@ -92,6 +92,18 @@ const Kind = ({ value }: { value: Kinds }) => { ); }; +const Tags = ({ tags }: { tags: any }) => { + return Object.keys(tags).map((key: any) => ( + + )); +}; + type TableProps = { data: AzureSite[]; loading: boolean; @@ -224,6 +236,11 @@ export const AzureSitesOverviewTable = ({ data, loading }: TableProps) => { field: 'status', render: (func: AzureSite) => , }, + { + title: 'Tags', + field: 'tags', + render: (func: AzureSite) => (func.tags ? : ''), + }, { title: 'last modified', field: 'lastModifiedDate', diff --git a/plugins/badges-backend/CHANGELOG.md b/plugins/badges-backend/CHANGELOG.md index bbb536b028..c0135f7ee8 100644 --- a/plugins/badges-backend/CHANGELOG.md +++ b/plugins/badges-backend/CHANGELOG.md @@ -1,5 +1,135 @@ # @backstage/plugin-badges-backend +## 0.3.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.3.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## 0.3.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.3.6-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.3-next.0 + +## 0.3.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/catalog-client@1.5.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.3.5-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + +## 0.3.5-next.2 + +### Patch Changes + +- Updated dependencies + - @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/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.3.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## 0.3.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.3.4 + +### Patch Changes + +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.1 + ## 0.3.4-next.2 ### Patch Changes diff --git a/plugins/badges-backend/package.json b/plugins/badges-backend/package.json index 4a49697345..893a5b6969 100644 --- a/plugins/badges-backend/package.json +++ b/plugins/badges-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-badges-backend", "description": "A Backstage backend plugin that generates README badges for your entities", - "version": "0.3.4-next.2", + "version": "0.3.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -55,8 +55,7 @@ "devDependencies": { "@backstage/backend-test-utils": "workspace:^", "@backstage/catalog-client": "workspace:^", - "@backstage/cli": "workspace:^", - "cross-fetch": "^4.0.0" + "@backstage/cli": "workspace:^" }, "files": [ "dist", diff --git a/plugins/badges/CHANGELOG.md b/plugins/badges/CHANGELOG.md index b7df261971..0897cf4caf 100644 --- a/plugins/badges/CHANGELOG.md +++ b/plugins/badges/CHANGELOG.md @@ -1,5 +1,120 @@ # @backstage/plugin-badges +## 0.2.53 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.2.53-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.2.53-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.2.53-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + +## 0.2.52 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.2.52-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## 0.2.52-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + +## 0.2.52-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## 0.2.52-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.2.50 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + ## 0.2.50-next.2 ### Patch Changes diff --git a/plugins/badges/package.json b/plugins/badges/package.json index fc407675c7..688536d260 100644 --- a/plugins/badges/package.json +++ b/plugins/badges/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-badges", "description": "A Backstage plugin that generates README badges for your entities", - "version": "0.2.50-next.2", + "version": "0.2.53", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,10 +35,7 @@ "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", - "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.61", "@types/react": "^16.13.1 || ^17.0.0", "react-use": "^17.2.4" }, @@ -49,7 +46,6 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", "@backstage/dev-utils": "workspace:^", "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^6.0.0" diff --git a/plugins/bazaar-backend/CHANGELOG.md b/plugins/bazaar-backend/CHANGELOG.md index 825e3f42ba..51dac2f648 100644 --- a/plugins/bazaar-backend/CHANGELOG.md +++ b/plugins/bazaar-backend/CHANGELOG.md @@ -1,5 +1,114 @@ # @backstage/plugin-bazaar-backend +## 0.3.7 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/config@1.1.1 + +## 0.3.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## 0.3.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + +## 0.3.7-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.0 + +## 0.3.6 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.3.6-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + +## 0.3.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.3.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## 0.3.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.3.5 + +### Patch Changes + +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. +- 8613ba3928: Switched to using `"exports"` field for `/alpha` subpath export. +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.1 + ## 0.3.5-next.2 ### Patch Changes diff --git a/plugins/bazaar-backend/alpha-api-report.md b/plugins/bazaar-backend/api-report-alpha.md similarity index 100% rename from plugins/bazaar-backend/alpha-api-report.md rename to plugins/bazaar-backend/api-report-alpha.md diff --git a/plugins/bazaar-backend/package.json b/plugins/bazaar-backend/package.json index 82ce689cab..82f4c66a76 100644 --- a/plugins/bazaar-backend/package.json +++ b/plugins/bazaar-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-bazaar-backend", - "version": "0.3.5-next.2", + "version": "0.3.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -44,7 +44,6 @@ "@backstage/backend-common": "workspace:^", "@backstage/backend-plugin-api": "workspace:^", "@backstage/config": "workspace:^", - "@backstage/errors": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", "@types/express": "^4.17.6", "express": "^4.17.1", diff --git a/plugins/bazaar-backend/src/service/DatabaseHandler.test.ts b/plugins/bazaar-backend/src/service/DatabaseHandler.test.ts index 4e46581240..39fa01ed3f 100644 --- a/plugins/bazaar-backend/src/service/DatabaseHandler.test.ts +++ b/plugins/bazaar-backend/src/service/DatabaseHandler.test.ts @@ -36,7 +36,7 @@ jest.setTimeout(60_000); describe('DatabaseHandler', () => { const databases = TestDatabases.create({ - ids: ['POSTGRES_13', 'POSTGRES_9', 'SQLITE_3', 'MYSQL_8'], + ids: ['POSTGRES_16', 'POSTGRES_12', 'SQLITE_3', 'MYSQL_8'], }); function createDatabaseManager( diff --git a/plugins/bazaar/CHANGELOG.md b/plugins/bazaar/CHANGELOG.md index 8bb4cad655..5e048efb1b 100644 --- a/plugins/bazaar/CHANGELOG.md +++ b/plugins/bazaar/CHANGELOG.md @@ -1,5 +1,147 @@ # @backstage/plugin-bazaar +## 0.2.21 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.2.21-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.2.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.2.21-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + +## 0.2.20 + +### Patch Changes + +- 5d79682: Internalize 'AboutField' to break catalog dependency +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-client@1.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.2.20-next.4 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## 0.2.20-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + +## 0.2.20-next.2 + +### Patch Changes + +- 5d796829bb: Internalize 'AboutField' to break catalog dependency +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## 0.2.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.16.0-next.1 + +## 0.2.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/plugin-catalog@1.16.0-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.2.18 + +### Patch Changes + +- c6e7940ccf: Updated Readme document in bazaar plugin +- 4e66e37bd1: Added alert popup for link and unlink entity in bazaar project +- c5aad900e3: Adding descending sort in a bazaar plugin +- 6c2b872153: Add official support for React 18. +- 69ee8d75f4: Remove `button` prop from used MaterialUI `MenuItem` component fixing incompatibility with MaterialUI v5. +- b3acba9091: Added alert popup in the bazaar plugin +- 1a40159acb: Removed unnecessary dependency on `@backstage/cli`. +- 62b5922916: Internal theme type updates +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/plugin-catalog@1.15.0 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + ## 0.2.18-next.2 ### Patch Changes diff --git a/plugins/bazaar/package.json b/plugins/bazaar/package.json index bb21e6303e..058ead5ca3 100644 --- a/plugins/bazaar/package.json +++ b/plugins/bazaar/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-bazaar", - "version": "0.2.18-next.2", + "version": "0.2.21", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,9 +34,7 @@ "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", - "@backstage/plugin-catalog": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", - "@backstage/theme": "workspace:^", "@date-io/luxon": "1.x", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", diff --git a/plugins/bazaar/src/components/CardContentFields/AboutField.tsx b/plugins/bazaar/src/components/CardContentFields/AboutField.tsx new file mode 100644 index 0000000000..e8c49bf4d7 --- /dev/null +++ b/plugins/bazaar/src/components/CardContentFields/AboutField.tsx @@ -0,0 +1,72 @@ +/* + * 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 { useElementFilter } from '@backstage/core-plugin-api'; +import { Grid, makeStyles, Typography } from '@material-ui/core'; +import React from 'react'; + +const useStyles = makeStyles(theme => ({ + value: { + fontWeight: 'bold', + overflow: 'hidden', + lineHeight: '24px', + wordBreak: 'break-word', + }, + label: { + color: theme.palette.text.secondary, + textTransform: 'uppercase', + fontSize: '10px', + fontWeight: 'bold', + letterSpacing: 0.5, + overflow: 'hidden', + whiteSpace: 'nowrap', + }, +})); + +/** + * Props for {@link AboutField}. + */ +export interface AboutFieldProps { + label: string; + value?: string; + gridSizes?: Record; + children?: React.ReactNode; +} + +export function AboutField(props: AboutFieldProps) { + const { label, value, gridSizes, children } = props; + const classes = useStyles(); + + const childElements = useElementFilter(children, c => c.getElements()); + + // Content is either children or a string prop `value` + const content = + childElements.length > 0 ? ( + childElements + ) : ( + + {value || `unknown`} + + ); + return ( + + + {label} + + {content} + + ); +} diff --git a/plugins/bazaar/src/components/CardContentFields/CardContentFields.tsx b/plugins/bazaar/src/components/CardContentFields/CardContentFields.tsx index 82ab9df89d..f252efebee 100644 --- a/plugins/bazaar/src/components/CardContentFields/CardContentFields.tsx +++ b/plugins/bazaar/src/components/CardContentFields/CardContentFields.tsx @@ -25,8 +25,8 @@ import { import { parseEntityRef } from '@backstage/catalog-model'; import { Avatar, Link } from '@backstage/core-components'; import { useRouteRef } from '@backstage/core-plugin-api'; -import { AboutField } from '@backstage/plugin-catalog'; import { entityRouteRef } from '@backstage/plugin-catalog-react'; +import { AboutField } from './AboutField'; import { StatusTag } from '../StatusTag'; import { Member, BazaarProject } from '../../types'; diff --git a/plugins/bazaar/src/components/InputSelector/InputSelector.tsx b/plugins/bazaar/src/components/InputSelector/InputSelector.tsx index b7e9ecd96a..69907f9b3e 100644 --- a/plugins/bazaar/src/components/InputSelector/InputSelector.tsx +++ b/plugins/bazaar/src/components/InputSelector/InputSelector.tsx @@ -60,7 +60,7 @@ export const InputSelector = ({ name, options, control, error }: Props) => { > {options.map(option => { return ( - + {option} ); diff --git a/plugins/bitbucket-cloud-common/CHANGELOG.md b/plugins/bitbucket-cloud-common/CHANGELOG.md index cbe27eeda7..d2883dce02 100644 --- a/plugins/bitbucket-cloud-common/CHANGELOG.md +++ b/plugins/bitbucket-cloud-common/CHANGELOG.md @@ -1,5 +1,36 @@ # @backstage/plugin-bitbucket-cloud-common +## 0.2.15 + +### Patch Changes + +- acf9390: Updated dependency `ts-morph` to `^20.0.0`. +- Updated dependencies + - @backstage/integration@1.8.0 + +## 0.2.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + +## 0.2.15-next.0 + +### Patch Changes + +- acf93904e7: Updated dependency `ts-morph` to `^20.0.0`. +- Updated dependencies + - @backstage/integration@1.8.0-next.0 + +## 0.2.14 + +### Patch Changes + +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- Updated dependencies + - @backstage/integration@1.7.2 + ## 0.2.14-next.0 ### Patch Changes diff --git a/plugins/bitbucket-cloud-common/package.json b/plugins/bitbucket-cloud-common/package.json index b4dd8d4482..d9a11c9a5d 100644 --- a/plugins/bitbucket-cloud-common/package.json +++ b/plugins/bitbucket-cloud-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-bitbucket-cloud-common", "description": "Common functionalities for bitbucket-cloud plugins", - "version": "0.2.14-next.0", + "version": "0.2.15", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -41,7 +41,7 @@ "@backstage/cli": "workspace:^", "@openapitools/openapi-generator-cli": "^2.4.26", "msw": "^1.0.0", - "ts-morph": "^17.0.0" + "ts-morph": "^20.0.0" }, "files": [ "dist" diff --git a/plugins/bitrise/CHANGELOG.md b/plugins/bitrise/CHANGELOG.md index ace0b27c13..efc87f6839 100644 --- a/plugins/bitrise/CHANGELOG.md +++ b/plugins/bitrise/CHANGELOG.md @@ -1,5 +1,112 @@ # @backstage/plugin-bitrise +## 0.1.56 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## 0.1.56-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.1.56-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + +## 0.1.56-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + +## 0.1.55 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + +## 0.1.55-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## 0.1.55-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## 0.1.55-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## 0.1.55-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + +## 0.1.53 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + ## 0.1.53-next.2 ### Patch Changes diff --git a/plugins/bitrise/package.json b/plugins/bitrise/package.json index b3b7f771b3..2dd804f746 100644 --- a/plugins/bitrise/package.json +++ b/plugins/bitrise/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-bitrise", "description": "A Backstage plugin that integrates towards Bitrise", - "version": "0.1.53-next.2", + "version": "0.1.56", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,7 +34,6 @@ "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", diff --git a/plugins/catalog-backend-module-aws/CHANGELOG.md b/plugins/catalog-backend-module-aws/CHANGELOG.md index b7c33a1823..ff0c82bcc4 100644 --- a/plugins/catalog-backend-module-aws/CHANGELOG.md +++ b/plugins/catalog-backend-module-aws/CHANGELOG.md @@ -1,5 +1,182 @@ # @backstage/plugin-catalog-backend-module-aws +## 0.3.3 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- 22e88d0: Added status and e-mail as labels to the AWS Account Resource +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-kubernetes-common@0.7.3 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/integration-aws-node@0.1.8 + - @backstage/plugin-catalog-common@1.0.20 + +## 0.3.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## 0.3.3-next.1 + +### Patch Changes + +- 22e88d0: Added status and e-mail as labels to the AWS Account Resource +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/integration-aws-node@0.1.8 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-catalog-node@1.6.1-next.1 + - @backstage/plugin-kubernetes-common@0.7.3-next.0 + +## 0.3.3-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/plugin-kubernetes-common@0.7.3-next.0 + - @backstage/plugin-catalog-node@1.6.1-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/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/integration-aws-node@0.1.8 + - @backstage/plugin-catalog-common@1.0.19 + +## 0.3.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/plugin-kubernetes-common@0.7.2 + - @backstage/integration@1.8.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + +## 0.3.2-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.6.0-next.3 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + +## 0.3.2-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/backend-common@0.20.0-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/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + +## 0.3.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## 0.3.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/plugin-kubernetes-common@0.7.2-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + +## 0.3.1 + +### Patch Changes + +- 20d97d28a3: Updated dependency `aws-sdk-client-mock-jest` to `^3.0.0`. +- 3d043526f4: Updated dependency `aws-sdk-client-mock` to `^3.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/plugin-kubernetes-common@0.7.1 + - @backstage/integration@1.7.2 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/integration-aws-node@0.1.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + ## 0.3.1-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-aws/alpha-api-report.md b/plugins/catalog-backend-module-aws/api-report-alpha.md similarity index 100% rename from plugins/catalog-backend-module-aws/alpha-api-report.md rename to plugins/catalog-backend-module-aws/api-report-alpha.md diff --git a/plugins/catalog-backend-module-aws/package.json b/plugins/catalog-backend-module-aws/package.json index dea39d792b..af507e3c68 100644 --- a/plugins/catalog-backend-module-aws/package.json +++ b/plugins/catalog-backend-module-aws/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-aws", "description": "A Backstage catalog backend module that helps integrate towards AWS", - "version": "0.3.1-next.2", + "version": "0.3.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -62,8 +62,6 @@ "@backstage/plugin-catalog-common": "workspace:^", "@backstage/plugin-catalog-node": "workspace:^", "@backstage/plugin-kubernetes-common": "workspace:^", - "@backstage/types": "workspace:^", - "lodash": "^4.17.21", "p-limit": "^3.0.2", "uuid": "^8.0.0", "winston": "^3.2.1" @@ -72,7 +70,6 @@ "@aws-sdk/util-stream-node": "^3.350.0", "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", - "@types/lodash": "^4.14.151", "aws-sdk-client-mock": "^3.0.0", "aws-sdk-client-mock-jest": "^3.0.0", "luxon": "^3.0.0", diff --git a/plugins/catalog-backend-module-aws/src/module/catalogModuleAwsS3EntityProvider.ts b/plugins/catalog-backend-module-aws/src/module/catalogModuleAwsS3EntityProvider.ts index 521d61d3d8..e7816ae12f 100644 --- a/plugins/catalog-backend-module-aws/src/module/catalogModuleAwsS3EntityProvider.ts +++ b/plugins/catalog-backend-module-aws/src/module/catalogModuleAwsS3EntityProvider.ts @@ -29,7 +29,7 @@ import { AwsS3EntityProvider } from '../providers'; */ export const catalogModuleAwsS3EntityProvider = createBackendModule({ pluginId: 'catalog', - moduleId: 'awsS3EntityProvider', + moduleId: 'aws-s3-entity-provider', register(env) { env.registerInit({ deps: { diff --git a/plugins/catalog-backend-module-aws/src/processors/AwsOrganizationCloudAccountProcessor.test.ts b/plugins/catalog-backend-module-aws/src/processors/AwsOrganizationCloudAccountProcessor.test.ts index 458a1f3531..05b247720a 100644 --- a/plugins/catalog-backend-module-aws/src/processors/AwsOrganizationCloudAccountProcessor.test.ts +++ b/plugins/catalog-backend-module-aws/src/processors/AwsOrganizationCloudAccountProcessor.test.ts @@ -40,7 +40,9 @@ describe('AwsOrganizationCloudAccountProcessor', () => { Accounts: [ { Arn: 'arn:aws:organizations::192594491037:account/o-1vl18kc5a3/957140518395', - Name: 'testaccount', + Name: 'Test Account', + Email: 'aws-test-account@backstage.io', + Status: 'ACTIVE', }, ], NextToken: undefined, @@ -59,7 +61,12 @@ describe('AwsOrganizationCloudAccountProcessor', () => { 'amazonaws.com/account-id': '957140518395', 'amazonaws.com/organization-id': 'o-1vl18kc5a3', }, - name: 'testaccount', + labels: { + 'amazonaws.com/account-status': 'active', + 'amazonaws.com/account-email': 'aws-test-account@backstage.io', + }, + name: 'test-account', + title: 'Test Account', namespace: 'default', }, spec: { @@ -79,11 +86,11 @@ describe('AwsOrganizationCloudAccountProcessor', () => { Accounts: [ { Arn: 'arn:aws:organizations::192594491037:account/o-1vl18kc5a3/957140518395', - Name: 'testaccount', + Name: 'Test Account', }, { Arn: 'arn:aws:organizations::192594491037:account/o-zzzzzzzzz/957140518395', - Name: 'testaccount2', + Name: 'Test Account 2', }, ], NextToken: undefined, @@ -103,7 +110,12 @@ describe('AwsOrganizationCloudAccountProcessor', () => { 'amazonaws.com/account-id': '957140518395', 'amazonaws.com/organization-id': 'o-1vl18kc5a3', }, - name: 'testaccount', + labels: { + 'amazonaws.com/account-status': '', + 'amazonaws.com/account-email': '', + }, + name: 'test-account', + title: 'Test Account', namespace: 'default', }, spec: { diff --git a/plugins/catalog-backend-module-aws/src/processors/AwsOrganizationCloudAccountProcessor.ts b/plugins/catalog-backend-module-aws/src/processors/AwsOrganizationCloudAccountProcessor.ts index 264fa7a50d..3e42fc79d2 100644 --- a/plugins/catalog-backend-module-aws/src/processors/AwsOrganizationCloudAccountProcessor.ts +++ b/plugins/catalog-backend-module-aws/src/processors/AwsOrganizationCloudAccountProcessor.ts @@ -41,6 +41,9 @@ const ACCOUNTID_ANNOTATION = 'amazonaws.com/account-id'; const ARN_ANNOTATION = 'amazonaws.com/arn'; const ORGANIZATION_ANNOTATION = 'amazonaws.com/organization-id'; +const ACCOUNT_STATUS_LABEL = 'amazonaws.com/account-status'; +const ACCOUNT_EMAIL_LABEL = 'amazonaws.com/account-email'; + /** * A processor for ingesting AWS Accounts from AWS Organizations. * @@ -123,6 +126,10 @@ export class AwsOrganizationCloudAccountProcessor implements CatalogProcessor { .replace(/[^a-zA-Z0-9\-]/g, '-'); } + private normalizeAccountStatus(name: string): string { + return name.toLocaleLowerCase('en-US'); + } + private extractInformationFromArn(arn: string): { accountId: string; organizationId: string; @@ -165,7 +172,14 @@ export class AwsOrganizationCloudAccountProcessor implements CatalogProcessor { [ARN_ANNOTATION]: account.Arn || '', [ORGANIZATION_ANNOTATION]: organizationId, }, + labels: { + [ACCOUNT_EMAIL_LABEL]: account.Email || '', + [ACCOUNT_STATUS_LABEL]: this.normalizeAccountStatus( + account.Status || '', + ), + }, name: this.normalizeName(account.Name || ''), + title: account.Name || '', namespace: 'default', }, spec: { diff --git a/plugins/catalog-backend-module-azure/CHANGELOG.md b/plugins/catalog-backend-module-azure/CHANGELOG.md index 280325be31..e33d32aa36 100644 --- a/plugins/catalog-backend-module-azure/CHANGELOG.md +++ b/plugins/catalog-backend-module-azure/CHANGELOG.md @@ -1,5 +1,154 @@ # @backstage/plugin-catalog-backend-module-azure +## 0.1.28 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + - @backstage/plugin-catalog-common@1.0.20 + +## 0.1.28-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## 0.1.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-catalog-node@1.6.1-next.1 + +## 0.1.28-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/plugin-catalog-node@1.6.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/backend-tasks@0.5.14-next.0 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + - @backstage/plugin-catalog-common@1.0.19 + +## 0.1.27 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/integration@1.8.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + +## 0.1.27-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.6.0-next.3 + +## 0.1.27-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/backend-common@0.20.0-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/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + +## 0.1.27-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## 0.1.27-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + +## 0.1.26 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/integration@1.7.2 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + ## 0.1.26-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-azure/alpha-api-report.md b/plugins/catalog-backend-module-azure/api-report-alpha.md similarity index 100% rename from plugins/catalog-backend-module-azure/alpha-api-report.md rename to plugins/catalog-backend-module-azure/api-report-alpha.md diff --git a/plugins/catalog-backend-module-azure/package.json b/plugins/catalog-backend-module-azure/package.json index 590a4edab1..05d2587746 100644 --- a/plugins/catalog-backend-module-azure/package.json +++ b/plugins/catalog-backend-module-azure/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-azure", "description": "A Backstage catalog backend module that helps integrate towards Azure", - "version": "0.1.26-next.2", + "version": "0.1.28", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -48,14 +48,10 @@ "@backstage/backend-common": "workspace:^", "@backstage/backend-plugin-api": "workspace:^", "@backstage/backend-tasks": "workspace:^", - "@backstage/catalog-model": "workspace:^", "@backstage/config": "workspace:^", - "@backstage/errors": "workspace:^", "@backstage/integration": "workspace:^", "@backstage/plugin-catalog-common": "workspace:^", "@backstage/plugin-catalog-node": "workspace:^", - "@backstage/types": "workspace:^", - "lodash": "^4.17.21", "node-fetch": "^2.6.7", "uuid": "^8.0.0", "winston": "^3.2.1" @@ -63,7 +59,6 @@ "devDependencies": { "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", - "@types/lodash": "^4.14.151", "luxon": "^3.0.0", "msw": "^1.0.0" }, diff --git a/plugins/catalog-backend-module-azure/src/module/catalogModuleAzureDevOpsEntityProvider.ts b/plugins/catalog-backend-module-azure/src/module/catalogModuleAzureDevOpsEntityProvider.ts index 804c0d4712..b9c55041b3 100644 --- a/plugins/catalog-backend-module-azure/src/module/catalogModuleAzureDevOpsEntityProvider.ts +++ b/plugins/catalog-backend-module-azure/src/module/catalogModuleAzureDevOpsEntityProvider.ts @@ -29,7 +29,7 @@ import { AzureDevOpsEntityProvider } from '../providers'; */ export const catalogModuleAzureDevOpsEntityProvider = createBackendModule({ pluginId: 'catalog', - moduleId: 'azureDevOpsEntityProvider', + moduleId: 'azure-dev-ops-entity-provider', register(env) { env.registerInit({ deps: { diff --git a/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md b/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md index d18925cdd4..28d4c10240 100644 --- a/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md +++ b/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md @@ -1,5 +1,151 @@ # @backstage/plugin-catalog-backend-module-backstage-openapi +## 0.1.2 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-openapi-utils@0.1.2 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.1.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/backend-openapi-utils@0.1.2-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## 0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/backend-openapi-utils@0.1.2-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-node@1.6.1-next.1 + +## 0.1.2-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-openapi-utils@0.1.2-next.0 + - @backstage/plugin-catalog-node@1.6.1-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/errors@1.2.3 + +## 0.1.1 + +### Patch Changes + +- eb44e92: Support authenticated backends +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/backend-openapi-utils@0.1.1 + - @backstage/backend-tasks@0.5.13 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.1.1-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-openapi-utils@0.1.1-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-node@1.6.0-next.3 + +## 0.1.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/backend-common@0.20.0-next.2 + - @backstage/backend-openapi-utils@0.1.1-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/errors@1.2.3 + +## 0.1.1-next.1 + +### Patch Changes + +- eb44e92898: Support authenticated backends +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-openapi-utils@0.1.1-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## 0.1.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-openapi-utils@0.1.1-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.1.0 + +### Minor Changes + +- 785fb1ea75: Adds a new catalog module for ingesting Backstage plugin OpenAPI specs into the catalog for display as an API entity. + +### Patch Changes + +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/backend-openapi-utils@0.1.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + ## 0.1.0-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-backstage-openapi/package.json b/plugins/catalog-backend-module-backstage-openapi/package.json index 55cf189ac7..ff331aeca5 100644 --- a/plugins/catalog-backend-module-backstage-openapi/package.json +++ b/plugins/catalog-backend-module-backstage-openapi/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-backstage-openapi", - "version": "0.1.0-next.2", + "version": "0.1.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,8 +31,6 @@ "@backstage/errors": "workspace:^", "@backstage/plugin-catalog-node": "workspace:^", "cross-fetch": "^4.0.0", - "express": "^4.17.1", - "express-promise-router": "^4.1.0", "lodash": "^4.17.21", "openapi-merge": "^1.3.2", "uuid": "^9.0.0", @@ -40,12 +38,9 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/test-utils": "workspace:^", "@types/express": "*", "@types/supertest": "^2.0.8", - "msw": "^1.0.0", - "openapi3-ts": "^3.1.2", - "supertest": "^6.2.4" + "openapi3-ts": "^3.1.2" }, "configSchema": "config.d.ts", "files": [ diff --git a/plugins/catalog-backend-module-backstage-openapi/src/InternalOpenApiDocumentationProvider.ts b/plugins/catalog-backend-module-backstage-openapi/src/InternalOpenApiDocumentationProvider.ts index 33c461d95a..a8782e5eea 100644 --- a/plugins/catalog-backend-module-backstage-openapi/src/InternalOpenApiDocumentationProvider.ts +++ b/plugins/catalog-backend-module-backstage-openapi/src/InternalOpenApiDocumentationProvider.ts @@ -25,6 +25,7 @@ import { EntityProviderConnection, } from '@backstage/plugin-catalog-node'; import { merge, isErrorResult } from 'openapi-merge'; +import { TokenManager } from '@backstage/backend-common'; import { getOpenApiSpecRoute } from '@backstage/backend-openapi-utils'; import type { OpenAPIObject, @@ -107,17 +108,25 @@ const loadSpecs = async ({ discovery, plugins, logger, + tokenManager, }: { baseUrl: string; plugins: string[]; discovery: DiscoveryService; logger: LoggerService; + tokenManager: TokenManager; }) => { const specs: OpenAPIObject[] = []; for (const pluginId of plugins) { const url = await discovery.getExternalBaseUrl(pluginId); const openApiUrl = getOpenApiSpecRoute(url); - const response = await fetch(openApiUrl); + const { token } = await tokenManager.getToken(); + const response = await fetch(openApiUrl, { + method: 'GET', + headers: { + Authorization: `Bearer ${token}`, + }, + }); if (response.ok) { const spec = await response.json(); addTagsToSpec(spec, pluginId); @@ -144,6 +153,7 @@ export class InternalOpenApiDocumentationProvider implements EntityProvider { public readonly config: Config, public readonly discovery: DiscoveryService, public readonly logger: LoggerService, + public readonly tokenManager: TokenManager, taskRunner: TaskRunner, ) { this.scheduleFn = this.createScheduleFn(taskRunner); @@ -155,6 +165,7 @@ export class InternalOpenApiDocumentationProvider implements EntityProvider { discovery: DiscoveryService; logger: LoggerService; schedule: PluginTaskScheduler; + tokenManager: TokenManager; }, ) { const taskRunner = options.schedule.createScheduledTaskRunner({ @@ -169,6 +180,7 @@ export class InternalOpenApiDocumentationProvider implements EntityProvider { config, options.discovery, options.logger, + options.tokenManager, taskRunner, ); } @@ -231,6 +243,7 @@ export class InternalOpenApiDocumentationProvider implements EntityProvider { await loadSpecs({ baseUrl: this.config.getString('backend.baseUrl'), discovery: this.discovery, + tokenManager: this.tokenManager, plugins: pluginsToMerge, logger, }), diff --git a/plugins/catalog-backend-module-backstage-openapi/src/index.ts b/plugins/catalog-backend-module-backstage-openapi/src/index.ts index 226442666c..ac425afaf2 100644 --- a/plugins/catalog-backend-module-backstage-openapi/src/index.ts +++ b/plugins/catalog-backend-module-backstage-openapi/src/index.ts @@ -44,13 +44,22 @@ export const catalogModuleInternalOpenApiSpec = createBackendModule({ discovery: coreServices.discovery, scheduler: coreServices.scheduler, logger: coreServices.logger, + tokenManager: coreServices.tokenManager, }, - async init({ catalog, config, discovery, scheduler, logger }) { + async init({ + catalog, + config, + discovery, + scheduler, + logger, + tokenManager, + }) { catalog.addEntityProvider( InternalOpenApiDocumentationProvider.fromConfig(config, { discovery, schedule: scheduler, logger, + tokenManager, }), ); }, diff --git a/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md index 0fea22581e..0fb20563d0 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,171 @@ # @backstage/plugin-catalog-backend-module-bitbucket-cloud +## 0.1.24 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.15 + - @backstage/plugin-catalog-common@1.0.20 + - @backstage/plugin-events-node@0.2.18 + +## 0.1.24-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/plugin-events-node@0.2.18-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## 0.1.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-bitbucket-cloud-common@0.2.15 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-catalog-node@1.6.1-next.1 + - @backstage/plugin-events-node@0.2.18-next.1 + +## 0.1.24-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/plugin-catalog-node@1.6.1-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-bitbucket-cloud-common@0.2.15 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-events-node@0.2.18-next.0 + +## 0.1.23 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/catalog-client@1.5.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/plugin-bitbucket-cloud-common@0.2.15 + - @backstage/integration@1.8.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-events-node@0.2.17 + +## 0.1.23-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-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-bitbucket-cloud-common@0.2.15-next.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.6.0-next.3 + - @backstage/plugin-events-node@0.2.17-next.3 + +## 0.1.23-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/backend-common@0.20.0-next.2 + - @backstage/catalog-client@1.5.0-next.1 + - @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-bitbucket-cloud-common@0.2.15-next.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-events-node@0.2.17-next.2 + +## 0.1.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-bitbucket-cloud-common@0.2.15-next.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-events-node@0.2.17-next.1 + +## 0.1.23-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.15-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-events-node@0.2.17-next.0 + +## 0.1.22 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/integration@1.7.2 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/catalog-client@1.4.6 + - @backstage/plugin-bitbucket-cloud-common@0.2.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-events-node@0.2.16 + ## 0.1.22-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket-cloud/alpha-api-report.md b/plugins/catalog-backend-module-bitbucket-cloud/api-report-alpha.md similarity index 100% rename from plugins/catalog-backend-module-bitbucket-cloud/alpha-api-report.md rename to plugins/catalog-backend-module-bitbucket-cloud/api-report-alpha.md diff --git a/plugins/catalog-backend-module-bitbucket-cloud/package.json b/plugins/catalog-backend-module-bitbucket-cloud/package.json index 3e446c3ef3..e1352c6363 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/package.json +++ b/plugins/catalog-backend-module-bitbucket-cloud/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-bitbucket-cloud", "description": "A Backstage catalog backend module that helps integrate towards Bitbucket Cloud", - "version": "0.1.22-next.2", + "version": "0.1.24", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-bitbucket-cloud/src/module/catalogModuleBitbucketCloudEntityProvider.ts b/plugins/catalog-backend-module-bitbucket-cloud/src/module/catalogModuleBitbucketCloudEntityProvider.ts index e5e1ad1609..39265dc1a5 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/src/module/catalogModuleBitbucketCloudEntityProvider.ts +++ b/plugins/catalog-backend-module-bitbucket-cloud/src/module/catalogModuleBitbucketCloudEntityProvider.ts @@ -31,7 +31,7 @@ import { BitbucketCloudEntityProvider } from '../providers/BitbucketCloudEntityP */ export const catalogModuleBitbucketCloudEntityProvider = createBackendModule({ pluginId: 'catalog', - moduleId: 'bitbucketCloudEntityProvider', + moduleId: 'bitbucket-cloud-entity-provider', register(env) { env.registerInit({ deps: { diff --git a/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md index 4a388c5d25..d3abaf1608 100644 --- a/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md @@ -1,5 +1,143 @@ # @backstage/plugin-catalog-backend-module-bitbucket-server +## 0.1.22 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## 0.1.22-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## 0.1.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-node@1.6.1-next.1 + +## 0.1.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/plugin-catalog-node@1.6.1-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/errors@1.2.3 + - @backstage/integration@1.8.0 + +## 0.1.21 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/integration@1.8.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.1.21-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/plugin-catalog-node@1.6.0-next.3 + +## 0.1.21-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/backend-common@0.20.0-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/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + +## 0.1.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## 0.1.21-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.1.20 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/integration@1.7.2 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + ## 0.1.20-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket-server/alpha-api-report.md b/plugins/catalog-backend-module-bitbucket-server/api-report-alpha.md similarity index 100% rename from plugins/catalog-backend-module-bitbucket-server/alpha-api-report.md rename to plugins/catalog-backend-module-bitbucket-server/api-report-alpha.md diff --git a/plugins/catalog-backend-module-bitbucket-server/package.json b/plugins/catalog-backend-module-bitbucket-server/package.json index a593ce88ff..00f8c6572f 100644 --- a/plugins/catalog-backend-module-bitbucket-server/package.json +++ b/plugins/catalog-backend-module-bitbucket-server/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-bitbucket-server", - "version": "0.1.20-next.2", + "version": "0.1.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-bitbucket-server/src/module/catalogModuleBitbucketServerEntityProvider.ts b/plugins/catalog-backend-module-bitbucket-server/src/module/catalogModuleBitbucketServerEntityProvider.ts index ef71df9b06..dd2a423cdc 100644 --- a/plugins/catalog-backend-module-bitbucket-server/src/module/catalogModuleBitbucketServerEntityProvider.ts +++ b/plugins/catalog-backend-module-bitbucket-server/src/module/catalogModuleBitbucketServerEntityProvider.ts @@ -27,7 +27,7 @@ import { BitbucketServerEntityProvider } from '../providers'; */ export const catalogModuleBitbucketServerEntityProvider = createBackendModule({ pluginId: 'catalog', - moduleId: 'bitbucketServerEntityProvider', + moduleId: 'bitbucket-server-entity-provider', register(env) { env.registerInit({ deps: { diff --git a/plugins/catalog-backend-module-bitbucket/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket/CHANGELOG.md index 4b621af6bc..b39778b2fb 100644 --- a/plugins/catalog-backend-module-bitbucket/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket/CHANGELOG.md @@ -1,5 +1,132 @@ # @backstage/plugin-catalog-backend-module-bitbucket +## 0.2.24 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.15 + +## 0.2.24-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + +## 0.2.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/plugin-bitbucket-cloud-common@0.2.15 + - @backstage/plugin-catalog-node@1.6.1-next.1 + +## 0.2.24-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/plugin-catalog-node@1.6.1-next.0 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.15 + +## 0.2.23 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.15 + - @backstage/integration@1.8.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.2.23-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-bitbucket-cloud-common@0.2.15-next.1 + - @backstage/plugin-catalog-node@1.6.0-next.3 + +## 0.2.23-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/backend-common@0.20.0-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-bitbucket-cloud-common@0.2.15-next.1 + +## 0.2.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-bitbucket-cloud-common@0.2.15-next.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## 0.2.23-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.15-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.2.22 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/integration@1.7.2 + - @backstage/backend-common@0.19.9 + - @backstage/plugin-bitbucket-cloud-common@0.2.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + ## 0.2.22-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket/package.json b/plugins/catalog-backend-module-bitbucket/package.json index 178f3d3e4d..2625835a5b 100644 --- a/plugins/catalog-backend-module-bitbucket/package.json +++ b/plugins/catalog-backend-module-bitbucket/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-bitbucket", "description": "A Backstage catalog backend module that helps integrate towards Bitbucket", - "version": "0.2.22-next.2", + "version": "0.2.24", "deprecated": true, "main": "src/index.ts", "types": "src/index.ts", @@ -34,21 +34,16 @@ }, "dependencies": { "@backstage/backend-common": "workspace:^", - "@backstage/catalog-model": "workspace:^", "@backstage/config": "workspace:^", - "@backstage/errors": "workspace:^", "@backstage/integration": "workspace:^", "@backstage/plugin-bitbucket-cloud-common": "workspace:^", "@backstage/plugin-catalog-node": "workspace:^", - "@backstage/types": "workspace:^", - "lodash": "^4.17.21", "node-fetch": "^2.6.7", "winston": "^3.2.1" }, "devDependencies": { "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", - "@types/lodash": "^4.14.151", "msw": "^1.0.0" }, "files": [ diff --git a/plugins/catalog-backend-module-gcp/CHANGELOG.md b/plugins/catalog-backend-module-gcp/CHANGELOG.md index f94c653b04..aef3c0c14a 100644 --- a/plugins/catalog-backend-module-gcp/CHANGELOG.md +++ b/plugins/catalog-backend-module-gcp/CHANGELOG.md @@ -1,5 +1,137 @@ # @backstage/plugin-catalog-backend-module-gcp +## 0.1.9 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-kubernetes-common@0.7.3 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + +## 0.1.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## 0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-node@1.6.1-next.1 + - @backstage/plugin-kubernetes-common@0.7.3-next.0 + +## 0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/plugin-kubernetes-common@0.7.3-next.0 + - @backstage/plugin-catalog-node@1.6.1-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 + +## 0.1.8 + +### Patch Changes + +- 42c1aee: Updated dependency `@google-cloud/container` to `^5.0.0`. +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/plugin-kubernetes-common@0.7.2 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + +## 0.1.8-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-node@1.6.0-next.3 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + +## 0.1.8-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/backend-common@0.20.0-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/plugin-kubernetes-common@0.7.2-next.1 + +## 0.1.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## 0.1.8-next.0 + +### Patch Changes + +- 42c1aee741: Updated dependency `@google-cloud/container` to `^5.0.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/plugin-kubernetes-common@0.7.2-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + +## 0.1.7 + +### Patch Changes + +- 62180df4ee: Allow integration with kubernetes dashboard +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/plugin-kubernetes-common@0.7.1 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + ## 0.1.7-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-gcp/alpha-api-report.md b/plugins/catalog-backend-module-gcp/api-report-alpha.md similarity index 100% rename from plugins/catalog-backend-module-gcp/alpha-api-report.md rename to plugins/catalog-backend-module-gcp/api-report-alpha.md diff --git a/plugins/catalog-backend-module-gcp/package.json b/plugins/catalog-backend-module-gcp/package.json index 7c0c4ff0b5..5515feeb5b 100644 --- a/plugins/catalog-backend-module-gcp/package.json +++ b/plugins/catalog-backend-module-gcp/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-gcp", "description": "A Backstage catalog backend module that helps integrate towards GCP", - "version": "0.1.7-next.2", + "version": "0.1.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -52,7 +52,7 @@ "@backstage/config": "workspace:^", "@backstage/plugin-catalog-node": "workspace:^", "@backstage/plugin-kubernetes-common": "workspace:^", - "@google-cloud/container": "^4.15.0", + "@google-cloud/container": "^5.0.0", "winston": "^3.2.1" }, "devDependencies": { diff --git a/plugins/catalog-backend-module-gcp/src/module/catalogModuleGcpGkeEntityProvider.ts b/plugins/catalog-backend-module-gcp/src/module/catalogModuleGcpGkeEntityProvider.ts index 7f93bddbfe..acc216e1f6 100644 --- a/plugins/catalog-backend-module-gcp/src/module/catalogModuleGcpGkeEntityProvider.ts +++ b/plugins/catalog-backend-module-gcp/src/module/catalogModuleGcpGkeEntityProvider.ts @@ -29,7 +29,7 @@ import { GkeEntityProvider } from '../providers/GkeEntityProvider'; */ export const catalogModuleGcpGkeEntityProvider = createBackendModule({ pluginId: 'catalog', - moduleId: 'gcpGkeEntityProvider', + moduleId: 'gcp-gke-entity-provider', register(env) { env.registerInit({ deps: { diff --git a/plugins/catalog-backend-module-gerrit/CHANGELOG.md b/plugins/catalog-backend-module-gerrit/CHANGELOG.md index 5e8d10ce5a..f43a1a7550 100644 --- a/plugins/catalog-backend-module-gerrit/CHANGELOG.md +++ b/plugins/catalog-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,142 @@ # @backstage/plugin-catalog-backend-module-gerrit +## 0.1.25 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## 0.1.25-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## 0.1.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-node@1.6.1-next.1 + +## 0.1.25-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/plugin-catalog-node@1.6.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/backend-tasks@0.5.14-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## 0.1.24 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/integration@1.8.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.1.24-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/plugin-catalog-node@1.6.0-next.3 + +## 0.1.24-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/backend-common@0.20.0-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/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + +## 0.1.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## 0.1.24-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.1.23 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/integration@1.7.2 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + ## 0.1.23-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-gerrit/alpha-api-report.md b/plugins/catalog-backend-module-gerrit/api-report-alpha.md similarity index 100% rename from plugins/catalog-backend-module-gerrit/alpha-api-report.md rename to plugins/catalog-backend-module-gerrit/api-report-alpha.md diff --git a/plugins/catalog-backend-module-gerrit/package.json b/plugins/catalog-backend-module-gerrit/package.json index 1dc5e7ecfe..95f90287c3 100644 --- a/plugins/catalog-backend-module-gerrit/package.json +++ b/plugins/catalog-backend-module-gerrit/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-gerrit", - "version": "0.1.23-next.2", + "version": "0.1.25", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -44,7 +44,6 @@ "@backstage/backend-common": "workspace:^", "@backstage/backend-plugin-api": "workspace:^", "@backstage/backend-tasks": "workspace:^", - "@backstage/catalog-model": "workspace:^", "@backstage/config": "workspace:^", "@backstage/errors": "workspace:^", "@backstage/integration": "workspace:^", diff --git a/plugins/catalog-backend-module-gerrit/src/module/catalogModuleGerritEntityProvider.ts b/plugins/catalog-backend-module-gerrit/src/module/catalogModuleGerritEntityProvider.ts index bb29ce6eef..af870d095f 100644 --- a/plugins/catalog-backend-module-gerrit/src/module/catalogModuleGerritEntityProvider.ts +++ b/plugins/catalog-backend-module-gerrit/src/module/catalogModuleGerritEntityProvider.ts @@ -27,7 +27,7 @@ import { GerritEntityProvider } from '../providers/GerritEntityProvider'; */ export const catalogModuleGerritEntityProvider = createBackendModule({ pluginId: 'catalog', - moduleId: 'gerritEntityProvider', + moduleId: 'gerrit-entity-provider', register(env) { env.registerInit({ deps: { diff --git a/plugins/catalog-backend-module-github-org/CHANGELOG.md b/plugins/catalog-backend-module-github-org/CHANGELOG.md index 364093e236..2dac3fa910 100644 --- a/plugins/catalog-backend-module-github-org/CHANGELOG.md +++ b/plugins/catalog-backend-module-github-org/CHANGELOG.md @@ -1,5 +1,126 @@ # @backstage/plugin-catalog-backend-module-github-org +## 0.1.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-catalog-backend-module-github@0.4.7 + - @backstage/config@1.1.1 + +## 0.1.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-catalog-backend-module-github@0.4.7-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## 0.1.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/plugin-catalog-backend-module-github@0.4.7-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/plugin-catalog-node@1.6.1-next.1 + +## 0.1.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/plugin-catalog-node@1.6.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/backend-tasks@0.5.14-next.0 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-backend-module-github@0.4.7-next.0 + +## 0.1.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/plugin-catalog-backend-module-github@0.4.6 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + +## 0.1.2-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-backend-module-github@0.4.6-next.3 + - @backstage/plugin-catalog-node@1.6.0-next.3 + +## 0.1.2-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-catalog-backend-module-github@0.4.6-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/backend-tasks@0.5.13-next.2 + - @backstage/config@1.1.1 + +## 0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-backend-module-github@0.4.6-next.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## 0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/plugin-catalog-backend-module-github@0.4.6-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + +## 0.1.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/plugin-catalog-backend-module-github@0.4.5 + - @backstage/config@1.1.1 + ## 0.1.1-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-github-org/package.json b/plugins/catalog-backend-module-github-org/package.json index b2a24d483a..bd7e23f90d 100644 --- a/plugins/catalog-backend-module-github-org/package.json +++ b/plugins/catalog-backend-module-github-org/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-github-org", "description": "The github-org backend module for the catalog plugin.", - "version": "0.1.1-next.2", + "version": "0.1.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-github-org/src/module.ts b/plugins/catalog-backend-module-github-org/src/module.ts index e510464bb7..d666f78bde 100644 --- a/plugins/catalog-backend-module-github-org/src/module.ts +++ b/plugins/catalog-backend-module-github-org/src/module.ts @@ -68,7 +68,7 @@ export const githubOrgEntityProviderTransformsExtensionPoint = */ export const catalogModuleGithubOrgEntityProvider = createBackendModule({ pluginId: 'catalog', - moduleId: 'githubOrgEntityProvider', + moduleId: 'github-org-entity-provider', register(env) { let userTransformer: UserTransformer | undefined; let teamTransformer: TeamTransformer | undefined; diff --git a/plugins/catalog-backend-module-github/CHANGELOG.md b/plugins/catalog-backend-module-github/CHANGELOG.md index f9b466604b..6ea0c50666 100644 --- a/plugins/catalog-backend-module-github/CHANGELOG.md +++ b/plugins/catalog-backend-module-github/CHANGELOG.md @@ -1,5 +1,173 @@ # @backstage/plugin-catalog-backend-module-github +## 0.4.7 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-catalog-backend@1.16.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + - @backstage/plugin-catalog-common@1.0.20 + - @backstage/plugin-events-node@0.2.18 + +## 0.4.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-catalog-backend@1.16.1-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/plugin-events-node@0.2.18-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## 0.4.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/plugin-catalog-backend@1.16.1-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-catalog-node@1.6.1-next.1 + - @backstage/plugin-events-node@0.2.18-next.1 + +## 0.4.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/plugin-catalog-node@1.6.1-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-catalog-backend@1.16.1-next.0 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-events-node@0.2.18-next.0 + +## 0.4.6 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/plugin-catalog-backend@1.16.0 + - @backstage/catalog-client@1.5.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/integration@1.8.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-events-node@0.2.17 + +## 0.4.6-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-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-catalog-backend@1.16.0-next.3 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.6.0-next.3 + - @backstage/plugin-events-node@0.2.17-next.3 + +## 0.4.6-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/plugin-catalog-backend@1.16.0-next.2 + - @backstage/backend-common@0.20.0-next.2 + - @backstage/catalog-client@1.5.0-next.1 + - @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-catalog-common@1.0.18 + - @backstage/plugin-events-node@0.2.17-next.2 + +## 0.4.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.15.1-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-events-node@0.2.17-next.1 + +## 0.4.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/plugin-catalog-backend@1.15.1-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-events-node@0.2.17-next.0 + +## 0.4.5 + +### Patch Changes + +- 88b673aa76: Import `AnalyzeOptions` and `ScmLocationAnalyzer` types from `@backstage/plugin-catalog-node` +- Updated dependencies + - @backstage/plugin-catalog-backend@1.15.0 + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/integration@1.7.2 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-events-node@0.2.16 + ## 0.4.5-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-github/alpha-api-report.md b/plugins/catalog-backend-module-github/api-report-alpha.md similarity index 100% rename from plugins/catalog-backend-module-github/alpha-api-report.md rename to plugins/catalog-backend-module-github/api-report-alpha.md diff --git a/plugins/catalog-backend-module-github/package.json b/plugins/catalog-backend-module-github/package.json index 0d1e1bd7fc..9231a0cd69 100644 --- a/plugins/catalog-backend-module-github/package.json +++ b/plugins/catalog-backend-module-github/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-github", "description": "A Backstage catalog backend module that helps integrate towards GitHub", - "version": "0.4.5-next.2", + "version": "0.4.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-github/src/module/catalogModuleGithubEntityProvider.ts b/plugins/catalog-backend-module-github/src/module/catalogModuleGithubEntityProvider.ts index 8e052bd0a0..bfa8cf2a4e 100644 --- a/plugins/catalog-backend-module-github/src/module/catalogModuleGithubEntityProvider.ts +++ b/plugins/catalog-backend-module-github/src/module/catalogModuleGithubEntityProvider.ts @@ -29,7 +29,7 @@ import { GithubEntityProvider } from '../providers/GithubEntityProvider'; */ export const catalogModuleGithubEntityProvider = createBackendModule({ pluginId: 'catalog', - moduleId: 'githubEntityProvider', + moduleId: 'github-entity-provider', register(env) { env.registerInit({ deps: { diff --git a/plugins/catalog-backend-module-gitlab/CHANGELOG.md b/plugins/catalog-backend-module-gitlab/CHANGELOG.md index 22e01f5ea7..138796de12 100644 --- a/plugins/catalog-backend-module-gitlab/CHANGELOG.md +++ b/plugins/catalog-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,136 @@ # @backstage/plugin-catalog-backend-module-gitlab +## 0.3.6 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + +## 0.3.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## 0.3.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-node@1.6.1-next.1 + +## 0.3.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/plugin-catalog-node@1.6.1-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 + +## 0.3.5 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/integration@1.8.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + +## 0.3.5-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/plugin-catalog-node@1.6.0-next.3 + +## 0.3.5-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/backend-common@0.20.0-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 + +## 0.3.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## 0.3.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + +## 0.3.4 + +### Patch Changes + +- d732f17610: Added try catch around fetching gitlab group users to prevent refresh from failing completely while only a select number of groups might not be able to load correctly. +- 0873a43ac1: Resolved a bug affecting the retrieval of users from group members. By appending '/all' to the API call, we now include members from all inherited groups, as per Gitlab's API specifications. This change is reflected in the listSaaSUsers function. +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/integration@1.7.2 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + ## 0.3.4-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-gitlab/alpha-api-report.md b/plugins/catalog-backend-module-gitlab/api-report-alpha.md similarity index 100% rename from plugins/catalog-backend-module-gitlab/alpha-api-report.md rename to plugins/catalog-backend-module-gitlab/api-report-alpha.md diff --git a/plugins/catalog-backend-module-gitlab/api-report.md b/plugins/catalog-backend-module-gitlab/api-report.md index 6620f6445f..bb52d8908a 100644 --- a/plugins/catalog-backend-module-gitlab/api-report.md +++ b/plugins/catalog-backend-module-gitlab/api-report.md @@ -8,10 +8,14 @@ import { CatalogProcessorEmit } from '@backstage/plugin-catalog-node'; import { Config } from '@backstage/config'; import { EntityProvider } from '@backstage/plugin-catalog-node'; import { EntityProviderConnection } from '@backstage/plugin-catalog-node'; +import { GitLabIntegrationConfig } from '@backstage/integration'; +import { GroupEntity } from '@backstage/catalog-model'; import { LocationSpec } from '@backstage/plugin-catalog-node'; import { Logger } from 'winston'; import { PluginTaskScheduler } from '@backstage/backend-tasks'; import { TaskRunner } from '@backstage/backend-tasks'; +import { TaskScheduleDefinition } from '@backstage/backend-tasks'; +import { UserEntity } from '@backstage/catalog-model'; // @public export class GitlabDiscoveryEntityProvider implements EntityProvider { @@ -53,6 +57,20 @@ export class GitLabDiscoveryProcessor implements CatalogProcessor { ): Promise; } +// @public +export type GitLabGroup = { + id: number; + name: string; + full_path: string; + description?: string; + parent_id?: number; +}; + +// @public (undocumented) +export type GitLabGroupSamlIdentity = { + extern_uid: string; +}; + // @public export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { // (undocumented) @@ -64,9 +82,84 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { logger: Logger; schedule?: TaskRunner; scheduler?: PluginTaskScheduler; + userTransformer?: UserTransformer; + groupEntitiesTransformer?: GroupTransformer; + groupNameTransformer?: GroupNameTransformer; }, ): GitlabOrgDiscoveryEntityProvider[]; // (undocumented) getProviderName(): string; } + +// @public +export type GitlabProviderConfig = { + host: string; + group: string; + id: string; + branch?: string; + fallbackBranch: string; + catalogFile: string; + projectPattern: RegExp; + userPattern: RegExp; + groupPattern: RegExp; + orgEnabled?: boolean; + schedule?: TaskScheduleDefinition; + skipForkedRepos?: boolean; +}; + +// @public +export type GitLabUser = { + id: number; + username: string; + email?: string; + name: string; + state: string; + web_url: string; + avatar_url: string; + groups?: GitLabGroup[]; + group_saml_identity?: GitLabGroupSamlIdentity; +}; + +// @public +export type GroupNameTransformer = ( + options: GroupNameTransformerOptions, +) => string; + +// @public +export interface GroupNameTransformerOptions { + // (undocumented) + group: GitLabGroup; + // (undocumented) + providerConfig: GitlabProviderConfig; +} + +// @public +export type GroupTransformer = ( + options: GroupTransformerOptions, +) => GroupEntity[]; + +// @public +export interface GroupTransformerOptions { + // (undocumented) + groupNameTransformer: GroupNameTransformer; + // (undocumented) + groups: GitLabGroup[]; + // (undocumented) + providerConfig: GitlabProviderConfig; +} + +// @public +export type UserTransformer = (options: UserTransformerOptions) => UserEntity; + +// @public +export interface UserTransformerOptions { + // (undocumented) + groupNameTransformer: GroupNameTransformer; + // (undocumented) + integrationConfig: GitLabIntegrationConfig; + // (undocumented) + providerConfig: GitlabProviderConfig; + // (undocumented) + user: GitLabUser; +} ``` diff --git a/plugins/catalog-backend-module-gitlab/package.json b/plugins/catalog-backend-module-gitlab/package.json index 071e408322..4092a1dab2 100644 --- a/plugins/catalog-backend-module-gitlab/package.json +++ b/plugins/catalog-backend-module-gitlab/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-gitlab", "description": "A Backstage catalog backend module that helps integrate towards GitLab", - "version": "0.3.4-next.2", + "version": "0.3.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-gitlab/src/index.ts b/plugins/catalog-backend-module-gitlab/src/index.ts index 2dd19c041d..cedcb828d6 100644 --- a/plugins/catalog-backend-module-gitlab/src/index.ts +++ b/plugins/catalog-backend-module-gitlab/src/index.ts @@ -25,3 +25,15 @@ export { GitlabDiscoveryEntityProvider, GitlabOrgDiscoveryEntityProvider, } from './providers'; +export type { + GitLabUser, + GitLabGroup, + GitlabProviderConfig, + GitLabGroupSamlIdentity, + GroupNameTransformer, + GroupNameTransformerOptions, + GroupTransformer, + GroupTransformerOptions, + UserTransformer, + UserTransformerOptions, +} from './lib'; diff --git a/plugins/catalog-backend-module-gitlab/src/lib/defaultTransformers.ts b/plugins/catalog-backend-module-gitlab/src/lib/defaultTransformers.ts new file mode 100644 index 0000000000..d7a6bf76e9 --- /dev/null +++ b/plugins/catalog-backend-module-gitlab/src/lib/defaultTransformers.ts @@ -0,0 +1,150 @@ +/* + * 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 { GroupEntity, UserEntity } from '@backstage/catalog-model'; +import { + GitLabGroup, + GroupNameTransformerOptions, + GroupTransformerOptions, + UserTransformerOptions, +} from './types'; + +export function defaultGroupNameTransformer( + options: GroupNameTransformerOptions, +): string { + if ( + options.providerConfig.group && + options.group.full_path.startsWith(`${options.providerConfig.group}/`) + ) { + return options.group.full_path + .replace(`${options.providerConfig.group}/`, '') + .replaceAll('/', '-'); + } + return options.group.full_path.replaceAll('/', '-'); +} + +export function defaultGroupEntitiesTransformer( + options: GroupTransformerOptions, +): GroupEntity[] { + const idMapped: { [groupId: number]: GitLabGroup } = {}; + const entities: GroupEntity[] = []; + + for (const group of options.groups) { + idMapped[group.id] = group; + } + + for (const group of options.groups) { + const annotations: { [annotationName: string]: string } = {}; + + annotations[`${options.providerConfig.host}/team-path`] = group.full_path; + + const entity: GroupEntity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { + name: options.groupNameTransformer({ + group, + providerConfig: options.providerConfig, + }), + annotations: annotations, + }, + spec: { + type: 'team', + children: [], + profile: { + displayName: group.name, + }, + }, + }; + + if (group.description) { + entity.metadata.description = group.description; + } + + if (group.parent_id && idMapped.hasOwnProperty(group.parent_id)) { + entity.spec.parent = options.groupNameTransformer({ + group: idMapped[group.parent_id], + providerConfig: options.providerConfig, + }); + } + + entities.push(entity); + } + + return entities; +} + +/** + * The default implementation of the transformation from a graph user entry to + * a User entity. + * + * @public + */ +export function defaultUserTransformer( + options: UserTransformerOptions, +): UserEntity { + const annotations: { [annotationName: string]: string } = {}; + + annotations[`${options.integrationConfig.host}/user-login`] = + options.user.web_url; + if (options.user?.group_saml_identity?.extern_uid) { + annotations[`${options.integrationConfig.host}/saml-external-uid`] = + options.user.group_saml_identity.extern_uid; + } + + const entity: UserEntity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'User', + metadata: { + name: options.user.username, + annotations: annotations, + }, + spec: { + profile: { + displayName: options.user.name || undefined, + picture: options.user.avatar_url || undefined, + }, + memberOf: [], + }, + }; + + if (options.user.email) { + if (!entity.spec) { + entity.spec = {}; + } + + if (!entity.spec.profile) { + entity.spec.profile = {}; + } + + entity.spec.profile.email = options.user.email; + } + + if (options.user.groups) { + for (const group of options.user.groups) { + if (!entity.spec.memberOf) { + entity.spec.memberOf = []; + } + entity.spec.memberOf.push( + options.groupNameTransformer({ + group, + providerConfig: options.providerConfig, + }), + ); + } + } + + return entity; +} diff --git a/plugins/catalog-backend-module-gitlab/src/lib/index.ts b/plugins/catalog-backend-module-gitlab/src/lib/index.ts index 53fad07994..1eee268862 100644 --- a/plugins/catalog-backend-module-gitlab/src/lib/index.ts +++ b/plugins/catalog-backend-module-gitlab/src/lib/index.ts @@ -16,8 +16,17 @@ export { GitLabClient, paginated } from './client'; export type { + GitLabUser, + GitLabGroup, + GitLabGroupSamlIdentity, GitLabProject, GitlabProviderConfig, GitlabGroupDescription, + GroupNameTransformer, + GroupNameTransformerOptions, + GroupTransformer, + GroupTransformerOptions, + UserTransformer, + UserTransformerOptions, } from './types'; export { readGitlabConfigs } from '../providers/config'; diff --git a/plugins/catalog-backend-module-gitlab/src/lib/types.ts b/plugins/catalog-backend-module-gitlab/src/lib/types.ts index fa2eb73da6..25c9a4a232 100644 --- a/plugins/catalog-backend-module-gitlab/src/lib/types.ts +++ b/plugins/catalog-backend-module-gitlab/src/lib/types.ts @@ -14,6 +14,8 @@ * limitations under the License. */ import { TaskScheduleDefinition } from '@backstage/backend-tasks'; +import { GroupEntity, UserEntity } from '@backstage/catalog-model'; +import { GitLabIntegrationConfig } from '@backstage/integration'; export type PagedResponse = { items: T[]; @@ -40,6 +42,11 @@ export type GitLabProject = { forked_from_project?: GitlabProjectForkedFrom; }; +/** + * Representation of a GitLab user in the GitLab API + * + * @public + */ export type GitLabUser = { id: number; username: string; @@ -52,10 +59,18 @@ export type GitLabUser = { group_saml_identity?: GitLabGroupSamlIdentity; }; +/** + * @public + */ export type GitLabGroupSamlIdentity = { extern_uid: string; }; +/** + * Representation of a GitLab group in the GitLab API + * + * @public + */ export type GitLabGroup = { id: number; name: string; @@ -113,10 +128,25 @@ export type GitLabDescendantGroupsResponse = { }; }; }; - +/** + * The configuration parameters for the GitlabProvider + * + * @public + */ export type GitlabProviderConfig = { + /** + * Identifies one of the hosts set up in the integrations + */ host: string; + /** + * Required for gitlab.com when `orgEnabled: true`. + * Optional for self managed. Must not end with slash. + * Accepts only groups under the provided path (which will be stripped) + */ group: string; + /** + * ??? + */ id: string; /** * The name of the branch to be used, to discover catalog files. @@ -128,11 +158,85 @@ export type GitlabProviderConfig = { * Defaults to: `master` */ fallbackBranch: string; + /** + * Defaults to `catalog-info.yaml` + */ catalogFile: string; + /** + * Filters found projects based on provided patter. + * Defaults to `[\s\S]*`, which means to not filter anything + */ projectPattern: RegExp; + /** + * Filters found users based on provided patter. + * Defaults to `[\s\S]*`, which means to not filter anything + */ userPattern: RegExp; + /** + * Filters found groups based on provided patter. + * Defaults to `[\s\S]*`, which means to not filter anything + */ groupPattern: RegExp; + orgEnabled?: boolean; schedule?: TaskScheduleDefinition; + /** + * If the project is a fork, skip repository + */ skipForkedRepos?: boolean; }; + +/** + * Customize how group names are generated + * + * @public + */ +export type GroupNameTransformer = ( + options: GroupNameTransformerOptions, +) => string; + +/** + * The GroupTransformerOptions + * + * @public + */ +export interface GroupNameTransformerOptions { + group: GitLabGroup; + providerConfig: GitlabProviderConfig; +} +/** + * Customize the ingested User entity + * + * @public + */ +export type UserTransformer = (options: UserTransformerOptions) => UserEntity; +/** + * The UserTransformerOptions + * + * @public + */ +export interface UserTransformerOptions { + user: GitLabUser; + integrationConfig: GitLabIntegrationConfig; + providerConfig: GitlabProviderConfig; + groupNameTransformer: GroupNameTransformer; +} + +/** + * Customize the ingested Group entity + * + * @public + */ +export type GroupTransformer = ( + options: GroupTransformerOptions, +) => GroupEntity[]; +/** + * The GroupTransformer options + * + * @public + */ +export interface GroupTransformerOptions { + groups: GitLabGroup[]; + providerConfig: GitlabProviderConfig; + groupNameTransformer: GroupNameTransformer; +} diff --git a/plugins/catalog-backend-module-gitlab/src/module/catalogModuleGitlabDiscoveryEntityProvider.ts b/plugins/catalog-backend-module-gitlab/src/module/catalogModuleGitlabDiscoveryEntityProvider.ts index d192e8f3a5..9979d0862e 100644 --- a/plugins/catalog-backend-module-gitlab/src/module/catalogModuleGitlabDiscoveryEntityProvider.ts +++ b/plugins/catalog-backend-module-gitlab/src/module/catalogModuleGitlabDiscoveryEntityProvider.ts @@ -29,7 +29,7 @@ import { GitlabDiscoveryEntityProvider } from '../providers'; */ export const catalogModuleGitlabDiscoveryEntityProvider = createBackendModule({ pluginId: 'catalog', - moduleId: 'gitlabDiscoveryEntityProvider', + moduleId: 'gitlab-discovery-entity-provider', register(env) { env.registerInit({ deps: { diff --git a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts index affa8a41cf..1157a2f1f3 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts @@ -18,8 +18,6 @@ import { ANNOTATION_LOCATION, ANNOTATION_ORIGIN_LOCATION, Entity, - GroupEntity, - UserEntity, } from '@backstage/catalog-model'; import { Config } from '@backstage/config'; import { GitLabIntegration, ScmIntegrations } from '@backstage/integration'; @@ -37,7 +35,19 @@ import { paginated, readGitlabConfigs, } from '../lib'; -import { GitLabGroup, GitLabUser, PagedResponse } from '../lib/types'; +import { + GitLabGroup, + GitLabUser, + PagedResponse, + UserTransformer, + GroupTransformer as GroupEntitiesTransformer, + GroupNameTransformer, +} from '../lib/types'; +import { + defaultGroupNameTransformer, + defaultGroupEntitiesTransformer, + defaultUserTransformer, +} from '../lib/defaultTransformers'; type Result = { scanned: number; @@ -59,6 +69,9 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { private readonly logger: Logger; private readonly scheduleFn: () => Promise; private connection?: EntityProviderConnection; + private userTransformer: UserTransformer; + private groupEntitiesTransformer: GroupEntitiesTransformer; + private groupNameTransformer: GroupNameTransformer; static fromConfig( config: Config, @@ -66,6 +79,9 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { logger: Logger; schedule?: TaskRunner; scheduler?: PluginTaskScheduler; + userTransformer?: UserTransformer; + groupEntitiesTransformer?: GroupEntitiesTransformer; + groupNameTransformer?: GroupNameTransformer; }, ): GitlabOrgDiscoveryEntityProvider[] { if (!options.schedule && !options.scheduler) { @@ -122,6 +138,9 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { integration: GitLabIntegration; logger: Logger; taskRunner: TaskRunner; + userTransformer?: UserTransformer; + groupEntitiesTransformer?: GroupEntitiesTransformer; + groupNameTransformer?: GroupNameTransformer; }) { this.config = options.config; this.integration = options.integration; @@ -129,6 +148,11 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { target: this.getProviderName(), }); this.scheduleFn = this.createScheduleFn(options.taskRunner); + this.userTransformer = options.userTransformer ?? defaultUserTransformer; + this.groupEntitiesTransformer = + options.groupEntitiesTransformer ?? defaultGroupEntitiesTransformer; + this.groupNameTransformer = + options.groupNameTransformer ?? defaultGroupNameTransformer; } getProviderName(): string { @@ -271,13 +295,20 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { }); const userEntities = res.matches.map(p => - this.createUserEntity(p, this.integration.config.host), - ); - const groupEntities = this.createGroupEntities( - groupsWithUsers, - this.integration.config.host, + this.userTransformer({ + user: p, + integrationConfig: this.integration.config, + providerConfig: this.config, + groupNameTransformer: this.groupNameTransformer, + }), ); + const groupEntities = this.groupEntitiesTransformer({ + groups: groupsWithUsers, + providerConfig: this.config, + groupNameTransformer: this.groupNameTransformer, + }); + await this.connection.applyMutation({ type: 'full', entities: [...userEntities, ...groupEntities].map(entity => ({ @@ -291,32 +322,6 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { }); } - private createGroupEntities( - groupResult: GitLabGroup[], - host: string, - ): GroupEntity[] { - const idMapped: { [groupId: number]: GitLabGroup } = {}; - const entities: GroupEntity[] = []; - - for (const group of groupResult) { - idMapped[group.id] = group; - } - - for (const group of groupResult) { - const entity = this.createGroupEntity(group, host); - - if (group.parent_id && idMapped.hasOwnProperty(group.parent_id)) { - entity.spec.parent = this.groupName( - idMapped[group.parent_id].full_path, - ); - } - - entities.push(entity); - } - - return entities; - } - private withLocations(host: string, baseUrl: string, entity: Entity): Entity { const location = entity.kind === 'Group' @@ -334,90 +339,4 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { entity, ) as Entity; } - - private createUserEntity(user: GitLabUser, host: string): UserEntity { - const annotations: { [annotationName: string]: string } = {}; - - annotations[`${host}/user-login`] = user.web_url; - if (user?.group_saml_identity?.extern_uid) { - annotations[`${host}/saml-external-uid`] = - user.group_saml_identity.extern_uid; - } - - const entity: UserEntity = { - apiVersion: 'backstage.io/v1alpha1', - kind: 'User', - metadata: { - name: user.username, - annotations: annotations, - }, - spec: { - profile: { - displayName: user.name || undefined, - picture: user.avatar_url || undefined, - }, - memberOf: [], - }, - }; - - if (user.email) { - if (!entity.spec) { - entity.spec = {}; - } - - if (!entity.spec.profile) { - entity.spec.profile = {}; - } - - entity.spec.profile.email = user.email; - } - - if (user.groups) { - for (const group of user.groups) { - if (!entity.spec.memberOf) { - entity.spec.memberOf = []; - } - entity.spec.memberOf.push(this.groupName(group.full_path)); - } - } - - return entity; - } - - private groupName(full_path: string): string { - if (this.config.group && full_path.startsWith(`${this.config.group}/`)) { - return full_path - .replace(`${this.config.group}/`, '') - .replaceAll('/', '-'); - } - return full_path.replaceAll('/', '-'); - } - - private createGroupEntity(group: GitLabGroup, host: string): GroupEntity { - const annotations: { [annotationName: string]: string } = {}; - - annotations[`${host}/team-path`] = group.full_path; - - const entity: GroupEntity = { - apiVersion: 'backstage.io/v1alpha1', - kind: 'Group', - metadata: { - name: this.groupName(group.full_path), - annotations: annotations, - }, - spec: { - type: 'team', - children: [], - profile: { - displayName: group.name, - }, - }, - }; - - if (group.description) { - entity.metadata.description = group.description; - } - - return entity; - } } diff --git a/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md b/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md index cfc689a57b..24fd6a0b30 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md +++ b/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md @@ -1,5 +1,166 @@ # @backstage/plugin-catalog-backend-module-incremental-ingestion +## 0.4.13 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-catalog-backend@1.16.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-events-node@0.2.18 + +## 0.4.13-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-catalog-backend@1.16.1-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/plugin-events-node@0.2.18-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## 0.4.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/plugin-catalog-backend@1.16.1-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @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 + +## 0.4.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/plugin-catalog-node@1.6.1-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/errors@1.2.3 + - @backstage/plugin-catalog-backend@1.16.1-next.0 + - @backstage/plugin-events-node@0.2.18-next.0 + - @backstage/plugin-permission-common@0.7.11 + +## 0.4.12 + +### Patch Changes + +- 43b2eb8: Ensure that cursors always come back as JSON on sqlite too +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/plugin-catalog-backend@1.16.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-events-node@0.2.17 + +## 0.4.12-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-backend@1.16.0-next.3 + - @backstage/plugin-catalog-node@1.6.0-next.3 + - @backstage/plugin-events-node@0.2.17-next.3 + - @backstage/plugin-permission-common@0.7.10 + +## 0.4.12-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/plugin-catalog-backend@1.16.0-next.2 + - @backstage/backend-common@0.20.0-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/errors@1.2.3 + - @backstage/plugin-events-node@0.2.17-next.2 + - @backstage/plugin-permission-common@0.7.10 + +## 0.4.12-next.1 + +### Patch Changes + +- 43b2eb8f70: Ensure that cursors always come back as JSON on sqlite too +- Updated dependencies + - @backstage/plugin-catalog-backend@1.15.1-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-events-node@0.2.17-next.1 + - @backstage/plugin-permission-common@0.7.10 + +## 0.4.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/plugin-catalog-backend@1.15.1-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-events-node@0.2.17-next.0 + - @backstage/plugin-permission-common@0.7.10 + +## 0.4.11 + +### Patch Changes + +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. +- Updated dependencies + - @backstage/plugin-catalog-backend@1.15.0 + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-events-node@0.2.16 + ## 0.4.11-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-incremental-ingestion/alpha-api-report.md b/plugins/catalog-backend-module-incremental-ingestion/api-report-alpha.md similarity index 100% rename from plugins/catalog-backend-module-incremental-ingestion/alpha-api-report.md rename to plugins/catalog-backend-module-incremental-ingestion/api-report-alpha.md diff --git a/plugins/catalog-backend-module-incremental-ingestion/package.json b/plugins/catalog-backend-module-incremental-ingestion/package.json index cd0a4dd0d4..41c0abd811 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/package.json +++ b/plugins/catalog-backend-module-incremental-ingestion/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-incremental-ingestion", "description": "An entity provider for streaming large asset sources into the catalog", - "version": "0.4.11-next.2", + "version": "0.4.13", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-incremental-ingestion/src/database/IncrementalIngestionDatabaseManager.test.ts b/plugins/catalog-backend-module-incremental-ingestion/src/database/IncrementalIngestionDatabaseManager.test.ts new file mode 100644 index 0000000000..a8862cfc2a --- /dev/null +++ b/plugins/catalog-backend-module-incremental-ingestion/src/database/IncrementalIngestionDatabaseManager.test.ts @@ -0,0 +1,79 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { TestDatabases } from '@backstage/backend-test-utils'; +import { IncrementalIngestionDatabaseManager } from './IncrementalIngestionDatabaseManager'; +import { v4 as uuid } from 'uuid'; + +const migrationsDir = `${__dirname}/../../migrations`; + +jest.setTimeout(60_000); + +describe('IncrementalIngestionDatabaseManager', () => { + const databases = TestDatabases.create({ + ids: ['POSTGRES_13', 'POSTGRES_9', 'SQLITE_3'], + }); + + it.each(databases.eachSupportedId())( + 'stores and retrieves marks, %p', + async databaseId => { + const knex = await databases.init(databaseId); + await knex.migrate.latest({ directory: migrationsDir }); + + const manager = new IncrementalIngestionDatabaseManager({ client: knex }); + const { ingestionId } = (await manager.createProviderIngestionRecord( + 'myProvider', + ))!; + + const cursorId = uuid(); + + await manager.createMark({ + record: { + id: cursorId, + ingestion_id: ingestionId, + sequence: 1, + cursor: { data: 1 }, + }, + }); + + await expect(manager.getFirstMark(ingestionId)).resolves.toEqual({ + created_at: expect.anything(), + cursor: { data: 1 }, + id: cursorId, + ingestion_id: ingestionId, + sequence: 1, + }); + + await expect(manager.getLastMark(ingestionId)).resolves.toEqual({ + created_at: expect.anything(), + cursor: { data: 1 }, + id: cursorId, + ingestion_id: ingestionId, + sequence: 1, + }); + + await expect(manager.getAllMarks(ingestionId)).resolves.toEqual([ + { + created_at: expect.anything(), + cursor: { data: 1 }, + id: cursorId, + ingestion_id: ingestionId, + sequence: 1, + }, + ]); + }, + ); +}); diff --git a/plugins/catalog-backend-module-incremental-ingestion/src/database/IncrementalIngestionDatabaseManager.ts b/plugins/catalog-backend-module-incremental-ingestion/src/database/IncrementalIngestionDatabaseManager.ts index 527d345706..e47954f47e 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/src/database/IncrementalIngestionDatabaseManager.ts +++ b/plugins/catalog-backend-module-incremental-ingestion/src/database/IncrementalIngestionDatabaseManager.ts @@ -542,7 +542,7 @@ export class IncrementalIngestionDatabaseManager { .where('ingestion_id', ingestionId) .orderBy('sequence', 'desc') .first(); - return mark; + return this.#decodeMark(this.client, mark); }); } @@ -557,7 +557,7 @@ export class IncrementalIngestionDatabaseManager { .where('ingestion_id', ingestionId) .orderBy('sequence', 'asc') .first(); - return mark; + return this.#decodeMark(this.client, mark); }); } @@ -566,7 +566,7 @@ export class IncrementalIngestionDatabaseManager { const marks = await tx('ingestion_marks') .where('ingestion_id', ingestionId) .orderBy('sequence', 'desc'); - return marks; + return marks.map(m => this.#decodeMark(this.client, m)); }); } @@ -580,6 +580,19 @@ export class IncrementalIngestionDatabaseManager { await tx('ingestion_marks').insert(record); }); } + + // Handles the fact that sqlite does not support json columns; they just + // persist the stringified data instead + #decodeMark(knex: Knex, record: T): T { + if (record && knex.client.config.client.includes('sqlite3')) { + return { + ...record, + cursor: JSON.parse(record.cursor as string), + }; + } + return record; + } + /** * Performs an upsert to the `ingestion_mark_entities` table for all deferred entities. * @param markId - string diff --git a/plugins/catalog-backend-module-incremental-ingestion/src/database/tables.ts b/plugins/catalog-backend-module-incremental-ingestion/src/database/tables.ts index 00d40fb4a1..e1a47c040c 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/src/database/tables.ts +++ b/plugins/catalog-backend-module-incremental-ingestion/src/database/tables.ts @@ -89,7 +89,7 @@ export interface MarkRecord { id: string; sequence: number; ingestion_id: string; - cursor: string; + cursor: unknown; created_at: string; } diff --git a/plugins/catalog-backend-module-incremental-ingestion/src/module/WrapperProviders.test.ts b/plugins/catalog-backend-module-incremental-ingestion/src/module/WrapperProviders.test.ts index 7d138e4812..9416fa27eb 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/src/module/WrapperProviders.test.ts +++ b/plugins/catalog-backend-module-incremental-ingestion/src/module/WrapperProviders.test.ts @@ -26,7 +26,7 @@ jest.setTimeout(60_000); describe('WrapperProviders', () => { const applyDatabaseMigrations = jest.fn(); const databases = TestDatabases.create({ - ids: ['POSTGRES_13', 'POSTGRES_9', 'SQLITE_3', 'MYSQL_8'], + ids: ['POSTGRES_16', 'POSTGRES_12', 'SQLITE_3', 'MYSQL_8'], }); const config = new ConfigReader({}); const logger = getVoidLogger(); diff --git a/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.test.ts b/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.test.ts index 7d76ddf480..316a4be7eb 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.test.ts +++ b/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.test.ts @@ -48,7 +48,7 @@ describe('catalogModuleIncrementalIngestionEntityProvider', () => { catalogModuleIncrementalIngestionEntityProvider(), createBackendModule({ pluginId: 'catalog', - moduleId: 'incrementalTest', + moduleId: 'incremental-test', register(env) { env.registerInit({ deps: { extension: incrementalIngestionProvidersExtensionPoint }, diff --git a/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.ts b/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.ts index 4e94088ef6..adb5ab6a04 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.ts +++ b/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.ts @@ -49,7 +49,7 @@ export interface IncrementalIngestionProviderExtensionPoint { * ```ts * backend.add(createBackendModule({ * pluginId: 'catalog', - * moduleId: 'myIncrementalProvider', + * moduleId: 'my-incremental-provider', * register(env) { * env.registerInit({ * deps: { @@ -85,7 +85,7 @@ export const incrementalIngestionProvidersExtensionPoint = export const catalogModuleIncrementalIngestionEntityProvider = createBackendModule({ pluginId: 'catalog', - moduleId: 'incrementalIngestionEntityProvider', + moduleId: 'incremental-ingestion-entity-provider', register(env) { const addedProviders = new Array<{ provider: IncrementalEntityProvider; diff --git a/plugins/catalog-backend-module-incremental-ingestion/src/run.ts b/plugins/catalog-backend-module-incremental-ingestion/src/run.ts index c24deb6adb..5af31482a6 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/src/run.ts +++ b/plugins/catalog-backend-module-incremental-ingestion/src/run.ts @@ -67,7 +67,7 @@ async function main() { backend.add( createBackendModule({ pluginId: 'catalog', - moduleId: 'incrementalTestProvider', + moduleId: 'incremental-test-provider', register(reg) { reg.registerInit({ deps: { extension: incrementalIngestionProvidersExtensionPoint }, diff --git a/plugins/catalog-backend-module-ldap/CHANGELOG.md b/plugins/catalog-backend-module-ldap/CHANGELOG.md index 66377e8eeb..5e01cf2f97 100644 --- a/plugins/catalog-backend-module-ldap/CHANGELOG.md +++ b/plugins/catalog-backend-module-ldap/CHANGELOG.md @@ -1,5 +1,130 @@ # @backstage/plugin-catalog-backend-module-ldap +## 0.5.24 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.20 + +## 0.5.24-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## 0.5.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-catalog-node@1.6.1-next.1 + +## 0.5.24-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.1-next.0 + - @backstage/backend-tasks@0.5.14-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + +## 0.5.23 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + +## 0.5.23-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.6.0-next.3 + +## 0.5.23-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/backend-tasks@0.5.13-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + +## 0.5.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## 0.5.23-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + +## 0.5.22 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/backend-tasks@0.5.12 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + ## 0.5.22-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-ldap/package.json b/plugins/catalog-backend-module-ldap/package.json index 5bf7ede085..6a16e89ff1 100644 --- a/plugins/catalog-backend-module-ldap/package.json +++ b/plugins/catalog-backend-module-ldap/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-ldap", "description": "A Backstage catalog backend module that helps integrate towards LDAP", - "version": "0.5.22-next.2", + "version": "0.5.24", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-msgraph/CHANGELOG.md b/plugins/catalog-backend-module-msgraph/CHANGELOG.md index cec1263ea7..8ea92b99b9 100644 --- a/plugins/catalog-backend-module-msgraph/CHANGELOG.md +++ b/plugins/catalog-backend-module-msgraph/CHANGELOG.md @@ -1,5 +1,136 @@ # @backstage/plugin-catalog-backend-module-msgraph +## 0.5.16 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.20 + +## 0.5.16-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## 0.5.16-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-catalog-node@1.6.1-next.1 + +## 0.5.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/plugin-catalog-node@1.6.1-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/plugin-catalog-common@1.0.19 + +## 0.5.15 + +### Patch Changes + +- 99fb541: Updated dependency `@azure/identity` to `^4.0.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + +## 0.5.15-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.6.0-next.3 + +## 0.5.15-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/backend-common@0.20.0-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/plugin-catalog-common@1.0.18 + +## 0.5.15-next.1 + +### Patch Changes + +- 99fb54183b: Updated dependency `@azure/identity` to `^4.0.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## 0.5.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + +## 0.5.14 + +### Patch Changes + +- 224aa6f64c: export the function to read ms graph provider config +- 243c655a68: JSDoc and Error message updates to handle `Azure Active Directory` re-brand to `Entra ID` +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + ## 0.5.14-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-msgraph/alpha-api-report.md b/plugins/catalog-backend-module-msgraph/api-report-alpha.md similarity index 100% rename from plugins/catalog-backend-module-msgraph/alpha-api-report.md rename to plugins/catalog-backend-module-msgraph/api-report-alpha.md diff --git a/plugins/catalog-backend-module-msgraph/package.json b/plugins/catalog-backend-module-msgraph/package.json index 00ff5da3b8..1187c93262 100644 --- a/plugins/catalog-backend-module-msgraph/package.json +++ b/plugins/catalog-backend-module-msgraph/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-msgraph", "description": "A Backstage catalog backend module that helps integrate towards Microsoft Graph", - "version": "0.5.14-next.2", + "version": "0.5.16", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -45,7 +45,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@azure/identity": "^3.2.1", + "@azure/identity": "^4.0.0", "@backstage/backend-common": "workspace:^", "@backstage/backend-plugin-api": "workspace:^", "@backstage/backend-tasks": "workspace:^", diff --git a/plugins/catalog-backend-module-openapi/CHANGELOG.md b/plugins/catalog-backend-module-openapi/CHANGELOG.md index df5ecf9aa5..ff1f865a28 100644 --- a/plugins/catalog-backend-module-openapi/CHANGELOG.md +++ b/plugins/catalog-backend-module-openapi/CHANGELOG.md @@ -1,5 +1,152 @@ # @backstage/plugin-catalog-backend-module-openapi +## 0.1.26 + +### Patch Changes + +- 4ebf99b: Add support for the new backend system. + + A new backend module for the catalog backend + was added and exported as `default`. + + You can use it with the new backend system like + + ```ts title="packages/backend/src/index.ts" + backend.add(import('@backstage/plugin-catalog-backend-module-openapi')); + ``` + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-catalog-backend@1.16.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.20 + +## 0.1.26-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-catalog-backend@1.16.1-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + +## 0.1.26-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-backend@1.16.1-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-catalog-node@1.6.1-next.1 + +## 0.1.26-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/plugin-catalog-node@1.6.1-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-backend@1.16.1-next.0 + - @backstage/plugin-catalog-common@1.0.19 + +## 0.1.25 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/plugin-catalog-backend@1.16.0 + - @backstage/integration@1.8.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + +## 0.1.25-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-backend@1.16.0-next.3 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.6.0-next.3 + +## 0.1.25-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/backend-common@0.20.0-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + +## 0.1.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.15.1-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## 0.1.25-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/plugin-catalog-backend@1.15.1-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + +## 0.1.24 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.15.0 + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/integration@1.7.2 + - @backstage/backend-common@0.19.9 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + ## 0.1.24-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-openapi/README.md b/plugins/catalog-backend-module-openapi/README.md index 6b988e15f5..6a8028895d 100644 --- a/plugins/catalog-backend-module-openapi/README.md +++ b/plugins/catalog-backend-module-openapi/README.md @@ -17,6 +17,33 @@ yarn add --cwd packages/backend @backstage/plugin-catalog-backend-module-openapi ### Adding the plugin to your `packages/backend` +```ts title="packages/backend/src/index.ts" +backend.add(import('@backstage/plugin-catalog-backend-module-openapi')); +``` + +This will add the `jsonSchemaRefPlaceholderResolver` for +the placeholder resolver keys `asyncapi` and `openapi`. + +This allows you to use the `$openapi` placeholder when referencing your OpenAPI specification and `$asyncapi` when referencing your AsyncAPI specifications. This will then resolve all `$ref` instances in your specification. + +You can also use this resolver for other kind of yaml files to resolve $ref pointer. + +```yaml +apiVersion: backstage.io/v1alpha1 +kind: API +metadata: + name: example + description: Example API +spec: + type: openapi + lifecycle: production + owner: team + definition: + $openapi: ./spec/openapi.yaml # by using $openapi Backstage will now resolve all $ref instances +``` + +### Adding the plugin to your `packages/backend` (old backend system) + #### **jsonSchemaRefPlaceholderResolver** The placeholder resolver can be added by importing `jsonSchemaRefPlaceholderResolver` in `src/plugins/catalog.ts` in your `backend` package and adding the following. diff --git a/plugins/catalog-backend-module-openapi/api-report.md b/plugins/catalog-backend-module-openapi/api-report.md index 455816645a..206cfac291 100644 --- a/plugins/catalog-backend-module-openapi/api-report.md +++ b/plugins/catalog-backend-module-openapi/api-report.md @@ -3,6 +3,7 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { BackendFeature } from '@backstage/backend-plugin-api'; import { CatalogProcessor } from '@backstage/plugin-catalog-node'; import { Config } from '@backstage/config'; import { Entity } from '@backstage/catalog-model'; @@ -13,6 +14,10 @@ import { PlaceholderResolverParams } from '@backstage/plugin-catalog-backend'; import { ScmIntegrations } from '@backstage/integration'; import { UrlReader } from '@backstage/backend-common'; +// @public +const catalogModuleJsonSchemaRefPlaceholderResolver: () => BackendFeature; +export default catalogModuleJsonSchemaRefPlaceholderResolver; + // @public (undocumented) export function jsonSchemaRefPlaceholderResolver( params: PlaceholderResolverParams, diff --git a/plugins/catalog-backend-module-openapi/package.json b/plugins/catalog-backend-module-openapi/package.json index 1a9dcd8cde..1b3a2e46a0 100644 --- a/plugins/catalog-backend-module-openapi/package.json +++ b/plugins/catalog-backend-module-openapi/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-openapi", "description": "A Backstage catalog backend module that helps with OpenAPI specifications", - "version": "0.1.24-next.2", + "version": "0.1.26", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,6 +34,7 @@ "dependencies": { "@apidevtools/json-schema-ref-parser": "^9.0.6", "@backstage/backend-common": "workspace:^", + "@backstage/backend-plugin-api": "workspace:^", "@backstage/catalog-model": "workspace:^", "@backstage/config": "workspace:^", "@backstage/integration": "workspace:^", diff --git a/plugins/catalog-backend-module-openapi/src/index.ts b/plugins/catalog-backend-module-openapi/src/index.ts index 170c925a7f..70ab88c2ff 100644 --- a/plugins/catalog-backend-module-openapi/src/index.ts +++ b/plugins/catalog-backend-module-openapi/src/index.ts @@ -22,3 +22,6 @@ export { jsonSchemaRefPlaceholderResolver } from './jsonSchemaRefPlaceholderReso * @deprecated replaced by jsonSchemaRefPlaceholderResolver */ export const openApiPlaceholderResolver = jsonSchemaRefPlaceholderResolver; + +export * from './module'; +export { default } from './module'; diff --git a/plugins/catalog-backend-module-openapi/src/module/catalogModuleJsonSchemaRefPlaceholderResolver.test.ts b/plugins/catalog-backend-module-openapi/src/module/catalogModuleJsonSchemaRefPlaceholderResolver.test.ts new file mode 100644 index 0000000000..cfea25341e --- /dev/null +++ b/plugins/catalog-backend-module-openapi/src/module/catalogModuleJsonSchemaRefPlaceholderResolver.test.ts @@ -0,0 +1,54 @@ +/* + * 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 { startTestBackend } from '@backstage/backend-test-utils'; +import { PlaceholderResolver } from '@backstage/plugin-catalog-node'; +import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; +import { catalogModuleJsonSchemaRefPlaceholderResolver } from './catalogModuleJsonSchemaRefPlaceholderResolver'; +import { jsonSchemaRefPlaceholderResolver } from '../jsonSchemaRefPlaceholderResolver'; + +describe('catalogModuleJsonSchemaRefPlaceholderResolver', () => { + it('should register provider at the catalog extension point', async () => { + const registeredPlaceholderResolvers: { + [key: string]: PlaceholderResolver; + } = {}; + + const extensionPoint = { + addPlaceholderResolver: ( + key: string, + resolver: PlaceholderResolver, + ): void => { + registeredPlaceholderResolvers[key] = resolver; + }, + }; + + await startTestBackend({ + extensionPoints: [[catalogProcessingExtensionPoint, extensionPoint]], + features: [catalogModuleJsonSchemaRefPlaceholderResolver()], + }); + + expect(Object.keys(registeredPlaceholderResolvers)).toEqual([ + 'asyncapi', + 'openapi', + ]); + expect(registeredPlaceholderResolvers.asyncapi).toBe( + jsonSchemaRefPlaceholderResolver, + ); + expect(registeredPlaceholderResolvers.openapi).toBe( + jsonSchemaRefPlaceholderResolver, + ); + }); +}); diff --git a/plugins/catalog-backend-module-openapi/src/module/catalogModuleJsonSchemaRefPlaceholderResolver.ts b/plugins/catalog-backend-module-openapi/src/module/catalogModuleJsonSchemaRefPlaceholderResolver.ts new file mode 100644 index 0000000000..053951866a --- /dev/null +++ b/plugins/catalog-backend-module-openapi/src/module/catalogModuleJsonSchemaRefPlaceholderResolver.ts @@ -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 { createBackendModule } from '@backstage/backend-plugin-api'; +import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; +import { jsonSchemaRefPlaceholderResolver } from '../jsonSchemaRefPlaceholderResolver'; + +/** + * Registers the jsonSchemaRefPlaceholderResolver + * as placeholder resolver for `$asyncapi` and `$openapi`. + * + * @public + */ +export const catalogModuleJsonSchemaRefPlaceholderResolver = + createBackendModule({ + pluginId: 'catalog', + moduleId: 'json-schema-ref-placeholder-resolver', + register(env) { + env.registerInit({ + deps: { + catalog: catalogProcessingExtensionPoint, + }, + async init({ catalog }) { + catalog.addPlaceholderResolver( + 'asyncapi', + jsonSchemaRefPlaceholderResolver, + ); + catalog.addPlaceholderResolver( + 'openapi', + jsonSchemaRefPlaceholderResolver, + ); + }, + }); + }, + }); diff --git a/plugins/catalog-backend-module-openapi/src/module/index.ts b/plugins/catalog-backend-module-openapi/src/module/index.ts new file mode 100644 index 0000000000..b914472c8d --- /dev/null +++ b/plugins/catalog-backend-module-openapi/src/module/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 { catalogModuleJsonSchemaRefPlaceholderResolver as default } from './catalogModuleJsonSchemaRefPlaceholderResolver'; diff --git a/plugins/catalog-backend-module-puppetdb/CHANGELOG.md b/plugins/catalog-backend-module-puppetdb/CHANGELOG.md index d50f4e10ae..dbc84f46f7 100644 --- a/plugins/catalog-backend-module-puppetdb/CHANGELOG.md +++ b/plugins/catalog-backend-module-puppetdb/CHANGELOG.md @@ -1,5 +1,143 @@ # @backstage/plugin-catalog-backend-module-puppetdb +## 0.1.14 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.1.14-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## 0.1.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-node@1.6.1-next.1 + +## 0.1.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/plugin-catalog-node@1.6.1-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/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.1.13 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.1.13-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-node@1.6.0-next.3 + +## 0.1.13-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/backend-common@0.20.0-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/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.1.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + +## 0.1.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.1.12 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + ## 0.1.12-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-puppetdb/alpha-api-report.md b/plugins/catalog-backend-module-puppetdb/api-report-alpha.md similarity index 100% rename from plugins/catalog-backend-module-puppetdb/alpha-api-report.md rename to plugins/catalog-backend-module-puppetdb/api-report-alpha.md diff --git a/plugins/catalog-backend-module-puppetdb/package.json b/plugins/catalog-backend-module-puppetdb/package.json index eb398bebc4..d9bdb74b16 100644 --- a/plugins/catalog-backend-module-puppetdb/package.json +++ b/plugins/catalog-backend-module-puppetdb/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-puppetdb", "description": "A Backstage catalog backend module that helps integrate towards PuppetDB", - "version": "0.1.12-next.2", + "version": "0.1.14", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-puppetdb/src/module/catalogModulePuppetDbEntityProvider.ts b/plugins/catalog-backend-module-puppetdb/src/module/catalogModulePuppetDbEntityProvider.ts index 5546b5283b..aad28eb47a 100644 --- a/plugins/catalog-backend-module-puppetdb/src/module/catalogModulePuppetDbEntityProvider.ts +++ b/plugins/catalog-backend-module-puppetdb/src/module/catalogModulePuppetDbEntityProvider.ts @@ -29,7 +29,7 @@ import { PuppetDbEntityProvider } from '../providers/PuppetDbEntityProvider'; */ export const catalogModulePuppetDbEntityProvider = createBackendModule({ pluginId: 'catalog', - moduleId: 'puppetDbEntityProvider', + moduleId: 'puppetdb-entity-provider', register(env) { env.registerInit({ deps: { diff --git a/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md b/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md index 2ba8c5973c..4901341e46 100644 --- a/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md +++ b/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md @@ -1,5 +1,122 @@ # @backstage/plugin-catalog-backend-module-scaffolder-entity-model +## 0.1.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.4.5 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.20 + +## 0.1.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + +## 0.1.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-catalog-node@1.6.1-next.1 + - @backstage/plugin-scaffolder-common@1.4.4 + +## 0.1.6-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-scaffolder-common@1.4.4 + +## 0.1.5 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-scaffolder-common@1.4.4 + +## 0.1.5-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.6.0-next.3 + - @backstage/plugin-scaffolder-common@1.4.3 + +## 0.1.5-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/backend-common@0.20.0-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-scaffolder-common@1.4.3 + +## 0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-scaffolder-common@1.4.3 + +## 0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-scaffolder-common@1.4.3 + +## 0.1.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/plugin-scaffolder-common@1.4.3 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.18 + ## 0.1.4-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-scaffolder-entity-model/package.json b/plugins/catalog-backend-module-scaffolder-entity-model/package.json index 7a6aa74799..3dc896f7c7 100644 --- a/plugins/catalog-backend-module-scaffolder-entity-model/package.json +++ b/plugins/catalog-backend-module-scaffolder-entity-model/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-scaffolder-entity-model", "description": "Adds support for the scaffolder specific entity model (e.g. the Template kind) to the catalog backend plugin.", - "version": "0.1.4-next.2", + "version": "0.1.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,7 +32,6 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/backend-common": "workspace:^", "@backstage/backend-plugin-api": "workspace:^", "@backstage/catalog-model": "workspace:^", "@backstage/plugin-catalog-common": "workspace:^", diff --git a/plugins/catalog-backend-module-scaffolder-entity-model/src/module.ts b/plugins/catalog-backend-module-scaffolder-entity-model/src/module.ts index 8ed763d32c..c11bc7f7d2 100644 --- a/plugins/catalog-backend-module-scaffolder-entity-model/src/module.ts +++ b/plugins/catalog-backend-module-scaffolder-entity-model/src/module.ts @@ -16,7 +16,7 @@ import { createBackendModule } from '@backstage/backend-plugin-api'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; -import { ScaffolderEntitiesProcessor } from '@backstage/plugin-catalog-backend-module-scaffolder-entity-model'; +import { ScaffolderEntitiesProcessor } from './processor'; /** * Registers support for the scaffolder specific entity model (e.g. the Template @@ -26,7 +26,7 @@ import { ScaffolderEntitiesProcessor } from '@backstage/plugin-catalog-backend-m */ export const catalogModuleScaffolderEntityModel = createBackendModule({ pluginId: 'catalog', - moduleId: 'scaffolderEntityModel', + moduleId: 'scaffolder-entity-model', register(env) { env.registerInit({ deps: { diff --git a/plugins/catalog-backend-module-unprocessed/CHANGELOG.md b/plugins/catalog-backend-module-unprocessed/CHANGELOG.md index ce2f89a953..947fdb5914 100644 --- a/plugins/catalog-backend-module-unprocessed/CHANGELOG.md +++ b/plugins/catalog-backend-module-unprocessed/CHANGELOG.md @@ -1,5 +1,97 @@ # @backstage/plugin-catalog-backend-module-unprocessed +## 0.3.6 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + +## 0.3.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## 0.3.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-model@1.4.3 + +## 0.3.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-auth-node@0.4.3-next.0 + +## 0.3.5 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + +## 0.3.5-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + +## 0.3.5-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + +## 0.3.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## 0.3.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-model@1.4.3 + +## 0.3.4 + +### Patch Changes + +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. +- Updated dependencies + - @backstage/backend-plugin-api@0.6.7 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-auth-node@0.4.1 + ## 0.3.4-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-unprocessed/package.json b/plugins/catalog-backend-module-unprocessed/package.json index c32c4fb144..4412c4ef7c 100644 --- a/plugins/catalog-backend-module-unprocessed/package.json +++ b/plugins/catalog-backend-module-unprocessed/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-unprocessed", "description": "Backstage Catalog module to view unprocessed entities", - "version": "0.3.4-next.2", + "version": "0.3.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-unprocessed/src/module.ts b/plugins/catalog-backend-module-unprocessed/src/module.ts index 1db4fd70b0..8c724d432d 100644 --- a/plugins/catalog-backend-module-unprocessed/src/module.ts +++ b/plugins/catalog-backend-module-unprocessed/src/module.ts @@ -27,7 +27,7 @@ import { UnprocessedEntitiesModule } from './UnprocessedEntitiesModule'; */ export const catalogModuleUnprocessedEntities = createBackendModule({ pluginId: 'catalog', - moduleId: 'catalogModuleUnprocessedEntities', + moduleId: 'catalog-module-unprocessed-entities', register(env) { env.registerInit({ deps: { diff --git a/plugins/catalog-backend/CHANGELOG.md b/plugins/catalog-backend/CHANGELOG.md index 45d54108d9..3330de7fd3 100644 --- a/plugins/catalog-backend/CHANGELOG.md +++ b/plugins/catalog-backend/CHANGELOG.md @@ -1,5 +1,263 @@ # @backstage/plugin-catalog-backend +## 1.16.1 + +### Patch Changes + +- c3249d6: Parse the URL using a different method rather than `git-url-parse` to support wildcards for URLs which are not VCS providers +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-search-backend-module-catalog@0.1.13 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-openapi-utils@0.1.2 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.20 + - @backstage/plugin-events-node@0.2.18 + +## 1.16.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/backend-openapi-utils@0.1.2-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/plugin-events-node@0.2.18-next.2 + - @backstage/plugin-permission-node@0.7.20-next.2 + - @backstage/plugin-search-backend-module-catalog@0.1.13-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## 1.16.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/plugin-permission-node@0.7.20-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.13-next.1 + - @backstage/backend-openapi-utils@0.1.2-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + - @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 + +## 1.16.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.13-next.0 + - @backstage/backend-openapi-utils@0.1.2-next.0 + - @backstage/plugin-catalog-node@1.6.1-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/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.0 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-events-node@0.2.18-next.0 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.20-next.0 + +## 1.16.0 + +### Minor Changes + +- 7804597: Permission rules can now be added for the Catalog plugin through the `CatalogPermissionExtensionPoint` interface. + +### Patch Changes + +- 3834067: Update the OpenAPI spec to support the use of `openapi-generator`. +- 50ee804: Wrap single `pipelineLoop` of TaskPipeline in a span for better traces +- 7123c58: Updated dependency `@types/glob` to `^8.0.0`. +- 0cbb03b: Fixing regular expression ReDoS with zod packages. Upgrading to latest. ref: https://security.snyk.io/vuln/SNYK-JS-ZOD-5925617 +- a168507: Deprecated `EntitiesSearchFilter` and `EntityFilter`, which can now be imported from `@backstage/plugin-catalog-node` instead +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/catalog-client@1.5.0 + - @backstage/backend-openapi-utils@0.1.1 + - @backstage/backend-tasks@0.5.13 + - @backstage/integration@1.8.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.19 + - @backstage/plugin-search-backend-module-catalog@0.1.12 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-events-node@0.2.17 + +## 1.16.0-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-openapi-utils@0.1.1-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/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.3 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.6.0-next.3 + - @backstage/plugin-events-node@0.2.17-next.3 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.3 + - @backstage/plugin-search-backend-module-catalog@0.1.12-next.3 + +## 1.16.0-next.2 + +### Minor Changes + +- 7804597: Permission rules can now be added for the Catalog plugin through the `CatalogPermissionExtensionPoint` interface. + +### Patch Changes + +- 50ee804: Wrap single `pipelineLoop` of TaskPipeline in a span for better traces +- a168507: Deprecated `EntitiesSearchFilter` and `EntityFilter`, which can now be imported from `@backstage/plugin-catalog-node` instead +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.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-search-backend-module-catalog@0.1.12-next.2 + - @backstage/backend-openapi-utils@0.1.1-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/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-events-node@0.2.17-next.2 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.2 + +## 1.15.1-next.1 + +### Patch Changes + +- 38340678c3: Update the OpenAPI spec to support the use of `openapi-generator`. +- 7123c58b3d: Updated dependency `@types/glob` to `^8.0.0`. +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-openapi-utils@0.1.1-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-events-node@0.2.17-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.12-next.1 + +## 1.15.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-openapi-utils@0.1.1-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/plugin-permission-node@0.7.19-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.12-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-events-node@0.2.17-next.0 + - @backstage/plugin-permission-common@0.7.10 + +## 1.15.0 + +### Minor Changes + +- e5bf3749ad: Support adding location analyzers in new catalog analysis extension point and move `AnalyzeOptions` and `ScmLocationAnalyzer` types to `@backstage/plugin-catalog-node` +- 8d756968f9: Introduce a new optional config parameter `catalog.stitchingStrategy.mode`, + which can have the values `'immediate'` (default) and `'deferred'`. The default + is for stitching to work as it did before this change, which means that it + happens "in-band" (blocking) immediately when each processing task finishes. + When set to `'deferred'`, stitching is instead deferred to happen on a separate + asynchronous worker queue just like processing. + + Deferred stitching should make performance smoother when ingesting large amounts + of entities, and reduce p99 processing times and repeated over-stitching of + hot spot entities when fan-out/fan-in in terms of relations is very large. It + does however also come with some performance cost due to the queuing with how + much wall-clock time some types of task take. + +### Patch Changes + +- 6694b369a3: Update the OpenAPI spec with more complete error responses and request bodies using Optic. Also, updates the test cases to use the new `supertest` pass through from `@backstage/backend-openapi-utils`. +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/integration@1.7.2 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/catalog-client@1.4.6 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/backend-openapi-utils@0.1.0 + - @backstage/plugin-search-backend-module-catalog@0.1.11 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-events-node@0.2.16 + - @backstage/plugin-permission-node@0.7.18 + ## 1.15.0-next.2 ### Patch Changes diff --git a/plugins/catalog-backend/alpha-api-report.md b/plugins/catalog-backend/api-report-alpha.md similarity index 97% rename from plugins/catalog-backend/alpha-api-report.md rename to plugins/catalog-backend/api-report-alpha.md index 1682d1cbae..51a2ec6114 100644 --- a/plugins/catalog-backend/alpha-api-report.md +++ b/plugins/catalog-backend/api-report-alpha.md @@ -6,6 +6,7 @@ import { BackendFeature } from '@backstage/backend-plugin-api'; import { ConditionalPolicyDecision } from '@backstage/plugin-permission-common'; import { Conditions } from '@backstage/plugin-permission-node'; +import { EntitiesSearchFilter } from '@backstage/plugin-catalog-node'; import { Entity } from '@backstage/catalog-model'; import { PermissionCondition } from '@backstage/plugin-permission-common'; import { PermissionCriteria } from '@backstage/plugin-permission-common'; @@ -90,12 +91,6 @@ export const createCatalogPermissionRule: < rule: PermissionRule, ) => PermissionRule; -// @public -export type EntitiesSearchFilter = { - key: string; - values?: string[]; -}; - // @alpha export const permissionRules: { hasAnnotation: PermissionRule< diff --git a/plugins/catalog-backend/api-report.md b/plugins/catalog-backend/api-report.md index 1aed0ea8b0..8b7565bd1f 100644 --- a/plugins/catalog-backend/api-report.md +++ b/plugins/catalog-backend/api-report.md @@ -28,7 +28,9 @@ import { Config } from '@backstage/config'; import { DefaultCatalogCollatorFactory as DefaultCatalogCollatorFactory_2 } from '@backstage/plugin-search-backend-module-catalog'; import type { DefaultCatalogCollatorFactoryOptions as DefaultCatalogCollatorFactoryOptions_2 } from '@backstage/plugin-search-backend-module-catalog'; import { DeferredEntity as DeferredEntity_2 } from '@backstage/plugin-catalog-node'; +import { EntitiesSearchFilter as EntitiesSearchFilter_2 } from '@backstage/plugin-catalog-node'; import { Entity } from '@backstage/catalog-model'; +import { EntityFilter as EntityFilter_2 } from '@backstage/plugin-catalog-node'; import { EntityPolicy } from '@backstage/catalog-model'; import { EntityProvider as EntityProvider_2 } from '@backstage/plugin-catalog-node'; import { EntityProviderConnection as EntityProviderConnection_2 } from '@backstage/plugin-catalog-node'; @@ -191,7 +193,7 @@ export type CatalogEnvironment = { // @public export type CatalogPermissionRuleInput< TParams extends PermissionRuleParams = PermissionRuleParams, -> = PermissionRule; +> = PermissionRule; // @public export interface CatalogProcessingEngine { @@ -313,24 +315,11 @@ export type DefaultCatalogCollatorFactoryOptions = // @public @deprecated (undocumented) export type DeferredEntity = DeferredEntity_2; -// @public -export type EntitiesSearchFilter = { - key: string; - values?: string[]; -}; +// @public @deprecated (undocumented) +export type EntitiesSearchFilter = EntitiesSearchFilter_2; -// @public -export type EntityFilter = - | { - allOf: EntityFilter[]; - } - | { - anyOf: EntityFilter[]; - } - | { - not: EntityFilter; - } - | EntitiesSearchFilter; +// @public @deprecated (undocumented) +export type EntityFilter = EntityFilter_2; // @public @deprecated (undocumented) export type EntityProvider = EntityProvider_2; diff --git a/plugins/catalog-backend/optic.yml b/plugins/catalog-backend/optic.yml index 8b0c050516..dbbdefcf68 100644 --- a/plugins/catalog-backend/optic.yml +++ b/plugins/catalog-backend/optic.yml @@ -12,4 +12,4 @@ capture: # ℹ️ Requests should be sent to the Optic proxy, the address of which is injected into 'run.command's env as OPTIC_PROXY (or the value of 'run.proxy_variable'). run: # 🔧 Specify a command that will generate traffic - command: yarn backstage-cli package test --no-watch src/service/router.test.ts src/service/createRouter.test.ts + command: yarn backstage-cli package test --no-watch "src/service/router.test.ts" "src/service/createRouter.test.ts" diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index f02f865618..42f40cccd2 100644 --- a/plugins/catalog-backend/package.json +++ b/plugins/catalog-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend", "description": "The Backstage backend plugin that provides the Backstage catalog", - "version": "1.15.0-next.2", + "version": "1.16.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -82,7 +82,7 @@ "winston": "^3.2.1", "yaml": "^2.0.0", "yn": "^4.0.0", - "zod": "^3.21.4" + "zod": "^3.22.4" }, "devDependencies": { "@backstage/backend-test-utils": "workspace:^", @@ -90,6 +90,7 @@ "@backstage/plugin-permission-common": "workspace:^", "@types/core-js": "^2.5.4", "@types/git-url-parse": "^9.0.0", + "@types/glob": "^8.0.0", "@types/lodash": "^4.14.151", "@types/supertest": "^2.0.8", "@types/uuid": "^8.0.0", diff --git a/plugins/catalog-backend/src/alpha.ts b/plugins/catalog-backend/src/alpha.ts index 06c9571bfa..f85ef02c80 100644 --- a/plugins/catalog-backend/src/alpha.ts +++ b/plugins/catalog-backend/src/alpha.ts @@ -14,11 +14,5 @@ * limitations under the License. */ -// TODO(Rugvip): Re-exported for alpha types as the API report will otherwise -// produce warnings due to the indirect dependency. Would be nice to avoid. -import type { EntitiesSearchFilter } from './catalog/types'; - -export type { /** @alpha */ EntitiesSearchFilter }; - export * from './permissions'; export { catalogPlugin as default } from './service/CatalogPlugin'; diff --git a/plugins/catalog-backend/src/catalog/types.ts b/plugins/catalog-backend/src/catalog/types.ts index 156b8aa64d..e9f5f154c2 100644 --- a/plugins/catalog-backend/src/catalog/types.ts +++ b/plugins/catalog-backend/src/catalog/types.ts @@ -15,19 +15,7 @@ */ import { Entity } from '@backstage/catalog-model'; - -/** - * A filter expression for entities. - * - * Any (at least one) of the outer sets must match, within which all of the - * individual filters must match. - * @public - */ -export type EntityFilter = - | { allOf: EntityFilter[] } - | { anyOf: EntityFilter[] } - | { not: EntityFilter } - | EntitiesSearchFilter; +import { EntityFilter } from '@backstage/plugin-catalog-node'; /** * A pagination rule for entities. @@ -46,27 +34,6 @@ export type EntityOrder = { order: 'asc' | 'desc'; }; -/** - * Matches rows in the search table. - * @public - */ -export type EntitiesSearchFilter = { - /** - * The key to match on. - * - * Matches are always case insensitive. - */ - key: string; - - /** - * Match on plain equality of values. - * - * Match on values that are equal to any of the given array items. Matches are - * always case insensitive. - */ - values?: string[]; -}; - export type PageInfo = | { hasNextPage: false; diff --git a/plugins/catalog-backend/src/database/DefaultCatalogDatabase.test.ts b/plugins/catalog-backend/src/database/DefaultCatalogDatabase.test.ts index bcc20816a4..ebcdc77287 100644 --- a/plugins/catalog-backend/src/database/DefaultCatalogDatabase.test.ts +++ b/plugins/catalog-backend/src/database/DefaultCatalogDatabase.test.ts @@ -25,9 +25,7 @@ jest.setTimeout(60_000); describe('DefaultCatalogDatabase', () => { const defaultLogger = getVoidLogger(); - const databases = TestDatabases.create({ - ids: ['MYSQL_8', 'POSTGRES_13', 'POSTGRES_9', 'SQLITE_3'], - }); + const databases = TestDatabases.create(); async function createDatabase( databaseId: TestDatabaseId, diff --git a/plugins/catalog-backend/src/database/DefaultProcessingDatabase.test.ts b/plugins/catalog-backend/src/database/DefaultProcessingDatabase.test.ts index db5153a8ba..080958da9b 100644 --- a/plugins/catalog-backend/src/database/DefaultProcessingDatabase.test.ts +++ b/plugins/catalog-backend/src/database/DefaultProcessingDatabase.test.ts @@ -37,9 +37,7 @@ jest.setTimeout(60_000); describe('DefaultProcessingDatabase', () => { const defaultLogger = getVoidLogger(); - const databases = TestDatabases.create({ - ids: ['MYSQL_8', 'POSTGRES_13', 'POSTGRES_9', 'SQLITE_3'], - }); + const databases = TestDatabases.create(); async function createDatabase( databaseId: TestDatabaseId, diff --git a/plugins/catalog-backend/src/database/DefaultProviderDatabase.test.ts b/plugins/catalog-backend/src/database/DefaultProviderDatabase.test.ts index 19093b542b..0d124b6d33 100644 --- a/plugins/catalog-backend/src/database/DefaultProviderDatabase.test.ts +++ b/plugins/catalog-backend/src/database/DefaultProviderDatabase.test.ts @@ -28,9 +28,7 @@ jest.setTimeout(60_000); describe('DefaultProviderDatabase', () => { const defaultLogger = getVoidLogger(); - const databases = TestDatabases.create({ - ids: ['MYSQL_8', 'POSTGRES_13', 'POSTGRES_9', 'SQLITE_3'], - }); + const databases = TestDatabases.create(); async function createDatabase( databaseId: TestDatabaseId, diff --git a/plugins/catalog-backend/src/database/operations/provider/deleteWithEagerPruningOfChildren.test.ts b/plugins/catalog-backend/src/database/operations/provider/deleteWithEagerPruningOfChildren.test.ts index 830cc20480..451f7bc1ac 100644 --- a/plugins/catalog-backend/src/database/operations/provider/deleteWithEagerPruningOfChildren.test.ts +++ b/plugins/catalog-backend/src/database/operations/provider/deleteWithEagerPruningOfChildren.test.ts @@ -28,9 +28,7 @@ import { deleteWithEagerPruningOfChildren } from './deleteWithEagerPruningOfChil jest.setTimeout(60_000); describe('deleteWithEagerPruningOfChildren', () => { - const databases = TestDatabases.create({ - ids: ['MYSQL_8', 'POSTGRES_13', 'POSTGRES_9', 'SQLITE_3'], - }); + const databases = TestDatabases.create(); async function createDatabase(databaseId: TestDatabaseId) { const knex = await databases.init(databaseId); diff --git a/plugins/catalog-backend/src/database/operations/stitcher/getDeferredStitchableEntities.test.ts b/plugins/catalog-backend/src/database/operations/stitcher/getDeferredStitchableEntities.test.ts index a909515f14..b66dc74ef2 100644 --- a/plugins/catalog-backend/src/database/operations/stitcher/getDeferredStitchableEntities.test.ts +++ b/plugins/catalog-backend/src/database/operations/stitcher/getDeferredStitchableEntities.test.ts @@ -21,9 +21,7 @@ import { getDeferredStitchableEntities } from './getDeferredStitchableEntities'; jest.setTimeout(60_000); describe('getDeferredStitchableEntities', () => { - const databases = TestDatabases.create({ - ids: ['MYSQL_8', 'POSTGRES_13', 'POSTGRES_9', 'SQLITE_3'], - }); + const databases = TestDatabases.create(); it.each(databases.eachSupportedId())( 'selects the right rows %p', diff --git a/plugins/catalog-backend/src/database/operations/stitcher/markDeferredStitchCompleted.test.ts b/plugins/catalog-backend/src/database/operations/stitcher/markDeferredStitchCompleted.test.ts index 76a6169cf4..b0957e0ec9 100644 --- a/plugins/catalog-backend/src/database/operations/stitcher/markDeferredStitchCompleted.test.ts +++ b/plugins/catalog-backend/src/database/operations/stitcher/markDeferredStitchCompleted.test.ts @@ -22,9 +22,7 @@ import { DbRefreshStateRow } from '../../tables'; jest.setTimeout(60_000); describe('markDeferredStitchCompleted', () => { - const databases = TestDatabases.create({ - ids: ['MYSQL_8', 'POSTGRES_13', 'POSTGRES_9', 'SQLITE_3'], - }); + const databases = TestDatabases.create(); it.each(databases.eachSupportedId())( 'completes only if unchanged %p', diff --git a/plugins/catalog-backend/src/database/operations/stitcher/markForStitching.test.ts b/plugins/catalog-backend/src/database/operations/stitcher/markForStitching.test.ts index 2cae76040b..011fe54e83 100644 --- a/plugins/catalog-backend/src/database/operations/stitcher/markForStitching.test.ts +++ b/plugins/catalog-backend/src/database/operations/stitcher/markForStitching.test.ts @@ -22,9 +22,7 @@ import { DbFinalEntitiesRow, DbRefreshStateRow } from '../../tables'; jest.setTimeout(60_000); describe('markForStitching', () => { - const databases = TestDatabases.create({ - ids: ['MYSQL_8', 'POSTGRES_13', 'POSTGRES_9', 'SQLITE_3'], - }); + const databases = TestDatabases.create(); it.each(databases.eachSupportedId())( 'marks the right rows in deferred mode %p', diff --git a/plugins/catalog-backend/src/database/operations/stitcher/performStitching.test.ts b/plugins/catalog-backend/src/database/operations/stitcher/performStitching.test.ts index a471f1dce2..e43424b361 100644 --- a/plugins/catalog-backend/src/database/operations/stitcher/performStitching.test.ts +++ b/plugins/catalog-backend/src/database/operations/stitcher/performStitching.test.ts @@ -30,9 +30,7 @@ import { performStitching } from './performStitching'; jest.setTimeout(60_000); describe('performStitching', () => { - const databases = TestDatabases.create({ - ids: ['MYSQL_8', 'POSTGRES_13', 'POSTGRES_9', 'SQLITE_3'], - }); + const databases = TestDatabases.create(); const logger = getVoidLogger(); // NOTE(freben): Testing the deferred path since it's a superset of the immediate one diff --git a/plugins/catalog-backend/src/database/operations/util/deleteOrphanedEntities.test.ts b/plugins/catalog-backend/src/database/operations/util/deleteOrphanedEntities.test.ts index 3dacc8f09b..1dc8a42d5f 100644 --- a/plugins/catalog-backend/src/database/operations/util/deleteOrphanedEntities.test.ts +++ b/plugins/catalog-backend/src/database/operations/util/deleteOrphanedEntities.test.ts @@ -29,9 +29,7 @@ import { deleteOrphanedEntities } from './deleteOrphanedEntities'; jest.setTimeout(60_000); describe('deleteOrphanedEntities', () => { - const databases = TestDatabases.create({ - ids: ['MYSQL_8', 'POSTGRES_13', 'POSTGRES_9', 'SQLITE_3'], - }); + const databases = TestDatabases.create(); async function createDatabase(databaseId: TestDatabaseId) { const knex = await databases.init(databaseId); diff --git a/plugins/catalog-backend/src/deprecated.ts b/plugins/catalog-backend/src/deprecated.ts index f3c199cbd3..2201bbbab4 100644 --- a/plugins/catalog-backend/src/deprecated.ts +++ b/plugins/catalog-backend/src/deprecated.ts @@ -18,6 +18,8 @@ import { locationSpecToMetadataName as _locationSpecToMetadataName, locationSpecToLocationEntity as _locationSpecToLocationEntity, processingResult as _processingResult, + type EntitiesSearchFilter as _EntitiesSearchFilter, + type EntityFilter as _EntityFilter, type DeferredEntity as _DeferredEntity, type EntityRelationSpec as _EntityRelationSpec, type CatalogProcessor as _CatalogProcessor, @@ -53,6 +55,16 @@ export const locationSpecToLocationEntity = _locationSpecToLocationEntity; * @deprecated import from `@backstage/plugin-catalog-node` instead */ export const processingResult = _processingResult; +/** + * @public + * @deprecated import from `@backstage/plugin-catalog-node` instead + */ +export type EntitiesSearchFilter = _EntitiesSearchFilter; +/** + * @public + * @deprecated import from `@backstage/plugin-catalog-node` instead + */ +export type EntityFilter = _EntityFilter; /** * @public * @deprecated import from `@backstage/plugin-catalog-node` instead diff --git a/plugins/catalog-backend/src/index.ts b/plugins/catalog-backend/src/index.ts index 55c1c672d3..d2f20d24d8 100644 --- a/plugins/catalog-backend/src/index.ts +++ b/plugins/catalog-backend/src/index.ts @@ -20,7 +20,6 @@ * @packageDocumentation */ -export * from './catalog'; export * from './ingestion'; export * from './modules'; export * from './processing'; diff --git a/plugins/catalog-backend/src/modules/core/DefaultLocationStore.test.ts b/plugins/catalog-backend/src/modules/core/DefaultLocationStore.test.ts index fca7faacf8..61eef2b8e5 100644 --- a/plugins/catalog-backend/src/modules/core/DefaultLocationStore.test.ts +++ b/plugins/catalog-backend/src/modules/core/DefaultLocationStore.test.ts @@ -22,9 +22,7 @@ import { DefaultLocationStore } from './DefaultLocationStore'; jest.setTimeout(60_000); describe('DefaultLocationStore', () => { - const databases = TestDatabases.create({ - ids: ['MYSQL_8', 'POSTGRES_13', 'POSTGRES_9', 'SQLITE_3'], - }); + const databases = TestDatabases.create(); async function createLocationStore(databaseId: TestDatabaseId) { const knex = await databases.init(databaseId); diff --git a/plugins/catalog-backend/src/modules/core/UrlReaderProcessor.test.ts b/plugins/catalog-backend/src/modules/core/UrlReaderProcessor.test.ts index c9575ce5cd..e2489df4b4 100644 --- a/plugins/catalog-backend/src/modules/core/UrlReaderProcessor.test.ts +++ b/plugins/catalog-backend/src/modules/core/UrlReaderProcessor.test.ts @@ -213,4 +213,34 @@ describe('UrlReaderProcessor', () => { expect(reader.search).toHaveBeenCalledTimes(1); }); + + it('parser return valid URL with wildcard *', async () => { + const logger = getVoidLogger(); + + const reader: jest.Mocked = { + readUrl: jest.fn(), + readTree: jest.fn(), + search: jest.fn().mockImplementation(async () => []), + }; + + const processor = new UrlReaderProcessor({ reader, logger }); + + const emit = jest.fn(); + + await processor.readLocation( + { + type: 'url', + target: 'https://storage.cloud.google.com/ah-backstage-poc-catalog/*', + }, + false, + emit, + defaultEntityDataParser, + mockCache, + ); + + expect(reader.search).toHaveBeenCalledWith( + 'https://storage.cloud.google.com/ah-backstage-poc-catalog/*', + { etag: undefined }, + ); + }); }); diff --git a/plugins/catalog-backend/src/modules/core/UrlReaderProcessor.ts b/plugins/catalog-backend/src/modules/core/UrlReaderProcessor.ts index 5e31dcbd1a..c568f03a81 100644 --- a/plugins/catalog-backend/src/modules/core/UrlReaderProcessor.ts +++ b/plugins/catalog-backend/src/modules/core/UrlReaderProcessor.ts @@ -17,7 +17,6 @@ import { UrlReader } from '@backstage/backend-common'; import { Entity } from '@backstage/catalog-model'; import { assertError } from '@backstage/errors'; -import parseGitUrl from 'git-url-parse'; import limiterFactory from 'p-limit'; import { Logger } from 'winston'; import { LocationSpec } from '@backstage/plugin-catalog-common'; @@ -124,7 +123,8 @@ export class UrlReaderProcessor implements CatalogProcessor { ): Promise<{ response: { data: Buffer; url: string }[]; etag?: string }> { // Does it contain globs? I.e. does it contain asterisks or question marks // (no curly braces for now) - const { filepath } = parseGitUrl(location); + + const { pathname: filepath } = new URL(location); if (filepath?.match(/[*?]/)) { const limiter = limiterFactory(5); const response = await this.options.reader.search(location, { etag }); diff --git a/plugins/catalog-backend/src/permissions/rules/isEntityKind.ts b/plugins/catalog-backend/src/permissions/rules/isEntityKind.ts index 8ebad5521c..568aae4838 100644 --- a/plugins/catalog-backend/src/permissions/rules/isEntityKind.ts +++ b/plugins/catalog-backend/src/permissions/rules/isEntityKind.ts @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { RESOURCE_TYPE_CATALOG_ENTITY } from '@backstage/plugin-catalog-common/alpha'; import { z } from 'zod'; -import { EntitiesSearchFilter } from '../../catalog/types'; import { createCatalogPermissionRule } from './util'; /** @@ -36,7 +36,7 @@ export const isEntityKind = createCatalogPermissionRule({ const resourceKind = resource.kind.toLocaleLowerCase('en-US'); return kinds.some(kind => kind.toLocaleLowerCase('en-US') === resourceKind); }, - toQuery({ kinds }): EntitiesSearchFilter { + toQuery({ kinds }) { return { key: 'kind', values: kinds.map(kind => kind.toLocaleLowerCase('en-US')), diff --git a/plugins/catalog-backend/src/permissions/rules/util.ts b/plugins/catalog-backend/src/permissions/rules/util.ts index 466f5ce70b..c3e642490c 100644 --- a/plugins/catalog-backend/src/permissions/rules/util.ts +++ b/plugins/catalog-backend/src/permissions/rules/util.ts @@ -16,12 +16,12 @@ import { Entity } from '@backstage/catalog-model'; import { RESOURCE_TYPE_CATALOG_ENTITY } from '@backstage/plugin-catalog-common/alpha'; +import { EntitiesSearchFilter } from '@backstage/plugin-catalog-node'; import { PermissionRuleParams } from '@backstage/plugin-permission-common'; import { makeCreatePermissionRule, PermissionRule, } from '@backstage/plugin-permission-node'; -import { EntitiesSearchFilter } from '../../catalog/types'; /** * Convenience type for {@link @backstage/plugin-permission-node#PermissionRule} diff --git a/plugins/catalog-backend/src/processing/TaskPipeline.ts b/plugins/catalog-backend/src/processing/TaskPipeline.ts index 44030be9e0..b808e41ce4 100644 --- a/plugins/catalog-backend/src/processing/TaskPipeline.ts +++ b/plugins/catalog-backend/src/processing/TaskPipeline.ts @@ -14,7 +14,11 @@ * limitations under the License. */ +import { TRACER_ID, withActiveSpan } from '../util/opentelemetry'; +import { trace } from '@opentelemetry/api'; + const DEFAULT_POLLING_INTERVAL_MS = 1000; +const tracer = trace.getTracer(TRACER_ID); type Options = { /** @@ -86,33 +90,35 @@ export function startTaskPipeline(options: Options) { async function pipelineLoop() { while (!abortSignal.aborted) { if (state.inFlightCount <= lowWatermark) { - const loadCount = highWatermark - state.inFlightCount; - const loadedItems = await Promise.resolve() - .then(() => loadTasks(loadCount)) - .catch(() => { - // Silently swallow errors and go back to sleep to try again; we - // delegate to the loadTasks function itself to catch errors and log - // if it so desires - return []; - }); - if (loadedItems.length && !abortSignal.aborted) { - state.inFlightCount += loadedItems.length; - for (const item of loadedItems) { - Promise.resolve() - .then(() => processTask(item)) - .catch(() => { - // Silently swallow errors and go back to sleep to try again; we - // delegate to the processTask function itself to catch errors - // and log if it so desires - }) - .finally(() => { - state.inFlightCount -= 1; - barrier.release(); - }); + await withActiveSpan(tracer, 'TaskPipelineLoop', async span => { + const loadCount = highWatermark - state.inFlightCount; + const loadedItems = await Promise.resolve() + .then(() => loadTasks(loadCount)) + .catch(() => { + // Silently swallow errors and go back to sleep to try again; we + // delegate to the loadTasks function itself to catch errors and log + // if it so desires + return []; + }); + span.setAttribute('itemCount', loadedItems.length); + if (loadedItems.length && !abortSignal.aborted) { + state.inFlightCount += loadedItems.length; + for (const item of loadedItems) { + Promise.resolve() + .then(() => processTask(item)) + .catch(() => { + // Silently swallow errors and go back to sleep to try again; we + // delegate to the processTask function itself to catch errors + // and log if it so desires + }) + .finally(() => { + state.inFlightCount -= 1; + barrier.release(); + }); + } } - } + }); } - await barrier.wait(); } } diff --git a/plugins/catalog-backend/src/schema/openapi.generated.ts b/plugins/catalog-backend/src/schema/openapi.generated.ts index a31615dfc6..fe64c75373 100644 --- a/plugins/catalog-backend/src/schema/openapi.generated.ts +++ b/plugins/catalog-backend/src/schema/openapi.generated.ts @@ -36,6 +36,9 @@ export const spec = { { url: '/', }, + { + url: 'catalog', + }, ], components: { examples: {}, @@ -105,6 +108,7 @@ export const spec = { description: 'Restrict to just these fields in the response.', required: false, allowReserved: true, + explode: false, schema: { type: 'array', items: { @@ -248,12 +252,13 @@ export const spec = { }, }, required: ['error', 'response'], + additionalProperties: {}, }, JsonObject: { type: 'object', properties: {}, description: 'A type representing all allowed JSON object values.', - additionalProperties: true, + additionalProperties: {}, }, MapStringString: { type: 'object', @@ -291,70 +296,62 @@ export const spec = { additionalProperties: false, }, EntityMeta: { - allOf: [ - { - $ref: '#/components/schemas/JsonObject', - }, - { - type: 'object', - properties: { - links: { - type: 'array', - items: { - $ref: '#/components/schemas/EntityLink', - }, - description: - 'A list of external hyperlinks related to the entity.', - }, - tags: { - type: 'array', - items: { - type: 'string', - }, - description: - 'A list of single-valued strings, to for example classify catalog entities in\nvarious ways.', - }, - annotations: { - $ref: '#/components/schemas/MapStringString', - }, - labels: { - $ref: '#/components/schemas/MapStringString', - }, - description: { - type: 'string', - description: - 'A short (typically relatively few words, on one line) description of the\nentity.', - }, - title: { - type: 'string', - description: - 'A display name of the entity, to be presented in user interfaces instead\nof the `name` property above, when available.\nThis field is sometimes useful when the `name` is cumbersome or ends up\nbeing perceived as overly technical. The title generally does not have\nas stringent format requirements on it, so it may contain special\ncharacters and be more explanatory. Do keep it very short though, and\navoid situations where a title can be confused with the name of another\nentity, or where two entities share a title.\nNote that this is only for display purposes, and may be ignored by some\nparts of the code. Entity references still always make use of the `name`\nproperty, not the title.', - }, - namespace: { - type: 'string', - description: 'The namespace that the entity belongs to.', - }, - name: { - type: 'string', - description: - 'The name of the entity.\nMust be unique within the catalog at any given point in time, for any\ngiven namespace + kind pair. This value is part of the technical\nidentifier of the entity, and as such it will appear in URLs, database\ntables, entity references, and similar. It is subject to restrictions\nregarding what characters are allowed.\nIf you want to use a different, more human readable string with fewer\nrestrictions on it in user interfaces, see the `title` field below.', - }, - etag: { - type: 'string', - description: - 'An opaque string that changes for each update operation to any part of\nthe entity, including metadata.\nThis field can not be set by the user at creation time, and the server\nwill reject an attempt to do so. The field will be populated in read\noperations. The field can (optionally) be specified when performing\nupdate or delete operations, and the server will then reject the\noperation if it does not match the current stored value.', - }, - uid: { - type: 'string', - description: - 'A globally unique ID for the entity.\nThis field can not be set by the user at creation time, and the server\nwill reject an attempt to do so. The field will be populated in read\noperations. The field can (optionally) be specified when performing\nupdate or delete operations, but the server is free to reject requests\nthat do so in such a way that it breaks semantics.', - }, + type: 'object', + properties: { + links: { + type: 'array', + items: { + $ref: '#/components/schemas/EntityLink', }, - required: ['name'], + description: 'A list of external hyperlinks related to the entity.', }, - ], + tags: { + type: 'array', + items: { + type: 'string', + }, + description: + 'A list of single-valued strings, to for example classify catalog entities in\nvarious ways.', + }, + annotations: { + $ref: '#/components/schemas/MapStringString', + }, + labels: { + $ref: '#/components/schemas/MapStringString', + }, + description: { + type: 'string', + description: + 'A short (typically relatively few words, on one line) description of the\nentity.', + }, + title: { + type: 'string', + description: + 'A display name of the entity, to be presented in user interfaces instead\nof the `name` property above, when available.\nThis field is sometimes useful when the `name` is cumbersome or ends up\nbeing perceived as overly technical. The title generally does not have\nas stringent format requirements on it, so it may contain special\ncharacters and be more explanatory. Do keep it very short though, and\navoid situations where a title can be confused with the name of another\nentity, or where two entities share a title.\nNote that this is only for display purposes, and may be ignored by some\nparts of the code. Entity references still always make use of the `name`\nproperty, not the title.', + }, + namespace: { + type: 'string', + description: 'The namespace that the entity belongs to.', + }, + name: { + type: 'string', + description: + 'The name of the entity.\nMust be unique within the catalog at any given point in time, for any\ngiven namespace + kind pair. This value is part of the technical\nidentifier of the entity, and as such it will appear in URLs, database\ntables, entity references, and similar. It is subject to restrictions\nregarding what characters are allowed.\nIf you want to use a different, more human readable string with fewer\nrestrictions on it in user interfaces, see the `title` field below.', + }, + etag: { + type: 'string', + description: + 'An opaque string that changes for each update operation to any part of\nthe entity, including metadata.\nThis field can not be set by the user at creation time, and the server\nwill reject an attempt to do so. The field will be populated in read\noperations. The field can (optionally) be specified when performing\nupdate or delete operations, and the server will then reject the\noperation if it does not match the current stored value.', + }, + uid: { + type: 'string', + description: + 'A globally unique ID for the entity.\nThis field can not be set by the user at creation time, and the server\nwill reject an attempt to do so. The field will be populated in read\noperations. The field can (optionally) be specified when performing\nupdate or delete operations, but the server is free to reject requests\nthat do so in such a way that it breaks semantics.', + }, + }, + required: ['name'], description: 'Metadata fields common to all versions/kinds of entity.', - additionalProperties: true, + additionalProperties: {}, }, EntityRelation: { type: 'object', @@ -403,7 +400,6 @@ export const spec = { required: ['metadata', 'kind', 'apiVersion'], description: "The parts of the format that's common to all versions/kinds of entity.", - additionalProperties: true, }, NullableEntity: { type: 'object', @@ -435,7 +431,6 @@ export const spec = { required: ['metadata', 'kind', 'apiVersion'], description: "The parts of the format that's common to all versions/kinds of entity.", - additionalProperties: true, nullable: true, }, EntityAncestryResponse: { @@ -472,11 +467,7 @@ export const spec = { items: { type: 'array', items: { - anyOf: [ - { - $ref: '#/components/schemas/NullableEntity', - }, - ], + $ref: '#/components/schemas/NullableEntity', }, description: 'The list of entities, in the same order as the refs in the request. Entries\nthat are null signify that no entity existed with that ref.', @@ -495,6 +486,7 @@ export const spec = { type: 'number', }, }, + required: ['value', 'count'], additionalProperties: false, }, EntityFacetsResponse: { @@ -782,6 +774,7 @@ export const spec = { }, }, }, + required: ['items', 'totalItems', 'pageInfo'], additionalProperties: false, }, }, @@ -1076,11 +1069,6 @@ export const spec = { JWT: [], }, ], - parameters: [ - { - $ref: '#/components/parameters/fields', - }, - ], requestBody: { required: false, content: { @@ -1257,8 +1245,8 @@ export const spec = { operationId: 'CreateLocation', description: 'Create a location for a given target.', responses: { - '200': { - description: 'Ok', + '201': { + description: 'Created', content: { 'application/json': { schema: { @@ -1282,38 +1270,6 @@ export const spec = { }, }, }, - '201': { - description: '201 response', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - location: { - type: 'object', - properties: { - id: { - type: 'string', - }, - type: { - type: 'string', - }, - target: { - type: 'string', - }, - }, - required: ['id', 'type', 'target'], - }, - entities: { - type: 'array', - items: {}, - }, - }, - required: ['location', 'entities'], - }, - }, - }, - }, '400': { $ref: '#/components/responses/ErrorResponse', }, @@ -1524,7 +1480,7 @@ export const spec = { description: 'Ok', }, '400': { - description: '400 response', + description: 'Validation errors.', content: { 'application/json; charset=utf-8': { schema: { @@ -1543,6 +1499,7 @@ export const spec = { }, }, required: ['name', 'message'], + additionalProperties: {}, }, }, }, @@ -1571,7 +1528,7 @@ export const spec = { }, entity: { type: 'object', - additionalProperties: true, + additionalProperties: {}, }, }, required: ['location', 'entity'], diff --git a/plugins/catalog-backend/src/schema/openapi.yaml b/plugins/catalog-backend/src/schema/openapi.yaml index 3375f7fe15..d3ef718286 100644 --- a/plugins/catalog-backend/src/schema/openapi.yaml +++ b/plugins/catalog-backend/src/schema/openapi.yaml @@ -9,6 +9,7 @@ info: contact: {} servers: - url: / + - url: catalog components: examples: {} headers: {} @@ -65,6 +66,7 @@ components: description: Restrict to just these fields in the response. required: false allowReserved: true + explode: false schema: type: array items: @@ -180,11 +182,12 @@ components: required: - error - response + additionalProperties: {} JsonObject: type: object properties: {} description: A type representing all allowed JSON object values. - additionalProperties: true + additionalProperties: {} MapStringString: type: object properties: {} @@ -211,82 +214,80 @@ components: description: A link to external information that is related to the entity. additionalProperties: false EntityMeta: - allOf: - - $ref: '#/components/schemas/JsonObject' - - type: object - properties: - links: - type: array - items: - $ref: '#/components/schemas/EntityLink' - description: A list of external hyperlinks related to the entity. - tags: - type: array - items: - type: string - description: |- - A list of single-valued strings, to for example classify catalog entities in - various ways. - annotations: - $ref: '#/components/schemas/MapStringString' - labels: - $ref: '#/components/schemas/MapStringString' - description: - type: string - description: |- - A short (typically relatively few words, on one line) description of the - entity. - title: - type: string - description: |- - A display name of the entity, to be presented in user interfaces instead - of the `name` property above, when available. - This field is sometimes useful when the `name` is cumbersome or ends up - being perceived as overly technical. The title generally does not have - as stringent format requirements on it, so it may contain special - characters and be more explanatory. Do keep it very short though, and - avoid situations where a title can be confused with the name of another - entity, or where two entities share a title. - Note that this is only for display purposes, and may be ignored by some - parts of the code. Entity references still always make use of the `name` - property, not the title. - namespace: - type: string - description: The namespace that the entity belongs to. - name: - type: string - description: |- - The name of the entity. - Must be unique within the catalog at any given point in time, for any - given namespace + kind pair. This value is part of the technical - identifier of the entity, and as such it will appear in URLs, database - tables, entity references, and similar. It is subject to restrictions - regarding what characters are allowed. - If you want to use a different, more human readable string with fewer - restrictions on it in user interfaces, see the `title` field below. - etag: - type: string - description: |- - An opaque string that changes for each update operation to any part of - the entity, including metadata. - This field can not be set by the user at creation time, and the server - will reject an attempt to do so. The field will be populated in read - operations. The field can (optionally) be specified when performing - update or delete operations, and the server will then reject the - operation if it does not match the current stored value. - uid: - type: string - description: |- - A globally unique ID for the entity. - This field can not be set by the user at creation time, and the server - will reject an attempt to do so. The field will be populated in read - operations. The field can (optionally) be specified when performing - update or delete operations, but the server is free to reject requests - that do so in such a way that it breaks semantics. - required: - - name + type: object + properties: + links: + type: array + items: + $ref: '#/components/schemas/EntityLink' + description: A list of external hyperlinks related to the entity. + tags: + type: array + items: + type: string + description: |- + A list of single-valued strings, to for example classify catalog entities in + various ways. + annotations: + $ref: '#/components/schemas/MapStringString' + labels: + $ref: '#/components/schemas/MapStringString' + description: + type: string + description: |- + A short (typically relatively few words, on one line) description of the + entity. + title: + type: string + description: |- + A display name of the entity, to be presented in user interfaces instead + of the `name` property above, when available. + This field is sometimes useful when the `name` is cumbersome or ends up + being perceived as overly technical. The title generally does not have + as stringent format requirements on it, so it may contain special + characters and be more explanatory. Do keep it very short though, and + avoid situations where a title can be confused with the name of another + entity, or where two entities share a title. + Note that this is only for display purposes, and may be ignored by some + parts of the code. Entity references still always make use of the `name` + property, not the title. + namespace: + type: string + description: The namespace that the entity belongs to. + name: + type: string + description: |- + The name of the entity. + Must be unique within the catalog at any given point in time, for any + given namespace + kind pair. This value is part of the technical + identifier of the entity, and as such it will appear in URLs, database + tables, entity references, and similar. It is subject to restrictions + regarding what characters are allowed. + If you want to use a different, more human readable string with fewer + restrictions on it in user interfaces, see the `title` field below. + etag: + type: string + description: |- + An opaque string that changes for each update operation to any part of + the entity, including metadata. + This field can not be set by the user at creation time, and the server + will reject an attempt to do so. The field will be populated in read + operations. The field can (optionally) be specified when performing + update or delete operations, and the server will then reject the + operation if it does not match the current stored value. + uid: + type: string + description: |- + A globally unique ID for the entity. + This field can not be set by the user at creation time, and the server + will reject an attempt to do so. The field will be populated in read + operations. The field can (optionally) be specified when performing + update or delete operations, but the server is free to reject requests + that do so in such a way that it breaks semantics. + required: + - name description: Metadata fields common to all versions/kinds of entity. - additionalProperties: true + additionalProperties: {} EntityRelation: type: object properties: @@ -326,7 +327,6 @@ components: - kind - apiVersion description: The parts of the format that's common to all versions/kinds of entity. - additionalProperties: true NullableEntity: type: object properties: @@ -352,7 +352,6 @@ components: - kind - apiVersion description: The parts of the format that's common to all versions/kinds of entity. - additionalProperties: true nullable: true EntityAncestryResponse: type: object @@ -383,8 +382,7 @@ components: items: type: array items: - anyOf: - - $ref: '#/components/schemas/NullableEntity' + $ref: '#/components/schemas/NullableEntity' description: |- The list of entities, in the same order as the refs in the request. Entries that are null signify that no entity existed with that ref. @@ -398,6 +396,9 @@ components: type: string count: type: number + required: + - value + - count additionalProperties: false EntityFacetsResponse: type: object @@ -660,6 +661,10 @@ components: prevCursor: type: string description: The cursor for the previous batch of entities. + required: + - items + - totalItems + - pageInfo additionalProperties: false securitySchemes: JWT: @@ -829,8 +834,6 @@ paths: security: - {} - JWT: [] - parameters: - - $ref: '#/components/parameters/fields' requestBody: required: false content: @@ -942,8 +945,8 @@ paths: operationId: CreateLocation description: Create a location for a given target. responses: - '200': - description: Ok + '201': + description: Created content: application/json: schema: @@ -960,32 +963,6 @@ paths: required: - entities - location - '201': - description: 201 response - content: - application/json: - schema: - type: object - properties: - location: - type: object - properties: - id: - type: string - type: - type: string - target: - type: string - required: - - id - - type - - target - entities: - type: array - items: {} - required: - - location - - entities '400': $ref: '#/components/responses/ErrorResponse' default: @@ -1120,7 +1097,7 @@ paths: '200': description: Ok '400': - description: 400 response + description: Validation errors. content: application/json; charset=utf-8: schema: @@ -1138,6 +1115,7 @@ paths: required: - name - message + additionalProperties: {} required: - errors security: @@ -1155,7 +1133,7 @@ paths: type: string entity: type: object - additionalProperties: true + additionalProperties: {} required: - location - entity diff --git a/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.test.ts b/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.test.ts index 2ee47dae19..ce9221e16e 100644 --- a/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.test.ts +++ b/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.test.ts @@ -20,8 +20,9 @@ import { createConditionTransformer } from '@backstage/plugin-permission-node'; import { isEntityKind } from '../permissions/rules/isEntityKind'; import { CatalogPermissionRule } from '../permissions/rules'; import { AuthorizedEntitiesCatalog } from './AuthorizedEntitiesCatalog'; -import { Cursor, EntityFilter, QueryEntitiesResponse } from '../catalog/types'; +import { Cursor, QueryEntitiesResponse } from '../catalog/types'; import { Entity } from '@backstage/catalog-model'; +import { EntityFilter } from '@backstage/plugin-catalog-node'; describe('AuthorizedEntitiesCatalog', () => { const fakeCatalog = { diff --git a/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.ts b/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.ts index 0ce1ee87e7..6a04c4d7a1 100644 --- a/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.ts +++ b/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.ts @@ -35,12 +35,12 @@ import { EntityAncestryResponse, EntityFacetsRequest, EntityFacetsResponse, - EntityFilter, QueryEntitiesRequest, QueryEntitiesResponse, } from '../catalog/types'; import { basicEntityFilter } from './request/basicEntityFilter'; import { isQueryEntitiesCursorRequest } from './util'; +import { EntityFilter } from '@backstage/plugin-catalog-node'; export class AuthorizedEntitiesCatalog implements EntitiesCatalog { constructor( diff --git a/plugins/catalog-backend/src/service/CatalogBuilder.ts b/plugins/catalog-backend/src/service/CatalogBuilder.ts index 5cf76ee1ac..f8ed166118 100644 --- a/plugins/catalog-backend/src/service/CatalogBuilder.ts +++ b/plugins/catalog-backend/src/service/CatalogBuilder.ts @@ -37,6 +37,7 @@ import lodash, { keyBy } from 'lodash'; import { CatalogProcessor, CatalogProcessorParser, + EntitiesSearchFilter, EntityProvider, ScmLocationAnalyzer, } from '@backstage/plugin-catalog-node'; @@ -79,7 +80,6 @@ import { Config, readDurationFromConfig } from '@backstage/config'; import { Logger } from 'winston'; import { connectEntityProviders } from '../processing/connectEntityProviders'; import { PermissionRuleParams } from '@backstage/plugin-permission-common'; -import { EntitiesSearchFilter } from '../catalog/types'; import { permissionRules as catalogPermissionRules } from '../permissions/rules'; import { PermissionRule } from '@backstage/plugin-permission-node'; import { diff --git a/plugins/catalog-backend/src/service/CatalogPlugin.ts b/plugins/catalog-backend/src/service/CatalogPlugin.ts index fa53ef510b..0800d41340 100644 --- a/plugins/catalog-backend/src/service/CatalogPlugin.ts +++ b/plugins/catalog-backend/src/service/CatalogPlugin.ts @@ -17,12 +17,14 @@ import { createBackendPlugin, coreServices, } from '@backstage/backend-plugin-api'; -import { CatalogBuilder } from './CatalogBuilder'; +import { CatalogBuilder, CatalogPermissionRuleInput } from './CatalogBuilder'; import { CatalogAnalysisExtensionPoint, catalogAnalysisExtensionPoint, CatalogProcessingExtensionPoint, catalogProcessingExtensionPoint, + CatalogPermissionExtensionPoint, + catalogPermissionExtensionPoint, } from '@backstage/plugin-catalog-node/alpha'; import { CatalogProcessor, @@ -86,6 +88,24 @@ class CatalogAnalysisExtensionPointImpl } } +class CatalogPermissionExtensionPointImpl + implements CatalogPermissionExtensionPoint +{ + #permissionRules = new Array(); + + addPermissionRules( + ...rules: Array< + CatalogPermissionRuleInput | Array + > + ): void { + this.#permissionRules.push(...rules.flat()); + } + + get permissionRules() { + return this.#permissionRules; + } +} + /** * Catalog plugin * @alpha @@ -106,6 +126,12 @@ export const catalogPlugin = createBackendPlugin({ analysisExtensions, ); + const permissionExtensions = new CatalogPermissionExtensionPointImpl(); + env.registerExtensionPoint( + catalogPermissionExtensionPoint, + permissionExtensions, + ); + env.registerInit({ deps: { logger: coreServices.logger, @@ -142,6 +168,7 @@ export const catalogPlugin = createBackendPlugin({ ([key, resolver]) => builder.setPlaceholderResolver(key, resolver), ); builder.addLocationAnalyzers(...analysisExtensions.locationAnalyzers); + builder.addPermissionRules(...permissionExtensions.permissionRules); const { processingEngine, router } = await builder.build(); diff --git a/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.test.ts b/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.test.ts index fde3408c4b..fe7d57c89a 100644 --- a/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.test.ts +++ b/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.test.ts @@ -44,9 +44,7 @@ describe('DefaultEntitiesCatalog', () => { await knex.destroy(); }); - const databases = TestDatabases.create({ - ids: ['MYSQL_8', 'POSTGRES_13', 'POSTGRES_9', 'SQLITE_3'], - }); + const databases = TestDatabases.create(); const stitch = jest.fn(); const stitcher: Stitcher = { stitch } as any; diff --git a/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts b/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts index 24f0432419..0245fe1d4e 100644 --- a/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts +++ b/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts @@ -31,11 +31,9 @@ import { EntitiesCatalog, EntitiesRequest, EntitiesResponse, - EntitiesSearchFilter, EntityAncestryResponse, EntityFacetsRequest, EntityFacetsResponse, - EntityFilter, EntityPagination, QueryEntitiesRequest, QueryEntitiesResponse, @@ -55,6 +53,10 @@ import { isQueryEntitiesCursorRequest, isQueryEntitiesInitialRequest, } from './util'; +import { + EntitiesSearchFilter, + EntityFilter, +} from '@backstage/plugin-catalog-node'; const defaultSortField: EntityOrder = { field: 'metadata.uid', diff --git a/plugins/catalog-backend/src/service/DefaultRefreshService.test.ts b/plugins/catalog-backend/src/service/DefaultRefreshService.test.ts index 5b29bb34d5..e1b775cce6 100644 --- a/plugins/catalog-backend/src/service/DefaultRefreshService.test.ts +++ b/plugins/catalog-backend/src/service/DefaultRefreshService.test.ts @@ -39,9 +39,7 @@ jest.setTimeout(60_000); describe('DefaultRefreshService', () => { const defaultLogger = getVoidLogger(); - const databases = TestDatabases.create({ - ids: ['MYSQL_8', 'POSTGRES_13', 'POSTGRES_9', 'SQLITE_3'], - }); + const databases = TestDatabases.create(); async function createDatabase( databaseId: TestDatabaseId, diff --git a/plugins/catalog-backend/src/service/createRouter.test.ts b/plugins/catalog-backend/src/service/createRouter.test.ts index 700e35edc1..05ebf6e1a9 100644 --- a/plugins/catalog-backend/src/service/createRouter.test.ts +++ b/plugins/catalog-backend/src/service/createRouter.test.ts @@ -198,6 +198,45 @@ describe('createRouter readonly disabled', () => { }); }); + it('parses encoded params request', async () => { + entitiesCatalog.queryEntities.mockResolvedValueOnce({ + items: [], + pageInfo: {}, + totalItems: 0, + }); + const response = await request(app).get( + `/entities/by-query?filter=${encodeURIComponent( + 'a=1,a=2,b=3', + )}&filter=c=4&orderField=${encodeURIComponent( + 'metadata.name,asc', + )}&orderField=metadata.uid,desc`, + ); + + expect(response.status).toEqual(200); + expect(entitiesCatalog.queryEntities).toHaveBeenCalledTimes(1); + expect(entitiesCatalog.queryEntities).toHaveBeenCalledWith({ + filter: { + anyOf: [ + { + allOf: [ + { key: 'a', values: ['1', '2'] }, + { key: 'b', values: ['3'] }, + ], + }, + { allOf: [{ key: 'c', values: ['4'] }] }, + ], + }, + orderFields: [ + { field: 'metadata.name', order: 'asc' }, + { field: 'metadata.uid', order: 'desc' }, + ], + fullTextFilter: { + fields: undefined, + term: '', + }, + }); + }); + it('parses cursor request', async () => { const items: Entity[] = [ { apiVersion: 'a', kind: 'b', metadata: { name: 'n' } }, diff --git a/plugins/catalog-backend/src/service/request/basicEntityFilter.ts b/plugins/catalog-backend/src/service/request/basicEntityFilter.ts index 36448e0304..43824160a2 100644 --- a/plugins/catalog-backend/src/service/request/basicEntityFilter.ts +++ b/plugins/catalog-backend/src/service/request/basicEntityFilter.ts @@ -14,7 +14,10 @@ * limitations under the License. */ -import { EntitiesSearchFilter, EntityFilter } from '../../catalog'; +import { + EntitiesSearchFilter, + EntityFilter, +} from '@backstage/plugin-catalog-node'; /** * Forms a full EntityFilter based on a single key-value(s) object. diff --git a/plugins/catalog-backend/src/service/request/parseEntityFilterParams.ts b/plugins/catalog-backend/src/service/request/parseEntityFilterParams.ts index 767a36ce71..cfd9aa0aa5 100644 --- a/plugins/catalog-backend/src/service/request/parseEntityFilterParams.ts +++ b/plugins/catalog-backend/src/service/request/parseEntityFilterParams.ts @@ -15,8 +15,11 @@ */ import { InputError } from '@backstage/errors'; -import { EntitiesSearchFilter, EntityFilter } from '../../catalog'; import { parseStringsParam } from './common'; +import { + EntitiesSearchFilter, + EntityFilter, +} from '@backstage/plugin-catalog-node'; /** * Parses the filtering part of a query, like diff --git a/plugins/catalog-backend/src/service/util.ts b/plugins/catalog-backend/src/service/util.ts index 699bca2fc9..af1279a59a 100644 --- a/plugins/catalog-backend/src/service/util.ts +++ b/plugins/catalog-backend/src/service/util.ts @@ -20,11 +20,11 @@ import lodash from 'lodash'; import { z } from 'zod'; import { Cursor, - EntityFilter, QueryEntitiesCursorRequest, QueryEntitiesInitialRequest, QueryEntitiesRequest, } from '../catalog/types'; +import { EntityFilter } from '@backstage/plugin-catalog-node'; export async function requireRequestBody(req: Request): Promise { const contentType = req.header('content-type'); diff --git a/plugins/catalog-backend/src/setupTests.ts b/plugins/catalog-backend/src/setupTests.ts index d3232290a7..f7c56ef27d 100644 --- a/plugins/catalog-backend/src/setupTests.ts +++ b/plugins/catalog-backend/src/setupTests.ts @@ -14,4 +14,10 @@ * limitations under the License. */ +import { TestDatabases } from '@backstage/backend-test-utils'; + export {}; + +TestDatabases.setDefaults({ + ids: ['MYSQL_8', 'POSTGRES_16', 'POSTGRES_12', 'SQLITE_3'], +}); diff --git a/plugins/catalog-backend/src/stitching/DefaultStitcher.test.ts b/plugins/catalog-backend/src/stitching/DefaultStitcher.test.ts index 5b33fc424c..5e7ba7ef71 100644 --- a/plugins/catalog-backend/src/stitching/DefaultStitcher.test.ts +++ b/plugins/catalog-backend/src/stitching/DefaultStitcher.test.ts @@ -30,9 +30,7 @@ import { DefaultStitcher } from './DefaultStitcher'; jest.setTimeout(60_000); describe('Stitcher', () => { - const databases = TestDatabases.create({ - ids: ['MYSQL_8', 'POSTGRES_13', 'POSTGRES_9', 'SQLITE_3'], - }); + const databases = TestDatabases.create(); const logger = getVoidLogger(); it.each(databases.eachSupportedId())( diff --git a/plugins/catalog-backend/src/tests/migrations.test.ts b/plugins/catalog-backend/src/tests/migrations.test.ts index aa305598aa..d961427f5e 100644 --- a/plugins/catalog-backend/src/tests/migrations.test.ts +++ b/plugins/catalog-backend/src/tests/migrations.test.ts @@ -42,9 +42,7 @@ async function migrateUntilBefore(knex: Knex, target: string): Promise { jest.setTimeout(60_000); describe('migrations', () => { - const databases = TestDatabases.create({ - ids: ['MYSQL_8', 'POSTGRES_13', 'POSTGRES_9', 'SQLITE_3'], - }); + const databases = TestDatabases.create(); it.each(databases.eachSupportedId())( 'latest version correctly cascades deletions, %p', diff --git a/plugins/catalog-backend/src/tests/performance/stitchingPerformance.test.ts b/plugins/catalog-backend/src/tests/performance/stitchingPerformance.test.ts index ad659ce845..e0d3f87124 100644 --- a/plugins/catalog-backend/src/tests/performance/stitchingPerformance.test.ts +++ b/plugins/catalog-backend/src/tests/performance/stitchingPerformance.test.ts @@ -155,7 +155,7 @@ class Tracker { describePerformanceTest('stitchingPerformance', () => { const databases = TestDatabases.create({ - ids: [/* 'MYSQL_8', */ 'POSTGRES_13', 'POSTGRES_9', 'SQLITE_3'], + ids: [/* 'MYSQL_8', */ 'POSTGRES_16', 'POSTGRES_12', 'SQLITE_3'], }); it.each(databases.eachSupportedId())( @@ -188,8 +188,8 @@ describePerformanceTest('stitchingPerformance', () => { factory: () => ({ getClient: async () => knex }), }), createBackendModule({ - moduleId: 'syntheticLoadEntities', pluginId: 'catalog', + moduleId: 'synthetic-load-entities', register(reg) { reg.registerInit({ deps: { @@ -245,8 +245,8 @@ describePerformanceTest('stitchingPerformance', () => { factory: () => ({ getClient: async () => knex }), }), createBackendModule({ - moduleId: 'syntheticLoadEntities', pluginId: 'catalog', + moduleId: 'synthetic-load-entities', register(reg) { reg.registerInit({ deps: { diff --git a/plugins/catalog-common/CHANGELOG.md b/plugins/catalog-common/CHANGELOG.md index 3dbde65433..9f2b511676 100644 --- a/plugins/catalog-common/CHANGELOG.md +++ b/plugins/catalog-common/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/plugin-catalog-common +## 1.0.20 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.12 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-search-common@1.2.10 + +## 1.0.19 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.11 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-search-common@1.2.9 + +## 1.0.18 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.10 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-search-common@1.2.8 + ## 1.0.17 ### Patch Changes diff --git a/plugins/catalog-common/alpha-api-report.md b/plugins/catalog-common/api-report-alpha.md similarity index 100% rename from plugins/catalog-common/alpha-api-report.md rename to plugins/catalog-common/api-report-alpha.md diff --git a/plugins/catalog-common/package.json b/plugins/catalog-common/package.json index 68ab60e7c3..9642746fd7 100644 --- a/plugins/catalog-common/package.json +++ b/plugins/catalog-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-common", "description": "Common functionalities for the catalog plugin", - "version": "1.0.17", + "version": "1.0.20", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-graph/CHANGELOG.md b/plugins/catalog-graph/CHANGELOG.md index d172e599aa..235e5c25fb 100644 --- a/plugins/catalog-graph/CHANGELOG.md +++ b/plugins/catalog-graph/CHANGELOG.md @@ -1,5 +1,145 @@ # @backstage/plugin-catalog-graph +## 0.3.3 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + +## 0.3.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.3.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + +## 0.3.3-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/types@1.1.1 + +## 0.3.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-client@1.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + +## 0.3.2-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## 0.3.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/types@1.1.1 + +## 0.3.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + +## 0.3.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + +## 0.3.0 + +### Minor Changes + +- a604623324: Add the entire `Entity` to `EntityNodeData` and deprecate `name`, `kind`, `title`, `namespace` and `spec`. + + To get the deprecated properties in your custom component you can use: + + ```typescript + import { DEFAULT_NAMESPACE } from '@backstage/catalog-model'; + + const { + kind, + metadata: { name, namespace = DEFAULT_NAMESPACE, title }, + } = entity; + ``` + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 62b5922916: Internal theme type updates +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + ## 0.2.38-next.2 ### Patch Changes diff --git a/plugins/catalog-graph/README.md b/plugins/catalog-graph/README.md index 010a129b0f..f00d11810f 100644 --- a/plugins/catalog-graph/README.md +++ b/plugins/catalog-graph/README.md @@ -90,7 +90,7 @@ To use the catalog graph plugin, you have to add some things to your Backstage a Copy the default implementation `DefaultRenderNode.tsx` and add more classes to the styles: ```typescript -const useStyles = makeStyles( +const useStyles = makeStyles( theme => ({ node: { … diff --git a/plugins/catalog-graph/package.json b/plugins/catalog-graph/package.json index ab45ef6ea2..a38f1a4480 100644 --- a/plugins/catalog-graph/package.json +++ b/plugins/catalog-graph/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-graph", - "version": "0.2.38-next.2", + "version": "0.3.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,7 +34,6 @@ "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", - "@backstage/theme": "workspace:^", "@backstage/types": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", diff --git a/plugins/catalog-graphql/CHANGELOG.md b/plugins/catalog-graphql/CHANGELOG.md deleted file mode 100644 index 0a8a24b828..0000000000 --- a/plugins/catalog-graphql/CHANGELOG.md +++ /dev/null @@ -1,701 +0,0 @@ -# @backstage/plugin-catalog-graphql - -## 0.4.1-next.0 - -### Patch Changes - -- 6c2b872153: Add official support for React 18. -- Updated dependencies - - @backstage/catalog-model@1.4.3 - - @backstage/config@1.1.1 - - @backstage/types@1.1.1 - -## 0.4.0 - -### Minor Changes - -- 9def1e95ab: This package has been deprecated, consider using [@frontside/backstage-plugin-graphql-backend](https://www.npmjs.com/package/@frontside/backstage-plugin-graphql-backend) instead. - -### Patch Changes - -- Updated dependencies - - @backstage/catalog-model@1.4.3 - - @backstage/config@1.1.1 - - @backstage/types@1.1.1 - -## 0.3.24-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/catalog-model@1.4.3-next.0 - - @backstage/config@1.1.1-next.0 - - @backstage/types@1.1.1 - -## 0.3.23 - -### Patch Changes - -- Updated dependencies - - @backstage/config@1.1.0 - - @backstage/catalog-model@1.4.2 - - @backstage/types@1.1.1 - -## 0.3.23-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/catalog-model@1.4.2-next.2 - - @backstage/config@1.1.0-next.2 - - @backstage/types@1.1.1-next.0 - -## 0.3.23-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/config@1.1.0-next.1 - - @backstage/catalog-model@1.4.2-next.1 - - @backstage/types@1.1.0 - -## 0.3.23-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/config@1.1.0-next.0 - - @backstage/catalog-model@1.4.2-next.0 - - @backstage/types@1.1.0 - -## 0.3.22 - -### Patch Changes - -- Updated dependencies - - @backstage/catalog-model@1.4.1 - - @backstage/config@1.0.8 - - @backstage/types@1.1.0 - -## 0.3.22-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/catalog-model@1.4.1-next.0 - - @backstage/config@1.0.8 - - @backstage/types@1.1.0 - -## 0.3.21 - -### Patch Changes - -- Updated dependencies - - @backstage/types@1.1.0 - - @backstage/catalog-model@1.4.0 - - @backstage/config@1.0.8 - -## 0.3.21-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/catalog-model@1.4.0-next.1 - - @backstage/config@1.0.7 - - @backstage/types@1.0.2 - -## 0.3.21-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/catalog-model@1.4.0-next.0 - - @backstage/config@1.0.7 - - @backstage/types@1.0.2 - -## 0.3.20 - -### Patch Changes - -- e47e69eadf0: Updated dependency `@apollo/server` to `^4.0.0`. -- e0c6e8b9c3c: Update peer dependencies -- Updated dependencies - - @backstage/catalog-model@1.3.0 - - @backstage/config@1.0.7 - - @backstage/types@1.0.2 - -## 0.3.20-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/catalog-model@1.3.0-next.0 - - @backstage/config@1.0.7 - - @backstage/types@1.0.2 - -## 0.3.20-next.1 - -### Patch Changes - -- e0c6e8b9c3c: Update peer dependencies -- Updated dependencies - - @backstage/catalog-model@1.2.1 - - @backstage/config@1.0.7 - - @backstage/types@1.0.2 - -## 0.3.20-next.0 - -### Patch Changes - -- e47e69eadf0: Updated dependency `@apollo/server` to `^4.0.0`. -- Updated dependencies - - @backstage/config@1.0.7 - - @backstage/catalog-model@1.2.1 - - @backstage/types@1.0.2 - -## 0.3.19 - -### Patch Changes - -- b990021ddeb: Updated dependency `@graphql-codegen/cli` to `^3.0.0`. - Updated dependency `@graphql-codegen/graphql-modules-preset` to `^3.0.0`. - Updated dependency `@graphql-codegen/typescript` to `^3.0.0`. - Updated dependency `@graphql-codegen/typescript-resolvers` to `^3.0.0`. -- 52b0022dab7: Updated dependency `msw` to `^1.0.0`. -- Updated dependencies - - @backstage/catalog-model@1.2.1 - - @backstage/config@1.0.7 - - @backstage/types@1.0.2 - -## 0.3.19-next.1 - -### Patch Changes - -- b990021ddeb: Updated dependency `@graphql-codegen/cli` to `^3.0.0`. - Updated dependency `@graphql-codegen/graphql-modules-preset` to `^3.0.0`. - Updated dependency `@graphql-codegen/typescript` to `^3.0.0`. - Updated dependency `@graphql-codegen/typescript-resolvers` to `^3.0.0`. -- 52b0022dab7: Updated dependency `msw` to `^1.0.0`. -- Updated dependencies - - @backstage/config@1.0.7-next.0 - - @backstage/catalog-model@1.2.1-next.1 - - @backstage/types@1.0.2 - -## 0.3.19-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/catalog-model@1.2.1-next.0 - - @backstage/config@1.0.6 - - @backstage/types@1.0.2 - -## 0.3.18 - -### Patch Changes - -- Updated dependencies - - @backstage/catalog-model@1.2.0 - - @backstage/config@1.0.6 - - @backstage/types@1.0.2 - -## 0.3.18-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/catalog-model@1.2.0-next.1 - - @backstage/config@1.0.6 - - @backstage/types@1.0.2 - -## 0.3.18-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/catalog-model@1.1.6-next.0 - -## 0.3.17 - -### Patch Changes - -- Updated dependencies - - @backstage/catalog-model@1.1.5 - - @backstage/config@1.0.6 - - @backstage/types@1.0.2 - -## 0.3.17-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/config@1.0.6-next.0 - - @backstage/catalog-model@1.1.5-next.1 - - @backstage/types@1.0.2 - -## 0.3.17-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/catalog-model@1.1.5-next.0 - - @backstage/config@1.0.5 - - @backstage/types@1.0.2 - -## 0.3.16 - -### Patch Changes - -- 3280711113: Updated dependency `msw` to `^0.49.0`. -- Updated dependencies - - @backstage/types@1.0.2 - - @backstage/catalog-model@1.1.4 - - @backstage/config@1.0.5 - -## 0.3.16-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/types@1.0.2-next.1 - - @backstage/config@1.0.5-next.1 - - @backstage/catalog-model@1.1.4-next.1 - -## 0.3.16-next.0 - -### Patch Changes - -- 3280711113: Updated dependency `msw` to `^0.49.0`. -- Updated dependencies - - @backstage/types@1.0.2-next.0 - - @backstage/catalog-model@1.1.4-next.0 - - @backstage/config@1.0.5-next.0 - -## 0.3.15 - -### Patch Changes - -- Updated dependencies - - @backstage/catalog-model@1.1.3 - - @backstage/types@1.0.1 - - @backstage/config@1.0.4 - -## 0.3.15-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/catalog-model@1.1.3-next.0 - - @backstage/types@1.0.1-next.0 - - @backstage/config@1.0.4-next.0 - -## 0.3.14 - -### Patch Changes - -- Updated dependencies - - @backstage/catalog-model@1.1.2 - - @backstage/config@1.0.3 - - @backstage/types@1.0.0 - -## 0.3.14-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/catalog-model@1.1.2-next.2 - - @backstage/config@1.0.3-next.2 - - @backstage/types@1.0.0 - -## 0.3.14-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/catalog-model@1.1.2-next.1 - - @backstage/config@1.0.3-next.1 - - @backstage/types@1.0.0 - -## 0.3.14-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/catalog-model@1.1.2-next.0 - - @backstage/config@1.0.3-next.0 - - @backstage/types@1.0.0 - -## 0.3.13 - -### Patch Changes - -- d669d89206: Minor API signatures cleanup -- 667d917488: Updated dependency `msw` to `^0.47.0`. -- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. -- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. -- Updated dependencies - - @backstage/catalog-model@1.1.1 - - @backstage/config@1.0.2 - -## 0.3.13-next.3 - -### Patch Changes - -- Updated dependencies - - @backstage/catalog-model@1.1.1-next.0 - - @backstage/config@1.0.2-next.0 - -## 0.3.13-next.2 - -### Patch Changes - -- 667d917488: Updated dependency `msw` to `^0.47.0`. -- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. - -## 0.3.13-next.1 - -### Patch Changes - -- d669d89206: Minor API signatures cleanup - -## 0.3.13-next.0 - -### Patch Changes - -- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. - -## 0.3.12 - -### Patch Changes - -- fa3eeee92d: Updated dependency `@graphql-tools/schema` to `^9.0.0`. - -## 0.3.11 - -### Patch Changes - -- a70869e775: Updated dependency `msw` to `^0.43.0`. -- 8006d0f9bf: Updated dependency `msw` to `^0.44.0`. -- Updated dependencies - - @backstage/catalog-model@1.1.0 - -## 0.3.11-next.1 - -### Patch Changes - -- a70869e775: Updated dependency `msw` to `^0.43.0`. -- Updated dependencies - - @backstage/catalog-model@1.1.0-next.3 - -## 0.3.11-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/catalog-model@1.1.0-next.0 - -## 0.3.10 - -### Patch Changes - -- 8f7b1835df: Updated dependency `msw` to `^0.41.0`. -- Updated dependencies - - @backstage/catalog-model@1.0.3 - -## 0.3.10-next.0 - -### Patch Changes - -- 8f7b1835df: Updated dependency `msw` to `^0.41.0`. -- Updated dependencies - - @backstage/catalog-model@1.0.3-next.0 - -## 0.3.9 - -### Patch Changes - -- Updated dependencies - - @backstage/config@1.0.1 - - @backstage/catalog-model@1.0.2 - -## 0.3.9-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/config@1.0.1-next.0 - - @backstage/catalog-model@1.0.2-next.0 - -## 0.3.8 - -### Patch Changes - -- Updated dependencies - - @backstage/catalog-model@1.0.1 - -## 0.3.8-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/catalog-model@1.0.1-next.0 - -## 0.3.7 - -### Patch Changes - -- 02ad19d189: Do not use `metadata.generation` from entity data -- Updated dependencies - - @backstage/catalog-model@1.0.0 - - @backstage/config@1.0.0 - - @backstage/types@1.0.0 - -## 0.3.6 - -### Patch Changes - -- Updated dependencies - - @backstage/catalog-model@0.13.0 - -## 0.3.6-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/catalog-model@0.13.0-next.0 - -## 0.3.5 - -### Patch Changes - -- Updated dependencies - - @backstage/catalog-model@0.12.0 - -## 0.3.4 - -### Patch Changes - -- 68913af4ff: chore(deps): bump `graphql-modules` from 1.4.4 to 2.0.0 -- Updated dependencies - - @backstage/catalog-model@0.11.0 - -## 0.3.3 - -### Patch Changes - -- Fix for the previous release with missing type declarations. -- Updated dependencies - - @backstage/catalog-model@0.10.1 - - @backstage/config@0.1.15 - - @backstage/types@0.1.3 - -## 0.3.2 - -### Patch Changes - -- 1ed305728b: Bump `node-fetch` to version 2.6.7 and `cross-fetch` to version 3.1.5 -- c77c5c7eb6: Added `backstage.role` to `package.json` -- Updated dependencies - - @backstage/catalog-model@0.10.0 - - @backstage/config@0.1.14 - - @backstage/types@0.1.2 - -## 0.3.1 - -### Patch Changes - -- Updated dependencies - - @backstage/config@0.1.13 - - @backstage/catalog-model@0.9.10 - -## 0.3.1-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/config@0.1.13-next.0 - - @backstage/catalog-model@0.9.10-next.0 - -## 0.3.0 - -### Minor Changes - -- 0fb17da164: chore: bumping dependencies in the GraphQL modules and bringing them up to date with the latest `graphql-modules` library - -### Patch Changes - -- cf01627a33: Bump graphql versions -- Updated dependencies - - @backstage/config@0.1.12 - - @backstage/catalog-model@0.9.9 - -## 0.2.14 - -### Patch Changes - -- 6b500622d5: Move to using node-fetch internally instead of cross-fetch - -## 0.2.13 - -### Patch Changes - -- 10615525f3: Switch to use the json and observable types from `@backstage/types` -- Updated dependencies - - @backstage/config@0.1.11 - - @backstage/catalog-model@0.9.6 - -## 0.2.12 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.9.0 - - @backstage/config@0.1.8 - -## 0.2.11 - -### Patch Changes - -- Updated dependencies - - @backstage/catalog-model@0.9.0 - - @backstage/backend-common@0.8.5 - -## 0.2.10 - -### Patch Changes - -- Updated dependencies [add62a455] -- Updated dependencies [704875e26] - - @backstage/catalog-model@0.8.0 - -## 0.2.9 - -### Patch Changes - -- 3be844496: chore: bump `ts-node` versions to 9.1.1 -- Updated dependencies [22fd8ce2a] -- Updated dependencies [10c008a3a] -- Updated dependencies [f9fb4a205] -- Updated dependencies [16be1d093] - - @backstage/backend-common@0.8.0 - - @backstage/catalog-model@0.7.9 - -## 0.2.8 - -### Patch Changes - -- Updated dependencies [e0bfd3d44] -- Updated dependencies [38ca05168] -- Updated dependencies [d8b81fd28] - - @backstage/backend-common@0.7.0 - - @backstage/catalog-model@0.7.8 - - @backstage/config@0.1.5 - -## 0.2.7 - -### Patch Changes - -- Updated dependencies [8686eb38c] -- Updated dependencies [0434853a5] -- Updated dependencies [8686eb38c] - - @backstage/backend-common@0.6.0 - - @backstage/config@0.1.4 - -## 0.2.6 - -### Patch Changes - -- Updated dependencies [def2307f3] -- Updated dependencies [0b135e7e0] -- Updated dependencies [294a70cab] -- Updated dependencies [0ea032763] -- Updated dependencies [5345a1f98] -- Updated dependencies [09a370426] -- Updated dependencies [a93f42213] - - @backstage/catalog-model@0.7.0 - - @backstage/backend-common@0.5.0 - -## 0.2.5 - -### Patch Changes - -- Updated dependencies [c911061b7] -- Updated dependencies [1d1c2860f] -- Updated dependencies [0e6298f7e] -- Updated dependencies [4eafdec4a] -- Updated dependencies [ac3560b42] - - @backstage/catalog-model@0.6.0 - - @backstage/backend-common@0.4.1 - -## 0.2.4 - -### Patch Changes - -- Updated dependencies [38e24db00] -- Updated dependencies [e3bd9fc2f] -- Updated dependencies [12bbd748c] -- Updated dependencies [83b6e0c1f] -- Updated dependencies [e3bd9fc2f] - - @backstage/backend-common@0.4.0 - - @backstage/config@0.1.2 - - @backstage/catalog-model@0.5.0 - -## 0.2.3 - -### Patch Changes - -- Updated dependencies [612368274] -- Updated dependencies [08835a61d] -- Updated dependencies [a9fd599f7] -- Updated dependencies [bcc211a08] - - @backstage/backend-common@0.3.3 - - @backstage/catalog-model@0.4.0 - -## 0.2.2 - -### Patch Changes - -- Updated dependencies [1166fcc36] -- Updated dependencies [bff3305aa] -- Updated dependencies [1185919f3] -- Updated dependencies [b47dce06f] - - @backstage/catalog-model@0.3.0 - - @backstage/backend-common@0.3.1 - -## 0.2.1 - -### Patch Changes - -- Updated dependencies [1722cb53c] -- Updated dependencies [1722cb53c] -- Updated dependencies [7b37e6834] -- Updated dependencies [8e2effb53] - - @backstage/backend-common@0.3.0 - -## 0.2.0 - -### Minor Changes - -- 28edd7d29: Create backend plugin through CLI - -### Patch Changes - -- Updated dependencies [3a4236570] -- Updated dependencies [e0be86b6f] -- Updated dependencies [f70a52868] -- Updated dependencies [12b5fe940] -- Updated dependencies [5249594c5] -- Updated dependencies [56e4eb589] -- Updated dependencies [e37c0a005] -- Updated dependencies [a768a07fb] -- Updated dependencies [f00ca3cb8] -- Updated dependencies [6579769df] -- Updated dependencies [5adfc005e] -- Updated dependencies [8c2b76e45] -- Updated dependencies [440a17b39] -- Updated dependencies [fa56f4615] -- Updated dependencies [8afce088a] -- Updated dependencies [b3d57961c] -- Updated dependencies [7bbeb049f] - - @backstage/catalog-model@0.2.0 - - @backstage/backend-common@0.2.0 diff --git a/plugins/catalog-graphql/README.md b/plugins/catalog-graphql/README.md deleted file mode 100644 index 021d0d1b20..0000000000 --- a/plugins/catalog-graphql/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Catalog GraphQL Plugin - -This package has been deprecated, consider using [@frontside/backstage-plugin-graphql-backend](https://www.npmjs.com/package/@frontside/backstage-plugin-graphql-backend) instead. diff --git a/plugins/catalog-graphql/api-report.md b/plugins/catalog-graphql/api-report.md deleted file mode 100644 index f03ed94af5..0000000000 --- a/plugins/catalog-graphql/api-report.md +++ /dev/null @@ -1,20 +0,0 @@ -## API Report File for "@backstage/plugin-catalog-graphql" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts -import { Config } from '@backstage/config'; -import { Logger } from 'winston'; -import { Module } from 'graphql-modules'; - -// @public (undocumented) -export function createModule(options: ModuleOptions): Promise; - -// @public (undocumented) -export interface ModuleOptions { - // (undocumented) - config: Config; - // (undocumented) - logger: Logger; -} -``` diff --git a/plugins/catalog-graphql/catalog-info.yaml b/plugins/catalog-graphql/catalog-info.yaml deleted file mode 100644 index 202acc8c95..0000000000 --- a/plugins/catalog-graphql/catalog-info.yaml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: backstage.io/v1alpha1 -kind: Component -metadata: - name: backstage-plugin-catalog-graphql - title: '@backstage/plugin-catalog-graphql' - description: An experimental Backstage catalog GraphQL module -spec: - lifecycle: experimental - type: backstage-backend-plugin - owner: catalog-maintainers diff --git a/plugins/catalog-graphql/codegen.yml b/plugins/catalog-graphql/codegen.yml deleted file mode 100644 index d71c9a7017..0000000000 --- a/plugins/catalog-graphql/codegen.yml +++ /dev/null @@ -1,14 +0,0 @@ -overwrite: true -generates: - ./src/graphql/types.ts: - schema: ./src/schema.js - plugins: - - typescript - - typescript-resolvers - hooks: - afterOneFileWrite: - - eslint --fix - config: - allowParentTypeOverride: true - useIndexSignature: true - defaultMapper: Partial<{T}> diff --git a/plugins/catalog-graphql/package.json b/plugins/catalog-graphql/package.json deleted file mode 100644 index de493b16f4..0000000000 --- a/plugins/catalog-graphql/package.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "name": "@backstage/plugin-catalog-graphql", - "description": "Deprecated, consider using @frontside/backstage-plugin-graphql-backend instead", - "version": "0.4.1-next.0", - "main": "src/index.ts", - "types": "src/index.ts", - "license": "Apache-2.0", - "publishConfig": { - "access": "public", - "main": "dist/index.cjs.js", - "types": "dist/index.d.ts" - }, - "backstage": { - "role": "backend-plugin" - }, - "homepage": "https://backstage.io", - "repository": { - "type": "git", - "url": "https://github.com/backstage/backstage", - "directory": "plugins/catalog-graphql" - }, - "keywords": [ - "backstage", - "graphql" - ], - "scripts": { - "start": "backstage-cli package start", - "build": "backstage-cli package build", - "lint": "backstage-cli package lint", - "test": "backstage-cli package test", - "prepack": "backstage-cli package prepack", - "postpack": "backstage-cli package postpack", - "generate:types": "graphql-codegen", - "clean": "backstage-cli package clean" - }, - "dependencies": { - "@apollo/client": "^3.0.0", - "@apollo/server": "^4.0.0", - "@backstage/catalog-model": "workspace:^", - "@backstage/config": "workspace:^", - "@backstage/types": "workspace:^", - "graphql": "^16.0.0", - "graphql-modules": "^2.0.0", - "graphql-tag": "^2.11.0", - "graphql-type-json": "^0.3.2", - "node-fetch": "^2.6.7", - "winston": "^3.2.1" - }, - "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/cli": "workspace:^", - "@backstage/test-utils": "workspace:^", - "@graphql-codegen/cli": "^3.0.0", - "@graphql-codegen/graphql-modules-preset": "^3.0.0", - "@graphql-codegen/typescript": "^3.0.0", - "@graphql-codegen/typescript-resolvers": "^3.0.0", - "@graphql-tools/schema": "^9.0.0", - "@types/react": "^16.13.1 || ^17.0.0", - "msw": "^1.0.0" - }, - "files": [ - "dist" - ] -} diff --git a/plugins/catalog-graphql/src/graphql/module.test.ts b/plugins/catalog-graphql/src/graphql/module.test.ts deleted file mode 100644 index d4589a2625..0000000000 --- a/plugins/catalog-graphql/src/graphql/module.test.ts +++ /dev/null @@ -1,314 +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 { createModule } from './module'; -import { makeExecutableSchema } from '@graphql-tools/schema'; -import { rest } from 'msw'; -import { setupServer } from 'msw/node'; -import { ConfigReader } from '@backstage/config'; -import { ReaderEntity } from '../service/client'; -import { createLogger } from 'winston'; -import { setupRequestMockHandlers } from '@backstage/test-utils'; -import { gql } from '@apollo/client'; -import { Module, createApplication, testkit } from 'graphql-modules'; - -describe('Catalog Module', () => { - const worker = setupServer(); - const mockCatalogBaseUrl = 'http://im.mock'; - const mockConfig = new ConfigReader({ - backend: { - baseUrl: mockCatalogBaseUrl, - }, - }); - - const createMockApplication = (module: Module) => { - const application = createApplication({ - modules: [module], - schemaBuilder(input) { - return makeExecutableSchema({ - ...input, - inheritResolversFromInterfaces: true, - }); - }, - }); - - return application; - }; - - setupRequestMockHandlers(worker); - - describe('Default Entity', () => { - beforeEach(() => { - const mockResponse: ReaderEntity[] = [ - { - apiVersion: 'something', - kind: 'Component', - metadata: { - annotations: {}, - etag: '123', - labels: {}, - name: 'Ben', - namespace: 'Blames', - uid: '123', - }, - spec: { - type: 'thing', - lifecycle: 'something', - owner: 'auser', - }, - }, - ]; - - worker.use( - rest.get(`${mockCatalogBaseUrl}/api/catalog/entities`, (_, res, ctx) => - res(ctx.status(200), ctx.json(mockResponse)), - ), - ); - }); - - it('should call the catalog client when requesting entities', async () => { - const app = createMockApplication( - await createModule({ - config: mockConfig, - logger: createLogger(), - }), - ); - - const result = await testkit.execute(app, { - document: gql` - query { - catalog { - list { - kind - apiVersion - metadata { - name - } - } - } - } - `, - }); - - const [catalogItem] = result.data?.catalog.list; - expect(catalogItem.kind).toBe('Component'); - expect(catalogItem.apiVersion).toBe('something'); - expect(catalogItem.metadata.name).toBe('Ben'); - }); - - it('Defaults to empty annotations when none are provided', async () => { - const mockResponse: ReaderEntity[] = [ - { - apiVersion: 'something', - kind: 'Component', - metadata: { - annotations: null as any, - etag: '123', - labels: {}, - name: 'Ben', - namespace: 'Blames', - uid: '123', - }, - spec: { - type: 'thing', - lifecycle: 'something', - owner: 'auser', - }, - }, - ]; - worker.use( - rest.get(`${mockCatalogBaseUrl}/api/catalog/entities`, (_, res, ctx) => - res(ctx.status(200), ctx.json(mockResponse)), - ), - ); - - const app = createMockApplication( - await createModule({ - config: mockConfig, - logger: createLogger(), - }), - ); - - const result = await testkit.execute(app, { - document: gql` - query { - catalog { - list { - metadata { - annotations - } - } - } - } - `, - }); - - const [catalogItem] = result.data?.catalog.list; - expect(catalogItem.metadata.annotations).toEqual({}); - }); - - it('Defaults to empty labels when none are provided', async () => { - const mockResponse: ReaderEntity[] = [ - { - apiVersion: 'something', - kind: 'Component', - metadata: { - annotations: {}, - etag: '123', - labels: null as any, - name: 'Ben', - namespace: 'Blames', - uid: '123', - }, - spec: { - type: 'thing', - lifecycle: 'something', - owner: 'auser', - }, - }, - ]; - worker.use( - rest.get(`${mockCatalogBaseUrl}/api/catalog/entities`, (_, res, ctx) => - res(ctx.status(200), ctx.json(mockResponse)), - ), - ); - - const app = createMockApplication( - await createModule({ - config: mockConfig, - logger: createLogger(), - }), - ); - - const result = await testkit.execute(app, { - document: gql` - query { - catalog { - list { - metadata { - labels - } - } - } - } - `, - }); - - const [catalogItem] = result.data?.catalog.list; - expect(catalogItem.metadata.labels).toEqual({}); - }); - it('Returns the correct record from the annotation dictionary', async () => { - const mockResponse: ReaderEntity[] = [ - { - apiVersion: 'something', - kind: 'Component', - metadata: { - annotations: { lob: 'bloben' }, - etag: '123', - labels: {}, - name: 'Ben', - namespace: 'Blames', - uid: '123', - }, - spec: { - type: 'thing', - lifecycle: 'something', - owner: 'auser', - }, - }, - ]; - worker.use( - rest.get(`${mockCatalogBaseUrl}/api/catalog/entities`, (_, res, ctx) => - res(ctx.status(200), ctx.json(mockResponse)), - ), - ); - - const app = createMockApplication( - await createModule({ - config: mockConfig, - logger: createLogger(), - }), - ); - - const result = await testkit.execute(app, { - document: gql` - query { - catalog { - list { - metadata { - test: annotation(name: "lob") - } - } - } - } - `, - }); - - const [catalogItem] = result.data?.catalog.list; - expect(catalogItem.metadata.test).toEqual('bloben'); - }); - it('Returns the correct record from the labels dictionary', async () => { - const mockResponse: ReaderEntity[] = [ - { - apiVersion: 'something', - kind: 'Component', - metadata: { - annotations: {}, - etag: '123', - labels: { lob2: 'bloben' }, - name: 'Ben', - namespace: 'Blames', - uid: '123', - }, - spec: { - type: 'thing', - lifecycle: 'something', - owner: 'auser', - }, - }, - ]; - worker.use( - rest.get(`${mockCatalogBaseUrl}/api/catalog/entities`, (_, res, ctx) => - res(ctx.status(200), ctx.json(mockResponse)), - ), - ); - - const app = createMockApplication( - await createModule({ - config: mockConfig, - logger: createLogger(), - }), - ); - - const result = await testkit.execute(app, { - document: gql` - query { - catalog { - list { - metadata { - test: label(name: "lob2") - } - } - } - } - `, - }); - - const [catalogItem] = result.data?.catalog.list; - expect(catalogItem.metadata.test).toEqual('bloben'); - }); - }); -}); diff --git a/plugins/catalog-graphql/src/graphql/module.ts b/plugins/catalog-graphql/src/graphql/module.ts deleted file mode 100644 index e27adbbaf1..0000000000 --- a/plugins/catalog-graphql/src/graphql/module.ts +++ /dev/null @@ -1,106 +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 { Logger } from 'winston'; -import { - createModule as createGraphQLModule, - Module, - gql, -} from 'graphql-modules'; -import { Resolvers, CatalogQuery } from './types'; -import { Config } from '@backstage/config'; -import { CatalogClient } from '../service/client'; -import GraphQLJSON, { GraphQLJSONObject } from 'graphql-type-json'; -import { Entity } from '@backstage/catalog-model'; -import typeDefs from '../schema'; - -/** @public */ -export interface ModuleOptions { - logger: Logger; - config: Config; -} - -/** @public */ -export async function createModule(options: ModuleOptions): Promise { - const catalogClient = new CatalogClient( - options.config.getString('backend.baseUrl'), - ); - - const resolvers: Resolvers = { - JSON: GraphQLJSON, - JSONObject: GraphQLJSONObject, - DefaultEntitySpec: { - raw: rootValue => { - const { entity } = rootValue as { entity: Entity }; - return entity.spec ?? null; - }, - }, - Query: { - catalog: () => ({} as CatalogQuery), - }, - CatalogQuery: { - list: async () => { - return await catalogClient.list(); - }, - }, - CatalogEntity: { - metadata: entity => ({ ...entity.metadata!, entity }), - spec: entity => ({ ...entity.spec!, entity }), - }, - EntityMetadata: { - __resolveType: rootValue => { - const { - entity: { kind }, - } = rootValue as { entity: Entity }; - - switch (kind) { - case 'Component': - return 'ComponentMetadata'; - case 'Template': - return 'TemplateMetadata'; - default: - return 'DefaultEntityMetadata'; - } - }, - annotation: (e, { name }) => e.annotations?.[name] ?? null, - labels: e => e.labels ?? {}, - annotations: e => e.annotations ?? {}, - label: (e, { name }) => e.labels?.[name] ?? null, - }, - EntitySpec: { - __resolveType: rootValue => { - const { - entity: { kind }, - } = rootValue as { entity: Entity }; - - switch (kind) { - case 'Component': - return 'ComponentEntitySpec'; - case 'Template': - return 'TemplateEntitySpec'; - default: - return 'DefaultEntitySpec'; - } - }, - }, - }; - - return createGraphQLModule({ - id: 'plugin-catalog-graphql', - typeDefs: gql(typeDefs), - resolvers, - }); -} diff --git a/plugins/catalog-graphql/src/graphql/types.ts b/plugins/catalog-graphql/src/graphql/types.ts deleted file mode 100644 index aecf2a1cd1..0000000000 --- a/plugins/catalog-graphql/src/graphql/types.ts +++ /dev/null @@ -1,544 +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 { - GraphQLResolveInfo, - GraphQLScalarType, - GraphQLScalarTypeConfig, -} from 'graphql'; - -export type Maybe = T | null; -export type InputMaybe = Maybe; -export type Exact = { - [K in keyof T]: T[K]; -}; -export type MakeOptional = Omit & { - [SubKey in K]?: Maybe; -}; -export type MakeMaybe = Omit & { - [SubKey in K]: Maybe; -}; -export type Omit = Pick>; -export type RequireFields = { - [X in Exclude]?: T[X]; -} & { [P in K]-?: NonNullable }; -/** All built-in and custom scalars, mapped to their actual values */ -export type Scalars = { - ID: string; - String: string; - Boolean: boolean; - Int: number; - Float: number; - JSON: any; - JSONObject: any; -}; - -export type CatalogEntity = { - __typename?: 'CatalogEntity'; - apiVersion: Scalars['String']; - kind: Scalars['String']; - metadata?: Maybe; - spec: EntitySpec; -}; - -export type CatalogQuery = { - __typename?: 'CatalogQuery'; - list: Array; -}; - -export type ComponentEntitySpec = { - __typename?: 'ComponentEntitySpec'; - lifecycle: Scalars['String']; - owner: Scalars['String']; - type: Scalars['String']; -}; - -export type ComponentMetadata = EntityMetadata & { - __typename?: 'ComponentMetadata'; - annotation?: Maybe; - annotations: Scalars['JSONObject']; - etag: Scalars['String']; - label?: Maybe; - labels: Scalars['JSONObject']; - name: Scalars['String']; - relationships?: Maybe; - uid: Scalars['String']; -}; - -export type ComponentMetadataAnnotationArgs = { - name: Scalars['String']; -}; - -export type ComponentMetadataLabelArgs = { - name: Scalars['String']; -}; - -export type DefaultEntityMetadata = EntityMetadata & { - __typename?: 'DefaultEntityMetadata'; - annotation?: Maybe; - annotations: Scalars['JSONObject']; - etag: Scalars['String']; - label?: Maybe; - labels: Scalars['JSONObject']; - name: Scalars['String']; - uid: Scalars['String']; -}; - -export type DefaultEntityMetadataAnnotationArgs = { - name: Scalars['String']; -}; - -export type DefaultEntityMetadataLabelArgs = { - name: Scalars['String']; -}; - -export type DefaultEntitySpec = { - __typename?: 'DefaultEntitySpec'; - raw?: Maybe; -}; - -export type EntityMetadata = { - annotation?: Maybe; - annotations: Scalars['JSONObject']; - etag: Scalars['String']; - label?: Maybe; - labels: Scalars['JSONObject']; - name: Scalars['String']; - uid: Scalars['String']; -}; - -export type EntityMetadataAnnotationArgs = { - name: Scalars['String']; -}; - -export type EntityMetadataLabelArgs = { - name: Scalars['String']; -}; - -export type EntitySpec = - | ComponentEntitySpec - | DefaultEntitySpec - | TemplateEntitySpec; - -export type Query = { - __typename?: 'Query'; - catalog: CatalogQuery; -}; - -export type TemplateEntitySpec = { - __typename?: 'TemplateEntitySpec'; - path?: Maybe; - schema: Scalars['JSONObject']; - templater: Scalars['String']; - type: Scalars['String']; -}; - -export type TemplateMetadata = EntityMetadata & { - __typename?: 'TemplateMetadata'; - annotation?: Maybe; - annotations: Scalars['JSONObject']; - etag: Scalars['String']; - label?: Maybe; - labels: Scalars['JSONObject']; - name: Scalars['String']; - uid: Scalars['String']; - updatedBy?: Maybe; -}; - -export type TemplateMetadataAnnotationArgs = { - name: Scalars['String']; -}; - -export type TemplateMetadataLabelArgs = { - name: Scalars['String']; -}; - -export type WithIndex = TObject & Record; -export type ResolversObject = WithIndex; - -export type ResolverTypeWrapper = Promise | T; - -export type ResolverWithResolve = { - resolve: ResolverFn; -}; -export type Resolver = - | ResolverFn - | ResolverWithResolve; - -export type ResolverFn = ( - parent: TParent, - args: TArgs, - context: TContext, - info: GraphQLResolveInfo, -) => Promise | TResult; - -export type SubscriptionSubscribeFn = ( - parent: TParent, - args: TArgs, - context: TContext, - info: GraphQLResolveInfo, -) => AsyncIterable | Promise>; - -export type SubscriptionResolveFn = ( - parent: TParent, - args: TArgs, - context: TContext, - info: GraphQLResolveInfo, -) => TResult | Promise; - -export interface SubscriptionSubscriberObject< - TResult, - TKey extends string, - TParent, - TContext, - TArgs, -> { - subscribe: SubscriptionSubscribeFn< - { [key in TKey]: TResult }, - TParent, - TContext, - TArgs - >; - resolve?: SubscriptionResolveFn< - TResult, - { [key in TKey]: TResult }, - TContext, - TArgs - >; -} - -export interface SubscriptionResolverObject { - subscribe: SubscriptionSubscribeFn; - resolve: SubscriptionResolveFn; -} - -export type SubscriptionObject< - TResult, - TKey extends string, - TParent, - TContext, - TArgs, -> = - | SubscriptionSubscriberObject - | SubscriptionResolverObject; - -export type SubscriptionResolver< - TResult, - TKey extends string, - TParent = {}, - TContext = {}, - TArgs = {}, -> = - | (( - ...args: any[] - ) => SubscriptionObject) - | SubscriptionObject; - -export type TypeResolveFn = ( - parent: TParent, - context: TContext, - info: GraphQLResolveInfo, -) => Maybe | Promise>; - -export type IsTypeOfResolverFn = ( - obj: T, - context: TContext, - info: GraphQLResolveInfo, -) => boolean | Promise; - -export type NextResolverFn = () => Promise; - -export type DirectiveResolverFn< - TResult = {}, - TParent = {}, - TContext = {}, - TArgs = {}, -> = ( - next: NextResolverFn, - parent: TParent, - args: TArgs, - context: TContext, - info: GraphQLResolveInfo, -) => TResult | Promise; - -/** Mapping between all available schema types and the resolvers types */ -export type ResolversTypes = ResolversObject<{ - Boolean: ResolverTypeWrapper>; - CatalogEntity: ResolverTypeWrapper< - Partial< - Omit & { spec: ResolversTypes['EntitySpec'] } - > - >; - CatalogQuery: ResolverTypeWrapper>; - ComponentEntitySpec: ResolverTypeWrapper>; - ComponentMetadata: ResolverTypeWrapper>; - DefaultEntityMetadata: ResolverTypeWrapper>; - DefaultEntitySpec: ResolverTypeWrapper>; - EntityMetadata: - | ResolversTypes['ComponentMetadata'] - | ResolversTypes['DefaultEntityMetadata'] - | ResolversTypes['TemplateMetadata']; - EntitySpec: Partial< - | ResolversTypes['ComponentEntitySpec'] - | ResolversTypes['DefaultEntitySpec'] - | ResolversTypes['TemplateEntitySpec'] - >; - Int: ResolverTypeWrapper>; - JSON: ResolverTypeWrapper>; - JSONObject: ResolverTypeWrapper>; - Query: ResolverTypeWrapper<{}>; - String: ResolverTypeWrapper>; - TemplateEntitySpec: ResolverTypeWrapper>; - TemplateMetadata: ResolverTypeWrapper>; -}>; - -/** Mapping between all available schema types and the resolvers parents */ -export type ResolversParentTypes = ResolversObject<{ - Boolean: Partial; - CatalogEntity: Partial< - Omit & { spec: ResolversParentTypes['EntitySpec'] } - >; - CatalogQuery: Partial; - ComponentEntitySpec: Partial; - ComponentMetadata: Partial; - DefaultEntityMetadata: Partial; - DefaultEntitySpec: Partial; - EntityMetadata: - | ResolversParentTypes['ComponentMetadata'] - | ResolversParentTypes['DefaultEntityMetadata'] - | ResolversParentTypes['TemplateMetadata']; - EntitySpec: Partial< - | ResolversParentTypes['ComponentEntitySpec'] - | ResolversParentTypes['DefaultEntitySpec'] - | ResolversParentTypes['TemplateEntitySpec'] - >; - Int: Partial; - JSON: Partial; - JSONObject: Partial; - Query: {}; - String: Partial; - TemplateEntitySpec: Partial; - TemplateMetadata: Partial; -}>; - -export type CatalogEntityResolvers< - ContextType = any, - ParentType = ResolversParentTypes['CatalogEntity'], -> = ResolversObject<{ - apiVersion?: Resolver; - kind?: Resolver; - metadata?: Resolver< - Maybe, - ParentType, - ContextType - >; - spec?: Resolver; - __isTypeOf?: IsTypeOfResolverFn; -}>; - -export type CatalogQueryResolvers< - ContextType = any, - ParentType = ResolversParentTypes['CatalogQuery'], -> = ResolversObject<{ - list?: Resolver< - Array, - ParentType, - ContextType - >; - __isTypeOf?: IsTypeOfResolverFn; -}>; - -export type ComponentEntitySpecResolvers< - ContextType = any, - ParentType = ResolversParentTypes['ComponentEntitySpec'], -> = ResolversObject<{ - lifecycle?: Resolver; - owner?: Resolver; - type?: Resolver; - __isTypeOf?: IsTypeOfResolverFn; -}>; - -export type ComponentMetadataResolvers< - ContextType = any, - ParentType = ResolversParentTypes['ComponentMetadata'], -> = ResolversObject<{ - annotation?: Resolver< - Maybe, - ParentType, - ContextType, - RequireFields - >; - annotations?: Resolver; - etag?: Resolver; - label?: Resolver< - Maybe, - ParentType, - ContextType, - RequireFields - >; - labels?: Resolver; - name?: Resolver; - relationships?: Resolver< - Maybe, - ParentType, - ContextType - >; - uid?: Resolver; - __isTypeOf?: IsTypeOfResolverFn; -}>; - -export type DefaultEntityMetadataResolvers< - ContextType = any, - ParentType = ResolversParentTypes['DefaultEntityMetadata'], -> = ResolversObject<{ - annotation?: Resolver< - Maybe, - ParentType, - ContextType, - RequireFields - >; - annotations?: Resolver; - etag?: Resolver; - label?: Resolver< - Maybe, - ParentType, - ContextType, - RequireFields - >; - labels?: Resolver; - name?: Resolver; - uid?: Resolver; - __isTypeOf?: IsTypeOfResolverFn; -}>; - -export type DefaultEntitySpecResolvers< - ContextType = any, - ParentType = ResolversParentTypes['DefaultEntitySpec'], -> = ResolversObject<{ - raw?: Resolver, ParentType, ContextType>; - __isTypeOf?: IsTypeOfResolverFn; -}>; - -export type EntityMetadataResolvers< - ContextType = any, - ParentType = ResolversParentTypes['EntityMetadata'], -> = ResolversObject<{ - __resolveType: TypeResolveFn< - 'ComponentMetadata' | 'DefaultEntityMetadata' | 'TemplateMetadata', - ParentType, - ContextType - >; - annotation?: Resolver< - Maybe, - ParentType, - ContextType, - RequireFields - >; - annotations?: Resolver; - etag?: Resolver; - label?: Resolver< - Maybe, - ParentType, - ContextType, - RequireFields - >; - labels?: Resolver; - name?: Resolver; - uid?: Resolver; -}>; - -export type EntitySpecResolvers< - ContextType = any, - ParentType = ResolversParentTypes['EntitySpec'], -> = ResolversObject<{ - __resolveType: TypeResolveFn< - 'ComponentEntitySpec' | 'DefaultEntitySpec' | 'TemplateEntitySpec', - ParentType, - ContextType - >; -}>; - -export interface JsonScalarConfig - extends GraphQLScalarTypeConfig { - name: 'JSON'; -} - -export interface JsonObjectScalarConfig - extends GraphQLScalarTypeConfig { - name: 'JSONObject'; -} - -export type QueryResolvers< - ContextType = any, - ParentType = ResolversParentTypes['Query'], -> = ResolversObject<{ - catalog?: Resolver; -}>; - -export type TemplateEntitySpecResolvers< - ContextType = any, - ParentType = ResolversParentTypes['TemplateEntitySpec'], -> = ResolversObject<{ - path?: Resolver, ParentType, ContextType>; - schema?: Resolver; - templater?: Resolver; - type?: Resolver; - __isTypeOf?: IsTypeOfResolverFn; -}>; - -export type TemplateMetadataResolvers< - ContextType = any, - ParentType = ResolversParentTypes['TemplateMetadata'], -> = ResolversObject<{ - annotation?: Resolver< - Maybe, - ParentType, - ContextType, - RequireFields - >; - annotations?: Resolver; - etag?: Resolver; - label?: Resolver< - Maybe, - ParentType, - ContextType, - RequireFields - >; - labels?: Resolver; - name?: Resolver; - uid?: Resolver; - updatedBy?: Resolver< - Maybe, - ParentType, - ContextType - >; - __isTypeOf?: IsTypeOfResolverFn; -}>; - -export type Resolvers = ResolversObject<{ - CatalogEntity?: CatalogEntityResolvers; - CatalogQuery?: CatalogQueryResolvers; - ComponentEntitySpec?: ComponentEntitySpecResolvers; - ComponentMetadata?: ComponentMetadataResolvers; - DefaultEntityMetadata?: DefaultEntityMetadataResolvers; - DefaultEntitySpec?: DefaultEntitySpecResolvers; - EntityMetadata?: EntityMetadataResolvers; - EntitySpec?: EntitySpecResolvers; - JSON?: GraphQLScalarType; - JSONObject?: GraphQLScalarType; - Query?: QueryResolvers; - TemplateEntitySpec?: TemplateEntitySpecResolvers; - TemplateMetadata?: TemplateMetadataResolvers; -}>; diff --git a/plugins/catalog-graphql/src/schema.js b/plugins/catalog-graphql/src/schema.js deleted file mode 100644 index cf6ccf3017..0000000000 --- a/plugins/catalog-graphql/src/schema.js +++ /dev/null @@ -1,104 +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. - */ - -const schema = /* GraphQL */ ` - scalar JSON - scalar JSONObject - - interface EntityMetadata { - name: String! - annotations: JSONObject! - annotation(name: String!): JSON - labels: JSONObject! - label(name: String!): JSON - uid: String! - etag: String! - } - - type DefaultEntityMetadata implements EntityMetadata { - name: String! - annotations: JSONObject! - annotation(name: String!): JSON - labels: JSONObject! - label(name: String!): JSON - uid: String! - etag: String! - } - - type ComponentMetadata implements EntityMetadata { - name: String! - annotations: JSONObject! - annotation(name: String!): JSON - labels: JSONObject! - label(name: String!): JSON - uid: String! - etag: String! - # mock field to prove extensions working - relationships: String - } - - type TemplateMetadata implements EntityMetadata { - name: String! - annotations: JSONObject! - annotation(name: String!): JSON - labels: JSONObject! - label(name: String!): JSON - uid: String! - etag: String! - # mock field to prove extensions working - updatedBy: String - } - - # TODO: move this definition into plugin-scaffolder-graphql - type TemplateEntitySpec { - type: String! - path: String - schema: JSONObject! - templater: String! - } - - type ComponentEntitySpec { - type: String! - lifecycle: String! - owner: String! - } - - type DefaultEntitySpec { - raw: JSONObject - } - - union EntitySpec = - DefaultEntitySpec - | TemplateEntitySpec - | ComponentEntitySpec - - type CatalogEntity { - apiVersion: String! - kind: String! - metadata: EntityMetadata - spec: EntitySpec! - } - - type CatalogQuery { - list: [CatalogEntity!]! - } - - type Query { - catalog: CatalogQuery! - } -`; - -export default schema; diff --git a/plugins/catalog-graphql/src/service/client.test.ts b/plugins/catalog-graphql/src/service/client.test.ts deleted file mode 100644 index 72041725a3..0000000000 --- a/plugins/catalog-graphql/src/service/client.test.ts +++ /dev/null @@ -1,56 +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 { CatalogClient } from './client'; -import { rest } from 'msw'; -import { setupServer } from 'msw/node'; -import { setupRequestMockHandlers } from '@backstage/test-utils'; - -describe('Catalog GraphQL Module', () => { - const worker = setupServer(); - setupRequestMockHandlers(worker); - - const baseUrl = 'http://localhost:1234'; - - it('will return the entities', async () => { - const expectedResponse = [{ id: 'something' }]; - - worker.use( - rest.get(`${baseUrl}/api/catalog/entities`, (_, res, ctx) => - res(ctx.status(200), ctx.json(expectedResponse)), - ), - ); - - const client = new CatalogClient(baseUrl); - - const response = await client.list(); - - expect(response).toEqual(expectedResponse); - }); - - it('throws an error with the text', async () => { - const expectedResponse = 'something broke'; - - worker.use( - rest.get(`${baseUrl}/api/catalog/entities`, (_, res, ctx) => - res(ctx.status(500), ctx.text(expectedResponse)), - ), - ); - - const client = new CatalogClient(baseUrl); - - await expect(() => client.list()).rejects.toThrow(expectedResponse); - }); -}); diff --git a/plugins/catalog-graphql/src/service/client.ts b/plugins/catalog-graphql/src/service/client.ts deleted file mode 100644 index c6a5cff140..0000000000 --- a/plugins/catalog-graphql/src/service/client.ts +++ /dev/null @@ -1,47 +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 { Entity, EntityMeta } from '@backstage/catalog-model'; -import fetch from 'node-fetch'; - -export interface ReaderEntityMeta extends EntityMeta { - uid: string; - etag: string; - namespace: string; - annotations: Record; - labels: Record; -} - -export interface ReaderEntity extends Entity { - metadata: ReaderEntityMeta; -} - -export class CatalogClient { - constructor(private baseUrl: string) {} - - async list(): Promise { - const res = await fetch(`${this.baseUrl}/api/catalog/entities`); - - if (!res.ok) { - // todo(blam): need some better way to handle errors here - // experiment with throwing the input errors etc and having graphql versions of that - throw new Error(await res.text()); - } - - const entities = (await res.json()) as ReaderEntity[]; - return entities; - } -} diff --git a/plugins/catalog-import/CHANGELOG.md b/plugins/catalog-import/CHANGELOG.md index 5d99d9cd83..ea9d4cb61e 100644 --- a/plugins/catalog-import/CHANGELOG.md +++ b/plugins/catalog-import/CHANGELOG.md @@ -1,5 +1,194 @@ # @backstage/plugin-catalog-import +## 0.10.5 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.1.1 + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/plugin-catalog-common@1.0.20 + +## 0.10.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.1.1-next.2 + - @backstage/frontend-plugin-api@0.4.1-next.2 + - @backstage/plugin-catalog-react@1.9.3-next.2 + - @backstage/integration-react@1.1.23-next.0 + +## 0.10.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/core-compat-api@0.1.1-next.1 + - @backstage/frontend-plugin-api@0.4.1-next.1 + - @backstage/integration-react@1.1.23-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.19 + +## 0.10.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/frontend-plugin-api@0.4.1-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/integration-react@1.1.22 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-compat-api@0.1.1-next.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/plugin-catalog-common@1.0.19 + +## 0.10.4 + +### Patch Changes + +- 03d0b6d: The `convertLegacyRouteRef` utility used by the alpha exports is now imported from `@backstage/core-compat-api`. +- a1227cc: Wrap `/alpha` export extension elements in backwards compatibility wrapper. +- 5814122: Updated `/alpha` exports to fit new naming patterns. +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- Updated dependencies + - @backstage/core-compat-api@0.1.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/frontend-plugin-api@0.4.0 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/catalog-client@1.5.0 + - @backstage/integration@1.8.0 + - @backstage/integration-react@1.1.22 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.19 + +## 0.10.4-next.4 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-compat-api@0.1.0-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/frontend-plugin-api@0.4.0-next.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## 0.10.4-next.3 + +### Patch Changes + +- a1227cc: Wrap `/alpha` export extension elements in backwards compatibility wrapper. +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.2 + - @backstage/core-compat-api@0.1.0-next.2 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-catalog-common@1.0.18 + +## 0.10.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/core-compat-api@0.0.1-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.18 + +## 0.10.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.0.1-next.0 + +## 0.10.4-next.0 + +### Patch Changes + +- 03d0b6dcdc: The `convertLegacyRouteRef` utility used by the alpha exports is now imported from `@backstage/core-compat-api`. +- Updated dependencies + - @backstage/core-compat-api@0.0.2-next.0 + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/frontend-plugin-api@0.3.1-next.0 + - @backstage/integration-react@1.1.22-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.18 + +## 0.10.2 + +### Patch Changes + +- 6db75b900a: Create an experimental plugin that is compatible with the declarative integration system, it is exported from the `/alpha` subpath. +- 6c2b872153: Add official support for React 18. +- dee1f39fcc: Fix missing children key warning on the default catalog import page. +- 71c97e7d73: The `app.title` configuration is now properly required to be a string. +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/frontend-plugin-api@0.3.0 + - @backstage/integration@1.7.2 + - @backstage/integration-react@1.1.21 + - @backstage/core-plugin-api@1.8.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.18 + ## 0.10.2-next.2 ### Patch Changes diff --git a/plugins/catalog-import/alpha-api-report.md b/plugins/catalog-import/api-report-alpha.md similarity index 100% rename from plugins/catalog-import/alpha-api-report.md rename to plugins/catalog-import/api-report-alpha.md diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json index b528ae0ac1..865f60a842 100644 --- a/plugins/catalog-import/package.json +++ b/plugins/catalog-import/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-import", "description": "A Backstage plugin the helps you import entities into your catalog", - "version": "0.10.2-next.2", + "version": "0.10.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -49,6 +49,7 @@ "@backstage/catalog-client": "workspace:^", "@backstage/catalog-model": "workspace:^", "@backstage/config": "workspace:^", + "@backstage/core-compat-api": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", diff --git a/plugins/catalog-import/src/alpha.tsx b/plugins/catalog-import/src/alpha.tsx index bde1048f13..304ee3f272 100644 --- a/plugins/catalog-import/src/alpha.tsx +++ b/plugins/catalog-import/src/alpha.tsx @@ -20,7 +20,10 @@ import { discoveryApiRef, identityApiRef, } from '@backstage/core-plugin-api'; -import { convertLegacyRouteRef } from '@backstage/core-plugin-api/alpha'; +import { + compatWrapper, + convertLegacyRouteRef, +} from '@backstage/core-compat-api'; import { createApiExtension, createPageExtension, @@ -37,14 +40,16 @@ import { catalogApiRef } from '@backstage/plugin-catalog-react'; // TODO: It's currently possible to override the import page with a custom one. We need to decide // whether this type of override is typically done with an input or by overriding the entire extension. -const CatalogImportPageExtension = createPageExtension({ - id: 'plugin.catalog-import.page', +const catalogImportPage = createPageExtension({ defaultPath: '/catalog-import', routeRef: convertLegacyRouteRef(rootRouteRef), - loader: () => import('./components/ImportPage').then(m => ), + loader: () => + import('./components/ImportPage').then(m => + compatWrapper(), + ), }); -const CatalogImportService = createApiExtension({ +const catalogImportApi = createApiExtension({ factory: createApiFactory({ api: catalogImportApiRef, deps: { @@ -77,7 +82,7 @@ const CatalogImportService = createApiExtension({ /** @alpha */ export default createPlugin({ id: 'catalog-import', - extensions: [CatalogImportService, CatalogImportPageExtension], + extensions: [catalogImportApi, catalogImportPage], routes: { importPage: convertLegacyRouteRef(rootRouteRef), }, diff --git a/plugins/catalog-node/CHANGELOG.md b/plugins/catalog-node/CHANGELOG.md index 228dd31789..cda3c22b0f 100644 --- a/plugins/catalog-node/CHANGELOG.md +++ b/plugins/catalog-node/CHANGELOG.md @@ -1,5 +1,149 @@ # @backstage/plugin-catalog-node +## 1.6.1 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.20 + +## 1.6.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-permission-node@0.7.20-next.2 + +## 1.6.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-node@0.7.20-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-permission-common@0.7.11 + +## 1.6.1-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.20-next.0 + +## 1.6.0 + +### Minor Changes + +- a168507: Added `EntitiesSearchFilter` and `EntityFilter` from `@backstage/plugin-catalog-backend`, for reuse +- 7804597: Permission rules can now be added for the Catalog plugin through the `CatalogPermissionExtensionPoint` interface. + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.19 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + +## 1.6.0-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.3 + +## 1.6.0-next.2 + +### Minor Changes + +- a168507: Added `EntitiesSearchFilter` and `EntityFilter` from `@backstage/plugin-catalog-backend`, for reuse +- 7804597: Permission rules can now be added for the Catalog plugin through the `CatalogPermissionExtensionPoint` interface. + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.2 + +## 1.5.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + +## 1.5.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + +## 1.5.0 + +### Minor Changes + +- e5bf3749ad: Support adding location analyzers in new catalog analysis extension point and move `AnalyzeOptions` and `ScmLocationAnalyzer` types to `@backstage/plugin-catalog-node` + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.7 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + ## 1.5.0-next.2 ### Patch Changes diff --git a/plugins/catalog-node/alpha-api-report.md b/plugins/catalog-node/api-report-alpha.md similarity index 65% rename from plugins/catalog-node/alpha-api-report.md rename to plugins/catalog-node/api-report-alpha.md index c4dc6b12e1..74339b1bc9 100644 --- a/plugins/catalog-node/alpha-api-report.md +++ b/plugins/catalog-node/api-report-alpha.md @@ -5,8 +5,12 @@ ```ts import { CatalogApi } from '@backstage/catalog-client'; import { CatalogProcessor } from '@backstage/plugin-catalog-node'; +import { EntitiesSearchFilter } from '@backstage/plugin-catalog-node'; +import { Entity } from '@backstage/catalog-model'; import { EntityProvider } from '@backstage/plugin-catalog-node'; import { ExtensionPoint } from '@backstage/backend-plugin-api'; +import { PermissionRule } from '@backstage/plugin-permission-node'; +import { PermissionRuleParams } from '@backstage/plugin-permission-common'; import { PlaceholderResolver } from '@backstage/plugin-catalog-node'; import { ScmLocationAnalyzer } from '@backstage/plugin-catalog-node'; import { ServiceRef } from '@backstage/backend-plugin-api'; @@ -20,6 +24,24 @@ export interface CatalogAnalysisExtensionPoint { // @alpha (undocumented) export const catalogAnalysisExtensionPoint: ExtensionPoint; +// @alpha (undocumented) +export interface CatalogPermissionExtensionPoint { + // (undocumented) + addPermissionRules( + ...rules: Array< + CatalogPermissionRuleInput | Array + > + ): void; +} + +// @alpha (undocumented) +export const catalogPermissionExtensionPoint: ExtensionPoint; + +// @alpha (undocumented) +export type CatalogPermissionRuleInput< + TParams extends PermissionRuleParams = PermissionRuleParams, +> = PermissionRule; + // @alpha (undocumented) export interface CatalogProcessingExtensionPoint { // (undocumented) diff --git a/plugins/catalog-node/api-report.md b/plugins/catalog-node/api-report.md index ef2c09e61f..a4ba95073f 100644 --- a/plugins/catalog-node/api-report.md +++ b/plugins/catalog-node/api-report.md @@ -105,6 +105,25 @@ export type DeferredEntity = { locationKey?: string; }; +// @public +export type EntitiesSearchFilter = { + key: string; + values?: string[]; +}; + +// @public +export type EntityFilter = + | { + allOf: EntityFilter[]; + } + | { + anyOf: EntityFilter[]; + } + | { + not: EntityFilter; + } + | EntitiesSearchFilter; + // @public export interface EntityProvider { connect(connection: EntityProviderConnection): Promise; diff --git a/plugins/catalog-node/package.json b/plugins/catalog-node/package.json index 27277b5381..013577d0b9 100644 --- a/plugins/catalog-node/package.json +++ b/plugins/catalog-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-node", "description": "The plugin-catalog-node module for @backstage/plugin-catalog-backend", - "version": "1.5.0-next.2", + "version": "1.6.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -47,10 +47,11 @@ "@backstage/catalog-model": "workspace:^", "@backstage/errors": "workspace:^", "@backstage/plugin-catalog-common": "workspace:^", + "@backstage/plugin-permission-common": "workspace:^", + "@backstage/plugin-permission-node": "workspace:^", "@backstage/types": "workspace:^" }, "devDependencies": { - "@backstage/backend-common": "workspace:^", "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^" }, diff --git a/plugins/catalog-node/src/alpha.ts b/plugins/catalog-node/src/alpha.ts index cec1a0eedb..3e958d1df1 100644 --- a/plugins/catalog-node/src/alpha.ts +++ b/plugins/catalog-node/src/alpha.ts @@ -19,3 +19,6 @@ export type { CatalogProcessingExtensionPoint } from './extensions'; export { catalogProcessingExtensionPoint } from './extensions'; export type { CatalogAnalysisExtensionPoint } from './extensions'; export { catalogAnalysisExtensionPoint } from './extensions'; +export type { CatalogPermissionRuleInput } from './extensions'; +export type { CatalogPermissionExtensionPoint } from './extensions'; +export { catalogPermissionExtensionPoint } from './extensions'; diff --git a/plugins/catalog-node/src/api/common.ts b/plugins/catalog-node/src/api/common.ts index c91aeca2d9..7f9bd3eabf 100644 --- a/plugins/catalog-node/src/api/common.ts +++ b/plugins/catalog-node/src/api/common.ts @@ -52,3 +52,36 @@ export type EntityRelationSpec = { */ target: CompoundEntityRef; }; + +/** + * A filter expression for entities. + * + * @public + */ +export type EntityFilter = + | { allOf: EntityFilter[] } + | { anyOf: EntityFilter[] } + | { not: EntityFilter } + | EntitiesSearchFilter; + +/** + * Matches rows in the search table. + * + * @public + */ +export type EntitiesSearchFilter = { + /** + * The key to match on. + * + * Matches are always case insensitive. + */ + key: string; + + /** + * Match on plain equality of values. + * + * Match on values that are equal to any of the given array items. Matches are + * always case insensitive. + */ + values?: string[]; +}; diff --git a/plugins/catalog-node/src/api/index.ts b/plugins/catalog-node/src/api/index.ts index 66e8d6bd21..292a6cd872 100644 --- a/plugins/catalog-node/src/api/index.ts +++ b/plugins/catalog-node/src/api/index.ts @@ -15,7 +15,12 @@ */ export { processingResult } from './processingResult'; -export type { EntityRelationSpec, LocationSpec } from './common'; +export type { + EntityRelationSpec, + LocationSpec, + EntitiesSearchFilter, + EntityFilter, +} from './common'; export type { CatalogProcessor, CatalogProcessorParser, diff --git a/plugins/catalog-node/src/extensions.ts b/plugins/catalog-node/src/extensions.ts index 247ef142ad..7aa9264030 100644 --- a/plugins/catalog-node/src/extensions.ts +++ b/plugins/catalog-node/src/extensions.ts @@ -13,13 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { createExtensionPoint } from '@backstage/backend-plugin-api'; +import { Entity } from '@backstage/catalog-model'; import { - EntityProvider, CatalogProcessor, + EntitiesSearchFilter, + EntityProvider, PlaceholderResolver, ScmLocationAnalyzer, } from '@backstage/plugin-catalog-node'; +import { PermissionRuleParams } from '@backstage/plugin-permission-common'; +import { PermissionRule } from '@backstage/plugin-permission-node'; /** * @alpha @@ -56,3 +61,29 @@ export const catalogAnalysisExtensionPoint = createExtensionPoint({ id: 'catalog.analysis', }); + +/** + * @alpha + */ +export type CatalogPermissionRuleInput< + TParams extends PermissionRuleParams = PermissionRuleParams, +> = PermissionRule; + +/** + * @alpha + */ +export interface CatalogPermissionExtensionPoint { + addPermissionRules( + ...rules: Array< + CatalogPermissionRuleInput | Array + > + ): void; +} + +/** + * @alpha + */ +export const catalogPermissionExtensionPoint = + createExtensionPoint({ + id: 'catalog.permission', + }); diff --git a/plugins/catalog-react/CHANGELOG.md b/plugins/catalog-react/CHANGELOG.md index 24a21d1e71..9bd729a8e6 100644 --- a/plugins/catalog-react/CHANGELOG.md +++ b/plugins/catalog-react/CHANGELOG.md @@ -1,5 +1,241 @@ # @backstage/plugin-catalog-react +## 1.9.3 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-catalog-common@1.0.20 + +## 1.9.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.1-next.2 + - @backstage/integration-react@1.1.23-next.0 + +## 1.9.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/frontend-plugin-api@0.4.1-next.1 + - @backstage/integration-react@1.1.23-next.0 + - @backstage/plugin-permission-react@0.4.19-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-permission-common@0.7.11 + +## 1.9.3-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/frontend-plugin-api@0.4.1-next.0 + - @backstage/plugin-permission-react@0.4.19-next.0 + - @backstage/integration-react@1.1.22 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-permission-common@0.7.11 + +## 1.9.2 + +### Patch Changes + +- 8587f06: Added pagination support to `EntityListProvider`. +- 5360097: Ensure that passed-in icons are taken advantage of in the presentation API +- fd9863c: Grouped all `/alpha` extension data reference exports under `catalogExtensionData`. +- 08d9e67: Add default icon for kind resource. +- aaa6fb3: Minor updates for TypeScript 5.2.2+ compatibility +- a5a0473: Internal refactor of alpha exports due to a change in how extension factories are defined. +- 4d9e3b3: Register component overrides in the global `OverrideComponentNameToClassKeys` provided by `@backstage/theme`. This will in turn will provide component style override types for `createUnifiedTheme`. +- 8f5d6c1: Updates to the `/alpha` exports to match the extension input wrapping change. +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- e223f22: Breaking alpha-API change to entity visibility filter functions to accept a bare entity as their first argument, instead of an object with an entity property. + + Functions that accept such filters now also support the string expression form of filters. + +- eee0ff2: Fixed a issue where `CatalogPage` wasn't using the chosen `initiallySelectedFilter` as intended. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/frontend-plugin-api@0.4.0 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-client@1.5.0 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/integration-react@1.1.22 + - @backstage/plugin-permission-react@0.4.18 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-catalog-common@1.0.19 + +## 1.9.2-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/frontend-plugin-api@0.4.0-next.3 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-react@0.4.18-next.1 + +## 1.9.2-next.2 + +### Patch Changes + +- 8f5d6c1: Updates to the `/alpha` exports to match the extension input wrapping change. +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.2 + - @backstage/theme@0.5.0-next.1 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-react@0.4.18-next.1 + +## 1.9.2-next.1 + +### Patch Changes + +- 53600976bb: Ensure that passed-in icons are taken advantage of in the presentation API +- 08d9e67199: Add default icon for kind resource. +- a5a04739e1: Internal refactor of alpha exports due to a change in how extension factories are defined. +- e223f2264d: Breaking alpha-API change to entity visibility filter functions to accept a bare entity as their first argument, instead of an object with an entity property. + + Functions that accept such filters now also support the string expression form of filters. + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-common@0.7.10 + +## 1.9.2-next.0 + +### Patch Changes + +- 8587f067d2: Added pagination support to `EntityListProvider`. +- aaa6fb3bc9: Minor updates for TypeScript 5.2.2+ compatibility +- 4d9e3b39e4: Register component overrides in the global `OverrideComponentNameToClassKeys` provided by `@backstage/theme`. This will in turn will provide component style override types for `createUnifiedTheme`. +- eee0ff2946: Fixed a issue where `CatalogPage` wasn't using the chosen `initiallySelectedFilter` as intended. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/frontend-plugin-api@0.3.1-next.0 + - @backstage/integration-react@1.1.22-next.0 + - @backstage/plugin-permission-react@0.4.18-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-common@0.7.10 + +## 1.9.0 + +### Minor Changes + +- 1e5b7d993a: Added an `EntityPresentationApi` and associated `entityPresentationApiRef`. This + API lets you control how references to entities (e.g. in links, headings, + iconography etc) are represented in the user interface. + + Usage of this API is initially added to the `EntityRefLink` and `EntityRefLinks` + components, so that they can render richer, more correct representation of + entity refs. There's also a new `EntityDisplayName` component, which works just like + the `EntityRefLink` but without the link. + + Along with that change, the `fetchEntities` and `getTitle` props of + `EntityRefLinksProps` are deprecated and no longer used, since the same need + instead is fulfilled (and by default always enabled) by the + `entityPresentationApiRef`. + +- 1fd53fa0c6: The `UserListPicker` component has undergone improvements to enhance its performance. + + The previous implementation inferred the number of owned and starred entities based on the entities available in the `EntityListContext`. The updated version no longer relies on the `EntityListContext` for inference, allowing for better decoupling. + + The component now loads the entities' count asynchronously, resulting in improved performance and responsiveness. For this purpose, some of the exported filters such as `EntityTagFilter`, `EntityOwnerFilter`, `EntityLifecycleFilter` and `EntityNamespaceFilter` have now the `getCatalogFilters` method implemented. + +### Patch Changes + +- 2ad1bacef7: Add EntityRef to Entity Inspector UI +- 6c2b872153: Add official support for React 18. +- 69ee8d75f4: Remove `button` prop from used MaterialUI `MenuItem` component fixing incompatibility with MaterialUI v5. +- 0bf6ebda88: Added new APIs at the `/alpha` subpath for creating entity page cards and content for the new frontend system. +- 77f009b35d: Internal updates to match changes in the experimental `@backstage/frontend-plugin-api`. +- 71c97e7d73: The `spec.type` field in entities will now always be rendered as a string. +- 69c14904b6: Move the `EntityRefLink` icon to the left hand side as per Material-UI guidelines +- 000dcd01af: Removed unnecessary `@backstage/integration` dependency, replaced by `@backstage/integration-react`. +- 6c357184e2: Export `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/frontend-plugin-api@0.3.0 + - @backstage/integration-react@1.1.21 + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-permission-react@0.4.17 + - @backstage/version-bridge@1.0.7 + - @backstage/theme@0.4.4 + - @backstage/catalog-client@1.4.6 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + ## 1.9.0-next.2 ### Patch Changes diff --git a/plugins/catalog-react/alpha-api-report.md b/plugins/catalog-react/api-report-alpha.md similarity index 64% rename from plugins/catalog-react/alpha-api-report.md rename to plugins/catalog-react/api-report-alpha.md index ed851f810a..cf9fdc6c3a 100644 --- a/plugins/catalog-react/alpha-api-report.md +++ b/plugins/catalog-react/api-report-alpha.md @@ -8,40 +8,49 @@ import { AnyExtensionInputMap } from '@backstage/frontend-plugin-api'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; import { Entity } from '@backstage/catalog-model'; -import { Extension } from '@backstage/frontend-plugin-api'; -import { ExtensionInputValues } from '@backstage/frontend-plugin-api'; +import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; +import { ResolvedExtensionInputs } from '@backstage/frontend-plugin-api'; import { ResourcePermission } from '@backstage/plugin-permission-common'; import { RouteRef } from '@backstage/frontend-plugin-api'; +// @alpha (undocumented) +export const catalogExtensionData: { + entityContentTitle: ConfigurableExtensionDataRef; + entityFilterFunction: ConfigurableExtensionDataRef< + (entity: Entity) => boolean, + {} + >; + entityFilterExpression: ConfigurableExtensionDataRef; +}; + // @alpha (undocumented) export function createEntityCardExtension< TInputs extends AnyExtensionInputMap, >(options: { - id: string; + namespace?: string; + name?: string; attachTo?: { id: string; input: string; }; disabled?: boolean; inputs?: TInputs; - filter?: (ctx: { entity: Entity }) => boolean; - loader: (options: { - inputs: Expand>; - }) => Promise; -}): Extension<{ filter?: - | { - isKind?: string | undefined; - isType?: string | undefined; - }[] - | undefined; + | typeof catalogExtensionData.entityFilterFunction.T + | typeof catalogExtensionData.entityFilterExpression.T; + loader: (options: { + inputs: Expand>; + }) => Promise; +}): ExtensionDefinition<{ + filter?: string | undefined; }>; // @alpha (undocumented) export function createEntityContentExtension< TInputs extends AnyExtensionInputMap, >(options: { - id: string; + namespace?: string; + name?: string; attachTo?: { id: string; input: string; @@ -51,33 +60,18 @@ export function createEntityContentExtension< routeRef?: RouteRef; defaultPath: string; defaultTitle: string; - filter?: (ctx: { entity: Entity }) => boolean; + filter?: + | typeof catalogExtensionData.entityFilterFunction.T + | typeof catalogExtensionData.entityFilterExpression.T; loader: (options: { - inputs: Expand>; + inputs: Expand>; }) => Promise; -}): Extension<{ +}): ExtensionDefinition<{ title: string; path: string; - filter?: - | { - isKind?: string | undefined; - isType?: string | undefined; - }[] - | undefined; + filter?: string | undefined; }>; -// @alpha (undocumented) -export const entityContentTitleExtensionDataRef: ConfigurableExtensionDataRef< - string, - {} ->; - -// @alpha (undocumented) -export const entityFilterExtensionDataRef: ConfigurableExtensionDataRef< - (ctx: { entity: Entity }) => boolean, - {} ->; - // @alpha export function isOwnerOf(owner: Entity, entity: Entity): boolean; diff --git a/plugins/catalog-react/api-report.md b/plugins/catalog-react/api-report.md index e84fa9815c..8c6b3a729f 100644 --- a/plugins/catalog-react/api-report.md +++ b/plugins/catalog-react/api-report.md @@ -284,13 +284,26 @@ export type EntityListContextProps< queryParameters: Partial>; loading: boolean; error?: Error; + pageInfo?: { + next?: () => void; + prev?: () => void; + }; }; // @public export const EntityListProvider: ( - props: PropsWithChildren<{}>, + props: EntityListProviderProps, ) => React_2.JSX.Element; +// @public (undocumented) +export type EntityListProviderProps = PropsWithChildren<{ + pagination?: + | boolean + | { + limit?: number; + }; +}>; + // @public (undocumented) export type EntityLoadingStatus = { entity?: TEntity; diff --git a/plugins/catalog-react/package.json b/plugins/catalog-react/package.json index abefaeadb9..93486c64db 100644 --- a/plugins/catalog-react/package.json +++ b/plugins/catalog-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-react", "description": "A frontend library that helps other Backstage plugins interact with the catalog", - "version": "1.9.0-next.2", + "version": "1.9.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -56,7 +56,6 @@ "@backstage/plugin-catalog-common": "workspace:^", "@backstage/plugin-permission-common": "workspace:^", "@backstage/plugin-permission-react": "workspace:^", - "@backstage/theme": "workspace:^", "@backstage/types": "workspace:^", "@backstage/version-bridge": "workspace:^", "@material-ui/core": "^4.12.2", diff --git a/plugins/catalog-react/src/alpha.tsx b/plugins/catalog-react/src/alpha.tsx index 8d0436e4be..330cd573cd 100644 --- a/plugins/catalog-react/src/alpha.tsx +++ b/plugins/catalog-react/src/alpha.tsx @@ -14,106 +14,75 @@ * limitations under the License. */ -import React, { lazy } from 'react'; import { AnyExtensionInputMap, ExtensionBoundary, - ExtensionInputValues, + ResolvedExtensionInputs, RouteRef, coreExtensionData, createExtension, createExtensionDataRef, createSchemaFromZod, } from '@backstage/frontend-plugin-api'; +import React, { lazy } from 'react'; +import { Entity } from '@backstage/catalog-model'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports import { Expand } from '../../../packages/frontend-plugin-api/src/types'; -import { Entity } from '@backstage/catalog-model'; -export { isOwnerOf } from './utils'; export { useEntityPermission } from './hooks/useEntityPermission'; +export { isOwnerOf } from './utils'; /** @alpha */ -export const entityContentTitleExtensionDataRef = - createExtensionDataRef('plugin.catalog.entity.content.title'); - -/** @alpha */ -export const entityFilterExtensionDataRef = createExtensionDataRef< - (ctx: { entity: Entity }) => boolean ->('plugin.catalog.entity.filter'); - -function applyFilter(a?: string, b?: string): boolean { - if (!a) { - return true; - } - return a.toLocaleLowerCase('en-US') === b?.toLocaleLowerCase('en-US'); -} - -// TODO: Only two hardcoded isKind and isType filters are available for now -// This is just an initial config filter implementation and needs to be revisited -function buildFilter( - config: { filter?: { isKind?: string; isType?: string }[] }, - filterFunc?: (ctx: { entity: Entity }) => boolean, -) { - return (ctx: { entity: Entity }) => { - const configuredFilterMatch = config.filter?.some(filter => { - const kindMatch = applyFilter(filter.isKind, ctx.entity.kind); - const typeMatch = applyFilter( - filter.isType, - ctx.entity.spec?.type?.toString(), - ); - return kindMatch && typeMatch; - }); - if (configuredFilterMatch) { - return true; - } - if (filterFunc) { - return filterFunc(ctx); - } - return true; - }; -} +export const catalogExtensionData = { + entityContentTitle: createExtensionDataRef( + 'catalog.entity-content-title', + ), + entityFilterFunction: createExtensionDataRef<(entity: Entity) => boolean>( + 'catalog.entity-filter-function', + ), + entityFilterExpression: createExtensionDataRef( + 'catalog.entity-filter-expression', + ), +}; // TODO: Figure out how to merge with provided config schema /** @alpha */ export function createEntityCardExtension< TInputs extends AnyExtensionInputMap, >(options: { - id: string; + namespace?: string; + name?: string; attachTo?: { id: string; input: string }; disabled?: boolean; inputs?: TInputs; - filter?: (ctx: { entity: Entity }) => boolean; + filter?: + | typeof catalogExtensionData.entityFilterFunction.T + | typeof catalogExtensionData.entityFilterExpression.T; loader: (options: { - inputs: Expand>; + inputs: Expand>; }) => Promise; }) { - const id = `entity.cards.${options.id}`; - return createExtension({ - id, + kind: 'entity-card', + namespace: options.namespace, + name: options.name, attachTo: options.attachTo ?? { - id: 'entity.content.overview', + id: 'entity-content:catalog/overview', input: 'cards', }, disabled: options.disabled ?? true, output: { element: coreExtensionData.reactElement, - filter: entityFilterExtensionDataRef, + filterFunction: catalogExtensionData.entityFilterFunction.optional(), + filterExpression: catalogExtensionData.entityFilterExpression.optional(), }, inputs: options.inputs, configSchema: createSchemaFromZod(z => z.object({ - filter: z - .array( - z.object({ - isKind: z.string().optional(), - isType: z.string().optional(), - }), - ) - .optional(), + filter: z.string().optional(), }), ), - factory({ config, inputs, source }) { + factory({ config, inputs, node }) { const ExtensionComponent = lazy(() => options .loader({ inputs }) @@ -122,11 +91,11 @@ export function createEntityCardExtension< return { element: ( - + ), - filter: buildFilter(config, options.filter), + ...mergeFilters({ config, options }), }; }, }); @@ -136,24 +105,27 @@ export function createEntityCardExtension< export function createEntityContentExtension< TInputs extends AnyExtensionInputMap, >(options: { - id: string; + namespace?: string; + name?: string; attachTo?: { id: string; input: string }; disabled?: boolean; inputs?: TInputs; routeRef?: RouteRef; defaultPath: string; defaultTitle: string; - filter?: (ctx: { entity: Entity }) => boolean; + filter?: + | typeof catalogExtensionData.entityFilterFunction.T + | typeof catalogExtensionData.entityFilterExpression.T; loader: (options: { - inputs: Expand>; + inputs: Expand>; }) => Promise; }) { - const id = `entity.content.${options.id}`; - return createExtension({ - id, + kind: 'entity-content', + namespace: options.namespace, + name: options.name, attachTo: options.attachTo ?? { - id: 'plugin.catalog.page.entity', + id: 'page:catalog/entity', input: 'contents', }, disabled: options.disabled ?? true, @@ -161,25 +133,19 @@ export function createEntityContentExtension< element: coreExtensionData.reactElement, path: coreExtensionData.routePath, routeRef: coreExtensionData.routeRef.optional(), - title: entityContentTitleExtensionDataRef, - filter: entityFilterExtensionDataRef, + title: catalogExtensionData.entityContentTitle, + filterFunction: catalogExtensionData.entityFilterFunction.optional(), + filterExpression: catalogExtensionData.entityFilterExpression.optional(), }, inputs: options.inputs, configSchema: createSchemaFromZod(z => z.object({ path: z.string().default(options.defaultPath), title: z.string().default(options.defaultTitle), - filter: z - .array( - z.object({ - isKind: z.string().optional(), - isType: z.string().optional(), - }), - ) - .optional(), + filter: z.string().optional(), }), ), - factory({ config, inputs, source }) { + factory({ config, inputs, node }) { const ExtensionComponent = lazy(() => options .loader({ inputs }) @@ -191,12 +157,39 @@ export function createEntityContentExtension< title: config.title, routeRef: options.routeRef, element: ( - + ), - filter: buildFilter(config, options.filter), + ...mergeFilters({ config, options }), }; }, }); } + +/** + * Decides what filter outputs to produce, given some options and config + */ +function mergeFilters(inputs: { + options: { + filter?: + | typeof catalogExtensionData.entityFilterFunction.T + | typeof catalogExtensionData.entityFilterExpression.T; + }; + config: { + filter?: string; + }; +}): { + filterFunction?: typeof catalogExtensionData.entityFilterFunction.T; + filterExpression?: typeof catalogExtensionData.entityFilterExpression.T; +} { + const { options, config } = inputs; + if (config.filter) { + return { filterExpression: config.filter }; + } else if (typeof options.filter === 'string') { + return { filterExpression: options.filter }; + } else if (typeof options.filter === 'function') { + return { filterFunction: options.filter }; + } + return {}; +} diff --git a/plugins/catalog-react/src/apis/EntityPresentationApi/defaultEntityPresentation.test.ts b/plugins/catalog-react/src/apis/EntityPresentationApi/defaultEntityPresentation.test.ts index ea755dfebc..5985a50b0d 100644 --- a/plugins/catalog-react/src/apis/EntityPresentationApi/defaultEntityPresentation.test.ts +++ b/plugins/catalog-react/src/apis/EntityPresentationApi/defaultEntityPresentation.test.ts @@ -37,7 +37,7 @@ describe('defaultEntityPresentation', () => { entityRef: 'component:default/test', primaryTitle: 'test', secondaryTitle: 'component:default/test | type | desc', - Icon: expect.anything(), + Icon: undefined, }); expect( @@ -58,7 +58,7 @@ describe('defaultEntityPresentation', () => { entityRef: 'component:default/test', primaryTitle: 'title', secondaryTitle: 'component:default/test | type | desc', - Icon: expect.anything(), + Icon: undefined, }); expect( @@ -82,7 +82,7 @@ describe('defaultEntityPresentation', () => { entityRef: 'component:default/test', primaryTitle: 'displayName', secondaryTitle: 'component:default/test | type | desc', - Icon: expect.anything(), + Icon: undefined, }); }); @@ -96,7 +96,7 @@ describe('defaultEntityPresentation', () => { entityRef: 'component:default/test', primaryTitle: 'test', secondaryTitle: 'component:default/test', - Icon: expect.anything(), + Icon: undefined, }); }); @@ -107,7 +107,7 @@ describe('defaultEntityPresentation', () => { entityRef: 'unknown:default/unknown', primaryTitle: 'unknown', secondaryTitle: 'unknown:default/unknown', - Icon: expect.anything(), + Icon: undefined, }); }); }); @@ -118,7 +118,7 @@ describe('defaultEntityPresentation', () => { entityRef: 'component:default/test', primaryTitle: 'test', secondaryTitle: 'component:default/test', - Icon: expect.anything(), + Icon: undefined, }); expect( @@ -129,7 +129,7 @@ describe('defaultEntityPresentation', () => { entityRef: 'component:default/test', primaryTitle: 'component:test', secondaryTitle: 'component:default/test', - Icon: expect.anything(), + Icon: undefined, }); expect( @@ -140,7 +140,7 @@ describe('defaultEntityPresentation', () => { entityRef: 'component:default/test', primaryTitle: 'default/test', secondaryTitle: 'component:default/test', - Icon: expect.anything(), + Icon: undefined, }); }); @@ -149,14 +149,14 @@ describe('defaultEntityPresentation', () => { entityRef: 'unknown:default/unknown', primaryTitle: 'unknown', secondaryTitle: 'unknown:default/unknown', - Icon: expect.anything(), + Icon: undefined, }); expect(defaultEntityPresentation('name')).toEqual({ entityRef: 'unknown:default/name', primaryTitle: 'name', secondaryTitle: 'unknown:default/name', - Icon: expect.anything(), + Icon: undefined, }); }); }); @@ -173,7 +173,7 @@ describe('defaultEntityPresentation', () => { entityRef: 'component:default/test', primaryTitle: 'test', secondaryTitle: 'component:default/test', - Icon: expect.anything(), + Icon: undefined, }); expect( @@ -187,7 +187,7 @@ describe('defaultEntityPresentation', () => { entityRef: 'component:default/test', primaryTitle: 'component:test', secondaryTitle: 'component:default/test', - Icon: expect.anything(), + Icon: undefined, }); expect( @@ -201,7 +201,7 @@ describe('defaultEntityPresentation', () => { entityRef: 'component:default/test', primaryTitle: 'default/test', secondaryTitle: 'component:default/test', - Icon: expect.anything(), + Icon: undefined, }); }); @@ -217,14 +217,14 @@ describe('defaultEntityPresentation', () => { entityRef: 'component:default/test', primaryTitle: 'default/test', secondaryTitle: 'component:default/test', - Icon: expect.anything(), + Icon: undefined, }); expect(defaultEntityPresentation('')).toEqual({ entityRef: 'unknown:default/unknown', primaryTitle: 'unknown', secondaryTitle: 'unknown:default/unknown', - Icon: expect.anything(), + Icon: undefined, }); }); }); @@ -235,7 +235,7 @@ describe('defaultEntityPresentation', () => { entityRef: 'unknown:default/unknown', primaryTitle: 'unknown', secondaryTitle: 'unknown:default/unknown', - Icon: expect.anything(), + Icon: undefined, }); expect(defaultEntityPresentation(undefined as unknown as Entity)).toEqual( @@ -243,7 +243,7 @@ describe('defaultEntityPresentation', () => { entityRef: 'unknown:default/unknown', primaryTitle: 'unknown', secondaryTitle: 'unknown:default/unknown', - Icon: expect.anything(), + Icon: undefined, }, ); @@ -253,7 +253,7 @@ describe('defaultEntityPresentation', () => { entityRef: 'unknown:default/unknown', primaryTitle: 'unknown', secondaryTitle: 'unknown:default/unknown', - Icon: expect.anything(), + Icon: undefined, }); }); }); diff --git a/plugins/catalog-react/src/apis/EntityPresentationApi/defaultEntityPresentation.ts b/plugins/catalog-react/src/apis/EntityPresentationApi/defaultEntityPresentation.ts index eacb659062..8d841f3c3c 100644 --- a/plugins/catalog-react/src/apis/EntityPresentationApi/defaultEntityPresentation.ts +++ b/plugins/catalog-react/src/apis/EntityPresentationApi/defaultEntityPresentation.ts @@ -20,32 +20,9 @@ import { Entity, stringifyEntityRef, } from '@backstage/catalog-model'; -import { IconComponent } from '@backstage/core-plugin-api'; -import ApartmentIcon from '@material-ui/icons/Apartment'; -import BusinessIcon from '@material-ui/icons/Business'; -import ExtensionIcon from '@material-ui/icons/Extension'; -import HelpIcon from '@material-ui/icons/Help'; -import LibraryAddIcon from '@material-ui/icons/LibraryAdd'; -import LocationOnIcon from '@material-ui/icons/LocationOn'; -import MemoryIcon from '@material-ui/icons/Memory'; -import PeopleIcon from '@material-ui/icons/People'; -import PersonIcon from '@material-ui/icons/Person'; import get from 'lodash/get'; import { EntityRefPresentationSnapshot } from './EntityPresentationApi'; -const UNKNOWN_KIND_ICON: IconComponent = HelpIcon; - -const DEFAULT_ICONS: Record = { - api: ExtensionIcon, - component: MemoryIcon, - system: BusinessIcon, - domain: ApartmentIcon, - location: LocationOnIcon, - user: PersonIcon, - group: PeopleIcon, - template: LibraryAddIcon, -}; - /** * This returns the default representation of an entity. * @@ -66,10 +43,6 @@ export function defaultEntityPresentation( const { kind, namespace, name, title, description, displayName, type } = getParts(entityOrRef); - const Icon = - (kind && DEFAULT_ICONS[kind.toLocaleLowerCase('en-US')]) || - UNKNOWN_KIND_ICON; - const entityRef: string = stringifyEntityRef({ kind: kind || 'unknown', namespace: namespace || DEFAULT_NAMESPACE, @@ -94,7 +67,7 @@ export function defaultEntityPresentation( entityRef, primaryTitle: primary, secondaryTitle: secondary || undefined, - Icon, + Icon: undefined, // leave it up to the presentation API to handle }; } diff --git a/plugins/catalog-react/src/components/CatalogFilterLayout/CatalogFilterLayout.tsx b/plugins/catalog-react/src/components/CatalogFilterLayout/CatalogFilterLayout.tsx index 1a1404edf2..1a0c446c9e 100644 --- a/plugins/catalog-react/src/components/CatalogFilterLayout/CatalogFilterLayout.tsx +++ b/plugins/catalog-react/src/components/CatalogFilterLayout/CatalogFilterLayout.tsx @@ -20,12 +20,12 @@ import { Button, Drawer, Grid, + Theme, Typography, useMediaQuery, useTheme, } from '@material-ui/core'; import FilterListIcon from '@material-ui/icons/FilterList'; -import { BackstageTheme } from '@backstage/theme'; /** @public */ export const Filters = (props: { @@ -35,10 +35,10 @@ export const Filters = (props: { drawerAnchor?: 'left' | 'right' | 'top' | 'bottom'; }; }) => { - const isScreenSmallerThanBreakpoint = useMediaQuery(theme => + const isScreenSmallerThanBreakpoint = useMediaQuery((theme: Theme) => theme.breakpoints.down(props.options?.drawerBreakpoint ?? 'md'), ); - const theme = useTheme(); + const theme = useTheme(); const [filterDrawerOpen, setFilterDrawerOpen] = useState(false); return isScreenSmallerThanBreakpoint ? ( diff --git a/plugins/catalog-react/src/components/EntityAutocompletePicker/EntityAutocompletePicker.tsx b/plugins/catalog-react/src/components/EntityAutocompletePicker/EntityAutocompletePicker.tsx index 3eaba51909..98e680aa12 100644 --- a/plugins/catalog-react/src/components/EntityAutocompletePicker/EntityAutocompletePicker.tsx +++ b/plugins/catalog-react/src/components/EntityAutocompletePicker/EntityAutocompletePicker.tsx @@ -130,7 +130,7 @@ export function EntityAutocompletePicker< {label} - multiple disableCloseOnSelect options={availableOptions} diff --git a/plugins/catalog-react/src/components/EntityProcessingStatusPicker/EntityProcessingStatusPicker.tsx b/plugins/catalog-react/src/components/EntityProcessingStatusPicker/EntityProcessingStatusPicker.tsx index 01a6e0188d..7b8a35d162 100644 --- a/plugins/catalog-react/src/components/EntityProcessingStatusPicker/EntityProcessingStatusPicker.tsx +++ b/plugins/catalog-react/src/components/EntityProcessingStatusPicker/EntityProcessingStatusPicker.tsx @@ -72,7 +72,7 @@ export const EntityProcessingStatusPicker = () => { Processing Status - multiple disableCloseOnSelect options={availableAdvancedItems} diff --git a/plugins/catalog-react/src/components/MissingAnnotationEmptyState/MissingAnnotationEmptyState.tsx b/plugins/catalog-react/src/components/MissingAnnotationEmptyState/MissingAnnotationEmptyState.tsx index 284025d8cd..4d9329e664 100644 --- a/plugins/catalog-react/src/components/MissingAnnotationEmptyState/MissingAnnotationEmptyState.tsx +++ b/plugins/catalog-react/src/components/MissingAnnotationEmptyState/MissingAnnotationEmptyState.tsx @@ -14,7 +14,6 @@ * limitations under the License. */ -import { BackstageTheme } from '@backstage/theme'; import Box from '@material-ui/core/Box'; import Button from '@material-ui/core/Button'; import { makeStyles } from '@material-ui/core/styles'; @@ -27,7 +26,7 @@ import { useEntity } from '../../hooks'; /** @public */ export type MissingAnnotationEmptyStateClassKey = 'code'; -const useStyles = makeStyles( +const useStyles = makeStyles( theme => ({ code: { borderRadius: 6, diff --git a/plugins/catalog-react/src/components/UserListPicker/UserListPicker.test.tsx b/plugins/catalog-react/src/components/UserListPicker/UserListPicker.test.tsx index ad56681d6c..5667447503 100644 --- a/plugins/catalog-react/src/components/UserListPicker/UserListPicker.test.tsx +++ b/plugins/catalog-react/src/components/UserListPicker/UserListPicker.test.tsx @@ -40,6 +40,7 @@ import { storageApiRef, } from '@backstage/core-plugin-api'; import { MockStarredEntitiesApi, starredEntitiesApiRef } from '../../apis'; +import { DefaultEntityFilters } from '../../hooks'; const mockUser: UserEntity = { apiVersion: 'backstage.io/v1alpha1', @@ -289,7 +290,12 @@ describe('', () => { const updateFilters = jest.fn(); render( - + , @@ -297,6 +303,25 @@ describe('', () => { fireEvent.click(screen.getByText('Starred')); + // wait until the component has finished loading + await waitFor(() => { + expect(mockCatalogApi.queryEntities).toHaveBeenCalledWith({ + filter: { kind: 'component', 'metadata.name': ['e-1', 'e-2'] }, + limit: 1000, + }); + expect(mockCatalogApi.queryEntities).toHaveBeenCalledWith({ + filter: { kind: 'component' }, + limit: 0, + }); + expect(mockCatalogApi.queryEntities).toHaveBeenCalledWith({ + filter: { + kind: 'component', + 'relations.ownedBy': ['user:default/testuser'], + }, + limit: 0, + }); + }); + await waitFor(() => expect(updateFilters).toHaveBeenLastCalledWith({ user: EntityUserFilter.starred([ @@ -360,12 +385,17 @@ describe('', () => { describe('filter resetting', () => { const updateFilters = jest.fn(); - const Picker = ({ ...props }: UserListPickerProps) => ( + const Picker = ({ + filters, + ...props + }: UserListPickerProps & { filters?: DefaultEntityFilters }) => ( @@ -413,6 +443,21 @@ describe('', () => { }); }); + it('does not reset the filter when request is empty', async () => { + render(); + + await waitFor(() => { + expect(mockCatalogApi.queryEntities).toHaveBeenCalledTimes(1); + expect(mockCatalogApi.queryEntities).toHaveBeenCalledWith({ + filter: { 'metadata.name': ['e-1', 'e-2'] }, + limit: 1000, + }); + }); + expect(updateFilters).not.toHaveBeenCalledWith({ + user: expect.any(Object), + }); + }); + it('resets the filter to "all" when entities are loaded', async () => { mockCatalogApi.queryEntities?.mockImplementation(async request => { if ( @@ -541,6 +586,21 @@ describe('', () => { }), ); }); + + it('does not reset the filter when request is empty xxxx', async () => { + render(); + + await waitFor(() => { + expect(mockCatalogApi.queryEntities).toHaveBeenCalledTimes(1); + expect(mockCatalogApi.queryEntities).toHaveBeenCalledWith({ + filter: { 'metadata.name': ['e-1', 'e-2'] }, + limit: 1000, + }); + }); + expect(updateFilters).not.toHaveBeenCalledWith({ + user: expect.any(Object), + }); + }); }); describe(`when there are some starred entities present`, () => { diff --git a/plugins/catalog-react/src/components/UserListPicker/UserListPicker.tsx b/plugins/catalog-react/src/components/UserListPicker/UserListPicker.tsx index 854a1cb1b7..950bf5ea70 100644 --- a/plugins/catalog-react/src/components/UserListPicker/UserListPicker.tsx +++ b/plugins/catalog-react/src/components/UserListPicker/UserListPicker.tsx @@ -27,7 +27,6 @@ import { ListItemText, makeStyles, MenuItem, - Theme, Typography, } from '@material-ui/core'; import SettingsIcon from '@material-ui/icons/Settings'; @@ -48,7 +47,7 @@ export type CatalogReactUserListPickerClassKey = | 'menuItem' | 'groupWrapper'; -const useStyles = makeStyles( +const useStyles = makeStyles( theme => ({ root: { backgroundColor: 'rgba(0, 0, 0, .11)', @@ -243,7 +242,6 @@ export const UserListPicker = (props: UserListPickerProps) => { setSelectedUserFilter(item.id)} selected={item.id === filters.user?.value} diff --git a/plugins/catalog-react/src/components/UserListPicker/useOwnedEntitiesCount.test.tsx b/plugins/catalog-react/src/components/UserListPicker/useOwnedEntitiesCount.test.tsx index 1f6fbfd53d..aeaa20c535 100644 --- a/plugins/catalog-react/src/components/UserListPicker/useOwnedEntitiesCount.test.tsx +++ b/plugins/catalog-react/src/components/UserListPicker/useOwnedEntitiesCount.test.tsx @@ -93,8 +93,8 @@ describe('useOwnedEntitiesCount', () => { ).rejects.toThrow(); expect(result.current).toEqual({ - count: 0, - loading: false, + count: undefined, + loading: true, filter: EntityUserFilter.owned([ 'user:default/spiderman', 'user:group/a-group', diff --git a/plugins/catalog-react/src/components/UserListPicker/useOwnedEntitiesCount.ts b/plugins/catalog-react/src/components/UserListPicker/useOwnedEntitiesCount.ts index 1adab49361..2f03a0b285 100644 --- a/plugins/catalog-react/src/components/UserListPicker/useOwnedEntitiesCount.ts +++ b/plugins/catalog-react/src/components/UserListPicker/useOwnedEntitiesCount.ts @@ -14,16 +14,16 @@ * limitations under the License. */ -import { QueryEntitiesInitialRequest } from '@backstage/catalog-client'; import { identityApiRef, useApi } from '@backstage/core-plugin-api'; -import { compact, intersection, isEqual } from 'lodash'; -import { useEffect, useMemo, useRef } from 'react'; +import { compact, intersection } from 'lodash'; +import { useMemo } from 'react'; import useAsync from 'react-use/lib/useAsync'; import { catalogApiRef } from '../../api'; import { EntityOwnerFilter, EntityUserFilter } from '../../filters'; import { useEntityList } from '../../hooks'; import { reduceCatalogFilters } from '../../utils'; import useAsyncFn from 'react-use/lib/useAsyncFn'; +import useDeepCompareEffect from 'react-use/lib/useDeepCompareEffect'; export function useOwnedEntitiesCount() { const identityApi = useApi(identityApiRef); @@ -37,79 +37,63 @@ export function useOwnedEntitiesCount() { [], ); - const prevRequest = useRef(); - - const request = useMemo(() => { - const { user, owners, ...allFilters } = filters; - const compacted = compact(Object.values(allFilters)); - const allFilter = reduceCatalogFilters(compacted); - const { ['metadata.name']: metadata, ...filter } = allFilter; - - const countFilter = getOwnedCountClaims(owners, ownershipEntityRefs); - - if ( - ownershipEntityRefs?.length === 0 || - countFilter === undefined || - Object.keys(filter).length === 0 - ) { - prevRequest.current = undefined; - return undefined; - } - const newRequest: QueryEntitiesInitialRequest = { - filter: { - ...filter, - 'relations.ownedBy': countFilter, - }, - limit: 0, - }; - - if (isEqual(newRequest, prevRequest.current)) { - return prevRequest.current; - } - - prevRequest.current = newRequest; - - return newRequest; - }, [filters, ownershipEntityRefs]); + const { user, owners, ...allFilters } = filters; + const { ['metadata.name']: metadata, ...filter } = reduceCatalogFilters( + compact(Object.values(allFilters)), + ); const [{ value: count, loading: loadingEntityOwnership }, fetchEntities] = useAsyncFn( - async ( - req: QueryEntitiesInitialRequest | undefined, - ownershipEntityRefsParam: string[], - ) => { - if (ownershipEntityRefsParam && !req) { + async (req: { + ownershipEntityRefs: string[]; + owners: EntityOwnerFilter | undefined; + filter: Record; + }) => { + const ownedClaims = getOwnedCountClaims( + req.owners, + req.ownershipEntityRefs, + ); + if (ownedClaims === undefined) { // this implicitly means that there aren't claims in common with // the logged in users, so avoid invoking the queryEntities endpoint // which will implicitly returns 0 return 0; } - const { totalItems } = await catalogApi.queryEntities(req); + + const { totalItems } = await catalogApi.queryEntities({ + filter: { + ...req.filter, + 'relations.ownedBy': ownedClaims, + }, + limit: 0, + }); return totalItems; }, [], { loading: true }, ); - useEffect(() => { - if (ownershipEntityRefs) { - if (request && Object.keys(request).length === 0) { - return; - } - fetchEntities(request, ownershipEntityRefs); + useDeepCompareEffect(() => { + // context contains no filter, wait + if (Object.keys(filter).length === 0) { + return; } - }, [fetchEntities, request, ownershipEntityRefs]); + // ownershipEntityRefs is loading, wait + if (ownershipEntityRefs === undefined) { + return; + } + fetchEntities({ ownershipEntityRefs, owners, filter }); + }, [ownershipEntityRefs, owners, filter]); const loading = loadingEntityRefs || loadingEntityOwnership; - const filter = useMemo( - () => EntityUserFilter.owned(ownershipEntityRefs ?? []), - [ownershipEntityRefs], - ); return { count, loading, - filter, + filter: useMemo( + () => EntityUserFilter.owned(ownershipEntityRefs ?? []), + [ownershipEntityRefs], + ), ownershipEntityRefs, }; } diff --git a/plugins/catalog-react/src/hooks/index.ts b/plugins/catalog-react/src/hooks/index.ts index ffd32206ef..c3021f8992 100644 --- a/plugins/catalog-react/src/hooks/index.ts +++ b/plugins/catalog-react/src/hooks/index.ts @@ -32,6 +32,7 @@ export { export type { DefaultEntityFilters, EntityListContextProps, + EntityListProviderProps, } from './useEntityListProvider'; export { useEntityTypeFilter } from './useEntityTypeFilter'; export { useRelatedEntities } from './useRelatedEntities'; diff --git a/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx b/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx index edbfb65c0c..f6881d4a80 100644 --- a/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx +++ b/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx @@ -31,14 +31,13 @@ import React, { PropsWithChildren } from 'react'; import { MemoryRouter } from 'react-router-dom'; import { catalogApiRef } from '../api'; import { starredEntitiesApiRef, MockStarredEntitiesApi } from '../apis'; -import { EntityKindPicker, UserListPicker } from '../components'; import { EntityKindFilter, EntityTypeFilter, EntityUserFilter, } from '../filters'; -import { UserListFilterKind } from '../types'; import { EntityListProvider, useEntityList } from './useEntityListProvider'; +import { useMountEffect } from '@react-hookz/web'; const entities: Entity[] = [ { @@ -77,43 +76,53 @@ const mockIdentityApi: Partial = { }), getCredentials: async () => ({ token: undefined }), }; -const mockCatalogApi: Partial = { - getEntities: jest.fn().mockImplementation(async () => ({ items: entities })), - getEntityByRef: async () => undefined, +const mockCatalogApi: Partial> = { + getEntities: jest.fn().mockResolvedValue({ items: entities }), + queryEntities: jest.fn().mockResolvedValue({ + items: entities, + pageInfo: { prevCursor: 'prevCursor', nextCursor: 'nextCursor' }, + totalItems: 10, + }), + getEntityByRef: jest.fn().mockResolvedValue(undefined), }; -const wrapper = ({ - userFilter, - location, - children, -}: PropsWithChildren<{ - userFilter?: UserListFilterKind; - location?: string; -}>) => { - return ( - - - - - - - ); -}; +const createWrapper = + (options: { location?: string; pagination: boolean }) => + (props: PropsWithChildren) => { + const InitialFiltersWrapper = ({ children }: PropsWithChildren) => { + const { updateFilters } = useEntityList(); + + useMountEffect(() => { + updateFilters({ kind: new EntityKindFilter('component') }); + }); + + return <>{children}; + }; + + return ( + + + + {props.children} + + + + ); + }; describe('', () => { const origReplaceState = window.history.replaceState; + const pagination = false; + beforeEach(() => { window.history.replaceState = jest.fn(); }); @@ -125,16 +134,17 @@ describe('', () => { jest.clearAllMocks(); }); - it('resolves backend filters', async () => { + it('should send backend filters', async () => { const { result } = renderHook(() => useEntityList(), { - wrapper, + wrapper: createWrapper({ pagination }), }); await waitFor(() => { - expect(result.current.backendEntities.length).toBeGreaterThan(0); + expect(result.current.backendEntities.length).toBe(2); }); - expect(result.current.backendEntities.length).toBe(2); + expect(result.current.entities.length).toBe(2); + expect(mockCatalogApi.getEntities).toHaveBeenCalledTimes(1); expect(mockCatalogApi.getEntities).toHaveBeenCalledWith({ filter: { kind: 'component' }, }); @@ -142,17 +152,12 @@ describe('', () => { it('resolves frontend filters', async () => { const { result } = renderHook(() => useEntityList(), { - wrapper, + wrapper: createWrapper({ pagination }), initialProps: { userFilter: 'all', }, }); - await waitFor(() => { - expect(result.current.backendEntities.length).toBeGreaterThan(0); - }); - expect(result.current.backendEntities.length).toBe(2); - act(() => result.current.updateFilters({ user: EntityUserFilter.owned(ownershipEntityRefs), @@ -171,8 +176,10 @@ describe('', () => { filters: { kind: 'component', type: 'service' }, }); const { result } = renderHook(() => useEntityList(), { - wrapper: ({ children }) => - wrapper({ location: `/catalog?${query}`, children }), + wrapper: createWrapper({ + location: `/catalog?${query}`, + pagination, + }), }); await waitFor(() => { @@ -186,7 +193,7 @@ describe('', () => { it('does not fetch when only frontend filters change', async () => { const { result } = renderHook(() => useEntityList(), { - wrapper, + wrapper: createWrapper({ pagination }), }); await waitFor(() => { @@ -202,13 +209,18 @@ describe('', () => { await waitFor(() => { expect(result.current.entities.length).toBe(1); - expect(mockCatalogApi.getEntities).toHaveBeenCalledTimes(1); }); + + await expect(() => + waitFor(() => { + expect(mockCatalogApi.getEntities).not.toHaveBeenCalledTimes(1); + }), + ).rejects.toThrow(); }); it('debounces multiple filter changes', async () => { const { result } = renderHook(() => useEntityList(), { - wrapper, + wrapper: createWrapper({ pagination }), }); await waitFor(() => { @@ -218,18 +230,20 @@ describe('', () => { expect(mockCatalogApi.getEntities).toHaveBeenCalledTimes(1); await act(async () => { - result.current.updateFilters({ kind: new EntityKindFilter('component') }); + result.current.updateFilters({ kind: new EntityKindFilter('api') }); result.current.updateFilters({ type: new EntityTypeFilter('service') }); }); await waitFor(() => { - expect(mockCatalogApi.getEntities).toHaveBeenCalledTimes(2); + expect(mockCatalogApi.getEntities).toHaveBeenNthCalledWith(2, { + filter: { kind: 'api', 'spec.type': ['service'] }, + }); }); }); it('returns an error on catalogApi failure', async () => { const { result } = renderHook(() => useEntityList(), { - wrapper, + wrapper: createWrapper({ pagination }), }); await waitFor(() => { @@ -237,7 +251,7 @@ describe('', () => { }); expect(result.current.backendEntities.length).toBe(2); - mockCatalogApi.getEntities = jest.fn().mockRejectedValue('error'); + mockCatalogApi.getEntities!.mockRejectedValueOnce('error'); act(() => { result.current.updateFilters({ kind: new EntityKindFilter('api') }); }); @@ -245,4 +259,230 @@ describe('', () => { expect(result.current.error).toBeDefined(); }); }); + + it('returns an empty pageInfo', async () => { + const { result } = renderHook(() => useEntityList(), { + wrapper: createWrapper({ pagination }), + }); + await waitFor(() => { + expect(mockCatalogApi.getEntities).toHaveBeenCalled(); + }); + + expect(result.current.pageInfo).toBeUndefined(); + }); +}); + +describe('', () => { + const origReplaceState = window.history.replaceState; + const pagination = true; + const limit = 20; + const orderFields = [{ field: 'metadata.name', order: 'asc' }]; + + beforeEach(() => { + window.history.replaceState = jest.fn(); + }); + afterEach(() => { + window.history.replaceState = origReplaceState; + }); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should send backend filters', async () => { + const { result } = renderHook(() => useEntityList(), { + wrapper: createWrapper({ pagination }), + }); + + await waitFor(() => { + expect(result.current.backendEntities.length).toBe(2); + }); + + expect(result.current.entities.length).toBe(2); + expect(mockCatalogApi.queryEntities).toHaveBeenCalledTimes(1); + expect(mockCatalogApi.queryEntities).toHaveBeenCalledWith({ + filter: { kind: 'component' }, + limit, + orderFields, + }); + }); + + it('resolves frontend filters', async () => { + const { result } = renderHook(() => useEntityList(), { + wrapper: createWrapper({ pagination }), + initialProps: { + userFilter: 'all', + }, + }); + + act(() => + result.current.updateFilters({ + user: EntityUserFilter.owned(ownershipEntityRefs), + }), + ); + + await waitFor(() => { + expect(result.current.backendEntities.length).toBe(2); + expect(result.current.entities.length).toBe(1); + expect(mockCatalogApi.queryEntities).toHaveBeenCalledTimes(1); + }); + }); + + it('resolves query param filter values', async () => { + const query = qs.stringify({ + filters: { kind: 'component', type: 'service' }, + }); + const { result } = renderHook(() => useEntityList(), { + wrapper: createWrapper({ + location: `/catalog?${query}`, + pagination, + }), + }); + + await waitFor(() => { + expect(result.current.queryParameters).toBeTruthy(); + }); + expect(result.current.queryParameters).toEqual({ + kind: 'component', + type: 'service', + }); + }); + + it('fetch when frontend filters change', async () => { + const { result } = renderHook(() => useEntityList(), { + wrapper: createWrapper({ pagination }), + }); + + await waitFor(() => { + expect(result.current.entities.length).toBe(2); + expect(mockCatalogApi.queryEntities).toHaveBeenCalledTimes(1); + }); + + act(() => + result.current.updateFilters({ + user: EntityUserFilter.owned(ownershipEntityRefs), + }), + ); + + await waitFor(() => { + expect(result.current.entities.length).toBe(1); + }); + + await waitFor(() => { + expect(mockCatalogApi.queryEntities).toHaveBeenCalledTimes(2); + }); + }); + + it('debounces multiple filter changes', async () => { + const { result } = renderHook(() => useEntityList(), { + wrapper: createWrapper({ pagination }), + }); + + await waitFor(() => { + expect(result.current.backendEntities.length).toBeGreaterThan(0); + }); + expect(result.current.backendEntities.length).toBe(2); + expect(mockCatalogApi.queryEntities).toHaveBeenCalledTimes(1); + + await act(async () => { + result.current.updateFilters({ kind: new EntityKindFilter('api') }); + result.current.updateFilters({ type: new EntityTypeFilter('service') }); + }); + + await waitFor(() => { + expect(mockCatalogApi.queryEntities).toHaveBeenNthCalledWith(2, { + filter: { kind: 'api', 'spec.type': ['service'] }, + limit, + orderFields, + }); + }); + }); + + it('returns an error on catalogApi failure', async () => { + const { result } = renderHook(() => useEntityList(), { + wrapper: createWrapper({ pagination }), + }); + + await waitFor(() => { + expect(result.current.backendEntities.length).toBeGreaterThan(0); + }); + expect(result.current.backendEntities.length).toBe(2); + + mockCatalogApi.queryEntities!.mockRejectedValueOnce('error'); + act(() => { + result.current.updateFilters({ kind: new EntityKindFilter('api') }); + }); + await waitFor(() => { + expect(result.current.error).toBeDefined(); + }); + }); + + describe('pageInfo', () => { + it('returns an empty pageInfo', async () => { + mockCatalogApi.queryEntities!.mockResolvedValueOnce({ + items: [], + pageInfo: {}, + totalItems: 10, + }); + const { result } = renderHook(() => useEntityList(), { + wrapper: createWrapper({ pagination }), + }); + await waitFor(() => { + expect(mockCatalogApi.queryEntities).toHaveBeenCalled(); + }); + + expect(result.current.pageInfo).toStrictEqual({ + prev: undefined, + next: undefined, + }); + }); + + it('returns pageInfo with next function and properly fetch next batch', async () => { + const { result } = renderHook(() => useEntityList(), { + wrapper: createWrapper({ pagination }), + }); + await waitFor(() => { + expect(mockCatalogApi.queryEntities).toHaveBeenCalled(); + }); + + await waitFor(() => { + expect(result.current.pageInfo!.next).toBeDefined(); + }); + + act(() => { + result.current.pageInfo!.next!(); + }); + + await waitFor(() => { + expect(mockCatalogApi.queryEntities).toHaveBeenCalledWith({ + cursor: 'nextCursor', + limit, + }); + }); + }); + + it('returns pageInfo with prev function and properly fetch prev batch', async () => { + const { result } = renderHook(() => useEntityList(), { + wrapper: createWrapper({ pagination }), + }); + await waitFor(() => { + expect(mockCatalogApi.queryEntities).toHaveBeenCalled(); + }); + + await waitFor(() => { + expect(result.current.pageInfo!.prev).toBeDefined(); + }); + + act(() => { + result.current.pageInfo!.prev!(); + }); + + await waitFor(() => { + expect(mockCatalogApi.queryEntities).toHaveBeenCalledWith({ + cursor: 'prevCursor', + limit, + }); + }); + }); + }); }); diff --git a/plugins/catalog-react/src/hooks/useEntityListProvider.tsx b/plugins/catalog-react/src/hooks/useEntityListProvider.tsx index 948efc969f..1ce87c262e 100644 --- a/plugins/catalog-react/src/hooks/useEntityListProvider.tsx +++ b/plugins/catalog-react/src/hooks/useEntityListProvider.tsx @@ -44,8 +44,13 @@ import { EntityUserFilter, } from '../filters'; import { EntityFilter } from '../types'; -import { reduceBackendCatalogFilters, reduceEntityFilters } from '../utils'; +import { + reduceBackendCatalogFilters, + reduceCatalogFilters, + reduceEntityFilters, +} from '../utils'; import { useApi } from '@backstage/core-plugin-api'; +import { QueryEntitiesResponse } from '@backstage/catalog-client'; /** @public */ export type DefaultEntityFilters = { @@ -98,6 +103,11 @@ export type EntityListContextProps< loading: boolean; error?: Error; + + pageInfo?: { + next?: () => void; + prev?: () => void; + }; }; /** @@ -110,16 +120,25 @@ export const EntityListContext = createContext< type OutputState = { appliedFilters: EntityFilters; + appliedCursor?: string; entities: Entity[]; backendEntities: Entity[]; + pageInfo?: QueryEntitiesResponse['pageInfo']; }; +/** + * @public + */ +export type EntityListProviderProps = PropsWithChildren<{ + pagination?: boolean | { limit?: number }; +}>; + /** * Provides entities and filters for a catalog listing. * @public */ export const EntityListProvider = ( - props: PropsWithChildren<{}>, + props: EntityListProviderProps, ) => { const isMounted = useMountedState(); const catalogApi = useApi(catalogApiRef); @@ -132,13 +151,32 @@ export const EntityListProvider = ( // trigger a useLocation change; this would instead come from an external source, such as a manual // update of the URL or two catalog sidebar links with different catalog filters. const location = useLocation(); - const queryParameters = useMemo( - () => - (qs.parse(location.search, { - ignoreQueryPrefix: true, - }).filters ?? {}) as Record, - [location], - ); + + const enablePagination = + props.pagination === true || typeof props.pagination === 'object'; + + const limit = + props.pagination && + typeof props.pagination === 'object' && + typeof props.pagination.limit === 'number' + ? props.pagination.limit + : 20; + + const { queryParameters, cursor: initialCursor } = useMemo(() => { + const parsed = qs.parse(location.search, { + ignoreQueryPrefix: true, + }); + + return { + queryParameters: (parsed.filters ?? {}) as Record< + string, + string | string[] + >, + cursor: typeof parsed.cursor === 'string' ? parsed.cursor : undefined, + }; + }, [location]); + + const [cursor, setCursor] = useState(initialCursor); const [outputState, setOutputState] = useState>( () => { @@ -146,6 +184,7 @@ export const EntityListProvider = ( appliedFilters: {} as EntityFilters, entities: [], backendEntities: [], + pageInfo: enablePagination ? {} : undefined, }; }, ); @@ -156,11 +195,6 @@ export const EntityListProvider = ( const [{ loading, error }, refresh] = useAsyncFn( async () => { const compacted = compact(Object.values(requestedFilters)); - const entityFilter = reduceEntityFilters(compacted); - const backendFilter = reduceBackendCatalogFilters(compacted); - const previousBackendFilter = reduceBackendCatalogFilters( - compact(Object.values(outputState.appliedFilters)), - ); const queryParams = Object.keys(requestedFilters).reduce( (params, key) => { @@ -175,26 +209,71 @@ export const EntityListProvider = ( {} as Record, ); - // TODO(mtlewis): currently entities will never be requested unless - // there's at least one filter, we should allow an initial request - // to happen with no filters. - if (!isEqual(previousBackendFilter, backendFilter)) { - // TODO(timbonicus): should limit fields here, but would need filter - // fields + table columns - const response = await catalogApi.getEntities({ - filter: backendFilter, - }); - setOutputState({ - appliedFilters: requestedFilters, - backendEntities: response.items, - entities: response.items.filter(entityFilter), - }); + if (enablePagination) { + if (cursor) { + if (cursor !== outputState.appliedCursor) { + const entityFilter = reduceEntityFilters(compacted); + const response = await catalogApi.queryEntities({ + cursor, + limit, + }); + setOutputState({ + appliedFilters: requestedFilters, + appliedCursor: cursor, + backendEntities: response.items, + entities: response.items.filter(entityFilter), + pageInfo: response.pageInfo, + }); + } + } else { + const entityFilter = reduceEntityFilters(compacted); + const backendFilter = reduceCatalogFilters(compacted); + const previousBackendFilter = reduceCatalogFilters( + compact(Object.values(outputState.appliedFilters)), + ); + + if (!isEqual(previousBackendFilter, backendFilter)) { + const response = await catalogApi.queryEntities({ + filter: backendFilter, + limit, + orderFields: [{ field: 'metadata.name', order: 'asc' }], + }); + setOutputState({ + appliedFilters: requestedFilters, + backendEntities: response.items, + entities: response.items.filter(entityFilter), + pageInfo: response.pageInfo, + }); + } + } } else { - setOutputState({ - appliedFilters: requestedFilters, - backendEntities: outputState.backendEntities, - entities: outputState.backendEntities.filter(entityFilter), - }); + const entityFilter = reduceEntityFilters(compacted); + const backendFilter = reduceBackendCatalogFilters(compacted); + const previousBackendFilter = reduceBackendCatalogFilters( + compact(Object.values(outputState.appliedFilters)), + ); + + // TODO(mtlewis): currently entities will never be requested unless + // there's at least one filter, we should allow an initial request + // to happen with no filters. + if (!isEqual(previousBackendFilter, backendFilter)) { + // TODO(timbonicus): should limit fields here, but would need filter + // fields + table columns + const response = await catalogApi.getEntities({ + filter: backendFilter, + }); + setOutputState({ + appliedFilters: requestedFilters, + backendEntities: response.items, + entities: response.items.filter(entityFilter), + }); + } else { + setOutputState({ + appliedFilters: requestedFilters, + backendEntities: outputState.backendEntities, + entities: outputState.backendEntities.filter(entityFilter), + }); + } } if (isMounted()) { @@ -202,7 +281,7 @@ export const EntityListProvider = ( ignoreQueryPrefix: true, }); const newParams = qs.stringify( - { ...oldParams, filters: queryParams }, + { ...oldParams, filters: queryParams, cursor }, { addQueryPrefix: true, arrayFormat: 'repeat' }, ); const newUrl = `${window.location.pathname}${newParams}`; @@ -214,13 +293,20 @@ export const EntityListProvider = ( window.history?.replaceState(null, document.title, newUrl); } }, - [catalogApi, queryParameters, requestedFilters, outputState], + [ + catalogApi, + queryParameters, + requestedFilters, + outputState, + cursor, + enablePagination, + ], { loading: true }, ); // Slight debounce on the refresh, since (especially on page load) several // filters will be calling this in rapid succession. - useDebounce(refresh, 10, [requestedFilters]); + useDebounce(refresh, 10, [requestedFilters, cursor]); const updateFilters = useCallback( ( @@ -228,6 +314,12 @@ export const EntityListProvider = ( | Partial | ((prevFilters: EntityFilters) => Partial), ) => { + // changing filters will affect pagination, so we need to reset + // the cursor and start from the first page. + // TODO(vinzscam): this is currently causing issues at page reload + // where the state is not kept. Unfortunately we need to rething + // the way filters work in order to fix this. + setCursor(undefined); setRequestedFilters(prevFilters => { const newFilters = typeof update === 'function' ? update(prevFilters) : update; @@ -237,6 +329,19 @@ export const EntityListProvider = ( [], ); + const pageInfo = useMemo(() => { + if (!enablePagination) { + return undefined; + } + + const prevCursor = outputState.pageInfo?.prevCursor; + const nextCursor = outputState.pageInfo?.nextCursor; + return { + prev: prevCursor ? () => setCursor(prevCursor) : undefined, + next: nextCursor ? () => setCursor(nextCursor) : undefined, + }; + }, [enablePagination, outputState.pageInfo]); + const value = useMemo( () => ({ filters: outputState.appliedFilters, @@ -246,8 +351,9 @@ export const EntityListProvider = ( queryParameters, loading, error, + pageInfo, }), - [outputState, updateFilters, queryParameters, loading, error], + [outputState, updateFilters, queryParameters, loading, error, pageInfo], ); return ( diff --git a/plugins/catalog-react/src/overridableComponents.ts b/plugins/catalog-react/src/overridableComponents.ts index e94af1c4fb..6424c95ab5 100644 --- a/plugins/catalog-react/src/overridableComponents.ts +++ b/plugins/catalog-react/src/overridableComponents.ts @@ -44,3 +44,8 @@ export type BackstageOverrides = Overrides & { StyleRules >; }; + +declare module '@backstage/theme' { + interface OverrideComponentNameToClassKeys + extends CatalogReactComponentsNameToClassKey {} +} diff --git a/plugins/catalog-unprocessed-entities/CHANGELOG.md b/plugins/catalog-unprocessed-entities/CHANGELOG.md index 97184a50cd..9a2be34228 100644 --- a/plugins/catalog-unprocessed-entities/CHANGELOG.md +++ b/plugins/catalog-unprocessed-entities/CHANGELOG.md @@ -1,5 +1,105 @@ # @backstage/plugin-catalog-unprocessed-entities +## 0.1.7 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.1.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.1.7-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + +## 0.1.6 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.1.6-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + +## 0.1.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + +## 0.1.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## 0.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.1.5 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- a11cdb9200: Added filtering and sorting to unprocessed entities tables. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + ## 0.1.5-next.2 ### Patch Changes diff --git a/plugins/catalog-unprocessed-entities/package.json b/plugins/catalog-unprocessed-entities/package.json index 50a27c05c6..d3b037788a 100644 --- a/plugins/catalog-unprocessed-entities/package.json +++ b/plugins/catalog-unprocessed-entities/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-unprocessed-entities", - "version": "0.1.5-next.2", + "version": "0.1.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,7 +33,6 @@ "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.9.13", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "^4.0.0-alpha.60", @@ -47,13 +46,9 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", "@backstage/dev-utils": "workspace:^", - "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "msw": "^1.0.0" + "@testing-library/react": "^14.0.0" }, "files": [ "dist" diff --git a/plugins/catalog/CHANGELOG.md b/plugins/catalog/CHANGELOG.md index 7d1b4820bc..a34341d585 100644 --- a/plugins/catalog/CHANGELOG.md +++ b/plugins/catalog/CHANGELOG.md @@ -1,5 +1,312 @@ # @backstage/plugin-catalog +## 1.16.1 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-compat-api@0.1.1 + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/plugin-scaffolder-common@1.4.5 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/plugin-search-react@1.7.5 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.20 + - @backstage/plugin-search-common@1.2.10 + +## 1.16.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.1.1-next.2 + - @backstage/frontend-plugin-api@0.4.1-next.2 + - @backstage/plugin-catalog-react@1.9.3-next.2 + - @backstage/plugin-search-react@1.7.5-next.2 + - @backstage/integration-react@1.1.23-next.0 + +## 1.16.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/core-compat-api@0.1.1-next.1 + - @backstage/frontend-plugin-api@0.4.1-next.1 + - @backstage/integration-react@1.1.23-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/plugin-permission-react@0.4.19-next.1 + - @backstage/plugin-search-react@1.7.5-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-scaffolder-common@1.4.4 + - @backstage/plugin-search-common@1.2.9 + +## 1.16.1-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/frontend-plugin-api@0.4.1-next.0 + - @backstage/plugin-permission-react@0.4.19-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/integration-react@1.1.22 + - @backstage/plugin-search-react@1.7.5-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-compat-api@0.1.1-next.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-scaffolder-common@1.4.4 + - @backstage/plugin-search-common@1.2.9 + +## 1.16.0 + +### Minor Changes + +- e223f22: Properly support both function- and string-form visibility filter expressions in the new extensions exported via `/alpha`. +- b8e1eb2: The `columns` prop can be an array or a function that returns an array in order to override the default columns of the `CatalogIndexPage`. + +### Patch Changes + +- bc7e6d3: Fix copy entity url function in http contexts. +- 5360097: Ensure that passed-in icons are taken advantage of in the presentation API +- 4785d05: Add permission check to catalog create and refresh button +- cd910c4: - Fixes bug where after unregistering an entity you are redirected to `/`. + - Adds an optional external route `unregisterRedirect` to override this behaviour to another route. +- 03d0b6d: The `convertLegacyRouteRef` utility used by the alpha exports is now imported from `@backstage/core-compat-api`. +- 2d708d8: Internal naming updates for `/alpha` exports. +- a5a0473: Internal refactor of alpha exports due to a change in how extension factories are defined. +- 4d9e3b3: Register component overrides in the global `OverrideComponentNameToClassKeys` provided by `@backstage/theme`. This will in turn will provide component style override types for `createUnifiedTheme`. +- a1227cc: Wrap `/alpha` export extension elements in backwards compatibility wrapper. +- 78a10bb: Adding in spec.type chip to search results for clarity +- 8f5d6c1: Updates to the `/alpha` exports to match the extension input wrapping change. +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- 8587f06: Added pagination support to `CatalogIndexPage` + + `CatalogIndexPage` now offers an optional pagination feature, designed to accommodate adopters managing extensive catalogs. This new capability allows for better handling of large amounts of data. + + To activate the pagination mode, simply update your `App.tsx` as follows: + + ```diff + const routes = ( + + ... + - } /> + + } /> + ... + ``` + + In case you have a custom catalog page and you want to enable pagination, you need to pass the `pagination` prop to `EntityListProvider` instead. + +- fb8f3bd: Updated alpha translation message keys to use nested format and camel case. +- 531e1a2: Updated alpha plugin to include the `unregisterRedirect` external route. +- Updated dependencies + - @backstage/core-compat-api@0.1.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/frontend-plugin-api@0.4.0 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-client@1.5.0 + - @backstage/plugin-search-react@1.7.4 + - @backstage/integration-react@1.1.22 + - @backstage/plugin-permission-react@0.4.18 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-scaffolder-common@1.4.4 + - @backstage/plugin-search-common@1.2.9 + +## 1.16.0-next.4 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/core-compat-api@0.1.0-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/frontend-plugin-api@0.4.0-next.3 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-react@1.9.2-next.3 + - @backstage/plugin-scaffolder-common@1.4.3 + - @backstage/plugin-search-common@1.2.8 + - @backstage/plugin-search-react@1.7.4-next.3 + +## 1.16.0-next.3 + +### Patch Changes + +- a1227cc: Wrap `/alpha` export extension elements in backwards compatibility wrapper. +- 8f5d6c1: Updates to the `/alpha` exports to match the extension input wrapping change. +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.2 + - @backstage/theme@0.5.0-next.1 + - @backstage/core-compat-api@0.1.0-next.2 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/plugin-search-react@1.7.4-next.2 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-scaffolder-common@1.4.3 + - @backstage/plugin-search-common@1.2.8 + +## 1.16.0-next.2 + +### Minor Changes + +- e223f2264d: Properly support both function- and string-form visibility filter expressions in the new extensions exported via `/alpha`. + +### Patch Changes + +- 53600976bb: Ensure that passed-in icons are taken advantage of in the presentation API +- a5a04739e1: Internal refactor of alpha exports due to a change in how extension factories are defined. +- 78a10bb085: Adding in spec.type chip to search results for clarity +- fb8f3bdbc2: Updated alpha translation message keys to use nested format and camel case. +- 531e1a2a79: Updated alpha plugin to include the `unregisterRedirect` external route. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/plugin-search-react@1.7.4-next.1 + - @backstage/core-compat-api@0.0.1-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-scaffolder-common@1.4.3 + - @backstage/plugin-search-common@1.2.8 + +## 1.16.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.0.1-next.0 + +## 1.16.0-next.0 + +### Minor Changes + +- b8e1eb2c0f: The `columns` prop can be an array or a function that returns an array in order to override the default columns of the `CatalogIndexPage`. + +### Patch Changes + +- bc7e6d3eb9: Fix copy entity url function in http contexts. +- cd910c4fa5: - Fixes bug where after unregistering an entity you are redirected to `/`. + - Adds an optional external route `unregisterRedirect` to override this behaviour to another route. +- 03d0b6dcdc: The `convertLegacyRouteRef` utility used by the alpha exports is now imported from `@backstage/core-compat-api`. +- 4d9e3b39e4: Register component overrides in the global `OverrideComponentNameToClassKeys` provided by `@backstage/theme`. This will in turn will provide component style override types for `createUnifiedTheme`. +- 8587f067d2: Added pagination support to `CatalogIndexPage` + + `CatalogIndexPage` now offers an optional pagination feature, designed to accommodate adopters managing extensive catalogs. This new capability allows for better handling of large amounts of data. + + To activate the pagination mode, simply update your `App.tsx` as follows: + + ```diff + const routes = ( + + ... + - } /> + + } /> + ... + ``` + + In case you have a custom catalog page and you want to enable pagination, you need to pass the `pagination` prop to `EntityListProvider` instead. + +- Updated dependencies + - @backstage/core-compat-api@0.0.2-next.0 + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/plugin-search-react@1.7.4-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/frontend-plugin-api@0.3.1-next.0 + - @backstage/integration-react@1.1.22-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-scaffolder-common@1.4.3 + - @backstage/plugin-search-common@1.2.8 + +## 1.15.0 + +### Minor Changes + +- 1e5b7d993a: Added the `DefaultEntityPresentationApi`, which is an implementation of the + `EntityPresentationApi` that `@backstage/plugin-catalog-react` exposes through + its `entityPresentationApiRef`. This implementation is also by default made + available automatically by the catalog plugin, unless you replace it with a + custom one. It batch fetches and caches data from the catalog as needed for + display, and is customizable by adopters to add their own rendering functions. + +### Patch Changes + +- eb817ee6d4: Fix spacing inconsistency with links and labels in headers +- 8a8445663b: Migrate catalog entity cards to new frontend system extension format. +- e964c17db9: Use default extensions boundary and suspense on the alpha declarative `createCatalogFilterExtension` extension factory. +- 71c97e7d73: The `spec.lifecycle' field in entities will now always be rendered as a string. +- 6c2b872153: Add official support for React 18. +- 0bf6ebda88: Initial entity page implementation for new frontend system at `/alpha`, with an overview page enabled by default and the about card available as an optional card. +- bb98953cb9: Create declarative extensions for the `Catalog` plugin; this initial plugin preset contains sidebar item, index page and filter extensions, all distributed via `/alpha` subpath. + + The `EntityPage` will be migrated in a follow-up patch. + +- 7c265b9758: Fix type error on `CatalogTable` when using Material UI v5 +- 69c14904b6: Use `EntityRefLinks` with `hideIcons` property to avoid double icons +- 62b5922916: Internal theme type updates +- 77f009b35d: Internal updates to match changes in the experimental `@backstage/frontend-plugin-api`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/frontend-plugin-api@0.3.0 + - @backstage/plugin-scaffolder-common@1.4.3 + - @backstage/integration-react@1.1.21 + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-search-react@1.7.2 + - @backstage/theme@0.4.4 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-search-common@1.2.8 + ## 1.15.0-next.2 ### Patch Changes diff --git a/plugins/catalog/alpha-api-report.md b/plugins/catalog/api-report-alpha.md similarity index 87% rename from plugins/catalog/alpha-api-report.md rename to plugins/catalog/api-report-alpha.md index 43e589bdc3..3226d10270 100644 --- a/plugins/catalog/alpha-api-report.md +++ b/plugins/catalog/api-report-alpha.md @@ -7,7 +7,7 @@ import { AnyExtensionInputMap } from '@backstage/frontend-plugin-api'; import { BackstagePlugin } from '@backstage/frontend-plugin-api'; -import { Extension } from '@backstage/frontend-plugin-api'; +import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { ExternalRouteRef } from '@backstage/frontend-plugin-api'; import { PortableSchema } from '@backstage/frontend-plugin-api'; import { RouteRef } from '@backstage/frontend-plugin-api'; @@ -17,11 +17,12 @@ export function createCatalogFilterExtension< TInputs extends AnyExtensionInputMap, TConfig = never, >(options: { - id: string; + namespace?: string; + name?: string; inputs?: TInputs; configSchema?: PortableSchema; loader: (options: { config: TConfig }) => Promise; -}): Extension; +}): ExtensionDefinition; // @alpha (undocumented) const _default: BackstagePlugin< @@ -50,6 +51,7 @@ const _default: BackstagePlugin< }, true >; + unregisterRedirect: ExternalRouteRef; } >; export default _default; diff --git a/plugins/catalog/api-report.md b/plugins/catalog/api-report.md index 6647f8deaa..bef24b50d8 100644 --- a/plugins/catalog/api-report.md +++ b/plugins/catalog/api-report.md @@ -11,6 +11,7 @@ import { CatalogApi } from '@backstage/plugin-catalog-react'; import { ComponentEntity } from '@backstage/catalog-model'; import { CompoundEntityRef } from '@backstage/catalog-model'; import { Entity } from '@backstage/catalog-model'; +import { EntityListContextProps } from '@backstage/plugin-catalog-react'; import { EntityOwnerPickerProps } from '@backstage/plugin-catalog-react'; import { EntityPresentationApi } from '@backstage/plugin-catalog-react'; import { EntityRefPresentation } from '@backstage/plugin-catalog-react'; @@ -122,6 +123,7 @@ export const catalogPlugin: BackstagePlugin< }, true >; + unregisterRedirect: ExternalRouteRef; } >; @@ -156,7 +158,9 @@ export const CatalogTable: { createSystemColumn(): TableColumn; createOwnerColumn(): TableColumn; createSpecTargetsColumn(): TableColumn; - createSpecTypeColumn(): TableColumn; + createSpecTypeColumn(options?: { + hidden: boolean; + }): TableColumn; createSpecLifecycleColumn(): TableColumn; createMetadataDescriptionColumn(): TableColumn; createTagsColumn(): TableColumn; @@ -180,12 +184,17 @@ export const CatalogTable: { }>; }; +// @public +export type CatalogTableColumnsFunc = ( + entityListContext: EntityListContextProps, +) => TableColumn[]; + // @public export interface CatalogTableProps { // (undocumented) actions?: TableProps['actions']; // (undocumented) - columns?: TableColumn[]; + columns?: TableColumn[] | CatalogTableColumnsFunc; // (undocumented) emptyContent?: ReactNode; // (undocumented) @@ -217,7 +226,7 @@ export interface DefaultCatalogPageProps { // (undocumented) actions?: TableProps['actions']; // (undocumented) - columns?: TableColumn[]; + columns?: TableColumn[] | CatalogTableColumnsFunc; // (undocumented) emptyContent?: ReactNode; // (undocumented) @@ -227,6 +236,12 @@ export interface DefaultCatalogPageProps { // (undocumented) ownerPickerMode?: EntityOwnerPickerProps['mode']; // (undocumented) + pagination?: + | boolean + | { + limit?: number; + }; + // (undocumented) tableOptions?: TableProps['options']; } diff --git a/plugins/catalog/config.d.ts b/plugins/catalog/config.d.ts new file mode 100644 index 0000000000..af749db905 --- /dev/null +++ b/plugins/catalog/config.d.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export interface Config { + catalog?: { + /** + * @deepVisibility frontend + */ + experimentalPagination?: + | boolean + | { + limit?: number; + }; + }; +} diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index 7d5220e2fb..4654a831f9 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog", "description": "The Backstage plugin for browsing the Backstage catalog", - "version": "1.15.0-next.2", + "version": "1.16.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -48,6 +48,7 @@ "dependencies": { "@backstage/catalog-client": "workspace:^", "@backstage/catalog-model": "workspace:^", + "@backstage/core-compat-api": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", @@ -55,14 +56,15 @@ "@backstage/integration-react": "workspace:^", "@backstage/plugin-catalog-common": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", + "@backstage/plugin-permission-react": "workspace:^", "@backstage/plugin-scaffolder-common": "workspace:^", "@backstage/plugin-search-common": "workspace:^", "@backstage/plugin-search-react": "workspace:^", - "@backstage/theme": "workspace:^", "@backstage/types": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", + "@mui/utils": "^5.14.15", "@types/react": "^16.13.1 || ^17.0.0", "dataloader": "^2.0.0", "expiry-map": "^2.0.0", @@ -81,7 +83,7 @@ "@backstage/cli": "workspace:^", "@backstage/core-app-api": "workspace:^", "@backstage/dev-utils": "workspace:^", - "@backstage/plugin-permission-react": "workspace:^", + "@backstage/plugin-permission-common": "workspace:^", "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", @@ -89,6 +91,8 @@ "@testing-library/user-event": "^14.0.0" }, "files": [ - "dist" - ] + "dist", + "config.d.ts" + ], + "configSchema": "config.d.ts" } diff --git a/plugins/catalog/src/alpha/EntityOverviewPage.tsx b/plugins/catalog/src/alpha/EntityOverviewPage.tsx index baa93845ae..932e13d962 100644 --- a/plugins/catalog/src/alpha/EntityOverviewPage.tsx +++ b/plugins/catalog/src/alpha/EntityOverviewPage.tsx @@ -14,29 +14,95 @@ * limitations under the License. */ -import React from 'react'; -import { useEntity } from '@backstage/plugin-catalog-react'; import { Entity } from '@backstage/catalog-model'; +import { useEntity } from '@backstage/plugin-catalog-react'; import Grid from '@material-ui/core/Grid'; +import React, { useMemo } from 'react'; +import { parseFilterExpression } from './filter/parseFilterExpression'; interface EntityOverviewPageProps { cards: Array<{ element: React.JSX.Element; - filter: (ctx: { entity: Entity }) => boolean; + filterFunction?: (entity: Entity) => boolean; + filterExpression?: string; }>; } +// Keeps track of what filter expression strings that we've seen duplicates of +// with functions, or which emitted parsing errors for so far +const seenParseErrorExpressionStrings = new Set(); +const seenDuplicateExpressionStrings = new Set(); + +// Given an optional filter function and an optional filter expression, make +// sure that at most one of them was given, and return a filter function that +// does the right thing. +function buildFilterFn( + filterFunction?: (entity: Entity) => boolean, + filterExpression?: string, +): (entity: Entity) => boolean { + if ( + filterFunction && + filterExpression && + !seenDuplicateExpressionStrings.has(filterExpression) + ) { + // eslint-disable-next-line no-console + console.warn( + `Duplicate entity filter methods found, both '${filterExpression}' as well as a callback function, which is not permitted - using the callback`, + ); + seenDuplicateExpressionStrings.add(filterExpression); + } + + const filter = filterFunction || filterExpression; + if (!filter) { + return () => true; + } else if (typeof filter === 'function') { + return subject => filter(subject); + } + + const result = parseFilterExpression(filter); + if ( + result.expressionParseErrors.length && + !seenParseErrorExpressionStrings.has(filter) + ) { + // eslint-disable-next-line no-console + console.warn( + `Error(s) in entity filter expression '${filter}'`, + result.expressionParseErrors, + ); + seenParseErrorExpressionStrings.add(filter); + } + + return result.filterFn; +} + +// Handles the memoized parsing of filter expressions for each card +function CardWrapper(props: { + entity: Entity; + element: React.JSX.Element; + filterFunction?: (entity: Entity) => boolean; + filterExpression?: string; +}) { + const { entity, element, filterFunction, filterExpression } = props; + + const filterFn = useMemo( + () => buildFilterFn(filterFunction, filterExpression), + [filterFunction, filterExpression], + ); + + return filterFn(entity) ? ( + + {element} + + ) : null; +} + export function EntityOverviewPage(props: EntityOverviewPageProps) { const { entity } = useEntity(); return ( - {props.cards - .filter(card => card.filter({ entity })) - .map(card => ( - - {card.element} - - ))} + {props.cards.map((card, index) => ( + + ))} ); } diff --git a/plugins/catalog/src/alpha/apis.tsx b/plugins/catalog/src/alpha/apis.tsx index a887a33a04..ae8dcf9a9a 100644 --- a/plugins/catalog/src/alpha/apis.tsx +++ b/plugins/catalog/src/alpha/apis.tsx @@ -28,7 +28,7 @@ import { } from '@backstage/plugin-catalog-react'; import { DefaultStarredEntitiesApi } from '../apis'; -export const CatalogApi = createApiExtension({ +export const catalogApi = createApiExtension({ factory: createApiFactory({ api: catalogApiRef, deps: { @@ -40,7 +40,7 @@ export const CatalogApi = createApiExtension({ }), }); -export const StarredEntitiesApi = createApiExtension({ +export const catalogStarredEntitiesApi = createApiExtension({ factory: createApiFactory({ api: starredEntitiesApiRef, deps: { storageApi: storageApiRef }, @@ -48,4 +48,4 @@ export const StarredEntitiesApi = createApiExtension({ }), }); -export default [CatalogApi, StarredEntitiesApi]; +export default [catalogApi, catalogStarredEntitiesApi]; diff --git a/plugins/catalog/src/alpha/createCatalogFilterExtension.tsx b/plugins/catalog/src/alpha/createCatalogFilterExtension.tsx index cf3dbd318a..48ee647b81 100644 --- a/plugins/catalog/src/alpha/createCatalogFilterExtension.tsx +++ b/plugins/catalog/src/alpha/createCatalogFilterExtension.tsx @@ -28,22 +28,23 @@ export function createCatalogFilterExtension< TInputs extends AnyExtensionInputMap, TConfig = never, >(options: { - id: string; + namespace?: string; + name?: string; inputs?: TInputs; configSchema?: PortableSchema; loader: (options: { config: TConfig }) => Promise; }) { - const id = `catalog.filter.${options.id}`; - return createExtension({ - id, - attachTo: { id: 'plugin.catalog.page.index', input: 'filters' }, + kind: 'catalog-filter', + namespace: options.namespace, + name: options.name, + attachTo: { id: 'page:catalog', input: 'filters' }, inputs: options.inputs ?? {}, configSchema: options.configSchema, output: { element: coreExtensionData.reactElement, }, - factory({ config, source }) { + factory({ config, node }) { const ExtensionComponent = lazy(() => options .loader({ config }) @@ -52,7 +53,7 @@ export function createCatalogFilterExtension< return { element: ( - + ), diff --git a/plugins/catalog/src/alpha/entityCards.tsx b/plugins/catalog/src/alpha/entityCards.tsx index c7b75679a7..da6a6a669e 100644 --- a/plugins/catalog/src/alpha/entityCards.tsx +++ b/plugins/catalog/src/alpha/entityCards.tsx @@ -16,89 +16,90 @@ import React from 'react'; import { createEntityCardExtension } from '@backstage/plugin-catalog-react/alpha'; +import { compatWrapper } from '@backstage/core-compat-api'; -export const EntityAboutCard = createEntityCardExtension({ - id: 'about', +export const catalogAboutEntityCard = createEntityCardExtension({ + name: 'about', loader: async () => - import('../components/AboutCard').then(m => ( - - )), + import('../components/AboutCard').then(m => + compatWrapper(), + ), }); -export const EntityLinksCard = createEntityCardExtension({ - id: 'links', - filter: ({ entity }) => Boolean(entity.metadata.links), +export const catalogLinksEntityCard = createEntityCardExtension({ + name: 'links', + filter: 'has:links', loader: async () => - import('../components/EntityLinksCard').then(m => { - return ; - }), + import('../components/EntityLinksCard').then(m => + compatWrapper(), + ), }); -export const EntityLabelsCard = createEntityCardExtension({ - id: 'labels', - filter: ({ entity }) => Boolean(entity.metadata.labels), +export const catalogLabelsEntityCard = createEntityCardExtension({ + name: 'labels', + filter: 'has:labels', loader: async () => - import('../components/EntityLabelsCard').then(m => ( - - )), + import('../components/EntityLabelsCard').then(m => + compatWrapper(), + ), }); -export const EntityDependsOnComponentsCard = createEntityCardExtension({ - id: 'dependsOn.components', +export const catalogDependsOnComponentsEntityCard = createEntityCardExtension({ + name: 'depends-on-components', loader: async () => - import('../components/DependsOnComponentsCard').then(m => ( - - )), + import('../components/DependsOnComponentsCard').then(m => + compatWrapper(), + ), }); -export const EntityDependsOnResourcesCard = createEntityCardExtension({ - id: 'dependsOn.resources', +export const catalogDependsOnResourcesEntityCard = createEntityCardExtension({ + name: 'depends-on-resources', loader: async () => - import('../components/DependsOnResourcesCard').then(m => ( - - )), + import('../components/DependsOnResourcesCard').then(m => + compatWrapper(), + ), }); -export const EntityHasComponentsCard = createEntityCardExtension({ - id: 'has.components', +export const catalogHasComponentsEntityCard = createEntityCardExtension({ + name: 'has-components', loader: async () => - import('../components/HasComponentsCard').then(m => ( - - )), + import('../components/HasComponentsCard').then(m => + compatWrapper(), + ), }); -export const EntityHasResourcesCard = createEntityCardExtension({ - id: 'has.resources', +export const catalogHasResourcesEntityCard = createEntityCardExtension({ + name: 'has-resources', loader: async () => - import('../components/HasResourcesCard').then(m => ( - - )), + import('../components/HasResourcesCard').then(m => + compatWrapper(), + ), }); -export const EntityHasSubcomponentsCard = createEntityCardExtension({ - id: 'has.subcomponents', +export const catalogHasSubcomponentsEntityCard = createEntityCardExtension({ + name: 'has-subcomponents', loader: async () => - import('../components/HasSubcomponentsCard').then(m => ( - - )), + import('../components/HasSubcomponentsCard').then(m => + compatWrapper(), + ), }); -export const EntityHasSystemsCard = createEntityCardExtension({ - id: 'has.systems', +export const catalogHasSystemsEntityCard = createEntityCardExtension({ + name: 'has-systems', loader: async () => - import('../components/HasSystemsCard').then(m => ( - - )), + import('../components/HasSystemsCard').then(m => + compatWrapper(), + ), }); export default [ - EntityAboutCard, - EntityLinksCard, - EntityLabelsCard, - EntityDependsOnComponentsCard, - EntityDependsOnResourcesCard, - EntityHasComponentsCard, - EntityHasResourcesCard, - EntityHasSubcomponentsCard, - EntityHasSystemsCard, + catalogAboutEntityCard, + catalogLinksEntityCard, + catalogLabelsEntityCard, + catalogDependsOnComponentsEntityCard, + catalogDependsOnResourcesEntityCard, + catalogHasComponentsEntityCard, + catalogHasResourcesEntityCard, + catalogHasSubcomponentsEntityCard, + catalogHasSystemsEntityCard, ]; diff --git a/plugins/catalog/src/alpha/entityContents.tsx b/plugins/catalog/src/alpha/entityContents.tsx index 9bef4a5e0d..75c3fef49f 100644 --- a/plugins/catalog/src/alpha/entityContents.tsx +++ b/plugins/catalog/src/alpha/entityContents.tsx @@ -21,24 +21,25 @@ import { } from '@backstage/frontend-plugin-api'; import { createEntityContentExtension, - entityFilterExtensionDataRef, + catalogExtensionData, } from '@backstage/plugin-catalog-react/alpha'; -export const OverviewEntityContent = createEntityContentExtension({ - id: 'overview', +export const catalogOverviewEntityContent = createEntityContentExtension({ + name: 'overview', defaultPath: '/', defaultTitle: 'Overview', disabled: false, inputs: { cards: createExtensionInput({ element: coreExtensionData.reactElement, - filter: entityFilterExtensionDataRef, + filterFunction: catalogExtensionData.entityFilterFunction.optional(), + filterExpression: catalogExtensionData.entityFilterExpression.optional(), }), }, loader: async ({ inputs }) => import('./EntityOverviewPage').then(m => ( - + c.output)} /> )), }); -export default [OverviewEntityContent]; +export default [catalogOverviewEntityContent]; diff --git a/plugins/catalog/src/alpha/filter/matrchers/createHasMatcher.test.ts b/plugins/catalog/src/alpha/filter/matrchers/createHasMatcher.test.ts new file mode 100644 index 0000000000..53524d228e --- /dev/null +++ b/plugins/catalog/src/alpha/filter/matrchers/createHasMatcher.test.ts @@ -0,0 +1,98 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Entity } from '@backstage/catalog-model'; +import { createHasMatcher } from './createHasMatcher'; + +describe('createHasMatcher', () => { + const empty1 = { + metadata: {}, + } as unknown as Entity; + const empty2 = { + metadata: { + labels: {}, + links: [], + }, + } as unknown as Entity; + const labels = { + metadata: { + labels: { a: 'b' }, + }, + } as unknown as Entity; + const links = { + metadata: { links: [{}] }, + } as unknown as Entity; + + const err = jest.fn(); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('supports valid parameters', () => { + expect(createHasMatcher(['labels'], err)(empty1)).toBe(false); + expect(createHasMatcher(['labels'], err)(empty2)).toBe(false); + expect(createHasMatcher(['labels'], err)(labels)).toBe(true); + + expect(createHasMatcher(['links'], err)(empty1)).toBe(false); + expect(createHasMatcher(['links'], err)(empty2)).toBe(false); + expect(createHasMatcher(['links'], err)(links)).toBe(true); + + expect(err).not.toHaveBeenCalled(); + }); + + it('matches if ANY parameter matches', () => { + expect(createHasMatcher(['labels', 'links'], err)(empty1)).toBe(false); + expect(createHasMatcher(['labels', 'links'], err)(empty2)).toBe(false); + expect(createHasMatcher(['labels', 'links'], err)(labels)).toBe(true); + expect(createHasMatcher(['labels', 'links'], err)(links)).toBe(true); + + expect(err).not.toHaveBeenCalled(); + }); + + it('emits errors properly, and skips over bad parameters', () => { + // throw if callback throws + expect(() => + createHasMatcher(['labels', 'bar'], e => { + throw e; + }), + ).toThrowErrorMatchingInlineSnapshot( + `"'bar' is not a valid parameter for 'has' filter expressions, expected one of 'labels','links'"`, + ); + expect(err).not.toHaveBeenCalled(); + + // continue if callback does not throw, and skip over the bad parameter + let matcher = createHasMatcher(['labels', 'foo', 'bar'], err); + expect(err).toHaveBeenCalledTimes(2); + expect(err).toHaveBeenCalledWith( + expect.objectContaining({ + message: `'foo' is not a valid parameter for 'has' filter expressions, expected one of 'labels','links'`, + }), + ); + expect(err).toHaveBeenCalledWith( + expect.objectContaining({ + message: `'bar' is not a valid parameter for 'has' filter expressions, expected one of 'labels','links'`, + }), + ); + expect(matcher(empty1)).toBe(false); + expect(matcher(labels)).toBe(true); + + // when no parameters at all match, just return true + matcher = createHasMatcher(['foo', 'bar'], err); + expect(matcher(empty1)).toBe(true); + expect(matcher(labels)).toBe(true); + }); +}); diff --git a/plugins/catalog/src/alpha/filter/matrchers/createHasMatcher.ts b/plugins/catalog/src/alpha/filter/matrchers/createHasMatcher.ts new file mode 100644 index 0000000000..9fd393a561 --- /dev/null +++ b/plugins/catalog/src/alpha/filter/matrchers/createHasMatcher.ts @@ -0,0 +1,52 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { InputError } from '@backstage/errors'; +import { EntityMatcherFn } from './types'; + +const allowedMatchers: Record = { + labels: entity => { + return Object.keys(entity.metadata.labels ?? {}).length > 0; + }, + links: entity => { + return (entity.metadata.links ?? []).length > 0; + }, +}; + +/** + * Matches on the non-empty presence of different parts of the entity + */ +export function createHasMatcher( + parameters: string[], + onParseError: (error: Error) => void, +): EntityMatcherFn { + const matchers = parameters.flatMap(parameter => { + const matcher = allowedMatchers[parameter.toLocaleLowerCase('en-US')]; + if (!matcher) { + const known = Object.keys(allowedMatchers).map(m => `'${m}'`); + onParseError( + new InputError( + `'${parameter}' is not a valid parameter for 'has' filter expressions, expected one of ${known}`, + ), + ); + return []; + } + return [matcher]; + }); + + return entity => + matchers.length ? matchers.some(matcher => matcher(entity)) : true; +} diff --git a/plugins/catalog/src/alpha/filter/matrchers/createIsMatcher.test.ts b/plugins/catalog/src/alpha/filter/matrchers/createIsMatcher.test.ts new file mode 100644 index 0000000000..4cb3094d62 --- /dev/null +++ b/plugins/catalog/src/alpha/filter/matrchers/createIsMatcher.test.ts @@ -0,0 +1,75 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Entity } from '@backstage/catalog-model'; +import { createIsMatcher } from './createIsMatcher'; + +describe('createIsMatcher', () => { + const empty = { + metadata: {}, + } as unknown as Entity; + const orphan = { + metadata: { + annotations: { ['backstage.io/orphan']: 'true' }, + }, + } as unknown as Entity; + + const err = jest.fn(); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('supports valid parameters', () => { + expect(createIsMatcher(['orphan'], err)(empty)).toBe(false); + expect(createIsMatcher(['orphan'], err)(orphan)).toBe(true); + + expect(err).not.toHaveBeenCalled(); + }); + + it('emits errors properly, and skips over bad parameters', () => { + // throw if callback throws + expect(() => + createIsMatcher(['orphan', 'foo'], e => { + throw e; + }), + ).toThrowErrorMatchingInlineSnapshot( + `"'foo' is not a valid parameter for 'is' filter expressions, expected one of 'orphan'"`, + ); + expect(err).not.toHaveBeenCalled(); + + // continue if callback does not throw, and skip over the bad parameter + let matcher = createIsMatcher(['orphan', 'foo', 'bar'], err); + expect(err).toHaveBeenCalledTimes(2); + expect(err).toHaveBeenCalledWith( + expect.objectContaining({ + message: `'foo' is not a valid parameter for 'is' filter expressions, expected one of 'orphan'`, + }), + ); + expect(err).toHaveBeenCalledWith( + expect.objectContaining({ + message: `'bar' is not a valid parameter for 'is' filter expressions, expected one of 'orphan'`, + }), + ); + expect(matcher(empty)).toBe(false); + expect(matcher(orphan)).toBe(true); + + // when no parameters at all match, just return true + matcher = createIsMatcher(['foo', 'bar'], err); + expect(matcher(empty)).toBe(true); + expect(matcher(orphan)).toBe(true); + }); +}); diff --git a/plugins/catalog/src/alpha/filter/matrchers/createIsMatcher.ts b/plugins/catalog/src/alpha/filter/matrchers/createIsMatcher.ts new file mode 100644 index 0000000000..49a54349d1 --- /dev/null +++ b/plugins/catalog/src/alpha/filter/matrchers/createIsMatcher.ts @@ -0,0 +1,48 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { InputError } from '@backstage/errors'; +import { EntityMatcherFn } from './types'; + +const allowedMatchers: Record = { + orphan: entity => + Boolean(entity.metadata.annotations?.['backstage.io/orphan']), +}; + +/** + * Matches on different semantic properties of the entity + */ +export function createIsMatcher( + parameters: string[], + onParseError: (error: Error) => void, +): EntityMatcherFn { + const matchers = parameters.flatMap(parameter => { + const matcher = allowedMatchers[parameter.toLocaleLowerCase('en-US')]; + if (!matcher) { + const known = Object.keys(allowedMatchers).map(m => `'${m}'`); + onParseError( + new InputError( + `'${parameter}' is not a valid parameter for 'is' filter expressions, expected one of ${known}`, + ), + ); + return []; + } + return [matcher]; + }); + + return entity => + matchers.length ? matchers.some(matcher => matcher(entity)) : true; +} diff --git a/plugins/catalog/src/alpha/filter/matrchers/createKindMatcher.test.ts b/plugins/catalog/src/alpha/filter/matrchers/createKindMatcher.test.ts new file mode 100644 index 0000000000..f109acccd4 --- /dev/null +++ b/plugins/catalog/src/alpha/filter/matrchers/createKindMatcher.test.ts @@ -0,0 +1,46 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Entity } from '@backstage/catalog-model'; +import { createKindMatcher } from './createKindMatcher'; + +describe('createKindMatcher', () => { + const component = { kind: 'Component' } as unknown as Entity; + const user = { kind: 'User' } as unknown as Entity; + const resource = { kind: 'Resource' } as unknown as Entity; + + const err = jest.fn(); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('supports valid parameters', () => { + expect(createKindMatcher(['component'], err)(component)).toBe(true); + expect(createKindMatcher(['componenT'], err)(component)).toBe(true); + expect(createKindMatcher(['user'], err)(component)).toBe(false); + + expect(err).not.toHaveBeenCalled(); + }); + + it('matches if ANY parameter matches', () => { + expect(createKindMatcher(['user', 'component'], err)(user)).toBe(true); + expect(createKindMatcher(['user', 'component'], err)(component)).toBe(true); + expect(createKindMatcher(['user', 'component'], err)(resource)).toBe(false); + + expect(err).not.toHaveBeenCalled(); + }); +}); diff --git a/plugins/catalog/src/alpha/filter/matrchers/createKindMatcher.ts b/plugins/catalog/src/alpha/filter/matrchers/createKindMatcher.ts new file mode 100644 index 0000000000..4f7c475ebe --- /dev/null +++ b/plugins/catalog/src/alpha/filter/matrchers/createKindMatcher.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. + */ + +import { EntityMatcherFn } from './types'; + +/** + * Matches on kind + */ +export function createKindMatcher( + parameters: string[], + _onParseError: (error: Error) => void, +): EntityMatcherFn { + const items = parameters.map(p => p.toLocaleLowerCase('en-US')); + return entity => items.includes(entity.kind.toLocaleLowerCase('en-US')); +} diff --git a/plugins/catalog/src/alpha/filter/matrchers/createTypeMatcher.test.ts b/plugins/catalog/src/alpha/filter/matrchers/createTypeMatcher.test.ts new file mode 100644 index 0000000000..31c9af7e11 --- /dev/null +++ b/plugins/catalog/src/alpha/filter/matrchers/createTypeMatcher.test.ts @@ -0,0 +1,54 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Entity } from '@backstage/catalog-model'; +import { createTypeMatcher } from './createTypeMatcher'; + +describe('createTypeMatcher', () => { + const empty1 = {} as unknown as Entity; + const empty2 = { spec: {} } as unknown as Entity; + const service = { spec: { type: 'service' } } as unknown as Entity; + const website = { spec: { type: 'website' } } as unknown as Entity; + const pipeline = { spec: { type: 'pipeline' } } as unknown as Entity; + + const err = jest.fn(); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('supports valid parameters', () => { + expect(createTypeMatcher(['service'], err)(empty1)).toBe(false); + expect(createTypeMatcher(['service'], err)(empty2)).toBe(false); + + expect(createTypeMatcher(['service'], err)(service)).toBe(true); + expect(createTypeMatcher(['sErViCe'], err)(service)).toBe(true); + expect(createTypeMatcher(['service'], err)(service)).toBe(true); + expect(createTypeMatcher(['website'], err)(service)).toBe(false); + + expect(err).not.toHaveBeenCalled(); + }); + + it('matches if ANY parameter matches', () => { + expect(createTypeMatcher(['service', 'website'], err)(service)).toBe(true); + expect(createTypeMatcher(['service', 'website'], err)(website)).toBe(true); + expect(createTypeMatcher(['service', 'website'], err)(pipeline)).toBe( + false, + ); + + expect(err).not.toHaveBeenCalled(); + }); +}); diff --git a/plugins/catalog/src/alpha/filter/matrchers/createTypeMatcher.ts b/plugins/catalog/src/alpha/filter/matrchers/createTypeMatcher.ts new file mode 100644 index 0000000000..31f7a5a461 --- /dev/null +++ b/plugins/catalog/src/alpha/filter/matrchers/createTypeMatcher.ts @@ -0,0 +1,34 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { EntityMatcherFn } from './types'; + +/** + * Matches on spec.type + */ +export function createTypeMatcher( + parameters: string[], + _onParseError: (error: Error) => void, +): EntityMatcherFn { + const items = parameters.map(p => p.toLocaleLowerCase('en-US')); + return entity => { + const value = entity.spec?.type; + return ( + typeof value === 'string' && + items.includes(value.toLocaleLowerCase('en-US')) + ); + }; +} diff --git a/plugins/catalog/src/alpha/filter/matrchers/types.ts b/plugins/catalog/src/alpha/filter/matrchers/types.ts new file mode 100644 index 0000000000..0fff91b3d5 --- /dev/null +++ b/plugins/catalog/src/alpha/filter/matrchers/types.ts @@ -0,0 +1,19 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Entity } from '@backstage/catalog-model'; + +export type EntityMatcherFn = (entity: Entity) => boolean; diff --git a/plugins/catalog/src/alpha/filter/parseFilterExpression.test.ts b/plugins/catalog/src/alpha/filter/parseFilterExpression.test.ts new file mode 100644 index 0000000000..616091739e --- /dev/null +++ b/plugins/catalog/src/alpha/filter/parseFilterExpression.test.ts @@ -0,0 +1,151 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Entity } from '@backstage/catalog-model'; +import { + parseFilterExpression, + splitFilterExpression, +} from './parseFilterExpression'; + +describe('parseFilterExpression', () => { + function run(expression: string) { + const result = parseFilterExpression(expression); + if (result.expressionParseErrors.length) { + throw result.expressionParseErrors[0]; + } + return result.filterFn; + } + + it('supports "kind" expressions', () => { + const component = { kind: 'Component' } as unknown as Entity; + const user = { kind: 'User' } as unknown as Entity; + const resource = { kind: 'Resource' } as unknown as Entity; + + expect(run('kind:user,component')(user)).toBe(true); + expect(run('kind:user,component')(component)).toBe(true); + expect(run('kind:user,component')(resource)).toBe(false); + }); + + it('supports "type" expressions', () => { + const empty = {} as unknown as Entity; + const service = { spec: { type: 'service' } } as unknown as Entity; + const website = { spec: { type: 'website' } } as unknown as Entity; + const pipeline = { spec: { type: 'pipeline' } } as unknown as Entity; + + expect(run('type:service,website')(empty)).toBe(false); + expect(run('type:service,website')(service)).toBe(true); + expect(run('type:service,website')(website)).toBe(true); + expect(run('type:service,website')(pipeline)).toBe(false); + }); + + it('supports "is" expressions', () => { + const empty = { + metadata: {}, + } as unknown as Entity; + const orphan = { + metadata: { + annotations: { ['backstage.io/orphan']: 'true' }, + }, + } as unknown as Entity; + + expect(run('is:orphan')(empty)).toBe(false); + expect(run('is:orphan')(orphan)).toBe(true); + + expect(() => run('is:orphan,bar')).toThrowErrorMatchingInlineSnapshot( + `"'bar' is not a valid parameter for 'is' filter expressions, expected one of 'orphan'"`, + ); + }); + + it('supports "has" expressions', () => { + const empty = { + metadata: {}, + } as unknown as Entity; + const labels = { + metadata: { labels: { a: 'b' } }, + } as unknown as Entity; + const annotations = { + metadata: { annotations: { a: 'b' } }, + } as unknown as Entity; + const links = { + metadata: { links: [{}] }, + } as unknown as Entity; + + expect(run('has:labels,links')(empty)).toBe(false); + expect(run('has:labels,links')(labels)).toBe(true); + expect(run('has:labels,links')(links)).toBe(true); + expect(run('has:labels,links')(annotations)).toBe(false); + + expect(() => run('has:labels,bar')).toThrowErrorMatchingInlineSnapshot( + `"'bar' is not a valid parameter for 'has' filter expressions, expected one of 'labels','links'"`, + ); + }); + + it('rejects unknown keys', () => { + expect(() => run('unknown:foo')).toThrowErrorMatchingInlineSnapshot( + `"'unknown' is not a valid filter expression key, expected one of 'kind','type','is','has'"`, + ); + }); + + it('rejects malformed inputs', () => { + expect(() => run(':')).toThrowErrorMatchingInlineSnapshot( + `"':' is not a valid filter expression, expected 'key:parameter' form"`, + ); + expect(() => run(':a')).toThrowErrorMatchingInlineSnapshot( + `"':a' is not a valid filter expression, expected 'key:parameter' form"`, + ); + expect(() => run('a:')).toThrowErrorMatchingInlineSnapshot( + `"'a:' is not a valid filter expression, expected 'key:parameter' form"`, + ); + }); +}); + +describe('splitFilterExpression', () => { + function run(expression: string) { + return splitFilterExpression(expression, e => { + throw e; + }); + } + + it('properly splits into expression atoms', () => { + expect(run('')).toEqual([]); + expect(run(' ')).toEqual([]); + expect(run('kind:component')).toEqual([ + { key: 'kind', parameters: ['component'] }, + ]); + expect(run('kind:component,user')).toEqual([ + { key: 'kind', parameters: ['component', 'user'] }, + ]); + expect(run('kind:component,user type:foo')).toEqual([ + { key: 'kind', parameters: ['component', 'user'] }, + { key: 'type', parameters: ['foo'] }, + ]); + expect(run('with:multiple:colons')).toEqual([ + { key: 'with', parameters: ['multiple:colons'] }, + ]); + }); + + it('rejects malformed inputs', () => { + expect(() => run(':')).toThrowErrorMatchingInlineSnapshot( + `"':' is not a valid filter expression, expected 'key:parameter' form"`, + ); + expect(() => run(':a')).toThrowErrorMatchingInlineSnapshot( + `"':a' is not a valid filter expression, expected 'key:parameter' form"`, + ); + expect(() => run('a:')).toThrowErrorMatchingInlineSnapshot( + `"'a:' is not a valid filter expression, expected 'key:parameter' form"`, + ); + }); +}); diff --git a/plugins/catalog/src/alpha/filter/parseFilterExpression.ts b/plugins/catalog/src/alpha/filter/parseFilterExpression.ts new file mode 100644 index 0000000000..a4c17cb8da --- /dev/null +++ b/plugins/catalog/src/alpha/filter/parseFilterExpression.ts @@ -0,0 +1,126 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Entity } from '@backstage/catalog-model'; +import { InputError } from '@backstage/errors'; +import { EntityMatcherFn } from './matrchers/types'; +import { createKindMatcher } from './matrchers/createKindMatcher'; +import { createTypeMatcher } from './matrchers/createTypeMatcher'; +import { createIsMatcher } from './matrchers/createIsMatcher'; +import { createHasMatcher } from './matrchers/createHasMatcher'; + +const rootMatcherFactories: Record< + string, + ( + parameters: string[], + onParseError: (error: Error) => void, + ) => EntityMatcherFn +> = { + kind: createKindMatcher, + type: createTypeMatcher, + is: createIsMatcher, + has: createHasMatcher, +}; + +/** + * Parses a filter expression that decides whether to render an entity component + * or not. Returns a function that matches entities based on that expression. + * + * @remarks + * + * Filter strings are on the form `kind:user,group is:orphan`. There's + * effectively an AND between the space separated parts, and an OR between comma + * separated parameters. So the example filter string semantically means + * "entities that are of either User or Group kind, and also are orphans". + * + * The `expressionParseErrors` array contains any errors that were encountered + * during initial parsing of the expression. Note that the parts of the input + * expression that had errors are ignored entirely and parsing continues as if + * they didn't exist. + */ +export function parseFilterExpression(expression: string): { + filterFn: (entity: Entity) => boolean; + expressionParseErrors: Error[]; +} { + const expressionParseErrors: Error[] = []; + + const parts = splitFilterExpression(expression, e => + expressionParseErrors.push(e), + ); + + const matchers = parts.flatMap(part => { + const factory = rootMatcherFactories[part.key]; + if (!factory) { + const known = Object.keys(rootMatcherFactories).map(m => `'${m}'`); + expressionParseErrors.push( + new InputError( + `'${part.key}' is not a valid filter expression key, expected one of ${known}`, + ), + ); + return []; + } + + const matcher = factory(part.parameters, e => + expressionParseErrors.push(e), + ); + return [matcher]; + }); + + const filterFn = (entity: Entity) => + matchers.every(matcher => { + try { + return matcher(entity); + } catch { + return false; + } + }); + + return { + filterFn, + expressionParseErrors, + }; +} + +export function splitFilterExpression( + expression: string, + onParseError: (error: Error) => void, +): Array<{ key: string; parameters: string[] }> { + const words = expression + .split(' ') + .map(w => w.trim()) + .filter(Boolean); + + const result = new Array<{ key: string; parameters: string[] }>(); + + for (const word of words) { + const match = word.match(/^([^:]+):(.+)$/); + if (!match) { + onParseError( + new InputError( + `'${word}' is not a valid filter expression, expected 'key:parameter' form`, + ), + ); + continue; + } + + const key = match[1]; + const parameters = match[2].split(',').filter(Boolean); // silently ignore double commas + + result.push({ key, parameters }); + } + + return result; +} diff --git a/plugins/catalog/src/alpha/filters.tsx b/plugins/catalog/src/alpha/filters.tsx index 7b73c2d14b..62cf9a1353 100644 --- a/plugins/catalog/src/alpha/filters.tsx +++ b/plugins/catalog/src/alpha/filters.tsx @@ -18,16 +18,16 @@ import React from 'react'; import { createCatalogFilterExtension } from './createCatalogFilterExtension'; import { createSchemaFromZod } from '@backstage/frontend-plugin-api'; -const CatalogEntityTagFilter = createCatalogFilterExtension({ - id: 'entity.tag', +const catalogTagCatalogFilter = createCatalogFilterExtension({ + name: 'tag', loader: async () => { const { EntityTagPicker } = await import('@backstage/plugin-catalog-react'); return ; }, }); -const CatalogEntityKindFilter = createCatalogFilterExtension({ - id: 'entity.kind', +const catalogKindCatalogFilter = createCatalogFilterExtension({ + name: 'kind', configSchema: createSchemaFromZod(z => z.object({ initialFilter: z.string().default('component'), @@ -41,8 +41,8 @@ const CatalogEntityKindFilter = createCatalogFilterExtension({ }, }); -const CatalogEntityTypeFilter = createCatalogFilterExtension({ - id: 'entity.type', +const catalogTypeCatalogFilter = createCatalogFilterExtension({ + name: 'type', loader: async () => { const { EntityTypePicker } = await import( '@backstage/plugin-catalog-react' @@ -51,8 +51,8 @@ const CatalogEntityTypeFilter = createCatalogFilterExtension({ }, }); -const CatalogEntityOwnerFilter = createCatalogFilterExtension({ - id: 'entity.mode', +const catalogModeCatalogFilter = createCatalogFilterExtension({ + name: 'mode', configSchema: createSchemaFromZod(z => z.object({ mode: z.enum(['owners-only', 'all']).optional(), @@ -66,8 +66,8 @@ const CatalogEntityOwnerFilter = createCatalogFilterExtension({ }, }); -const CatalogEntityNamespaceFilter = createCatalogFilterExtension({ - id: 'entity.namespace', +const catalogNamespaceCatalogFilter = createCatalogFilterExtension({ + name: 'namespace', loader: async () => { const { EntityNamespacePicker } = await import( '@backstage/plugin-catalog-react' @@ -76,8 +76,8 @@ const CatalogEntityNamespaceFilter = createCatalogFilterExtension({ }, }); -const CatalogEntityLifecycleFilter = createCatalogFilterExtension({ - id: 'entity.lifecycle', +const catalogLifecycleCatalogFilter = createCatalogFilterExtension({ + name: 'lifecycle', loader: async () => { const { EntityLifecyclePicker } = await import( '@backstage/plugin-catalog-react' @@ -86,8 +86,8 @@ const CatalogEntityLifecycleFilter = createCatalogFilterExtension({ }, }); -const CatalogEntityProcessingStatusFilter = createCatalogFilterExtension({ - id: 'entity.processing.status', +const catalogProcessingStatusCatalogFilter = createCatalogFilterExtension({ + name: 'processing-status', loader: async () => { const { EntityProcessingStatusPicker } = await import( '@backstage/plugin-catalog-react' @@ -96,8 +96,8 @@ const CatalogEntityProcessingStatusFilter = createCatalogFilterExtension({ }, }); -const CatalogUserListFilter = createCatalogFilterExtension({ - id: 'user.list', +const catalogListCatalogFilter = createCatalogFilterExtension({ + name: 'list', configSchema: createSchemaFromZod(z => z.object({ initialFilter: z.enum(['owned', 'starred', 'all']).default('owned'), @@ -110,12 +110,12 @@ const CatalogUserListFilter = createCatalogFilterExtension({ }); export default [ - CatalogEntityTagFilter, - CatalogEntityKindFilter, - CatalogEntityTypeFilter, - CatalogEntityOwnerFilter, - CatalogEntityNamespaceFilter, - CatalogEntityLifecycleFilter, - CatalogEntityProcessingStatusFilter, - CatalogUserListFilter, + catalogTagCatalogFilter, + catalogKindCatalogFilter, + catalogTypeCatalogFilter, + catalogModeCatalogFilter, + catalogNamespaceCatalogFilter, + catalogLifecycleCatalogFilter, + catalogProcessingStatusCatalogFilter, + catalogListCatalogFilter, ]; diff --git a/plugins/catalog/src/alpha/navItems.tsx b/plugins/catalog/src/alpha/navItems.tsx index b6481fd764..c1360cc29f 100644 --- a/plugins/catalog/src/alpha/navItems.tsx +++ b/plugins/catalog/src/alpha/navItems.tsx @@ -15,15 +15,14 @@ */ import HomeIcon from '@material-ui/icons/Home'; -import { convertLegacyRouteRef } from '@backstage/core-plugin-api/alpha'; +import { convertLegacyRouteRef } from '@backstage/core-compat-api'; import { createNavItemExtension } from '@backstage/frontend-plugin-api'; import { rootRouteRef } from '../routes'; -export const CatalogIndexNavItem = createNavItemExtension({ - id: 'catalog.nav.index', +export const catalogNavItem = createNavItemExtension({ routeRef: convertLegacyRouteRef(rootRouteRef), title: 'Catalog', icon: HomeIcon, }); -export default [CatalogIndexNavItem]; +export default [catalogNavItem]; diff --git a/plugins/catalog/src/alpha/pages.tsx b/plugins/catalog/src/alpha/pages.tsx index 6270ae777d..3f40796da9 100644 --- a/plugins/catalog/src/alpha/pages.tsx +++ b/plugins/catalog/src/alpha/pages.tsx @@ -15,7 +15,10 @@ */ import React from 'react'; -import { convertLegacyRouteRef } from '@backstage/core-plugin-api/alpha'; +import { + compatWrapper, + convertLegacyRouteRef, +} from '@backstage/core-compat-api'; import { createPageExtension, coreExtensionData, @@ -25,12 +28,11 @@ import { AsyncEntityProvider, entityRouteRef, } from '@backstage/plugin-catalog-react'; -import { entityContentTitleExtensionDataRef } from '@backstage/plugin-catalog-react/alpha'; +import { catalogExtensionData } from '@backstage/plugin-catalog-react/alpha'; import { rootRouteRef } from '../routes'; import { useEntityFromUrl } from '../components/CatalogEntityPage/useEntityFromUrl'; -export const CatalogIndexPage = createPageExtension({ - id: 'plugin.catalog.page.index', +export const catalogPage = createPageExtension({ defaultPath: '/catalog', routeRef: convertLegacyRouteRef(rootRouteRef), inputs: { @@ -40,13 +42,13 @@ export const CatalogIndexPage = createPageExtension({ }, loader: async ({ inputs }) => { const { BaseCatalogPage } = await import('../components/CatalogPage'); - const filters = inputs.filters.map(filter => filter.element); - return {filters}} />; + const filters = inputs.filters.map(filter => filter.output.element); + return compatWrapper({filters}} />); }, }); -export const CatalogEntityPage = createPageExtension({ - id: 'plugin.catalog.page.entity', +export const catalogEntityPage = createPageExtension({ + name: 'entity', defaultPath: '/catalog/:namespace/:kind/:name', routeRef: convertLegacyRouteRef(entityRouteRef), inputs: { @@ -54,7 +56,7 @@ export const CatalogEntityPage = createPageExtension({ element: coreExtensionData.reactElement, path: coreExtensionData.routePath, routeRef: coreExtensionData.routeRef.optional(), - title: entityContentTitleExtensionDataRef, + title: catalogExtensionData.entityContentTitle, }), }, loader: async ({ inputs }) => { @@ -65,19 +67,19 @@ export const CatalogEntityPage = createPageExtension({ {inputs.contents.map(content => ( - {content.element} + {content.output.element} ))} ); }; - return ; + return compatWrapper(); }, }); -export default [CatalogIndexPage, CatalogEntityPage]; +export default [catalogPage, catalogEntityPage]; diff --git a/plugins/catalog/src/alpha/plugin.tsx b/plugins/catalog/src/alpha/plugin.tsx index 2f019ca33e..99aacd27da 100644 --- a/plugins/catalog/src/alpha/plugin.tsx +++ b/plugins/catalog/src/alpha/plugin.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { convertLegacyRouteRef } from '@backstage/core-plugin-api/alpha'; +import { convertLegacyRouteRef } from '@backstage/core-compat-api'; import { createPlugin } from '@backstage/frontend-plugin-api'; import { entityRouteRef } from '@backstage/plugin-catalog-react'; @@ -23,6 +23,7 @@ import { createComponentRouteRef, createFromTemplateRouteRef, rootRouteRef, + unregisterRedirectRouteRef, viewTechDocRouteRef, } from '../routes'; @@ -45,6 +46,7 @@ export default createPlugin({ viewTechDoc: convertLegacyRouteRef(viewTechDocRouteRef), createComponent: convertLegacyRouteRef(createComponentRouteRef), createFromTemplate: convertLegacyRouteRef(createFromTemplateRouteRef), + unregisterRedirect: convertLegacyRouteRef(unregisterRedirectRouteRef), }, extensions: [ ...apis, diff --git a/plugins/catalog/src/alpha/searchResultItems.tsx b/plugins/catalog/src/alpha/searchResultItems.tsx index f677869136..5233144173 100644 --- a/plugins/catalog/src/alpha/searchResultItems.tsx +++ b/plugins/catalog/src/alpha/searchResultItems.tsx @@ -16,14 +16,12 @@ import { createSearchResultListItemExtension } from '@backstage/plugin-search-react/alpha'; -export const CatalogSearchResultListItemExtension = - createSearchResultListItemExtension({ - id: 'catalog', - predicate: result => result.type === 'software-catalog', - component: () => - import('../components/CatalogSearchResultListItem').then( - m => m.CatalogSearchResultListItem, - ), - }); +export const catalogSearchResultListItem = createSearchResultListItemExtension({ + predicate: result => result.type === 'software-catalog', + component: () => + import('../components/CatalogSearchResultListItem').then( + m => m.CatalogSearchResultListItem, + ), +}); -export default [CatalogSearchResultListItemExtension]; +export default [catalogSearchResultListItem]; diff --git a/plugins/catalog/src/apis/EntityPresentationApi/DefaultEntityPresentationApi.ts b/plugins/catalog/src/apis/EntityPresentationApi/DefaultEntityPresentationApi.ts index 5f1119e598..b610173421 100644 --- a/plugins/catalog/src/apis/EntityPresentationApi/DefaultEntityPresentationApi.ts +++ b/plugins/catalog/src/apis/EntityPresentationApi/DefaultEntityPresentationApi.ts @@ -34,6 +34,7 @@ import { DEFAULT_BATCH_DELAY, DEFAULT_CACHE_TTL, DEFAULT_ICONS, + UNKNOWN_KIND_ICON, createDefaultRenderer, } from './defaults'; @@ -134,10 +135,7 @@ export interface DefaultEntityPresentationApiOptions { * @remarks * * The keys are kinds (case insensitive) that map to icon values to represent - * kinds by. - * - * If you do not supply a set of icons here, a set of fallback icons will be - * used. If you supply the empty object, no fallback icons will be used. + * kinds by. These are merged with the default set of icons. */ kindIcons?: Record; @@ -194,11 +192,12 @@ export class DefaultEntityPresentationApi implements EntityPresentationApi { const renderer = options.renderer ?? createDefaultRenderer({ async: true }); const kindIcons: Record = {}; - Object.entries(options.kindIcons ?? DEFAULT_ICONS).forEach( - ([kind, icon]) => { - kindIcons[kind.toLocaleLowerCase('en-US')] = icon; - }, - ); + Object.entries(DEFAULT_ICONS).forEach(([kind, icon]) => { + kindIcons[kind.toLocaleLowerCase('en-US')] = icon; + }); + Object.entries(options.kindIcons ?? {}).forEach(([kind, icon]) => { + kindIcons[kind.toLocaleLowerCase('en-US')] = icon; + }); if (renderer.async) { if (!options.catalogApi) { @@ -396,6 +395,8 @@ export class DefaultEntityPresentationApi implements EntityPresentationApi { return false; } - return this.#kindIcons[kind.toLocaleLowerCase('en-US')]; + return ( + this.#kindIcons[kind.toLocaleLowerCase('en-US')] ?? UNKNOWN_KIND_ICON + ); } } diff --git a/plugins/catalog/src/apis/EntityPresentationApi/defaults.tsx b/plugins/catalog/src/apis/EntityPresentationApi/defaults.tsx index afcd1f5464..84f04c6f83 100644 --- a/plugins/catalog/src/apis/EntityPresentationApi/defaults.tsx +++ b/plugins/catalog/src/apis/EntityPresentationApi/defaults.tsx @@ -26,6 +26,7 @@ import LocationOnIcon from '@material-ui/icons/LocationOn'; import MemoryIcon from '@material-ui/icons/Memory'; import PeopleIcon from '@material-ui/icons/People'; import PersonIcon from '@material-ui/icons/Person'; +import WorkIcon from '@material-ui/icons/Work'; import { DefaultEntityPresentationApiRenderer } from './DefaultEntityPresentationApi'; export const DEFAULT_CACHE_TTL: HumanDuration = { seconds: 10 }; @@ -38,6 +39,7 @@ export const DEFAULT_ICONS: Record = { api: ExtensionIcon, component: MemoryIcon, system: BusinessIcon, + resource: WorkIcon, domain: ApartmentIcon, location: LocationOnIcon, user: PersonIcon, diff --git a/plugins/catalog/src/components/AboutCard/AboutCard.test.tsx b/plugins/catalog/src/components/AboutCard/AboutCard.test.tsx index 1679e2ddf5..e27de38913 100644 --- a/plugins/catalog/src/components/AboutCard/AboutCard.test.tsx +++ b/plugins/catalog/src/components/AboutCard/AboutCard.test.tsx @@ -33,6 +33,12 @@ import { RELATION_OWNED_BY } from '@backstage/catalog-model'; import React from 'react'; import { screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import { permissionApiRef } from '@backstage/plugin-permission-react'; +import { AuthorizeResult } from '@backstage/plugin-permission-common'; + +const mockAuthorize = jest.fn(); + +const mockPermissionApi = { authorize: mockAuthorize }; describe('', () => { const catalogApi: jest.Mocked = { @@ -87,6 +93,7 @@ describe('', () => { ), ], [catalogApiRef, catalogApi], + [permissionApiRef, {}], ]} > @@ -143,6 +150,7 @@ describe('', () => { ), ], [catalogApiRef, catalogApi], + [permissionApiRef, {}], ]} > @@ -198,6 +206,7 @@ describe('', () => { ), ], [catalogApiRef, catalogApi], + [permissionApiRef, {}], ]} > @@ -240,6 +249,7 @@ describe('', () => { ScmIntegrationsApi.fromConfig(new ConfigReader({})), ], [catalogApiRef, catalogApi], + [permissionApiRef, {}], ]} > @@ -276,6 +286,10 @@ describe('', () => { }, }; + mockAuthorize.mockImplementation(async () => ({ + result: AuthorizeResult.ALLOW, + })); + await renderInTestApp( ', () => { ScmIntegrationsApi.fromConfig(new ConfigReader({})), ], [catalogApiRef, catalogApi], + [permissionApiRef, mockPermissionApi], ]} > @@ -308,6 +323,55 @@ describe('', () => { ); }); + it('should not render refresh button if the permission is DENY', async () => { + const entity = { + apiVersion: 'v1', + kind: 'Component', + metadata: { + annotations: { + 'backstage.io/managed-by-location': + 'url:https://backstage.io/catalog-info.yaml', + }, + name: 'software-deny', + }, + spec: { + owner: 'guest', + type: 'service', + lifecycle: 'production', + }, + }; + + mockAuthorize.mockImplementation(async () => ({ + result: AuthorizeResult.DENY, + })); + + await renderInTestApp( + + + + + , + { + mountedRoutes: { + '/catalog/:namespace/:kind/:name': entityRouteRef, + }, + }, + ); + + expect( + screen.queryByTitle('Schedule entity refresh'), + ).not.toBeInTheDocument(); + }); + it('should not render refresh button if the location is not an url or file', async () => { const entity = { apiVersion: 'v1', @@ -330,6 +394,7 @@ describe('', () => { ScmIntegrationsApi.fromConfig(new ConfigReader({})), ], [catalogApiRef, catalogApi], + [permissionApiRef, {}], ]} > @@ -384,6 +449,7 @@ describe('', () => { ), ], [catalogApiRef, catalogApi], + [permissionApiRef, {}], ]} > @@ -440,6 +506,7 @@ describe('', () => { ), ], [catalogApiRef, catalogApi], + [permissionApiRef, {}], ]} > @@ -493,6 +560,7 @@ describe('', () => { ), ], [catalogApiRef, catalogApi], + [permissionApiRef, {}], ]} > @@ -546,6 +614,7 @@ describe('', () => { ), ], [catalogApiRef, catalogApi], + [permissionApiRef, {}], ]} > @@ -592,6 +661,7 @@ describe('', () => { ), ], [catalogApiRef, catalogApi], + [permissionApiRef, {}], ]} > @@ -659,6 +729,7 @@ describe('', () => { ), ], [catalogApiRef, catalogApi], + [permissionApiRef, {}], ]} > @@ -707,6 +778,7 @@ describe('', () => { ), ], [catalogApiRef, catalogApi], + [permissionApiRef, {}], ]} > diff --git a/plugins/catalog/src/components/AboutCard/AboutCard.tsx b/plugins/catalog/src/components/AboutCard/AboutCard.tsx index 34aa463c39..763f6fc094 100644 --- a/plugins/catalog/src/components/AboutCard/AboutCard.tsx +++ b/plugins/catalog/src/components/AboutCard/AboutCard.tsx @@ -60,6 +60,8 @@ import DocsIcon from '@material-ui/icons/Description'; import EditIcon from '@material-ui/icons/Edit'; import { isTemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; import { parseEntityRef } from '@backstage/catalog-model'; +import { useEntityPermission } from '@backstage/plugin-catalog-react/alpha'; +import { catalogEntityRefreshPermission } from '@backstage/plugin-catalog-common/alpha'; const TECHDOCS_ANNOTATION = 'backstage.io/techdocs-ref'; @@ -108,6 +110,9 @@ export function AboutCard(props: AboutCardProps) { const errorApi = useApi(errorApiRef); const viewTechdocLink = useRouteRef(viewTechDocRouteRef); const templateRoute = useRouteRef(createFromTemplateRouteRef); + const { allowed: canRefresh } = useEntityPermission( + catalogEntityRefreshPermission, + ); const entitySourceLocation = getEntitySourceLocation( entity, @@ -215,7 +220,7 @@ export function AboutCard(props: AboutCardProps) { title="About" action={ <> - {allowRefresh && ( + {allowRefresh && canRefresh && ( { const origReplaceState = window.history.replaceState; beforeEach(() => { @@ -166,6 +170,7 @@ describe('DefaultCatalogPage', () => { [identityApiRef, identityApi], [storageApiRef, storageApi], [starredEntitiesApiRef, new MockStarredEntitiesApi()], + [permissionApiRef, new MockPermissionApi()], ]} > {children} @@ -217,6 +222,25 @@ describe('DefaultCatalogPage', () => { expect(columnHeaderLabels).toEqual(['Foo', 'Bar', 'Baz', 'Actions']); }, 20_000); + it('should render the custom column function passed as prop', async () => { + const columns: CatalogTableColumnsFunc = ({ filters, entities }) => { + return filters.kind?.value === 'component' && entities.length + ? [ + { title: 'Foo', field: 'entity.foo' }, + { title: 'Bar', field: 'entity.bar' }, + { title: 'Baz', field: 'entity.spec.lifecycle' }, + ] + : []; + }; + await renderWrapped(); + + const columnHeader = screen + .getAllByRole('button') + .filter(c => c.tagName === 'SPAN'); + const columnHeaderLabels = columnHeader.map(c => c.textContent); + expect(columnHeaderLabels).toEqual(['Foo', 'Bar', 'Baz', 'Actions']); + }, 20_000); + it('should render the default actions of an item in the grid', async () => { await renderWrapped(); await waitFor(() => expect(catalogApi.queryEntities).toHaveBeenCalled()); diff --git a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx index e50c69b8ec..779b347b48 100644 --- a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx +++ b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx @@ -44,31 +44,41 @@ import { CatalogTable, CatalogTableRow } from '../CatalogTable'; import { catalogTranslationRef } from '../../translation'; import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; +import { CatalogTableColumnsFunc } from '../CatalogTable/types'; +import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common/alpha'; +import { usePermission } from '@backstage/plugin-permission-react'; + /** @internal */ -export interface BaseCatalogPageProps { +export type BaseCatalogPageProps = { filters: ReactNode; content?: ReactNode; -} + pagination?: boolean | { limit?: number }; +}; /** @internal */ export function BaseCatalogPage(props: BaseCatalogPageProps) { - const { filters, content = } = props; + const { filters, content = , pagination } = props; const orgName = useApi(configApiRef).getOptionalString('organization.name') ?? 'Backstage'; const createComponentLink = useRouteRef(createComponentRouteRef); const { t } = useTranslationRef(catalogTranslationRef); + const { allowed } = usePermission({ + permission: catalogEntityCreatePermission, + }); return ( - + - + {allowed && ( + + )} All your software catalog entities - + {filters} {content} @@ -86,12 +96,13 @@ export function BaseCatalogPage(props: BaseCatalogPageProps) { */ export interface DefaultCatalogPageProps { initiallySelectedFilter?: UserListFilterKind; - columns?: TableColumn[]; + columns?: TableColumn[] | CatalogTableColumnsFunc; actions?: TableProps['actions']; initialKind?: string; tableOptions?: TableProps['options']; emptyContent?: ReactNode; ownerPickerMode?: EntityOwnerPickerProps['mode']; + pagination?: boolean | { limit?: number }; } export function DefaultCatalogPage(props: DefaultCatalogPageProps) { @@ -102,6 +113,7 @@ export function DefaultCatalogPage(props: DefaultCatalogPageProps) { initialKind = 'component', tableOptions = {}, emptyContent, + pagination, ownerPickerMode, } = props; @@ -127,6 +139,7 @@ export function DefaultCatalogPage(props: DefaultCatalogPageProps) { emptyContent={emptyContent} /> } + pagination={pagination} /> ); } diff --git a/plugins/catalog/src/components/CatalogSearchResultListItem/CatalogSearchResultListItem.tsx b/plugins/catalog/src/components/CatalogSearchResultListItem/CatalogSearchResultListItem.tsx index 06906aecc1..4c6b567d8a 100644 --- a/plugins/catalog/src/components/CatalogSearchResultListItem/CatalogSearchResultListItem.tsx +++ b/plugins/catalog/src/components/CatalogSearchResultListItem/CatalogSearchResultListItem.tsx @@ -107,6 +107,7 @@ export function CatalogSearchResultListItem( /> {result.kind && } + {result.type && } {result.lifecycle && ( )} diff --git a/plugins/catalog/src/components/CatalogTable/CatalogTable.test.tsx b/plugins/catalog/src/components/CatalogTable/CatalogTable.test.tsx index c242372a97..052d8f4787 100644 --- a/plugins/catalog/src/components/CatalogTable/CatalogTable.test.tsx +++ b/plugins/catalog/src/components/CatalogTable/CatalogTable.test.tsx @@ -32,6 +32,7 @@ import { renderInTestApp, TestApiRegistry } from '@backstage/test-utils'; import { act, fireEvent, screen } from '@testing-library/react'; import * as React from 'react'; import { CatalogTable } from './CatalogTable'; +import { CatalogTableColumnsFunc } from './types'; const entities: Entity[] = [ { @@ -379,4 +380,63 @@ describe('CatalogTable component', () => { const labelCellValue = screen.getByText('generic'); expect(labelCellValue).toBeInTheDocument(); }); + + it('should render the label column with customised title and value as specified using function', async () => { + const columns: CatalogTableColumnsFunc = ({ + filters, + entities: entities1, + }) => { + return filters.kind?.value === 'api' && entities1.length + ? [ + CatalogTable.columns.createNameColumn({ defaultKind: 'API' }), + CatalogTable.columns.createLabelColumn('category', { + title: 'Category', + }), + ] + : []; + }; + + const entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'API', + metadata: { + name: 'APIWithLabel', + labels: { category: 'generic' }, + }, + }; + const expectedColumns = ['Name', 'Category', 'Actions']; + + await renderInTestApp( + + ({ kind: 'api' }), + toQueryValue: () => 'api', + }, + }, + }} + > + + + , + { + mountedRoutes: { + '/catalog/:namespace/:kind/:name': entityRouteRef, + }, + }, + ); + + const columnHeader = screen + .getAllByRole('button') + .filter(c => c.tagName === 'SPAN'); + const columnHeaderLabels = columnHeader.map(c => c.textContent); + expect(columnHeaderLabels).toEqual(expectedColumns); + + const labelCellValue = screen.getByText('generic'); + expect(labelCellValue).toBeInTheDocument(); + }); }); diff --git a/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx b/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx index 24ccb22908..006210bb1d 100644 --- a/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx +++ b/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx @@ -34,17 +34,19 @@ import { useEntityList, useStarredEntities, } from '@backstage/plugin-catalog-react'; -import { Typography } from '@material-ui/core'; +import Typography from '@material-ui/core/Typography'; import { withStyles } from '@material-ui/core/styles'; +import { visuallyHidden } from '@mui/utils'; import Edit from '@material-ui/icons/Edit'; import OpenInNew from '@material-ui/icons/OpenInNew'; import Star from '@material-ui/icons/Star'; import StarBorder from '@material-ui/icons/StarBorder'; import { capitalize } from 'lodash'; +import pluralize from 'pluralize'; import React, { ReactNode, useMemo } from 'react'; import { columnFactories } from './columns'; -import { CatalogTableRow } from './types'; -import pluralize from 'pluralize'; +import { CatalogTableColumnsFunc, CatalogTableRow } from './types'; +import { PaginatedCatalogTable } from './PaginatedCatalogTable'; /** * Props for {@link CatalogTable}. @@ -52,7 +54,7 @@ import pluralize from 'pluralize'; * @public */ export interface CatalogTableProps { - columns?: TableColumn[]; + columns?: TableColumn[] | CatalogTableColumnsFunc; actions?: TableProps['actions']; tableOptions?: TableProps['options']; emptyContent?: ReactNode; @@ -75,55 +77,66 @@ const refCompare = (a: Entity, b: Entity) => { return toRef(a).localeCompare(toRef(b)); }; +const defaultColumnsFunc: CatalogTableColumnsFunc = ({ filters, entities }) => { + const showTypeColumn = filters.type === undefined; + + return [ + columnFactories.createTitleColumn({ hidden: true }), + columnFactories.createNameColumn({ defaultKind: filters.kind?.value }), + ...createEntitySpecificColumns(), + columnFactories.createMetadataDescriptionColumn(), + columnFactories.createTagsColumn(), + ]; + + function createEntitySpecificColumns(): TableColumn[] { + const baseColumns = [ + columnFactories.createSystemColumn(), + columnFactories.createOwnerColumn(), + columnFactories.createSpecTypeColumn({ hidden: !showTypeColumn }), + columnFactories.createSpecLifecycleColumn(), + ]; + switch (filters.kind?.value) { + case 'user': + return []; + case 'domain': + case 'system': + return [columnFactories.createOwnerColumn()]; + case 'group': + case 'template': + return [ + columnFactories.createSpecTypeColumn({ hidden: !showTypeColumn }), + ]; + case 'location': + return [ + columnFactories.createSpecTypeColumn({ hidden: !showTypeColumn }), + columnFactories.createSpecTargetsColumn(), + ]; + default: + return entities.every(entity => entity.metadata.namespace === 'default') + ? baseColumns + : [...baseColumns, columnFactories.createNamespaceColumn()]; + } + } +}; + /** @public */ export const CatalogTable = (props: CatalogTableProps) => { - const { columns, actions, tableOptions, subtitle, emptyContent } = props; + const { + columns = defaultColumnsFunc, + tableOptions, + subtitle, + emptyContent, + } = props; const { isStarredEntity, toggleStarredEntity } = useStarredEntities(); - const { loading, error, entities, filters } = useEntityList(); + const entityListContext = useEntityList(); + const { loading, error, entities, filters, pageInfo } = entityListContext; + const enablePagination = !!pageInfo; - const defaultColumns: TableColumn[] = useMemo(() => { - return [ - columnFactories.createTitleColumn({ hidden: true }), - columnFactories.createNameColumn({ defaultKind: filters.kind?.value }), - ...createEntitySpecificColumns(), - columnFactories.createMetadataDescriptionColumn(), - columnFactories.createTagsColumn(), - ]; - - function createEntitySpecificColumns(): TableColumn[] { - const baseColumns = [ - columnFactories.createSystemColumn(), - columnFactories.createOwnerColumn(), - columnFactories.createSpecTypeColumn(), - columnFactories.createSpecLifecycleColumn(), - ]; - switch (filters.kind?.value) { - case 'user': - return []; - case 'domain': - case 'system': - return [columnFactories.createOwnerColumn()]; - case 'group': - case 'template': - return [columnFactories.createSpecTypeColumn()]; - case 'location': - return [ - columnFactories.createSpecTypeColumn(), - columnFactories.createSpecTargetsColumn(), - ]; - default: - return entities.every( - entity => entity.metadata.namespace === 'default', - ) - ? baseColumns - : [...baseColumns, columnFactories.createNamespaceColumn()]; - } - } - }, [filters.kind?.value, entities]); - - const showTypeColumn = filters.type === undefined; - // TODO(timbonicus): remove the title from the CatalogTable once using EntitySearchBar - const titlePreamble = capitalize(filters.user?.value ?? 'all'); + const tableColumns = useMemo( + () => + typeof columns === 'function' ? columns(entityListContext) : columns, + [columns, entityListContext], + ); if (error) { return ( @@ -146,7 +159,7 @@ export const CatalogTable = (props: CatalogTableProps) => { return { icon: () => ( <> - {title} + {title} ), @@ -165,7 +178,7 @@ export const CatalogTable = (props: CatalogTableProps) => { return { icon: () => ( <> - {title} + {title} ), @@ -185,7 +198,7 @@ export const CatalogTable = (props: CatalogTableProps) => { cellStyle: { paddingLeft: '1em' }, icon: () => ( <> - {title} + {title} {isStarred ? : } ), @@ -195,66 +208,58 @@ export const CatalogTable = (props: CatalogTableProps) => { }, ]; - const rows = entities.sort(refCompare).map(entity => { - const partOfSystemRelations = getEntityRelations(entity, RELATION_PART_OF, { - kind: 'system', - }); - const ownedByRelations = getEntityRelations(entity, RELATION_OWNED_BY); - - return { - entity, - resolved: { - // This name is here for backwards compatibility mostly; the - // presentation of refs in the table should in general be handled with - // EntityRefLink / EntityName components - name: humanizeEntityRef(entity, { - defaultKind: 'Component', - }), - entityRef: stringifyEntityRef(entity), - ownedByRelationsTitle: ownedByRelations - .map(r => humanizeEntityRef(r, { defaultKind: 'group' })) - .join(', '), - ownedByRelations, - partOfSystemRelationTitle: partOfSystemRelations - .map(r => - humanizeEntityRef(r, { - defaultKind: 'system', - }), - ) - .join(', '), - partOfSystemRelations, - }, - }; - }); - - const typeColumn = (columns || defaultColumns).find(c => c.title === 'Type'); - if (typeColumn) { - typeColumn.hidden = !showTypeColumn; - } - const showPagination = rows.length > 20; const currentKind = filters.kind?.value || ''; const currentType = filters.type?.value || ''; + // TODO(timbonicus): remove the title from the CatalogTable once using EntitySearchBar + const titlePreamble = capitalize(filters.user?.value ?? 'all'); const titleDisplay = [titlePreamble, currentType, pluralize(currentKind)] .filter(s => s) .join(' '); + const title = `${titleDisplay} (${entities.length})`; + const actions = props.actions || defaultActions; + const options = { + actionsColumnIndex: -1, + loadingType: 'linear' as const, + showEmptyDataSourceMessage: !loading, + padding: 'dense' as const, + ...tableOptions, + }; + + if (enablePagination) { + return ( + + ); + } + + const rows = entities.sort(refCompare).map(toEntityRow); + const pageSize = 20; + const showPagination = rows.length > pageSize; + return ( isLoading={loading} - columns={columns || defaultColumns} + columns={tableColumns} options={{ paging: showPagination, - pageSize: 20, - actionsColumnIndex: -1, - loadingType: 'linear', - showEmptyDataSourceMessage: !loading, - padding: 'dense', + pageSize: pageSize, pageSizeOptions: [20, 50, 100], - ...tableOptions, + ...options, }} title={`${titleDisplay} (${entities.length})`} data={rows} - actions={actions || defaultActions} + actions={actions} subtitle={subtitle} emptyContent={emptyContent} /> @@ -262,3 +267,35 @@ export const CatalogTable = (props: CatalogTableProps) => { }; CatalogTable.columns = columnFactories; + +function toEntityRow(entity: Entity) { + const partOfSystemRelations = getEntityRelations(entity, RELATION_PART_OF, { + kind: 'system', + }); + const ownedByRelations = getEntityRelations(entity, RELATION_OWNED_BY); + + return { + entity, + resolved: { + // This name is here for backwards compatibility mostly; the + // presentation of refs in the table should in general be handled with + // EntityRefLink / EntityName components + name: humanizeEntityRef(entity, { + defaultKind: 'Component', + }), + entityRef: stringifyEntityRef(entity), + ownedByRelationsTitle: ownedByRelations + .map(r => humanizeEntityRef(r, { defaultKind: 'group' })) + .join(', '), + ownedByRelations, + partOfSystemRelationTitle: partOfSystemRelations + .map(r => + humanizeEntityRef(r, { + defaultKind: 'system', + }), + ) + .join(', '), + partOfSystemRelations, + }, + }; +} diff --git a/plugins/catalog/src/components/CatalogTable/PaginatedCatalogTable.test.tsx b/plugins/catalog/src/components/CatalogTable/PaginatedCatalogTable.test.tsx new file mode 100644 index 0000000000..dbf37c2d5c --- /dev/null +++ b/plugins/catalog/src/components/CatalogTable/PaginatedCatalogTable.test.tsx @@ -0,0 +1,99 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; +import { fireEvent, render } from '@testing-library/react'; +import { PaginatedCatalogTable } from './PaginatedCatalogTable'; +import { screen } from '@testing-library/react'; +import { CatalogTableRow } from './types'; + +describe('PaginatedCatalogTable', () => { + const data = new Array(100).fill(0).map((_, index) => { + const name = `component-${index}`; + return { + entity: { + apiVersion: '1', + kind: 'component', + metadata: { + name, + }, + }, + resolved: { + name, + entityRef: 'component:default/component', + }, + } as CatalogTableRow; + }); + + const columns = [ + { + title: 'Title', + field: 'entity.metadata.name', + searchable: true, + }, + ]; + + it('should display all the items', () => { + render(); + + for (const item of data) { + expect(screen.queryByText(item.resolved.name)).toBeInTheDocument(); + } + }); + + it('should display and invoke the next button', async () => { + const { rerender } = render( + , + ); + + expect( + screen.queryAllByRole('button', { name: 'Next Page' })[0], + ).toBeDisabled(); + + const fn = jest.fn(); + + rerender(); + + const nextButton = screen.queryAllByRole('button', { + name: 'Next Page', + })[0]; + expect(nextButton).toBeEnabled(); + + fireEvent.click(nextButton); + expect(fn).toHaveBeenCalled(); + }); + + it('should display and invoke the prev button', async () => { + const { rerender } = render( + , + ); + + expect( + screen.queryAllByRole('button', { name: 'Next Page' })[0], + ).toBeDisabled(); + + const fn = jest.fn(); + + rerender(); + + const prevButton = screen.queryAllByRole('button', { + name: 'Previous Page', + })[0]; + expect(prevButton).toBeEnabled(); + + fireEvent.click(prevButton); + expect(fn).toHaveBeenCalled(); + }); +}); diff --git a/plugins/catalog/src/components/CatalogTable/PaginatedCatalogTable.tsx b/plugins/catalog/src/components/CatalogTable/PaginatedCatalogTable.tsx new file mode 100644 index 0000000000..771878b65c --- /dev/null +++ b/plugins/catalog/src/components/CatalogTable/PaginatedCatalogTable.tsx @@ -0,0 +1,58 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; + +import { Table, TableProps } from '@backstage/core-components'; +import { CatalogTableRow } from './types'; + +type PaginatedCatalogTableProps = { + prev?(): void; + next?(): void; +} & TableProps; + +/** + * @internal + */ +export function PaginatedCatalogTable(props: PaginatedCatalogTableProps) { + const { columns, data, next, prev } = props; + + return ( + { + if (page > 0) { + next?.(); + } else { + prev?.(); + } + }} + /* this will enable the prev button accordingly */ + page={prev ? 1 : 0} + /* this will enable the next button accordingly */ + totalCount={next ? Number.MAX_VALUE : Number.MAX_SAFE_INTEGER} + localization={{ pagination: { labelDisplayedRows: '' } }} + /> + ); +} diff --git a/plugins/catalog/src/components/CatalogTable/columns.tsx b/plugins/catalog/src/components/CatalogTable/columns.tsx index 3c31fcadf1..4260a0c26b 100644 --- a/plugins/catalog/src/components/CatalogTable/columns.tsx +++ b/plugins/catalog/src/components/CatalogTable/columns.tsx @@ -100,11 +100,15 @@ export const columnFactories = Object.freeze({ ), }; }, - createSpecTypeColumn(): TableColumn { + createSpecTypeColumn( + options: { + hidden: boolean; + } = { hidden: false }, + ): TableColumn { return { title: 'Type', field: 'entity.spec.type', - hidden: true, + hidden: options.hidden, width: 'auto', }; }, diff --git a/plugins/catalog/src/components/CatalogTable/index.ts b/plugins/catalog/src/components/CatalogTable/index.ts index 4e1b90f80a..f5d1ca1bb7 100644 --- a/plugins/catalog/src/components/CatalogTable/index.ts +++ b/plugins/catalog/src/components/CatalogTable/index.ts @@ -16,4 +16,4 @@ export { CatalogTable } from './CatalogTable'; export type { CatalogTableProps } from './CatalogTable'; -export type { CatalogTableRow } from './types'; +export type { CatalogTableRow, CatalogTableColumnsFunc } from './types'; diff --git a/plugins/catalog/src/components/CatalogTable/types.ts b/plugins/catalog/src/components/CatalogTable/types.ts index f2b3324169..c991205b11 100644 --- a/plugins/catalog/src/components/CatalogTable/types.ts +++ b/plugins/catalog/src/components/CatalogTable/types.ts @@ -14,7 +14,9 @@ * limitations under the License. */ -import { Entity, CompoundEntityRef } from '@backstage/catalog-model'; +import { CompoundEntityRef, Entity } from '@backstage/catalog-model'; +import { EntityListContextProps } from '@backstage/plugin-catalog-react'; +import { TableColumn } from '@backstage/core-components'; /** @public */ export interface CatalogTableRow { @@ -31,3 +33,12 @@ export interface CatalogTableRow { ownedByRelations: CompoundEntityRef[]; }; } + +/** + * Typed columns function to dynamically render columns based on entity list context. + * + * @public + */ +export type CatalogTableColumnsFunc = ( + entityListContext: EntityListContextProps, +) => TableColumn[]; diff --git a/plugins/catalog/src/components/EntityContextMenu/EntityContextMenu.tsx b/plugins/catalog/src/components/EntityContextMenu/EntityContextMenu.tsx index 9cd377b447..0fc746f455 100644 --- a/plugins/catalog/src/components/EntityContextMenu/EntityContextMenu.tsx +++ b/plugins/catalog/src/components/EntityContextMenu/EntityContextMenu.tsx @@ -28,12 +28,13 @@ import { Theme, makeStyles } from '@material-ui/core/styles'; import BugReportIcon from '@material-ui/icons/BugReport'; import MoreVert from '@material-ui/icons/MoreVert'; import FileCopyTwoToneIcon from '@material-ui/icons/FileCopyTwoTone'; -import React, { useCallback, useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { IconComponent } from '@backstage/core-plugin-api'; import { useEntityPermission } from '@backstage/plugin-catalog-react/alpha'; import { catalogEntityDeletePermission } from '@backstage/plugin-catalog-common/alpha'; import { UnregisterEntity, UnregisterEntityOptions } from './UnregisterEntity'; import { useApi, alertApiRef } from '@backstage/core-plugin-api'; +import useCopyToClipboard from 'react-use/lib/useCopyToClipboard'; /** @public */ export type EntityContextMenuClassKey = 'button'; @@ -87,16 +88,16 @@ export function EntityContextMenu(props: EntityContextMenuProps) { }; const alertApi = useApi(alertApiRef); - - const copyToClipboard = useCallback(() => { - window.navigator.clipboard.writeText(window.location.toString()).then(() => + const [copyState, copyToClipboard] = useCopyToClipboard(); + useEffect(() => { + if (!copyState.error && copyState.value) { alertApi.post({ message: 'Copied!', severity: 'info', display: 'transient', - }), - ); - }, [alertApi]); + }); + } + }, [copyState, alertApi]); const extraItems = UNSTABLE_extraContextMenuItems && [ ...UNSTABLE_extraContextMenuItems.map(item => ( @@ -163,7 +164,7 @@ export function EntityContextMenu(props: EntityContextMenuProps) { { onClose(); - copyToClipboard(); + copyToClipboard(window.location.toString()); }} > diff --git a/plugins/catalog/src/components/EntityLabelsCard/EntityLabelsEmptyState.tsx b/plugins/catalog/src/components/EntityLabelsCard/EntityLabelsEmptyState.tsx index a193a90d05..8878cb827f 100644 --- a/plugins/catalog/src/components/EntityLabelsCard/EntityLabelsEmptyState.tsx +++ b/plugins/catalog/src/components/EntityLabelsCard/EntityLabelsEmptyState.tsx @@ -14,7 +14,6 @@ * limitations under the License. */ -import { BackstageTheme } from '@backstage/theme'; import { Button, makeStyles, Typography } from '@material-ui/core'; import React from 'react'; import { CodeSnippet } from '@backstage/core-components'; @@ -24,7 +23,7 @@ const ENTITY_YAML = `metadata: labels: javaVersion: 1.2.3`; -const useStyles = makeStyles( +const useStyles = makeStyles( theme => ({ code: { borderRadius: 6, diff --git a/plugins/catalog/src/components/EntityLayout/EntityLayout.test.tsx b/plugins/catalog/src/components/EntityLayout/EntityLayout.test.tsx index 3634405af8..c222c2d7b6 100644 --- a/plugins/catalog/src/components/EntityLayout/EntityLayout.test.tsx +++ b/plugins/catalog/src/components/EntityLayout/EntityLayout.test.tsx @@ -15,7 +15,11 @@ */ import { CatalogApi } from '@backstage/catalog-client'; -import { Entity } from '@backstage/catalog-model'; +import { + ANNOTATION_ORIGIN_LOCATION, + Entity, + RELATION_OWNED_BY, +} from '@backstage/catalog-model'; import { ApiProvider } from '@backstage/core-app-api'; import { AlertApi, alertApiRef } from '@backstage/core-plugin-api'; import { @@ -30,27 +34,30 @@ import { permissionApiRef } from '@backstage/plugin-permission-react'; import { MockPermissionApi, renderInTestApp, + TestApiProvider, TestApiRegistry, } from '@backstage/test-utils'; -import { act, fireEvent, screen } from '@testing-library/react'; +import { act, fireEvent, screen, waitFor } from '@testing-library/react'; import React from 'react'; import { EntityLayout } from './EntityLayout'; - -const mockEntity = { - kind: 'MyKind', - metadata: { - name: 'my-entity', - }, -} as Entity; - -const mockApis = TestApiRegistry.from( - [catalogApiRef, {} as CatalogApi], - [alertApiRef, {} as AlertApi], - [starredEntitiesApiRef, new MockStarredEntitiesApi()], - [permissionApiRef, new MockPermissionApi()], -); +import { rootRouteRef, unregisterRedirectRouteRef } from '../../routes'; +import { Route, Routes } from 'react-router-dom'; describe('EntityLayout', () => { + const mockEntity = { + kind: 'MyKind', + metadata: { + name: 'my-entity', + }, + } as Entity; + + const mockApis = TestApiRegistry.from( + [catalogApiRef, {} as CatalogApi], + [alertApiRef, {} as AlertApi], + [starredEntitiesApiRef, new MockStarredEntitiesApi()], + [permissionApiRef, new MockPermissionApi()], + ); + it('renders simplest case', async () => { await renderInTestApp( @@ -65,6 +72,7 @@ describe('EntityLayout', () => { { mountedRoutes: { '/catalog/:namespace/:kind/:name': entityRouteRef, + '/catalog': rootRouteRef, }, }, ); @@ -97,6 +105,7 @@ describe('EntityLayout', () => { { mountedRoutes: { '/catalog/:namespace/:kind/:name': entityRouteRef, + '/catalog': rootRouteRef, }, }, ); @@ -120,6 +129,7 @@ describe('EntityLayout', () => { { mountedRoutes: { '/catalog/:namespace/:kind/:name': entityRouteRef, + '/catalog': rootRouteRef, }, }, ); @@ -146,6 +156,7 @@ describe('EntityLayout', () => { { mountedRoutes: { '/catalog/:namespace/:kind/:name': entityRouteRef, + '/catalog': rootRouteRef, }, }, ); @@ -178,6 +189,7 @@ describe('EntityLayout', () => { { mountedRoutes: { '/catalog/:namespace/:kind/:name': entityRouteRef, + '/catalog': rootRouteRef, }, }, ); @@ -225,6 +237,7 @@ describe('EntityLayout', () => { { mountedRoutes: { '/catalog/:namespace/:kind/:name': entityRouteRef, + '/catalog': rootRouteRef, }, }, ); @@ -253,6 +266,7 @@ describe('EntityLayout', () => { { mountedRoutes: { '/catalog/:namespace/:kind/:name': entityRouteRef, + '/catalog': rootRouteRef, }, }, ); @@ -265,3 +279,168 @@ describe('EntityLayout', () => { expect(linkParent?.tagName).toBe('P'); }); }); + +describe('EntityLayout - CleanUpAfterRemoval', () => { + const entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'n', + namespace: 'ns', + annotations: { + [ANNOTATION_ORIGIN_LOCATION]: 'url:http://example.com', + }, + }, + spec: { + owner: 'tools', + type: 'service', + }, + relations: [ + { + type: RELATION_OWNED_BY, + targetRef: 'group:default/tools', + }, + ], + }; + const getLocationByRef: jest.MockedFunction = + jest.fn(); + const getEntities: jest.MockedFunction = jest.fn(); + const removeEntityByUid: jest.MockedFunction< + CatalogApi['removeEntityByUid'] + > = jest.fn(); + const getEntityFacets: jest.MockedFunction = + jest.fn(); + getLocationByRef.mockResolvedValue(undefined); + getEntities.mockResolvedValue({ items: [{ ...entity }] }); + getEntityFacets.mockResolvedValue({ + facets: { + 'relations.ownedBy': [{ count: 1, value: 'group:default/tools' }], + }, + }); + + const alertApi: AlertApi = { + post() { + return undefined; + }, + alert$() { + throw new Error('not implemented'); + }, + }; + + it('redirects to externalRouteRef when unregisterRedirectRouteRef is bound', async () => { + await renderInTestApp( + + + + +
    tabbed-test-content
    +
    +
    +
    + + catalog-page

    } /> + external-page

    } /> +
    +
    , + { + mountedRoutes: { + '/catalog/:namespace/:kind/:name': entityRouteRef, + '/catalog': rootRouteRef, + '/testRoute': unregisterRedirectRouteRef, + }, + }, + ); + + const menuButton = screen.queryAllByTestId('menu-button')[0]; + fireEvent.click(menuButton); + const listItemUnregister = screen.queryAllByRole('menuitem', { + name: /Unregister entity/i, + })[0]; + fireEvent.click(listItemUnregister); + await waitFor(() => { + const deleteEntityButton = screen.getByRole('button', { + name: /Delete Entity/i, + }); + act(() => { + fireEvent.click(deleteEntityButton); + }); + }); + + await waitFor(() => { + expect(screen.getByText('external-page')).toBeInTheDocument(); + }); + }); + + it('redirects to rootRouteRef when unregisterRedirectRouteRef is not bound', async () => { + await renderInTestApp( + + + + +
    tabbed-test-content
    +
    +
    +
    + + catalog-page

    } /> + external-page

    } /> +
    +
    , + { + mountedRoutes: { + '/catalog/:namespace/:kind/:name': entityRouteRef, + '/catalog': rootRouteRef, + }, + }, + ); + + const menuButton = screen.queryAllByTestId('menu-button')[0]; + fireEvent.click(menuButton); + const listItemUnregister = screen.queryAllByRole('menuitem', { + name: /Unregister entity/i, + })[0]; + fireEvent.click(listItemUnregister); + await waitFor(() => { + const deleteEntityButton = screen.getByRole('button', { + name: /Delete Entity/i, + }); + act(() => { + fireEvent.click(deleteEntityButton); + }); + }); + + await waitFor(() => { + expect(screen.getByText('catalog-page')).toBeInTheDocument(); + }); + }); +}); diff --git a/plugins/catalog/src/components/EntityLayout/EntityLayout.tsx b/plugins/catalog/src/components/EntityLayout/EntityLayout.tsx index f9999f26e9..8e11f92599 100644 --- a/plugins/catalog/src/components/EntityLayout/EntityLayout.tsx +++ b/plugins/catalog/src/components/EntityLayout/EntityLayout.tsx @@ -33,6 +33,7 @@ import { attachComponentData, IconComponent, useElementFilter, + useRouteRef, useRouteRefParams, } from '@backstage/core-plugin-api'; import { @@ -50,6 +51,7 @@ import { Alert } from '@material-ui/lab'; import React, { useEffect, useState } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; import { EntityContextMenu } from '../EntityContextMenu/EntityContextMenu'; +import { rootRouteRef, unregisterRedirectRouteRef } from '../../routes'; /** @public */ export type EntityLayoutRouteProps = { @@ -229,10 +231,15 @@ export const EntityLayout = (props: EntityLayoutProps) => { const [confirmationDialogOpen, setConfirmationDialogOpen] = useState(false); const [inspectionDialogOpen, setInspectionDialogOpen] = useState(false); const navigate = useNavigate(); + const catalogRoute = useRouteRef(rootRouteRef); + const unregisterRedirectRoute = useRouteRef(unregisterRedirectRouteRef); + const cleanUpAfterRemoval = async () => { setConfirmationDialogOpen(false); setInspectionDialogOpen(false); - navigate('/'); + navigate( + unregisterRedirectRoute ? unregisterRedirectRoute() : catalogRoute(), + ); }; // Make sure to close the dialog if the user clicks links in it that navigate diff --git a/plugins/catalog/src/components/EntityLinksCard/EntityLinksEmptyState.tsx b/plugins/catalog/src/components/EntityLinksCard/EntityLinksEmptyState.tsx index f55527c78a..59ab3f3db2 100644 --- a/plugins/catalog/src/components/EntityLinksCard/EntityLinksEmptyState.tsx +++ b/plugins/catalog/src/components/EntityLinksCard/EntityLinksEmptyState.tsx @@ -14,7 +14,6 @@ * limitations under the License. */ -import { BackstageTheme } from '@backstage/theme'; import { Button, makeStyles, Typography } from '@material-ui/core'; import React from 'react'; import { CodeSnippet } from '@backstage/core-components'; @@ -29,7 +28,7 @@ const ENTITY_YAML = `metadata: /** @public */ export type EntityLinksEmptyStateClassKey = 'code'; -const useStyles = makeStyles( +const useStyles = makeStyles( theme => ({ code: { borderRadius: 6, diff --git a/plugins/catalog/src/components/EntityNotFound/EntityNotFound.tsx b/plugins/catalog/src/components/EntityNotFound/EntityNotFound.tsx index fca763c37b..d8d9fe0855 100644 --- a/plugins/catalog/src/components/EntityNotFound/EntityNotFound.tsx +++ b/plugins/catalog/src/components/EntityNotFound/EntityNotFound.tsx @@ -17,10 +17,9 @@ import React from 'react'; import { Grid, Button, Typography } from '@material-ui/core'; import { makeStyles } from '@material-ui/core/styles'; -import { BackstageTheme } from '@backstage/theme'; import { Illo } from './Illo'; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles(theme => ({ container: { paddingTop: theme.spacing(24), paddingLeft: theme.spacing(8), diff --git a/plugins/catalog/src/overridableComponents.ts b/plugins/catalog/src/overridableComponents.ts index 5cd82202d5..0d981b1700 100644 --- a/plugins/catalog/src/overridableComponents.ts +++ b/plugins/catalog/src/overridableComponents.ts @@ -33,3 +33,8 @@ export type BackstageOverrides = Overrides & { StyleRules >; }; + +declare module '@backstage/theme' { + interface OverrideComponentNameToClassKeys + extends PluginCatalogComponentsNameToClassKey {} +} diff --git a/plugins/catalog/src/plugin.ts b/plugins/catalog/src/plugin.ts index d310639fb1..f41fefe404 100644 --- a/plugins/catalog/src/plugin.ts +++ b/plugins/catalog/src/plugin.ts @@ -25,6 +25,7 @@ import { import { createComponentRouteRef, createFromTemplateRouteRef, + unregisterRedirectRouteRef, viewTechDocRouteRef, } from './routes'; import { @@ -89,6 +90,7 @@ export const catalogPlugin = createPlugin({ createComponent: createComponentRouteRef, viewTechDoc: viewTechDocRouteRef, createFromTemplate: createFromTemplateRouteRef, + unregisterRedirect: unregisterRedirectRouteRef, }, }); diff --git a/plugins/catalog/src/routes.ts b/plugins/catalog/src/routes.ts index ab70a3c551..dcc46c7988 100644 --- a/plugins/catalog/src/routes.ts +++ b/plugins/catalog/src/routes.ts @@ -36,6 +36,11 @@ export const createFromTemplateRouteRef = createExternalRouteRef({ params: ['namespace', 'templateName'], }); +export const unregisterRedirectRouteRef = createExternalRouteRef({ + id: 'catalog:unregister-redirect', + optional: true, +}); + export const rootRouteRef = createRouteRef({ id: 'catalog', }); diff --git a/plugins/catalog/src/translation.ts b/plugins/catalog/src/translation.ts index 2d1e3f2c8a..bd27069fde 100644 --- a/plugins/catalog/src/translation.ts +++ b/plugins/catalog/src/translation.ts @@ -20,7 +20,9 @@ import { createTranslationRef } from '@backstage/core-plugin-api/alpha'; export const catalogTranslationRef = createTranslationRef({ id: 'catalog', messages: { - catalog_page_title: `{{orgName}} Catalog`, - catalog_page_create_button_title: 'Create', + indexPage: { + title: `{{orgName}} Catalog`, + createButtonTitle: 'Create', + }, }, }); diff --git a/plugins/cicd-statistics-module-gitlab/CHANGELOG.md b/plugins/cicd-statistics-module-gitlab/CHANGELOG.md index c107239384..79d8cda7bf 100644 --- a/plugins/cicd-statistics-module-gitlab/CHANGELOG.md +++ b/plugins/cicd-statistics-module-gitlab/CHANGELOG.md @@ -1,5 +1,94 @@ # @backstage/plugin-cicd-statistics-module-gitlab +## 0.1.25 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-cicd-statistics@0.1.31 + +## 0.1.25-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-cicd-statistics@0.1.31-next.2 + +## 0.1.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/plugin-cicd-statistics@0.1.31-next.1 + - @backstage/catalog-model@1.4.3 + +## 0.1.25-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-cicd-statistics@0.1.31-next.0 + +## 0.1.24 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-cicd-statistics@0.1.30 + - @backstage/catalog-model@1.4.3 + +## 0.1.24-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-cicd-statistics@0.1.30-next.3 + +## 0.1.24-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-cicd-statistics@0.1.30-next.2 + +## 0.1.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-cicd-statistics@0.1.30-next.1 + - @backstage/catalog-model@1.4.3 + +## 0.1.24-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-cicd-statistics@0.1.30-next.0 + - @backstage/catalog-model@1.4.3 + +## 0.1.22 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-cicd-statistics@0.1.28 + - @backstage/catalog-model@1.4.3 + ## 0.1.22-next.2 ### Patch Changes diff --git a/plugins/cicd-statistics-module-gitlab/package.json b/plugins/cicd-statistics-module-gitlab/package.json index 8b5403d084..f84457a781 100644 --- a/plugins/cicd-statistics-module-gitlab/package.json +++ b/plugins/cicd-statistics-module-gitlab/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-cicd-statistics-module-gitlab", "description": "CI/CD Statistics plugin module; Gitlab CICD", - "version": "0.1.22-next.2", + "version": "0.1.25", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/cicd-statistics/CHANGELOG.md b/plugins/cicd-statistics/CHANGELOG.md index 75c87a0e29..e80e9d5d68 100644 --- a/plugins/cicd-statistics/CHANGELOG.md +++ b/plugins/cicd-statistics/CHANGELOG.md @@ -1,5 +1,94 @@ # @backstage/plugin-cicd-statistics +## 0.1.31 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## 0.1.31-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.1.31-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + +## 0.1.31-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + +## 0.1.30 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/catalog-model@1.4.3 + +## 0.1.30-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## 0.1.30-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + +## 0.1.30-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + +## 0.1.30-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/catalog-model@1.4.3 + +## 0.1.28 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-plugin-api@1.8.0 + - @backstage/catalog-model@1.4.3 + ## 0.1.28-next.2 ### Patch Changes diff --git a/plugins/cicd-statistics/package.json b/plugins/cicd-statistics/package.json index 51cc3ec539..aaa271baa7 100644 --- a/plugins/cicd-statistics/package.json +++ b/plugins/cicd-statistics/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-cicd-statistics", "description": "A frontend plugin visualizing CI/CD pipeline statistics (build time)", - "version": "0.1.28-next.2", + "version": "0.1.31", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/cicd-statistics/src/components/chart-filters.tsx b/plugins/cicd-statistics/src/components/chart-filters.tsx index 03cbea5dd0..026e81fd74 100644 --- a/plugins/cicd-statistics/src/components/chart-filters.tsx +++ b/plugins/cicd-statistics/src/components/chart-filters.tsx @@ -27,7 +27,6 @@ import { Switch, Tooltip, Typography, - Theme, makeStyles, } from '@material-ui/core'; import ShowChartIcon from '@material-ui/icons/ShowChart'; @@ -54,7 +53,7 @@ import { Toggle } from './toggle'; import { DurationSlider } from './duration-slider'; import { Label } from './label'; -export const useStyles = makeStyles( +export const useStyles = makeStyles( theme => ({ rootCard: { padding: theme.spacing(0, 0, 0, 0), diff --git a/plugins/cicd-statistics/src/components/label.tsx b/plugins/cicd-statistics/src/components/label.tsx index fe064d30a6..1c9a05b303 100644 --- a/plugins/cicd-statistics/src/components/label.tsx +++ b/plugins/cicd-statistics/src/components/label.tsx @@ -15,9 +15,9 @@ */ import React, { PropsWithChildren } from 'react'; -import { Typography, Theme, makeStyles } from '@material-ui/core'; +import { Typography, makeStyles } from '@material-ui/core'; -export const useStyles = makeStyles( +export const useStyles = makeStyles( theme => ({ label: { fontWeight: 'normal', diff --git a/plugins/cicd-statistics/src/entity-page.tsx b/plugins/cicd-statistics/src/entity-page.tsx index db5cba42aa..25b8477f61 100644 --- a/plugins/cicd-statistics/src/entity-page.tsx +++ b/plugins/cicd-statistics/src/entity-page.tsx @@ -15,7 +15,7 @@ */ import React, { useCallback, useState, useMemo, useEffect } from 'react'; -import { Grid, makeStyles, Theme } from '@material-ui/core'; +import { Grid, makeStyles } from '@material-ui/core'; import { Alert } from '@material-ui/lab'; import { useEntity } from '@backstage/plugin-catalog-react'; import { useApi, errorApiRef } from '@backstage/core-plugin-api'; @@ -57,7 +57,7 @@ export function EntityPageCicdCharts() { )); } -const useStyles = makeStyles( +const useStyles = makeStyles( theme => ({ pane: { padding: theme.spacing(1, 1, 1, 1), diff --git a/plugins/circleci/CHANGELOG.md b/plugins/circleci/CHANGELOG.md index 6fbb26f3f2..baabcaa66f 100644 --- a/plugins/circleci/CHANGELOG.md +++ b/plugins/circleci/CHANGELOG.md @@ -1,5 +1,115 @@ # @backstage/plugin-circleci +## 0.3.29 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## 0.3.29-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.3.29-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + +## 0.3.29-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + +## 0.3.28 + +### Patch Changes + +- 375b6f7: CircelCI plugin moved permanently +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + +## 0.3.28-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## 0.3.28-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## 0.3.28-next.1 + +### Patch Changes + +- 375b6f7d68: CircelCI plugin moved permanently +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## 0.3.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + +## 0.3.26 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + ## 0.3.26-next.2 ### Patch Changes diff --git a/plugins/circleci/README.md b/plugins/circleci/README.md index f468ab37e2..86af7081c7 100644 --- a/plugins/circleci/README.md +++ b/plugins/circleci/README.md @@ -1,6 +1,7 @@ # CircleCI Plugin -Website: [https://circleci.com/](https://circleci.com/) +> [!IMPORTANT] +> This plugin is now developed & maintained by CircleCI. Please refer to [their up-to-date documentation](https://github.com/CircleCI-Public/backstage-plugin) & [plugin repository](https://github.com/CircleCI-Public/backstage-plugin/) for help. ## Screenshots @@ -14,7 +15,7 @@ Website: [https://circleci.com/](https://circleci.com/) ```bash # From your Backstage root directory -yarn add --cwd packages/app @backstage/plugin-circleci +yarn add --cwd packages/app @circleci/backstage-plugin ``` 2. Add the `EntityCircleCIContent` extension to the entity page in your app: @@ -24,7 +25,7 @@ yarn add --cwd packages/app @backstage/plugin-circleci import { EntityCircleCIContent, isCircleCIAvailable, -} from '@backstage/plugin-circleci'; +} from '@circleci/backstage-plugin'; // For example in the CI/CD section const cicdContent = ( diff --git a/plugins/circleci/package.json b/plugins/circleci/package.json index de36505d2a..174dbda8d1 100644 --- a/plugins/circleci/package.json +++ b/plugins/circleci/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-circleci", "description": "A Backstage plugin that integrates towards Circle CI", - "version": "0.3.26-next.2", + "version": "0.3.29", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -38,10 +38,8 @@ "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.61", "@types/react": "^16.13.1 || ^17.0.0", "circleci-api": "^4.0.0", "humanize-duration": "^3.27.0", @@ -56,16 +54,8 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", "@backstage/dev-utils": "workspace:^", - "@backstage/test-utils": "workspace:^", - "@testing-library/dom": "^9.0.0", - "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "@types/humanize-duration": "^3.25.1", - "cross-fetch": "^4.0.0", - "msw": "^1.0.0" + "@types/humanize-duration": "^3.25.1" }, "files": [ "dist" diff --git a/plugins/cloudbuild/CHANGELOG.md b/plugins/cloudbuild/CHANGELOG.md index 152953b6d8..84cd321643 100644 --- a/plugins/cloudbuild/CHANGELOG.md +++ b/plugins/cloudbuild/CHANGELOG.md @@ -1,5 +1,114 @@ # @backstage/plugin-cloudbuild +## 0.3.29 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## 0.3.29-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.3.29-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + +## 0.3.29-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + +## 0.3.28 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + +## 0.3.28-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## 0.3.28-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## 0.3.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## 0.3.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + +## 0.3.26 + +### Patch Changes + +- 8ae07cab4c: Added Installation Steps so that it is clear what is needed to install and use the Google Cloud Plugin. +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + ## 0.3.26-next.2 ### Patch Changes diff --git a/plugins/cloudbuild/package.json b/plugins/cloudbuild/package.json index 822190f3b6..8d7c9a3282 100644 --- a/plugins/cloudbuild/package.json +++ b/plugins/cloudbuild/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-cloudbuild", "description": "A Backstage plugin that integrates towards Google Cloud Build", - "version": "0.3.26-next.2", + "version": "0.3.29", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -38,10 +38,8 @@ "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.61", "@types/react": "^16.13.1 || ^17.0.0", "luxon": "^3.0.0", "qs": "^6.9.4", @@ -54,15 +52,11 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", "@backstage/dev-utils": "workspace:^", "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "cross-fetch": "^4.0.0", - "msw": "^1.0.0" + "@testing-library/react": "^14.0.0" }, "files": [ "dist" diff --git a/plugins/cloudbuild/src/components/Cards/Cards.tsx b/plugins/cloudbuild/src/components/Cards/Cards.tsx index 2b7a8607b7..11efe520e0 100644 --- a/plugins/cloudbuild/src/components/Cards/Cards.tsx +++ b/plugins/cloudbuild/src/components/Cards/Cards.tsx @@ -19,7 +19,7 @@ import { useWorkflowRuns, WorkflowRun } from '../useWorkflowRuns'; import { WorkflowRunsTable } from '../WorkflowRunsTable'; import { useEntity } from '@backstage/plugin-catalog-react'; import { WorkflowRunStatus } from '../WorkflowRunStatus'; -import { Theme, makeStyles, LinearProgress } from '@material-ui/core'; +import { makeStyles, LinearProgress } from '@material-ui/core'; import ExternalLinkIcon from '@material-ui/icons/Launch'; import { CLOUDBUILD_ANNOTATION } from '../useProjectName'; @@ -31,7 +31,7 @@ import { } from '@backstage/core-components'; import { errorApiRef, useApi } from '@backstage/core-plugin-api'; -const useStyles = makeStyles({ +const useStyles = makeStyles({ externalLinkIcon: { fontSize: 'inherit', verticalAlign: 'bottom', diff --git a/plugins/cloudbuild/src/components/WorkflowRunDetails/WorkflowRunDetails.tsx b/plugins/cloudbuild/src/components/WorkflowRunDetails/WorkflowRunDetails.tsx index a35d9b6f6c..f55d7957a3 100644 --- a/plugins/cloudbuild/src/components/WorkflowRunDetails/WorkflowRunDetails.tsx +++ b/plugins/cloudbuild/src/components/WorkflowRunDetails/WorkflowRunDetails.tsx @@ -25,7 +25,6 @@ import { TableCell, TableContainer, TableRow, - Theme, Typography, } from '@material-ui/core'; import ExternalLinkIcon from '@material-ui/icons/Launch'; @@ -36,7 +35,7 @@ import { WorkflowRunStatus } from '../WorkflowRunStatus'; import { useWorkflowRunsDetails } from './useWorkflowRunsDetails'; import { Breadcrumbs, Link, WarningPanel } from '@backstage/core-components'; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles(theme => ({ root: { maxWidth: 720, margin: theme.spacing(2), diff --git a/plugins/code-climate/CHANGELOG.md b/plugins/code-climate/CHANGELOG.md index 3474d8150f..551e4fb262 100644 --- a/plugins/code-climate/CHANGELOG.md +++ b/plugins/code-climate/CHANGELOG.md @@ -1,5 +1,113 @@ # @backstage/plugin-code-climate +## 0.1.29 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## 0.1.29-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.1.29-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + +## 0.1.29-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + +## 0.1.28 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + +## 0.1.28-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## 0.1.28-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## 0.1.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## 0.1.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + +## 0.1.26 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 62b5922916: Internal theme type updates +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + ## 0.1.26-next.2 ### Patch Changes diff --git a/plugins/code-climate/package.json b/plugins/code-climate/package.json index 7a1ad81bd3..1c9971f476 100644 --- a/plugins/code-climate/package.json +++ b/plugins/code-climate/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-code-climate", - "version": "0.1.26-next.2", + "version": "0.1.29", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,10 +33,7 @@ "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", - "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.61", "@types/react": "^16.13.1 || ^17.0.0", "humanize-duration": "^3.27.1", "luxon": "^3.0.0", @@ -54,10 +51,8 @@ "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", "@types/humanize-duration": "^3.27.1", - "@types/luxon": "^3.0.0", - "msw": "^1.0.0" + "@types/luxon": "^3.0.0" }, "files": [ "dist" diff --git a/plugins/code-coverage-backend/CHANGELOG.md b/plugins/code-coverage-backend/CHANGELOG.md index bb640d02bc..e55df807d1 100644 --- a/plugins/code-coverage-backend/CHANGELOG.md +++ b/plugins/code-coverage-backend/CHANGELOG.md @@ -1,5 +1,144 @@ # @backstage/plugin-code-coverage-backend +## 0.2.23 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## 0.2.23-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## 0.2.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.2.23-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/plugin-auth-node@0.4.3-next.0 + +## 0.2.22 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/catalog-client@1.5.0 + - @backstage/integration@1.8.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.2.22-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/plugin-auth-node@0.4.2-next.3 + +## 0.2.22-next.2 + +### Patch Changes + +- Updated dependencies + - @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/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + +## 0.2.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## 0.2.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.2.21 + +### Patch Changes + +- 11f671eaa9: Added support for new backend system +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. +- Updated dependencies + - @backstage/integration@1.7.2 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.1 + ## 0.2.21-next.2 ### Patch Changes diff --git a/plugins/code-coverage-backend/package.json b/plugins/code-coverage-backend/package.json index 0b20b1fcaa..4fa0a8e6ec 100644 --- a/plugins/code-coverage-backend/package.json +++ b/plugins/code-coverage-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-code-coverage-backend", "description": "A Backstage backend plugin that helps you keep track of your code coverage", - "version": "0.2.21-next.2", + "version": "0.2.23", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -51,7 +51,6 @@ "@backstage/cli": "workspace:^", "@types/body-parser-xml": "^2.0.2", "@types/supertest": "^2.0.8", - "msw": "^1.0.0", "supertest": "^6.1.6", "xml2js": "^0.6.0" }, diff --git a/plugins/code-coverage/CHANGELOG.md b/plugins/code-coverage/CHANGELOG.md index bd28b8c0fd..5155660c36 100644 --- a/plugins/code-coverage/CHANGELOG.md +++ b/plugins/code-coverage/CHANGELOG.md @@ -1,5 +1,128 @@ # @backstage/plugin-code-coverage +## 0.2.22 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.2.22-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.2.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.2.22-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + +## 0.2.21 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.2.21-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## 0.2.21-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + +## 0.2.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## 0.2.21-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.2.19 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 71c97e7d73: The warning for missing code coverage will now render the entity as a reference. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + ## 0.2.19-next.2 ### Patch Changes diff --git a/plugins/code-coverage/package.json b/plugins/code-coverage/package.json index 12d2b501c1..c37036f1ff 100644 --- a/plugins/code-coverage/package.json +++ b/plugins/code-coverage/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-code-coverage", "description": "A Backstage plugin that helps you keep track of your code coverage", - "version": "0.2.19-next.2", + "version": "0.2.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,12 +31,10 @@ }, "dependencies": { "@backstage/catalog-model": "workspace:^", - "@backstage/config": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", @@ -53,17 +51,13 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", "@backstage/dev-utils": "workspace:^", - "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", "@types/highlightjs": "^10.1.0", "@types/react": "^16.13.1 || ^17.0.0", - "@types/recharts": "^1.8.15", - "msw": "^1.0.0" + "@types/recharts": "^1.8.15" }, "files": [ "dist" diff --git a/plugins/code-coverage/src/components/CoverageHistoryChart/CoverageHistoryChart.tsx b/plugins/code-coverage/src/components/CoverageHistoryChart/CoverageHistoryChart.tsx index 09f499fafd..3cb4ad5d56 100644 --- a/plugins/code-coverage/src/components/CoverageHistoryChart/CoverageHistoryChart.tsx +++ b/plugins/code-coverage/src/components/CoverageHistoryChart/CoverageHistoryChart.tsx @@ -15,7 +15,6 @@ */ import { useEntity } from '@backstage/plugin-catalog-react'; -import { BackstageTheme } from '@backstage/theme'; import { Box, Card, @@ -50,7 +49,7 @@ import { DateTime } from 'luxon'; type Coverage = 'line' | 'branch'; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles(theme => ({ trendDown: { color: theme.palette.status.warning, }, diff --git a/plugins/codescene/CHANGELOG.md b/plugins/codescene/CHANGELOG.md index a82096cabf..df9ed3199f 100644 --- a/plugins/codescene/CHANGELOG.md +++ b/plugins/codescene/CHANGELOG.md @@ -1,5 +1,105 @@ # @backstage/plugin-codescene +## 0.1.21 + +### Patch Changes + +- d5eda61: Updated Readme document in codescene plugin +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.1.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.1.21-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + +## 0.1.20 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.1.20-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + +## 0.1.20-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/config@1.1.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + +## 0.1.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## 0.1.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.1.19 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + ## 0.1.19-next.2 ### Patch Changes diff --git a/plugins/codescene/README.md b/plugins/codescene/README.md index bbfb58e68f..8c84c9015c 100644 --- a/plugins/codescene/README.md +++ b/plugins/codescene/README.md @@ -1,8 +1,8 @@ # codescene -[CodeScene](https://codescene.com/) is a multi-purpose tool bridging code, business and people. See hidden risks and social patterns in your code. Prioritize and reduce technical debt. +[CodeScene](https://codescene.com/) is a multi-purpose tool that connects code, businesses, and people. Discover hidden hazards and social trends in your code. Prioritise and minimise technical debt. -The CodeScene Backstage Plugin exposes a page component that will list the existing projects and their analysis data on your CodeScene instance. +The CodeScene Backstage Plugin provides a page component that displays a list of existing projects and associated analysis data on your CodeScene instance. ![screenshot](./docs/codescene-plugin-screenshot.png) diff --git a/plugins/codescene/package.json b/plugins/codescene/package.json index ced314c7ce..f0dfd20394 100644 --- a/plugins/codescene/package.json +++ b/plugins/codescene/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-codescene", - "version": "0.1.19-next.2", + "version": "0.1.21", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,9 +33,7 @@ "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", - "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", "@types/react": "^16.13.1 || ^17.0.0", "rc-progress": "3.5.1", @@ -54,7 +52,6 @@ "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, "files": [ diff --git a/plugins/codescene/src/components/Gauge/Gauge.tsx b/plugins/codescene/src/components/Gauge/Gauge.tsx index 97e6b33daf..df91136b6a 100644 --- a/plugins/codescene/src/components/Gauge/Gauge.tsx +++ b/plugins/codescene/src/components/Gauge/Gauge.tsx @@ -13,13 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { BackstagePalette, BackstageTheme } from '@backstage/theme'; + import { makeStyles, useTheme } from '@material-ui/core/styles'; +import { Palette } from '@material-ui/core/styles/createPalette'; import Tooltip from '@material-ui/core/Tooltip'; import { Circle } from 'rc-progress'; import React, { useEffect, useState } from 'react'; -const useStyles = makeStyles( +const useStyles = makeStyles( theme => ({ root: { position: 'relative', @@ -51,7 +52,7 @@ export type GaugeProps = { }; export type GaugePropsGetColorOptions = { - palette: BackstagePalette; + palette: Palette; value: number; max: number; }; @@ -78,11 +79,10 @@ export const getProgressColor: GaugePropsGetColor = ({ /** * Circular Progress Bar - * */ export function Gauge(props: GaugeProps) { const classes = useStyles(props); - const { palette } = useTheme(); + const { palette } = useTheme(); const [hoverRef, setHoverRef] = useState(null); const [open, setOpen] = useState(false); const { value, max, tooltipDelay, tooltipText } = { diff --git a/plugins/config-schema/CHANGELOG.md b/plugins/config-schema/CHANGELOG.md index 1137a9207b..0ed7d3afd5 100644 --- a/plugins/config-schema/CHANGELOG.md +++ b/plugins/config-schema/CHANGELOG.md @@ -1,5 +1,110 @@ # @backstage/plugin-config-schema +## 0.1.49 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.1.49-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.1.49-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.1.48 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.1.48-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/types@1.1.1 + +## 0.1.48-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/config@1.1.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.1.48-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + +## 0.1.48-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.1.47 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + ## 0.1.47-next.2 ### Patch Changes diff --git a/plugins/config-schema/package.json b/plugins/config-schema/package.json index 230639106c..15860d4e89 100644 --- a/plugins/config-schema/package.json +++ b/plugins/config-schema/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-config-schema", "description": "A Backstage plugin that lets you browse the configuration schema of your app", - "version": "0.1.47-next.2", + "version": "0.1.49", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,11 +30,9 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/config": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", - "@backstage/theme": "workspace:^", "@backstage/types": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -51,14 +49,10 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", "@backstage/dev-utils": "workspace:^", - "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "msw": "^1.0.0" + "@testing-library/react": "^14.0.0" }, "files": [ "dist" diff --git a/plugins/cost-insights/CHANGELOG.md b/plugins/cost-insights/CHANGELOG.md index 1f343ab3ee..cd0c31e2f1 100644 --- a/plugins/cost-insights/CHANGELOG.md +++ b/plugins/cost-insights/CHANGELOG.md @@ -1,5 +1,137 @@ # @backstage/plugin-cost-insights +## 0.12.18 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0 + - @backstage/plugin-cost-insights-common@0.1.2 + +## 0.12.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.12.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/config@1.1.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0 + - @backstage/plugin-cost-insights-common@0.1.2 + +## 0.12.18-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1 + - @backstage/theme@0.5.0 + - @backstage/plugin-cost-insights-common@0.1.2 + +## 0.12.17 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-cost-insights-common@0.1.2 + +## 0.12.17-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + - @backstage/plugin-cost-insights-common@0.1.2 + +## 0.12.17-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-cost-insights-common@0.1.2 + +## 0.12.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-cost-insights-common@0.1.2 + +## 0.12.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-cost-insights-common@0.1.2 + +## 0.12.15 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 69ee8d75f4: Remove `button` prop from used MaterialUI `MenuItem` component fixing incompatibility with MaterialUI v5. +- d49cffaf6a: Updated dependency `@types/pluralize` to `^0.0.33`. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- 7da799d5b7: Updated dependency `@types/pluralize` to `^0.0.32`. +- 62b5922916: Internal theme type updates +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-cost-insights-common@0.1.2 + ## 0.12.15-next.2 ### Patch Changes diff --git a/plugins/cost-insights/package.json b/plugins/cost-insights/package.json index 6627f1f175..2db994d466 100644 --- a/plugins/cost-insights/package.json +++ b/plugins/cost-insights/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-cost-insights", "description": "A Backstage plugin that helps you keep track of your cloud spend", - "version": "0.12.15-next.2", + "version": "0.12.18", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -74,9 +74,7 @@ "@types/recharts": "^1.8.14", "@types/regression": "^2.0.0", "@types/yup": "^0.29.13", - "canvas": "^2.10.2", - "cross-fetch": "^4.0.0", - "msw": "^1.0.0" + "canvas": "^2.10.2" }, "files": [ "dist", diff --git a/plugins/cost-insights/src/components/CostInsightsNavigation/CostInsightsNavigation.tsx b/plugins/cost-insights/src/components/CostInsightsNavigation/CostInsightsNavigation.tsx index 507016f391..0bdfed3855 100644 --- a/plugins/cost-insights/src/components/CostInsightsNavigation/CostInsightsNavigation.tsx +++ b/plugins/cost-insights/src/components/CostInsightsNavigation/CostInsightsNavigation.tsx @@ -44,7 +44,6 @@ const NavigationMenuItem = ({ navigation, icon, title }: NavigationItem) => { const [, setScroll] = useScroll(); return ( setScroll(navigation)} diff --git a/plugins/cost-insights/src/utils/styles.ts b/plugins/cost-insights/src/utils/styles.ts index cec9c0150d..c4c330138b 100644 --- a/plugins/cost-insights/src/utils/styles.ts +++ b/plugins/cost-insights/src/utils/styles.ts @@ -21,9 +21,9 @@ import { getLuminance, lighten, makeStyles, + Theme, } from '@material-ui/core'; import { CostInsightsTheme, CostInsightsThemeOptions } from '../types'; -import { BackstageTheme } from '@backstage/theme'; export const costInsightsLightTheme = { palette: { @@ -231,7 +231,7 @@ export const useCostInsightsStyles = makeStyles(theme => ({ }, })); -export const useCostInsightsTabsStyles = makeStyles(theme => ({ +export const useCostInsightsTabsStyles = makeStyles(theme => ({ tabs: { borderBottom: `1px solid ${theme.palette.textVerySubtle}`, backgroundColor: brighten(theme.palette.background.default), diff --git a/plugins/devtools-backend/CHANGELOG.md b/plugins/devtools-backend/CHANGELOG.md index 6cc2983ba7..62e91cc50c 100644 --- a/plugins/devtools-backend/CHANGELOG.md +++ b/plugins/devtools-backend/CHANGELOG.md @@ -1,5 +1,171 @@ # @backstage/plugin-devtools-backend +## 0.2.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/config-loader@1.6.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.8 + +## 0.2.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + - @backstage/plugin-permission-node@0.7.20-next.2 + - @backstage/config-loader@1.6.1-next.0 + +## 0.2.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.6.1-next.0 + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/plugin-permission-node@0.7.20-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.7 + - @backstage/plugin-permission-common@0.7.11 + +## 0.2.6-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.6.0 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.0 + - @backstage/plugin-devtools-common@0.1.7 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.20-next.0 + +## 0.2.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/config-loader@1.6.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.19 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.7 + +## 0.2.5-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.6.0-next.0 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.3 + - @backstage/plugin-devtools-common@0.1.6 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.3 + +## 0.2.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.6.0-next.0 + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.6 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.2 + +## 0.2.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.5.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-devtools-common@0.1.6 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + +## 0.2.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/plugin-permission-node@0.7.19-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/config-loader@1.5.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.6 + - @backstage/plugin-permission-common@0.7.10 + +## 0.2.4 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.5.3 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.1 + - @backstage/plugin-devtools-common@0.1.6 + - @backstage/plugin-permission-node@0.7.18 + ## 0.2.4-next.2 ### Patch Changes diff --git a/plugins/devtools-backend/package.json b/plugins/devtools-backend/package.json index 43a4bab569..4d56c3e9dd 100644 --- a/plugins/devtools-backend/package.json +++ b/plugins/devtools-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-devtools-backend", - "version": "0.2.4-next.2", + "version": "0.2.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -59,7 +59,6 @@ "@types/ping": "^0.4.1", "@types/supertest": "^2.0.8", "@types/yarnpkg__lockfile": "^1.1.4", - "msw": "^1.0.0", "supertest": "^6.2.4" }, "files": [ diff --git a/plugins/devtools-common/CHANGELOG.md b/plugins/devtools-common/CHANGELOG.md index 4a95434b3d..3bbc48a585 100644 --- a/plugins/devtools-common/CHANGELOG.md +++ b/plugins/devtools-common/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-devtools-common +## 0.1.8 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.12 + - @backstage/types@1.1.1 + +## 0.1.7 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.11 + - @backstage/types@1.1.1 + +## 0.1.6 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.10 + - @backstage/types@1.1.1 + ## 0.1.5 ### Patch Changes diff --git a/plugins/devtools-common/package.json b/plugins/devtools-common/package.json index 703ad2a5e3..a488e997a1 100644 --- a/plugins/devtools-common/package.json +++ b/plugins/devtools-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-devtools-common", "description": "Common functionalities for the devtools plugin", - "version": "0.1.5", + "version": "0.1.8", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/devtools/.eslintrc.js b/plugins/devtools/.eslintrc.js index e2a53a6ad2..e487f765b2 100644 --- a/plugins/devtools/.eslintrc.js +++ b/plugins/devtools/.eslintrc.js @@ -1 +1,5 @@ -module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, { + rules: { + '@backstage/no-top-level-material-ui-4-imports': 'error', + }, +}); diff --git a/plugins/devtools/CHANGELOG.md b/plugins/devtools/CHANGELOG.md index 87c2de069b..4237bd149a 100644 --- a/plugins/devtools/CHANGELOG.md +++ b/plugins/devtools/CHANGELOG.md @@ -1,5 +1,120 @@ # @backstage/plugin-devtools +## 0.1.8 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/errors@1.2.3 + - @backstage/plugin-devtools-common@0.1.8 + +## 0.1.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-permission-react@0.4.19-next.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-devtools-common@0.1.7 + +## 0.1.8-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-permission-react@0.4.19-next.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-devtools-common@0.1.7 + +## 0.1.7 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/plugin-permission-react@0.4.18 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.7 + +## 0.1.7-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.6 + - @backstage/plugin-permission-react@0.4.18-next.1 + +## 0.1.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.6 + - @backstage/plugin-permission-react@0.4.18-next.1 + +## 0.1.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.6 + +## 0.1.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-permission-react@0.4.18-next.0 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.6 + +## 0.1.6 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-permission-react@0.4.17 + - @backstage/theme@0.4.4 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.6 + ## 0.1.6-next.2 ### Patch Changes diff --git a/plugins/devtools/api-report.md b/plugins/devtools/api-report.md index 21754d7c1e..bba36a5a9a 100644 --- a/plugins/devtools/api-report.md +++ b/plugins/devtools/api-report.md @@ -10,7 +10,7 @@ import { default as default_2 } from 'react'; import { JSX as JSX_2 } from 'react'; import { default as React_2 } from 'react'; import { RouteRef } from '@backstage/core-plugin-api'; -import { TabProps } from '@material-ui/core'; +import { TabProps } from '@material-ui/core/Tab'; // @public (undocumented) export const ConfigContent: () => React_2.JSX.Element; diff --git a/plugins/devtools/package.json b/plugins/devtools/package.json index cb257371bc..ece8fe89e3 100644 --- a/plugins/devtools/package.json +++ b/plugins/devtools/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-devtools", - "version": "0.1.6-next.2", + "version": "0.1.8", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,8 +34,6 @@ "@backstage/errors": "workspace:^", "@backstage/plugin-devtools-common": "workspace:^", "@backstage/plugin-permission-react": "workspace:^", - "@backstage/theme": "workspace:^", - "@backstage/types": "workspace:^", "@material-ui/core": "^4.9.13", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "^4.0.0-alpha.57", @@ -50,14 +48,9 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", "@backstage/dev-utils": "workspace:^", - "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "cross-fetch": "^4.0.0", - "msw": "^1.0.0" + "@testing-library/react": "^14.0.0" }, "files": [ "dist" diff --git a/plugins/devtools/src/components/Content/ConfigContent/ConfigContent.tsx b/plugins/devtools/src/components/Content/ConfigContent/ConfigContent.tsx index 66129b5dae..aba46f85b7 100644 --- a/plugins/devtools/src/components/Content/ConfigContent/ConfigContent.tsx +++ b/plugins/devtools/src/components/Content/ConfigContent/ConfigContent.tsx @@ -15,16 +15,16 @@ */ import { Progress, WarningPanel } from '@backstage/core-components'; +import Box from '@material-ui/core/Box'; +import Paper from '@material-ui/core/Paper'; +import Typography from '@material-ui/core/Typography'; import { - Box, createStyles, makeStyles, - Paper, Theme, - Typography, useTheme, -} from '@material-ui/core'; -import { Alert } from '@material-ui/lab'; +} from '@material-ui/core/styles'; +import Alert from '@material-ui/lab/Alert'; import React from 'react'; import ReactJson from 'react-json-view'; import { useConfig } from '../../../hooks'; diff --git a/plugins/devtools/src/components/Content/ExternalDependenciesContent/ExternalDependenciesContent.tsx b/plugins/devtools/src/components/Content/ExternalDependenciesContent/ExternalDependenciesContent.tsx index a5dd825fe5..c6a46ea8fb 100644 --- a/plugins/devtools/src/components/Content/ExternalDependenciesContent/ExternalDependenciesContent.tsx +++ b/plugins/devtools/src/components/Content/ExternalDependenciesContent/ExternalDependenciesContent.tsx @@ -23,16 +23,12 @@ import { TableColumn, } from '@backstage/core-components'; import { ExternalDependency } from '@backstage/plugin-devtools-common'; -import { - Box, - createStyles, - Grid, - makeStyles, - Paper, - Theme, - Typography, -} from '@material-ui/core'; -import { Alert } from '@material-ui/lab'; +import Box from '@material-ui/core/Box'; +import Grid from '@material-ui/core/Grid'; +import Paper from '@material-ui/core/Paper'; +import Typography from '@material-ui/core/Typography'; +import { createStyles, makeStyles, Theme } from '@material-ui/core/styles'; +import Alert from '@material-ui/lab/Alert'; import React from 'react'; import { useExternalDependencies } from '../../../hooks'; diff --git a/plugins/devtools/src/components/Content/InfoContent/BackstageLogoIcon.tsx b/plugins/devtools/src/components/Content/InfoContent/BackstageLogoIcon.tsx index 32f35600f2..8a9df77546 100644 --- a/plugins/devtools/src/components/Content/InfoContent/BackstageLogoIcon.tsx +++ b/plugins/devtools/src/components/Content/InfoContent/BackstageLogoIcon.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { SvgIcon, SvgIconProps } from '@material-ui/core'; +import SvgIcon, { SvgIconProps } from '@material-ui/core/SvgIcon'; import React from 'react'; diff --git a/plugins/devtools/src/components/Content/InfoContent/InfoContent.tsx b/plugins/devtools/src/components/Content/InfoContent/InfoContent.tsx index 0ed43d2fee..fcbea53603 100644 --- a/plugins/devtools/src/components/Content/InfoContent/InfoContent.tsx +++ b/plugins/devtools/src/components/Content/InfoContent/InfoContent.tsx @@ -15,20 +15,16 @@ */ import { Progress } from '@backstage/core-components'; -import { - Avatar, - Box, - createStyles, - Divider, - List, - ListItem, - ListItemAvatar, - ListItemText, - makeStyles, - Paper, - Theme, -} from '@material-ui/core'; -import { Alert } from '@material-ui/lab'; +import Avatar from '@material-ui/core/Avatar'; +import Box from '@material-ui/core/Box'; +import Divider from '@material-ui/core/Divider'; +import List from '@material-ui/core/List'; +import ListItem from '@material-ui/core/ListItem'; +import ListItemAvatar from '@material-ui/core/ListItemAvatar'; +import ListItemText from '@material-ui/core/ListItemText'; +import Paper from '@material-ui/core/Paper'; +import { createStyles, makeStyles, Theme } from '@material-ui/core/styles'; +import Alert from '@material-ui/lab/Alert'; import React from 'react'; import { useInfo } from '../../../hooks'; import { InfoDependenciesTable } from './InfoDependenciesTable'; diff --git a/plugins/devtools/src/components/DevToolsLayout/DevToolsLayout.tsx b/plugins/devtools/src/components/DevToolsLayout/DevToolsLayout.tsx index ae9a337ced..bce0837ef1 100644 --- a/plugins/devtools/src/components/DevToolsLayout/DevToolsLayout.tsx +++ b/plugins/devtools/src/components/DevToolsLayout/DevToolsLayout.tsx @@ -19,7 +19,7 @@ import { attachComponentData, useElementFilter, } from '@backstage/core-plugin-api'; -import { TabProps } from '@material-ui/core'; +import { TabProps } from '@material-ui/core/Tab'; import { default as React } from 'react'; /** @public */ diff --git a/plugins/dynatrace/CHANGELOG.md b/plugins/dynatrace/CHANGELOG.md index a664369aa4..1cff141762 100644 --- a/plugins/dynatrace/CHANGELOG.md +++ b/plugins/dynatrace/CHANGELOG.md @@ -1,5 +1,112 @@ # @backstage/plugin-dynatrace +## 8.0.3 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## 8.0.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 8.0.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + +## 8.0.3-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + +## 8.0.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + +## 8.0.2-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## 8.0.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## 8.0.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## 8.0.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + +## 8.0.0 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + ## 8.0.0-next.2 ### Patch Changes diff --git a/plugins/dynatrace/package.json b/plugins/dynatrace/package.json index 51c62a94da..c82b8a4d5b 100644 --- a/plugins/dynatrace/package.json +++ b/plugins/dynatrace/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-dynatrace", - "version": "8.0.0-next.2", + "version": "8.0.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,10 +32,7 @@ "@backstage/catalog-model": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", - "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.61", "@types/react": "^16.13.1 || ^17.0.0", "react-use": "^17.2.4" }, @@ -52,10 +49,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "express": "^4.18.1", - "msw": "^1.0.0" + "@testing-library/react": "^14.0.0" }, "files": [ "dist", diff --git a/plugins/entity-feedback-backend/CHANGELOG.md b/plugins/entity-feedback-backend/CHANGELOG.md index 11714d4fa0..e9eec4b8f2 100644 --- a/plugins/entity-feedback-backend/CHANGELOG.md +++ b/plugins/entity-feedback-backend/CHANGELOG.md @@ -1,5 +1,134 @@ # @backstage/plugin-entity-feedback-backend +## 0.2.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## 0.2.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## 0.2.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## 0.2.6-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.0 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## 0.2.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/catalog-client@1.5.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## 0.2.5-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.3 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## 0.2.5-next.2 + +### Patch Changes + +- Updated dependencies + - @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/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## 0.2.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## 0.2.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## 0.2.4 + +### Patch Changes + +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.1 + - @backstage/plugin-entity-feedback-common@0.1.3 + ## 0.2.4-next.2 ### Patch Changes diff --git a/plugins/entity-feedback-backend/package.json b/plugins/entity-feedback-backend/package.json index c19bf4b0c4..8e5deafdf1 100644 --- a/plugins/entity-feedback-backend/package.json +++ b/plugins/entity-feedback-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-entity-feedback-backend", - "version": "0.2.4-next.2", + "version": "0.2.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -47,7 +47,6 @@ "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@types/supertest": "^2.0.12", - "msw": "^1.0.0", "supertest": "^6.2.4" }, "files": [ diff --git a/plugins/entity-feedback/CHANGELOG.md b/plugins/entity-feedback/CHANGELOG.md index 218acbb296..5cc2ae9468 100644 --- a/plugins/entity-feedback/CHANGELOG.md +++ b/plugins/entity-feedback/CHANGELOG.md @@ -1,5 +1,129 @@ # @backstage/plugin-entity-feedback +## 0.2.12 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## 0.2.12-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.2.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## 0.2.12-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## 0.2.11 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## 0.2.11-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## 0.2.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## 0.2.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## 0.2.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## 0.2.9 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-entity-feedback-common@0.1.3 + ## 0.2.9-next.2 ### Patch Changes diff --git a/plugins/entity-feedback/package.json b/plugins/entity-feedback/package.json index 5c0317d19a..226c76c106 100644 --- a/plugins/entity-feedback/package.json +++ b/plugins/entity-feedback/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-entity-feedback", - "version": "0.2.9-next.2", + "version": "0.2.12", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,10 +35,8 @@ "@backstage/errors": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", "@backstage/plugin-entity-feedback-common": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.9.13", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.61", "@types/react": "^16.13.1 || ^17.0.0", "react-use": "^17.2.4" }, @@ -49,8 +47,6 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", - "@backstage/dev-utils": "workspace:^", "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", diff --git a/plugins/entity-feedback/src/components/FeedbackResponseTable/FeedbackResponseTable.tsx b/plugins/entity-feedback/src/components/FeedbackResponseTable/FeedbackResponseTable.tsx index 654cfd1413..863cdcc6b6 100644 --- a/plugins/entity-feedback/src/components/FeedbackResponseTable/FeedbackResponseTable.tsx +++ b/plugins/entity-feedback/src/components/FeedbackResponseTable/FeedbackResponseTable.tsx @@ -18,7 +18,6 @@ import { ErrorPanel, Table } from '@backstage/core-components'; import { useApi } from '@backstage/core-plugin-api'; import { EntityRefLink } from '@backstage/plugin-catalog-react'; import { FeedbackResponse } from '@backstage/plugin-entity-feedback-common'; -import { BackstageTheme } from '@backstage/theme'; import { Chip, makeStyles } from '@material-ui/core'; import CheckIcon from '@material-ui/icons/Check'; import React from 'react'; @@ -28,7 +27,7 @@ import { entityFeedbackApiRef } from '../../api'; type ResponseRow = Omit; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles(theme => ({ consentCheck: { color: theme.palette.status.ok, }, diff --git a/plugins/entity-validation/CHANGELOG.md b/plugins/entity-validation/CHANGELOG.md index 50b1f294da..f1070960c8 100644 --- a/plugins/entity-validation/CHANGELOG.md +++ b/plugins/entity-validation/CHANGELOG.md @@ -1,5 +1,140 @@ # @backstage/plugin-entity-validation +## 0.1.14 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.20 + +## 0.1.14-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.1.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.19 + +## 0.1.14-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.19 + +## 0.1.13 + +### Patch Changes + +- a518c5a: Updated dependency `@react-hookz/web` to `^23.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-client@1.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.19 + +## 0.1.13-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## 0.1.13-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.18 + +## 0.1.13-next.1 + +### Patch Changes + +- a518c5a25b: Updated dependency `@react-hookz/web` to `^23.0.0`. +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-catalog-common@1.0.18 + +## 0.1.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.18 + +## 0.1.11 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.18 + ## 0.1.11-next.2 ### Patch Changes diff --git a/plugins/entity-validation/api-report.md b/plugins/entity-validation/api-report.md index 9d69458ed0..95fdfaf42c 100644 --- a/plugins/entity-validation/api-report.md +++ b/plugins/entity-validation/api-report.md @@ -7,12 +7,15 @@ import { BackstagePlugin } from '@backstage/core-plugin-api'; import { JSX as JSX_2 } from 'react'; +import { ReactNode } from 'react'; import { RouteRef } from '@backstage/core-plugin-api'; // @public (undocumented) export const EntityValidationPage: (props: { defaultYaml?: string | undefined; defaultLocation?: string | undefined; + hideFileLocationField?: boolean | undefined; + contentHead?: ReactNode; }) => JSX_2.Element; // @public (undocumented) diff --git a/plugins/entity-validation/package.json b/plugins/entity-validation/package.json index ead1a14221..7e2389dd7a 100644 --- a/plugins/entity-validation/package.json +++ b/plugins/entity-validation/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-entity-validation", - "version": "0.1.11-next.2", + "version": "0.1.14", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -36,14 +36,13 @@ "@backstage/errors": "workspace:^", "@backstage/plugin-catalog-common": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", - "@backstage/theme": "workspace:^", "@codemirror/language": "^6.0.0", "@codemirror/legacy-modes": "^6.1.0", "@codemirror/view": "^6.0.0", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", - "@react-hookz/web": "^20.0.0", + "@react-hookz/web": "^23.0.0", "@types/react": "^16.13.1 || ^17.0.0", "@uiw/react-codemirror": "^4.9.3", "lodash": "^4.17.21", @@ -57,14 +56,11 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", "@backstage/dev-utils": "workspace:^", "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "msw": "^1.0.0" + "@testing-library/react": "^14.0.0" }, "files": [ "dist" diff --git a/plugins/entity-validation/src/components/EntityValidationPage/EntityValidationPage.test.tsx b/plugins/entity-validation/src/components/EntityValidationPage/EntityValidationPage.test.tsx new file mode 100644 index 0000000000..c8827ffc13 --- /dev/null +++ b/plugins/entity-validation/src/components/EntityValidationPage/EntityValidationPage.test.tsx @@ -0,0 +1,91 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { TestApiProvider, renderInTestApp } from '@backstage/test-utils'; +import { EntityValidationPage } from './EntityValidationPage'; +import { CatalogApi, catalogApiRef } from '@backstage/plugin-catalog-react'; +import { MarkdownContent } from '@backstage/core-components'; + +describe('EntityValidatorPage', () => { + const catalogApi: Partial = { + getEntities: () => + Promise.resolve({ + items: [ + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'API', + metadata: { + name: 'Entity1', + annotations: { + 'backstage.io/view-url': 'viewurl', + 'backstage.io/edit-url': 'editurl', + }, + }, + spec: { type: 'openapi' }, + }, + ], + }), + }; + + const contentHead = ; + + it('should show loation text field', async () => { + const { getByText, getByTestId } = await renderInTestApp( + + + , + ); + const mainGrid = getByTestId('main-grid'); + + expect(mainGrid.children.length).toBe(2); + expect(getByText('File Location')).toBeInTheDocument(); + }); + + it('should not show loation text field', async () => { + const { queryByText, getByTestId } = await renderInTestApp( + + + , + ); + const mainGrid = getByTestId('main-grid'); + + expect(mainGrid.children.length).toBe(1); + expect(queryByText('File Location')).not.toBeInTheDocument(); + }); + + it('should not show content head', async () => { + const { getByTestId } = await renderInTestApp( + + + , + ); + const mainGrid = getByTestId('main-grid'); + + expect(mainGrid.children.length).toBe(2); + }); + + it('should show content head', async () => { + const { getByTestId } = await renderInTestApp( + + + , + ); + const mainGrid = getByTestId('main-grid'); + + expect(mainGrid.children.length).toBe(3); + }); +}); diff --git a/plugins/entity-validation/src/components/EntityValidationPage/EntityValidationPage.tsx b/plugins/entity-validation/src/components/EntityValidationPage/EntityValidationPage.tsx index 0f0e60366b..c3e6386a37 100644 --- a/plugins/entity-validation/src/components/EntityValidationPage/EntityValidationPage.tsx +++ b/plugins/entity-validation/src/components/EntityValidationPage/EntityValidationPage.tsx @@ -15,9 +15,9 @@ */ import React, { useState } from 'react'; -import { Content, Header, LinkButton, Page } from '@backstage/core-components'; +import { Content, Header, Page } from '@backstage/core-components'; import { EntityTextArea } from '../EntityTextArea'; -import { Grid, TextField } from '@material-ui/core'; +import { Button, Grid, TextField } from '@material-ui/core'; import { CatalogProcessorResult } from '../../types'; import { parseEntityYaml } from '../../utils'; import { EntityValidationOutput } from '../EntityValidationOutput'; @@ -40,10 +40,14 @@ spec: export const EntityValidationPage = (props: { defaultYaml?: string; defaultLocation?: string; + hideFileLocationField?: boolean; + contentHead?: React.ReactNode; }) => { const { defaultYaml = EXAMPLE_CATALOG_INFO_YAML, defaultLocation = 'https://github.com/backstage/backstage/blob/master/catalog-info.yaml', + hideFileLocationField = false, + contentHead, } = props; const [catalogYaml, setCatalogYaml] = useState(defaultYaml); @@ -67,8 +71,16 @@ export const EntityValidationPage = (props: { subtitle="Tool to validate catalog-info.yaml files" /> - - + + {contentHead} + + {!hideFileLocationField && ( setLocationUrl(e.target.value)} /> - - - - - - Validate - + )} + + + + + + setCatalogYaml(value)} + catalogYaml={catalogYaml} + /> + + + + - - - - - setCatalogYaml(value)} - catalogYaml={catalogYaml} - /> - - - - - + + + + + diff --git a/plugins/events-backend-module-aws-sqs/CHANGELOG.md b/plugins/events-backend-module-aws-sqs/CHANGELOG.md index c005cdb894..b77a2912ca 100644 --- a/plugins/events-backend-module-aws-sqs/CHANGELOG.md +++ b/plugins/events-backend-module-aws-sqs/CHANGELOG.md @@ -1,5 +1,132 @@ # @backstage/plugin-events-backend-module-aws-sqs +## 0.2.12 + +### Patch Changes + +- 7b8e551: Fix errors when deleting SQS messages: + + - If zero messages were received, skip deletion to avoid `EmptyBatchRequest` error from the SQS client. + - If zero failures were returned from the SQS client during deletion, skip error logging. + +- d5ddc4e: Add documentation on how to install the plugins with the new backend system. +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-tasks@0.5.14 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.18 + +## 0.2.12-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-events-node@0.2.18-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## 0.2.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.18-next.1 + +## 0.2.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/backend-tasks@0.5.14-next.0 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.18-next.0 + +## 0.2.11 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.17 + +## 0.2.11-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/backend-tasks@0.5.13-next.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.3 + +## 0.2.11-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/backend-tasks@0.5.13-next.2 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.2 + +## 0.2.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.1 + +## 0.2.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.0 + +## 0.2.10 + +### Patch Changes + +- 3d043526f4: Updated dependency `aws-sdk-client-mock` to `^3.0.0`. +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.16 + ## 0.2.10-next.2 ### Patch Changes diff --git a/plugins/events-backend-module-aws-sqs/README.md b/plugins/events-backend-module-aws-sqs/README.md index cb3a5045c0..397de35c10 100644 --- a/plugins/events-backend-module-aws-sqs/README.md +++ b/plugins/events-backend-module-aws-sqs/README.md @@ -40,3 +40,7 @@ events: # From your Backstage root directory yarn add --cwd packages/backend @backstage/plugin-events-backend-module-aws-sqs ``` + +```ts title="packages/backend/src/index.ts" +backend.add(import('@backstage/plugin-events-backend-module-aws-sqs/alpha')); +``` diff --git a/plugins/events-backend-module-aws-sqs/alpha-api-report.md b/plugins/events-backend-module-aws-sqs/api-report-alpha.md similarity index 100% rename from plugins/events-backend-module-aws-sqs/alpha-api-report.md rename to plugins/events-backend-module-aws-sqs/api-report-alpha.md diff --git a/plugins/events-backend-module-aws-sqs/package.json b/plugins/events-backend-module-aws-sqs/package.json index 89c909ce51..6e0c986554 100644 --- a/plugins/events-backend-module-aws-sqs/package.json +++ b/plugins/events-backend-module-aws-sqs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-aws-sqs", - "version": "0.2.10-next.2", + "version": "0.2.12", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-backend-module-aws-sqs/src/publisher/AwsSqsConsumingEventPublisher.ts b/plugins/events-backend-module-aws-sqs/src/publisher/AwsSqsConsumingEventPublisher.ts index 4f4e6ea55d..a2f6a00fe7 100644 --- a/plugins/events-backend-module-aws-sqs/src/publisher/AwsSqsConsumingEventPublisher.ts +++ b/plugins/events-backend-module-aws-sqs/src/publisher/AwsSqsConsumingEventPublisher.ts @@ -111,7 +111,7 @@ export class AwsSqsConsumingEventPublisher implements EventPublisher { } private async deleteMessages(messages?: Message[]): Promise { - if (!messages) { + if (!messages || messages.length === 0) { return; } @@ -129,7 +129,7 @@ export class AwsSqsConsumingEventPublisher implements EventPublisher { const result = await this.sqs.send( new DeleteMessageBatchCommand(deleteParams), ); - if (result.Failed) { + if (result.Failed && result.Failed.length > 0) { this.logger.error( `Failed to delete ${result.Failed!.length} of ${ messages.length diff --git a/plugins/events-backend-module-aws-sqs/src/service/eventsModuleAwsSqsConsumingEventPublisher.ts b/plugins/events-backend-module-aws-sqs/src/service/eventsModuleAwsSqsConsumingEventPublisher.ts index 9045047094..eabab94708 100644 --- a/plugins/events-backend-module-aws-sqs/src/service/eventsModuleAwsSqsConsumingEventPublisher.ts +++ b/plugins/events-backend-module-aws-sqs/src/service/eventsModuleAwsSqsConsumingEventPublisher.ts @@ -29,7 +29,7 @@ import { AwsSqsConsumingEventPublisher } from '../publisher/AwsSqsConsumingEvent */ export const eventsModuleAwsSqsConsumingEventPublisher = createBackendModule({ pluginId: 'events', - moduleId: 'awsSqsConsumingEventPublisher', + moduleId: 'aws-sqs-consuming-event-publisher', register(env) { env.registerInit({ deps: { diff --git a/plugins/events-backend-module-azure/CHANGELOG.md b/plugins/events-backend-module-azure/CHANGELOG.md index 1a0bedecf9..233d9f6eb5 100644 --- a/plugins/events-backend-module-azure/CHANGELOG.md +++ b/plugins/events-backend-module-azure/CHANGELOG.md @@ -1,5 +1,90 @@ # @backstage/plugin-events-backend-module-azure +## 0.1.19 + +### Patch Changes + +- af76a95: Add default exports for the new backend system and documentation. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-events-node@0.2.18 + +## 0.1.19-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-events-node@0.2.18-next.2 + +## 0.1.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/plugin-events-node@0.2.18-next.1 + +## 0.1.19-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/plugin-events-node@0.2.18-next.0 + +## 0.1.18 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8 + - @backstage/plugin-events-node@0.2.17 + +## 0.1.18-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/plugin-events-node@0.2.17-next.3 + +## 0.1.18-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/plugin-events-node@0.2.17-next.2 + +## 0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-events-node@0.2.17-next.1 + +## 0.1.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/plugin-events-node@0.2.17-next.0 + +## 0.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.7 + - @backstage/plugin-events-node@0.2.16 + ## 0.1.17-next.2 ### Patch Changes diff --git a/plugins/events-backend-module-azure/README.md b/plugins/events-backend-module-azure/README.md index 26bffbc45d..457fd81fbc 100644 --- a/plugins/events-backend-module-azure/README.md +++ b/plugins/events-backend-module-azure/README.md @@ -31,6 +31,14 @@ Install this module: yarn add --cwd packages/backend @backstage/plugin-events-backend-module-azure ``` +### Add to backend + +```ts title="packages/backend/src/index.ts" +backend.add(import('@backstage/plugin-events-backend-module-azure/alpha')); +``` + +### Add to backend (old) + Add the event router to the `EventsBackend` instance in `packages/backend/src/plugins/events.ts`: ```diff diff --git a/plugins/events-backend-module-azure/alpha-api-report.md b/plugins/events-backend-module-azure/api-report-alpha.md similarity index 65% rename from plugins/events-backend-module-azure/alpha-api-report.md rename to plugins/events-backend-module-azure/api-report-alpha.md index 1bd568d1df..d07f8852f3 100644 --- a/plugins/events-backend-module-azure/alpha-api-report.md +++ b/plugins/events-backend-module-azure/api-report-alpha.md @@ -6,7 +6,9 @@ import { BackendFeature } from '@backstage/backend-plugin-api'; // @alpha -export const eventsModuleAzureDevOpsEventRouter: () => BackendFeature; +const eventsModuleAzureDevOpsEventRouter: () => BackendFeature; +export default eventsModuleAzureDevOpsEventRouter; +export { eventsModuleAzureDevOpsEventRouter }; // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/events-backend-module-azure/package.json b/plugins/events-backend-module-azure/package.json index fa03b1f6d1..2530e2dfd9 100644 --- a/plugins/events-backend-module-azure/package.json +++ b/plugins/events-backend-module-azure/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-azure", - "version": "0.1.17-next.2", + "version": "0.1.19", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -48,8 +48,7 @@ "devDependencies": { "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", - "@backstage/plugin-events-backend-test-utils": "workspace:^", - "supertest": "^6.1.3" + "@backstage/plugin-events-backend-test-utils": "workspace:^" }, "files": [ "dist" diff --git a/plugins/events-backend-module-azure/src/alpha.ts b/plugins/events-backend-module-azure/src/alpha.ts index 07334fcbda..4de53df42a 100644 --- a/plugins/events-backend-module-azure/src/alpha.ts +++ b/plugins/events-backend-module-azure/src/alpha.ts @@ -15,3 +15,4 @@ */ export { eventsModuleAzureDevOpsEventRouter } from './service/eventsModuleAzureDevOpsEventRouter'; +export { eventsModuleAzureDevOpsEventRouter as default } from './service/eventsModuleAzureDevOpsEventRouter'; diff --git a/plugins/events-backend-module-azure/src/service/eventsModuleAzureDevOpsEventRouter.ts b/plugins/events-backend-module-azure/src/service/eventsModuleAzureDevOpsEventRouter.ts index 36f3acada0..50bc384502 100644 --- a/plugins/events-backend-module-azure/src/service/eventsModuleAzureDevOpsEventRouter.ts +++ b/plugins/events-backend-module-azure/src/service/eventsModuleAzureDevOpsEventRouter.ts @@ -27,7 +27,7 @@ import { AzureDevOpsEventRouter } from '../router/AzureDevOpsEventRouter'; */ export const eventsModuleAzureDevOpsEventRouter = createBackendModule({ pluginId: 'events', - moduleId: 'azureDevOpsEventRouter', + moduleId: 'azure-dev-ops-event-router', register(env) { env.registerInit({ deps: { diff --git a/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md index 4f727bc887..ae4db7e0fa 100644 --- a/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,90 @@ # @backstage/plugin-events-backend-module-bitbucket-cloud +## 0.1.19 + +### Patch Changes + +- af76a95: Add default exports for the new backend system and documentation. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-events-node@0.2.18 + +## 0.1.19-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-events-node@0.2.18-next.2 + +## 0.1.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/plugin-events-node@0.2.18-next.1 + +## 0.1.19-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/plugin-events-node@0.2.18-next.0 + +## 0.1.18 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8 + - @backstage/plugin-events-node@0.2.17 + +## 0.1.18-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/plugin-events-node@0.2.17-next.3 + +## 0.1.18-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/plugin-events-node@0.2.17-next.2 + +## 0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-events-node@0.2.17-next.1 + +## 0.1.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/plugin-events-node@0.2.17-next.0 + +## 0.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.7 + - @backstage/plugin-events-node@0.2.16 + ## 0.1.17-next.2 ### Patch Changes diff --git a/plugins/events-backend-module-bitbucket-cloud/README.md b/plugins/events-backend-module-bitbucket-cloud/README.md index 60fdf52af9..d70a70c87e 100644 --- a/plugins/events-backend-module-bitbucket-cloud/README.md +++ b/plugins/events-backend-module-bitbucket-cloud/README.md @@ -31,6 +31,16 @@ Install this module: yarn add --cwd packages/backend @backstage/plugin-events-backend-module-bitbucket-cloud ``` +### Add to backend + +```ts title="packages/backend/src/index.ts" +backend.add( + import('@backstage/plugin-events-backend-module-bitbucket-cloud/alpha'), +); +``` + +### Add to backend (old) + Add the event router to the `EventsBackend` instance in `packages/backend/src/plugins/events.ts`: ```diff diff --git a/plugins/events-backend-module-bitbucket-cloud/alpha-api-report.md b/plugins/events-backend-module-bitbucket-cloud/api-report-alpha.md similarity index 65% rename from plugins/events-backend-module-bitbucket-cloud/alpha-api-report.md rename to plugins/events-backend-module-bitbucket-cloud/api-report-alpha.md index 5e63ae36c8..fa7cdfa9f6 100644 --- a/plugins/events-backend-module-bitbucket-cloud/alpha-api-report.md +++ b/plugins/events-backend-module-bitbucket-cloud/api-report-alpha.md @@ -6,7 +6,9 @@ import { BackendFeature } from '@backstage/backend-plugin-api'; // @alpha -export const eventsModuleBitbucketCloudEventRouter: () => BackendFeature; +const eventsModuleBitbucketCloudEventRouter: () => BackendFeature; +export default eventsModuleBitbucketCloudEventRouter; +export { eventsModuleBitbucketCloudEventRouter }; // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/events-backend-module-bitbucket-cloud/package.json b/plugins/events-backend-module-bitbucket-cloud/package.json index 2642cda904..5dd1e3e00c 100644 --- a/plugins/events-backend-module-bitbucket-cloud/package.json +++ b/plugins/events-backend-module-bitbucket-cloud/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-bitbucket-cloud", - "version": "0.1.17-next.2", + "version": "0.1.19", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -48,8 +48,7 @@ "devDependencies": { "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", - "@backstage/plugin-events-backend-test-utils": "workspace:^", - "supertest": "^6.1.3" + "@backstage/plugin-events-backend-test-utils": "workspace:^" }, "files": [ "dist" diff --git a/plugins/events-backend-module-bitbucket-cloud/src/alpha.ts b/plugins/events-backend-module-bitbucket-cloud/src/alpha.ts index 75cda4327d..1f0e09a653 100644 --- a/plugins/events-backend-module-bitbucket-cloud/src/alpha.ts +++ b/plugins/events-backend-module-bitbucket-cloud/src/alpha.ts @@ -15,3 +15,4 @@ */ export { eventsModuleBitbucketCloudEventRouter } from './service/eventsModuleBitbucketCloudEventRouter'; +export { eventsModuleBitbucketCloudEventRouter as default } from './service/eventsModuleBitbucketCloudEventRouter'; diff --git a/plugins/events-backend-module-bitbucket-cloud/src/service/eventsModuleBitbucketCloudEventRouter.ts b/plugins/events-backend-module-bitbucket-cloud/src/service/eventsModuleBitbucketCloudEventRouter.ts index 60a8cc31c8..841a463001 100644 --- a/plugins/events-backend-module-bitbucket-cloud/src/service/eventsModuleBitbucketCloudEventRouter.ts +++ b/plugins/events-backend-module-bitbucket-cloud/src/service/eventsModuleBitbucketCloudEventRouter.ts @@ -27,7 +27,7 @@ import { BitbucketCloudEventRouter } from '../router/BitbucketCloudEventRouter'; */ export const eventsModuleBitbucketCloudEventRouter = createBackendModule({ pluginId: 'events', - moduleId: 'bitbucketCloudEventRouter', + moduleId: 'bitbucket-cloud-event-router', register(env) { env.registerInit({ deps: { diff --git a/plugins/events-backend-module-gerrit/CHANGELOG.md b/plugins/events-backend-module-gerrit/CHANGELOG.md index edcdba1470..6af1070a1f 100644 --- a/plugins/events-backend-module-gerrit/CHANGELOG.md +++ b/plugins/events-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,90 @@ # @backstage/plugin-events-backend-module-gerrit +## 0.1.19 + +### Patch Changes + +- af76a95: Add default exports for the new backend system and documentation. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-events-node@0.2.18 + +## 0.1.19-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-events-node@0.2.18-next.2 + +## 0.1.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/plugin-events-node@0.2.18-next.1 + +## 0.1.19-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/plugin-events-node@0.2.18-next.0 + +## 0.1.18 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8 + - @backstage/plugin-events-node@0.2.17 + +## 0.1.18-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/plugin-events-node@0.2.17-next.3 + +## 0.1.18-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/plugin-events-node@0.2.17-next.2 + +## 0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-events-node@0.2.17-next.1 + +## 0.1.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/plugin-events-node@0.2.17-next.0 + +## 0.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.7 + - @backstage/plugin-events-node@0.2.16 + ## 0.1.17-next.2 ### Patch Changes diff --git a/plugins/events-backend-module-gerrit/README.md b/plugins/events-backend-module-gerrit/README.md index 1808ef46ba..34b2d154be 100644 --- a/plugins/events-backend-module-gerrit/README.md +++ b/plugins/events-backend-module-gerrit/README.md @@ -30,6 +30,14 @@ Install this module: yarn add --cwd packages/backend @backstage/plugin-events-backend-module-gerrit ``` +### Add to backend + +```ts title="packages/backend/src/index.ts" +backend.add(import('@backstage/plugin-events-backend-module-gerrit/alpha')); +``` + +### Add to backend (old) + Add the event router to the `EventsBackend` instance in `packages/backend/src/plugins/events.ts`: ```diff diff --git a/plugins/events-backend-module-gerrit/alpha-api-report.md b/plugins/events-backend-module-gerrit/api-report-alpha.md similarity index 68% rename from plugins/events-backend-module-gerrit/alpha-api-report.md rename to plugins/events-backend-module-gerrit/api-report-alpha.md index d1be54730f..66dea72747 100644 --- a/plugins/events-backend-module-gerrit/alpha-api-report.md +++ b/plugins/events-backend-module-gerrit/api-report-alpha.md @@ -6,7 +6,9 @@ import { BackendFeature } from '@backstage/backend-plugin-api'; // @alpha -export const eventsModuleGerritEventRouter: () => BackendFeature; +const eventsModuleGerritEventRouter: () => BackendFeature; +export default eventsModuleGerritEventRouter; +export { eventsModuleGerritEventRouter }; // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/events-backend-module-gerrit/package.json b/plugins/events-backend-module-gerrit/package.json index 5c69c1522c..0593cd8664 100644 --- a/plugins/events-backend-module-gerrit/package.json +++ b/plugins/events-backend-module-gerrit/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-gerrit", - "version": "0.1.17-next.2", + "version": "0.1.19", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -48,8 +48,7 @@ "devDependencies": { "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", - "@backstage/plugin-events-backend-test-utils": "workspace:^", - "supertest": "^6.1.3" + "@backstage/plugin-events-backend-test-utils": "workspace:^" }, "files": [ "dist" diff --git a/plugins/events-backend-module-gerrit/src/alpha.ts b/plugins/events-backend-module-gerrit/src/alpha.ts index 788331b998..9c1eea0b75 100644 --- a/plugins/events-backend-module-gerrit/src/alpha.ts +++ b/plugins/events-backend-module-gerrit/src/alpha.ts @@ -15,3 +15,4 @@ */ export { eventsModuleGerritEventRouter } from './service/eventsModuleGerritEventRouter'; +export { eventsModuleGerritEventRouter as default } from './service/eventsModuleGerritEventRouter'; diff --git a/plugins/events-backend-module-gerrit/src/service/eventsModuleGerritEventRouter.ts b/plugins/events-backend-module-gerrit/src/service/eventsModuleGerritEventRouter.ts index 8d490ea0b2..780ff7f878 100644 --- a/plugins/events-backend-module-gerrit/src/service/eventsModuleGerritEventRouter.ts +++ b/plugins/events-backend-module-gerrit/src/service/eventsModuleGerritEventRouter.ts @@ -27,7 +27,7 @@ import { GerritEventRouter } from '../router/GerritEventRouter'; */ export const eventsModuleGerritEventRouter = createBackendModule({ pluginId: 'events', - moduleId: 'gerritEventRouter', + moduleId: 'gerrit-event-router', register(env) { env.registerInit({ deps: { diff --git a/plugins/events-backend-module-github/CHANGELOG.md b/plugins/events-backend-module-github/CHANGELOG.md index ea5e24bbcf..bff2a53470 100644 --- a/plugins/events-backend-module-github/CHANGELOG.md +++ b/plugins/events-backend-module-github/CHANGELOG.md @@ -1,5 +1,98 @@ # @backstage/plugin-events-backend-module-github +## 0.1.19 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.18 + +## 0.1.19-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-events-node@0.2.18-next.2 + +## 0.1.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/plugin-events-node@0.2.18-next.1 + +## 0.1.19-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.18-next.0 + +## 0.1.18 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.17 + +## 0.1.18-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.3 + +## 0.1.18-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.2 + +## 0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.1 + +## 0.1.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.0 + +## 0.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.7 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.16 + ## 0.1.17-next.2 ### Patch Changes diff --git a/plugins/events-backend-module-github/alpha-api-report.md b/plugins/events-backend-module-github/api-report-alpha.md similarity index 100% rename from plugins/events-backend-module-github/alpha-api-report.md rename to plugins/events-backend-module-github/api-report-alpha.md diff --git a/plugins/events-backend-module-github/package.json b/plugins/events-backend-module-github/package.json index 3d26afa7ef..97bd7b7cc6 100644 --- a/plugins/events-backend-module-github/package.json +++ b/plugins/events-backend-module-github/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-github", - "version": "0.1.17-next.2", + "version": "0.1.19", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -50,8 +50,7 @@ "devDependencies": { "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", - "@backstage/plugin-events-backend-test-utils": "workspace:^", - "supertest": "^6.1.3" + "@backstage/plugin-events-backend-test-utils": "workspace:^" }, "files": [ "config.d.ts", diff --git a/plugins/events-backend-module-github/src/service/eventsModuleGithubEventRouter.ts b/plugins/events-backend-module-github/src/service/eventsModuleGithubEventRouter.ts index 17485098c2..093307dfaf 100644 --- a/plugins/events-backend-module-github/src/service/eventsModuleGithubEventRouter.ts +++ b/plugins/events-backend-module-github/src/service/eventsModuleGithubEventRouter.ts @@ -27,7 +27,7 @@ import { GithubEventRouter } from '../router/GithubEventRouter'; */ export const eventsModuleGithubEventRouter = createBackendModule({ pluginId: 'events', - moduleId: 'githubEventRouter', + moduleId: 'github-event-router', register(env) { env.registerInit({ deps: { diff --git a/plugins/events-backend-module-github/src/service/eventsModuleGithubWebhook.ts b/plugins/events-backend-module-github/src/service/eventsModuleGithubWebhook.ts index b4bd666036..647b21c364 100644 --- a/plugins/events-backend-module-github/src/service/eventsModuleGithubWebhook.ts +++ b/plugins/events-backend-module-github/src/service/eventsModuleGithubWebhook.ts @@ -30,7 +30,7 @@ import { createGithubSignatureValidator } from '../http/createGithubSignatureVal */ export const eventsModuleGithubWebhook = createBackendModule({ pluginId: 'events', - moduleId: 'githubWebhook', + moduleId: 'github-webhook', register(env) { env.registerInit({ deps: { diff --git a/plugins/events-backend-module-gitlab/CHANGELOG.md b/plugins/events-backend-module-gitlab/CHANGELOG.md index e7f390c518..de697ee02c 100644 --- a/plugins/events-backend-module-gitlab/CHANGELOG.md +++ b/plugins/events-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,98 @@ # @backstage/plugin-events-backend-module-gitlab +## 0.1.19 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.18 + +## 0.1.19-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-events-node@0.2.18-next.2 + +## 0.1.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/plugin-events-node@0.2.18-next.1 + +## 0.1.19-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.18-next.0 + +## 0.1.18 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.17 + +## 0.1.18-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.3 + +## 0.1.18-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.2 + +## 0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.1 + +## 0.1.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.0 + +## 0.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.7 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.16 + ## 0.1.17-next.2 ### Patch Changes diff --git a/plugins/events-backend-module-gitlab/alpha-api-report.md b/plugins/events-backend-module-gitlab/api-report-alpha.md similarity index 100% rename from plugins/events-backend-module-gitlab/alpha-api-report.md rename to plugins/events-backend-module-gitlab/api-report-alpha.md diff --git a/plugins/events-backend-module-gitlab/package.json b/plugins/events-backend-module-gitlab/package.json index 7743604b31..7eacb91a61 100644 --- a/plugins/events-backend-module-gitlab/package.json +++ b/plugins/events-backend-module-gitlab/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-gitlab", - "version": "0.1.17-next.2", + "version": "0.1.19", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -49,8 +49,7 @@ "devDependencies": { "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", - "@backstage/plugin-events-backend-test-utils": "workspace:^", - "supertest": "^6.1.3" + "@backstage/plugin-events-backend-test-utils": "workspace:^" }, "files": [ "config.d.ts", diff --git a/plugins/events-backend-module-gitlab/src/service/eventsModuleGitlabEventRouter.ts b/plugins/events-backend-module-gitlab/src/service/eventsModuleGitlabEventRouter.ts index 3425601529..fc44e95057 100644 --- a/plugins/events-backend-module-gitlab/src/service/eventsModuleGitlabEventRouter.ts +++ b/plugins/events-backend-module-gitlab/src/service/eventsModuleGitlabEventRouter.ts @@ -27,7 +27,7 @@ import { GitlabEventRouter } from '../router/GitlabEventRouter'; */ export const eventsModuleGitlabEventRouter = createBackendModule({ pluginId: 'events', - moduleId: 'gitlabEventRouter', + moduleId: 'gitlab-event-router', register(env) { env.registerInit({ deps: { diff --git a/plugins/events-backend-module-gitlab/src/service/eventsModuleGitlabWebhook.ts b/plugins/events-backend-module-gitlab/src/service/eventsModuleGitlabWebhook.ts index bd596b4baf..77bca7236b 100644 --- a/plugins/events-backend-module-gitlab/src/service/eventsModuleGitlabWebhook.ts +++ b/plugins/events-backend-module-gitlab/src/service/eventsModuleGitlabWebhook.ts @@ -32,7 +32,7 @@ import { createGitlabTokenValidator } from '../http/createGitlabTokenValidator'; */ export const eventsModuleGitlabWebhook = createBackendModule({ pluginId: 'events', - moduleId: 'gitlabWebhook', + moduleId: 'gitlab-webhook', register(env) { env.registerInit({ deps: { diff --git a/plugins/events-backend-test-utils/CHANGELOG.md b/plugins/events-backend-test-utils/CHANGELOG.md index 0eb3531587..2651cbeffe 100644 --- a/plugins/events-backend-test-utils/CHANGELOG.md +++ b/plugins/events-backend-test-utils/CHANGELOG.md @@ -1,5 +1,75 @@ # @backstage/plugin-events-backend-test-utils +## 0.1.19 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.2.18 + +## 0.1.19-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.2.18-next.2 + +## 0.1.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.2.18-next.1 + +## 0.1.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.2.18-next.0 + +## 0.1.18 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.2.17 + +## 0.1.18-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.2.17-next.3 + +## 0.1.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.2.17-next.2 + +## 0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.2.17-next.1 + +## 0.1.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.2.17-next.0 + +## 0.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.2.16 + ## 0.1.17-next.2 ### Patch Changes diff --git a/plugins/events-backend-test-utils/package.json b/plugins/events-backend-test-utils/package.json index bba8cf31ef..aabd16558d 100644 --- a/plugins/events-backend-test-utils/package.json +++ b/plugins/events-backend-test-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-events-backend-test-utils", "description": "The plugin-events-backend-test-utils for @backstage/plugin-events-node", - "version": "0.1.17-next.2", + "version": "0.1.19", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-backend/CHANGELOG.md b/plugins/events-backend/CHANGELOG.md index 7904ab40cb..fb7607f8b1 100644 --- a/plugins/events-backend/CHANGELOG.md +++ b/plugins/events-backend/CHANGELOG.md @@ -1,5 +1,108 @@ # @backstage/plugin-events-backend +## 0.2.18 + +### Patch Changes + +- 92ea615: Update `README.md` +- d5ddc4e: Add documentation on how to install the plugins with the new backend system. +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.18 + +## 0.2.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-events-node@0.2.18-next.2 + +## 0.2.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/plugin-events-node@0.2.18-next.1 + +## 0.2.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.18-next.0 + +## 0.2.17 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.17 + +## 0.2.17-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.3 + +## 0.2.17-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.2 + +## 0.2.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.1 + +## 0.2.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.17-next.0 + +## 0.2.16 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.16 + ## 0.2.16-next.2 ### Patch Changes diff --git a/plugins/events-backend/README.md b/plugins/events-backend/README.md index 969e1bbcb2..2fd980f003 100644 --- a/plugins/events-backend/README.md +++ b/plugins/events-backend/README.md @@ -24,7 +24,15 @@ to the used event broker. yarn add --cwd packages/backend @backstage/plugin-events-backend @backstage/plugin-events-node ``` -### Event Broker +### Add to backend + +```ts title="packages/backend/src/index.ts" +backend.add(import('@backstage/plugin-events-backend/alpha')); +``` + +### Add to backend (old) + +#### Event Broker First you will need to add and implementation of the `EventBroker` interface to the backend plugin environment. This will allow event broker instance any backend plugins to publish and subscribe to events in order to communicate @@ -34,6 +42,7 @@ Add the following to `makeCreateEnv` ```diff // packages/backend/src/index.ts ++ import { DefaultEventBroker } from '@backstage/plugin-events-backend'; + const eventBroker = new DefaultEventBroker(root.child({ type: 'plugin' })); ``` @@ -41,10 +50,11 @@ Then update plugin environment to include the event broker. ```diff // packages/backend/src/types.ts ++ import { EventBroker } from '@backstage/plugin-events-node'; + eventBroker: EventBroker; ``` -### Publishing and Subscribing to events with the broker +#### Publishing and Subscribing to events with the broker Backend plugins are passed the event broker in the plugin environment at startup of the application. The plugin can make use of this to communicate between parts of the application. @@ -80,27 +90,27 @@ export default async function createPlugin( } ``` -### Implementing an `EventSubscriber` class +#### Implementing an `EventSubscriber` class More complex solutions might need the creation of a class that implements the `EventSubscriber` interface. e.g. ```typescript jsx -import { EventSubscriber } from "./EventSubscriber"; +import { EventSubscriber } from './EventSubscriber'; class ExampleSubscriber implements EventSubscriber { - ... + // ... supportsEventTopics() { - return ['publish.example'] + return ['publish.example']; } async onEvent(params: EventParams) { - env.logger.info(`receieved ${params.topic} event`) + env.logger.info(`receieved ${params.topic} event`); } } ``` -### Events Backend +#### Events Backend The events backend plugin provides a router to handler http events and publish the http requests onto the event broker. @@ -201,7 +211,7 @@ import { eventsExtensionPoint } from '@backstage/plugin-events-node'; export const yourModuleEventsModule = createBackendModule({ pluginId: 'events', - moduleId: 'yourModule', + moduleId: 'your-module', register(env) { // [...] env.registerInit({ @@ -252,7 +262,7 @@ import { eventsExtensionPoint } from '@backstage/plugin-events-node'; export const eventsModuleYourFeature = createBackendModule({ pluginId: 'events', - moduleId: 'yourFeature', + moduleId: 'your-feature', register(env) { // [...] env.registerInit({ diff --git a/plugins/events-backend/alpha-api-report.md b/plugins/events-backend/api-report-alpha.md similarity index 100% rename from plugins/events-backend/alpha-api-report.md rename to plugins/events-backend/api-report-alpha.md diff --git a/plugins/events-backend/package.json b/plugins/events-backend/package.json index 5314726051..ec4a59f4e9 100644 --- a/plugins/events-backend/package.json +++ b/plugins/events-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend", - "version": "0.2.16-next.2", + "version": "0.2.18", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-node/CHANGELOG.md b/plugins/events-node/CHANGELOG.md index 38276d2484..dd9844430c 100644 --- a/plugins/events-node/CHANGELOG.md +++ b/plugins/events-node/CHANGELOG.md @@ -1,5 +1,75 @@ # @backstage/plugin-events-node +## 0.2.18 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + +## 0.2.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + +## 0.2.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.1 + +## 0.2.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + +## 0.2.17 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8 + +## 0.2.17-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.3 + +## 0.2.17-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.2 + +## 0.2.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.1 + +## 0.2.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.0 + +## 0.2.16 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.7 + ## 0.2.16-next.2 ### Patch Changes diff --git a/plugins/events-node/alpha-api-report.md b/plugins/events-node/api-report-alpha.md similarity index 100% rename from plugins/events-node/alpha-api-report.md rename to plugins/events-node/api-report-alpha.md diff --git a/plugins/events-node/package.json b/plugins/events-node/package.json index 8505950cd6..d2a9e5424d 100644 --- a/plugins/events-node/package.json +++ b/plugins/events-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-events-node", "description": "The plugin-events-node module for @backstage/plugin-events-backend", - "version": "0.2.16-next.2", + "version": "0.2.18", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/example-todo-list-backend/CHANGELOG.md b/plugins/example-todo-list-backend/CHANGELOG.md index bb757870fd..2f4a7fb873 100644 --- a/plugins/example-todo-list-backend/CHANGELOG.md +++ b/plugins/example-todo-list-backend/CHANGELOG.md @@ -1,5 +1,110 @@ # @internal/plugin-todo-list-backend +## 1.0.21 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/errors@1.2.3 + +## 1.0.21-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## 1.0.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/errors@1.2.3 + +## 1.0.21-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.3-next.0 + +## 1.0.20 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 1.0.20-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + +## 1.0.20-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 1.0.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + +## 1.0.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 1.0.19 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.1 + ## 1.0.19-next.2 ### Patch Changes diff --git a/plugins/example-todo-list-backend/package.json b/plugins/example-todo-list-backend/package.json index 01e3aa75b2..65241fd128 100644 --- a/plugins/example-todo-list-backend/package.json +++ b/plugins/example-todo-list-backend/package.json @@ -1,6 +1,6 @@ { "name": "@internal/plugin-todo-list-backend", - "version": "1.0.19-next.2", + "version": "1.0.21", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,7 +31,6 @@ "dependencies": { "@backstage/backend-common": "workspace:^", "@backstage/backend-plugin-api": "workspace:^", - "@backstage/config": "workspace:^", "@backstage/errors": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", "@types/express": "^4.17.6", @@ -45,7 +44,6 @@ "@backstage/cli": "workspace:^", "@types/supertest": "^2.0.8", "@types/uuid": "^8.0.0", - "msw": "^1.0.0", "supertest": "^6.1.6" }, "files": [ diff --git a/plugins/example-todo-list-common/CHANGELOG.md b/plugins/example-todo-list-common/CHANGELOG.md index 8deaa18374..98d6bafa7f 100644 --- a/plugins/example-todo-list-common/CHANGELOG.md +++ b/plugins/example-todo-list-common/CHANGELOG.md @@ -1,5 +1,26 @@ # @internal/plugin-todo-list-common +## 1.0.17 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.12 + +## 1.0.16 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.11 + +## 1.0.15 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.10 + ## 1.0.14 ### Patch Changes diff --git a/plugins/example-todo-list-common/package.json b/plugins/example-todo-list-common/package.json index 05bbe0cc32..1d984812f9 100644 --- a/plugins/example-todo-list-common/package.json +++ b/plugins/example-todo-list-common/package.json @@ -1,6 +1,6 @@ { "name": "@internal/plugin-todo-list-common", - "version": "1.0.14", + "version": "1.0.17", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,12 +33,7 @@ "@backstage/plugin-permission-common": "workspace:^" }, "devDependencies": { - "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", - "@backstage/dev-utils": "workspace:^", - "@backstage/test-utils": "workspace:^", - "cross-fetch": "^4.0.0", - "msw": "^1.0.0" + "@backstage/cli": "workspace:^" }, "files": [ "dist" diff --git a/plugins/example-todo-list/CHANGELOG.md b/plugins/example-todo-list/CHANGELOG.md index b7d90099a8..8dfacdd105 100644 --- a/plugins/example-todo-list/CHANGELOG.md +++ b/plugins/example-todo-list/CHANGELOG.md @@ -1,5 +1,83 @@ # @internal/plugin-todo-list +## 1.0.21 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + +## 1.0.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + +## 1.0.21-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/core-plugin-api@1.8.1 + +## 1.0.20 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + +## 1.0.20-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + +## 1.0.20-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## 1.0.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.0 + +## 1.0.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + +## 1.0.19 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + ## 1.0.19-next.2 ### Patch Changes diff --git a/plugins/example-todo-list/package.json b/plugins/example-todo-list/package.json index adcdb1e3c8..63634879df 100644 --- a/plugins/example-todo-list/package.json +++ b/plugins/example-todo-list/package.json @@ -1,6 +1,6 @@ { "name": "@internal/plugin-todo-list", - "version": "1.0.19-next.2", + "version": "1.0.21", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,9 +32,7 @@ "dependencies": { "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", - "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", "react-use": "^17.2.4" }, @@ -45,15 +43,10 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", - "@backstage/dev-utils": "workspace:^", - "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "@types/react": "^16.13.1 || ^17.0.0", - "msw": "^1.0.0" + "@types/react": "^16.13.1 || ^17.0.0" }, "files": [ "dist" diff --git a/plugins/explore-backend/CHANGELOG.md b/plugins/explore-backend/CHANGELOG.md index 2d2d88d678..292a14f652 100644 --- a/plugins/explore-backend/CHANGELOG.md +++ b/plugins/explore-backend/CHANGELOG.md @@ -1,5 +1,120 @@ # @backstage/plugin-explore-backend +## 0.0.19 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-search-backend-module-explore@0.1.13 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + +## 0.0.19-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-search-backend-module-explore@0.1.13-next.2 + +## 0.0.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-search-backend-module-explore@0.1.13-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + +## 0.0.19-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/plugin-search-backend-module-explore@0.1.13-next.0 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + +## 0.0.18 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-search-backend-module-explore@0.1.12 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.9 + +## 0.0.18-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-backend-module-explore@0.1.12-next.3 + - @backstage/plugin-search-common@1.2.8 + +## 0.0.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-search-backend-module-explore@0.1.12-next.2 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.8 + +## 0.0.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-backend-module-explore@0.1.12-next.1 + - @backstage/plugin-search-common@1.2.8 + +## 0.0.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-search-backend-module-explore@0.1.12-next.0 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.8 + +## 0.0.17 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-backend-module-explore@0.1.11 + - @backstage/plugin-search-common@1.2.8 + ## 0.0.17-next.2 ### Patch Changes diff --git a/plugins/explore-backend/package.json b/plugins/explore-backend/package.json index d8ab7f3f5f..5af891fb02 100644 --- a/plugins/explore-backend/package.json +++ b/plugins/explore-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-explore-backend", - "version": "0.0.17-next.2", + "version": "0.0.19", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,7 +32,6 @@ "@backstage/config": "workspace:^", "@backstage/plugin-explore-common": "workspace:^", "@backstage/plugin-search-backend-module-explore": "workspace:^", - "@backstage/plugin-search-common": "workspace:^", "@backstage/types": "workspace:^", "@types/express": "*", "express": "^4.18.1", @@ -45,7 +44,6 @@ "devDependencies": { "@backstage/cli": "workspace:^", "@types/supertest": "^2.0.8", - "msw": "^1.0.0", "supertest": "^6.2.4" }, "files": [ diff --git a/plugins/explore-react/CHANGELOG.md b/plugins/explore-react/CHANGELOG.md index 006d3cf7e9..d9668070c2 100644 --- a/plugins/explore-react/CHANGELOG.md +++ b/plugins/explore-react/CHANGELOG.md @@ -1,5 +1,65 @@ # @backstage/plugin-explore-react +## 0.0.35 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-explore-common@0.0.2 + +## 0.0.35-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/plugin-explore-common@0.0.2 + +## 0.0.35-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-explore-common@0.0.2 + +## 0.0.34 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-explore-common@0.0.2 + +## 0.0.34-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-explore-common@0.0.2 + +## 0.0.34-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-explore-common@0.0.2 + +## 0.0.33 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-explore-common@0.0.2 + ## 0.0.33-next.0 ### Patch Changes diff --git a/plugins/explore-react/package.json b/plugins/explore-react/package.json index fdac14de5b..a3128511ac 100644 --- a/plugins/explore-react/package.json +++ b/plugins/explore-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-explore-react", "description": "A frontend library for Backstage plugins that want to interact with the explore plugin", - "version": "0.0.33-next.0", + "version": "0.0.35", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -43,15 +43,10 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/dev-utils": "workspace:^", - "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "@types/react": "^16.13.1 || ^17.0.0", - "cross-fetch": "^4.0.0", - "msw": "^1.0.0" + "@types/react": "^16.13.1 || ^17.0.0" }, "files": [ "dist" diff --git a/plugins/explore/CHANGELOG.md b/plugins/explore/CHANGELOG.md index aebd60fb4f..b1cdac03d7 100644 --- a/plugins/explore/CHANGELOG.md +++ b/plugins/explore/CHANGELOG.md @@ -1,5 +1,173 @@ # @backstage/plugin-explore +## 0.4.15 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/plugin-explore-react@0.0.35 + - @backstage/plugin-search-react@1.7.5 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.10 + +## 0.4.15-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.1-next.2 + - @backstage/plugin-catalog-react@1.9.3-next.2 + - @backstage/plugin-search-react@1.7.5-next.2 + +## 0.4.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/frontend-plugin-api@0.4.1-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/plugin-explore-react@0.0.35-next.1 + - @backstage/plugin-search-react@1.7.5-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.9 + +## 0.4.15-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/frontend-plugin-api@0.4.1-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/plugin-explore-react@0.0.35-next.0 + - @backstage/plugin-search-react@1.7.5-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.9 + +## 0.4.14 + +### Patch Changes + +- aac659e: Added option to set `Direction` for the graph in the `GroupsDiagram` +- 5814122: Updated `/alpha` exports to fit new naming patterns. +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/frontend-plugin-api@0.4.0 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/plugin-search-react@1.7.4 + - @backstage/plugin-explore-react@0.0.34 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.9 + +## 0.4.14-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/frontend-plugin-api@0.4.0-next.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-explore-react@0.0.34-next.1 + - @backstage/plugin-search-common@1.2.8 + - @backstage/plugin-search-react@1.7.4-next.3 + +## 0.4.14-next.2 + +### Patch Changes + +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.2 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/plugin-search-react@1.7.4-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-explore-react@0.0.34-next.1 + - @backstage/plugin-search-common@1.2.8 + +## 0.4.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-search-react@1.7.4-next.1 + - @backstage/plugin-explore-react@0.0.34-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.8 + +## 0.4.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/plugin-search-react@1.7.4-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/frontend-plugin-api@0.3.1-next.0 + - @backstage/plugin-explore-react@0.0.34-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.8 + +## 0.4.12 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- 62b5922916: Internal theme type updates +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/frontend-plugin-api@0.3.0 + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-explore-react@0.0.33 + - @backstage/plugin-search-react@1.7.2 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.8 + ## 0.4.12-next.2 ### Patch Changes diff --git a/plugins/explore/alpha-api-report.md b/plugins/explore/api-report-alpha.md similarity index 76% rename from plugins/explore/alpha-api-report.md rename to plugins/explore/api-report-alpha.md index 8670338f3e..7956cb8546 100644 --- a/plugins/explore/alpha-api-report.md +++ b/plugins/explore/api-report-alpha.md @@ -4,14 +4,14 @@ ```ts import { BackstagePlugin } from '@backstage/frontend-plugin-api'; -import { Extension } from '@backstage/frontend-plugin-api'; +import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; // @alpha (undocumented) const _default: BackstagePlugin<{}, {}>; export default _default; // @alpha (undocumented) -export const ExploreSearchResultListItemExtension: Extension<{ +export const exploreSearchResultListItem: ExtensionDefinition<{ noTrack?: boolean | undefined; }>; diff --git a/plugins/explore/api-report.md b/plugins/explore/api-report.md index d32a133685..532b853671 100644 --- a/plugins/explore/api-report.md +++ b/plugins/explore/api-report.md @@ -8,6 +8,7 @@ import { ApiRef } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/core-plugin-api'; import { default as default_2 } from 'react'; +import { DependencyGraphTypes } from '@backstage/core-components'; import { DiscoveryApi } from '@backstage/core-plugin-api'; import { DomainEntity } from '@backstage/catalog-model'; import { ExploreToolsConfig } from '@backstage/plugin-explore-react'; @@ -110,6 +111,7 @@ export const exploreRouteRef: RouteRef; // @public (undocumented) export const GroupsExplorerContent: (props: { title?: string | undefined; + direction?: DependencyGraphTypes.Direction | undefined; }) => JSX_2.Element; // @public (undocumented) diff --git a/plugins/explore/package.json b/plugins/explore/package.json index 00fce68df2..500480c1ad 100644 --- a/plugins/explore/package.json +++ b/plugins/explore/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-explore", "description": "A Backstage plugin for building an exploration page of your software ecosystem", - "version": "0.4.12-next.2", + "version": "0.4.15", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -56,10 +56,8 @@ "@backstage/plugin-explore-react": "workspace:^", "@backstage/plugin-search-common": "workspace:^", "@backstage/plugin-search-react": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.61", "@types/react": "^16.13.1 || ^17.0.0", "classnames": "^2.2.6", "pluralize": "^8.0.0", @@ -79,8 +77,6 @@ "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "cross-fetch": "^4.0.0", "msw": "^1.0.0" }, "files": [ diff --git a/plugins/explore/src/alpha.tsx b/plugins/explore/src/alpha.tsx index 1825af5ddb..3ee25f1bdb 100644 --- a/plugins/explore/src/alpha.tsx +++ b/plugins/explore/src/alpha.tsx @@ -18,18 +18,16 @@ import { createPlugin } from '@backstage/frontend-plugin-api'; import { createSearchResultListItemExtension } from '@backstage/plugin-search-react/alpha'; /** @alpha */ -export const ExploreSearchResultListItemExtension = - createSearchResultListItemExtension({ - id: 'explore', - predicate: result => result.type === 'tools', - component: () => - import('./components/ToolSearchResultListItem').then( - m => m.ToolSearchResultListItem, - ), - }); +export const exploreSearchResultListItem = createSearchResultListItemExtension({ + predicate: result => result.type === 'tools', + component: () => + import('./components/ToolSearchResultListItem').then( + m => m.ToolSearchResultListItem, + ), +}); /** @alpha */ export default createPlugin({ id: 'explore', - extensions: [ExploreSearchResultListItemExtension], + extensions: [exploreSearchResultListItem], }); diff --git a/plugins/explore/src/components/GroupsExplorerContent/GroupsDiagram.tsx b/plugins/explore/src/components/GroupsExplorerContent/GroupsDiagram.tsx index ea989c2834..f7f0eab0bd 100644 --- a/plugins/explore/src/components/GroupsExplorerContent/GroupsDiagram.tsx +++ b/plugins/explore/src/components/GroupsExplorerContent/GroupsDiagram.tsx @@ -164,7 +164,9 @@ function RenderNode(props: DependencyGraphTypes.RenderNodeProps) { /** * Dynamically generates a diagram of groups registered in the catalog. */ -export function GroupsDiagram() { +export function GroupsDiagram(props: { + direction?: DependencyGraphTypes.Direction; +}) { const nodes = new Array<{ id: string; kind: string; @@ -243,7 +245,7 @@ export function GroupsDiagram() { nodes={nodes} edges={edges} nodeMargin={10} - direction={DependencyGraphTypes.Direction.RIGHT_LEFT} + direction={props.direction || DependencyGraphTypes.Direction.RIGHT_LEFT} renderNode={RenderNode} className={classes.graph} fit="contain" diff --git a/plugins/explore/src/components/GroupsExplorerContent/GroupsExplorerContent.tsx b/plugins/explore/src/components/GroupsExplorerContent/GroupsExplorerContent.tsx index 61757a35b6..27a7f629ad 100644 --- a/plugins/explore/src/components/GroupsExplorerContent/GroupsExplorerContent.tsx +++ b/plugins/explore/src/components/GroupsExplorerContent/GroupsExplorerContent.tsx @@ -19,6 +19,7 @@ import { GroupsDiagram } from './GroupsDiagram'; import { Content, ContentHeader, + DependencyGraphTypes, SupportButton, } from '@backstage/core-components'; import { makeStyles } from '@material-ui/core/styles'; @@ -34,7 +35,10 @@ const useStyles = makeStyles( { name: 'ExploreGroupsContent' }, ); -export const GroupsExplorerContent = (props: { title?: string }) => { +export const GroupsExplorerContent = (props: { + title?: string; + direction?: DependencyGraphTypes.Direction; +}) => { const classes = useStyles(); return ( @@ -42,7 +46,7 @@ export const GroupsExplorerContent = (props: { title?: string }) => { Explore your groups. - + ); }; diff --git a/plugins/explore/src/components/ToolCard/ToolCard.tsx b/plugins/explore/src/components/ToolCard/ToolCard.tsx index c2d9079f8f..47c2cfb41d 100644 --- a/plugins/explore/src/components/ToolCard/ToolCard.tsx +++ b/plugins/explore/src/components/ToolCard/ToolCard.tsx @@ -15,7 +15,6 @@ */ import { ExploreTool } from '@backstage/plugin-explore-react'; -import { BackstageTheme } from '@backstage/theme'; import { Box, Card, @@ -24,6 +23,7 @@ import { CardMedia, Chip, makeStyles, + Theme, Typography, } from '@material-ui/core'; import { LinkButton } from '@backstage/core-components'; @@ -32,7 +32,7 @@ import React from 'react'; // TODO: Align styling between Domain and ToolCard -const useStyles = makeStyles( +const useStyles = makeStyles( theme => ({ media: { height: 128, diff --git a/plugins/firehydrant/CHANGELOG.md b/plugins/firehydrant/CHANGELOG.md index 1f9b202642..5272139970 100644 --- a/plugins/firehydrant/CHANGELOG.md +++ b/plugins/firehydrant/CHANGELOG.md @@ -1,5 +1,111 @@ # @backstage/plugin-firehydrant +## 0.2.13 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## 0.2.13-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.2.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + +## 0.2.13-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + +## 0.2.12 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + +## 0.2.12-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## 0.2.12-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## 0.2.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## 0.2.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + +## 0.2.10 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + ## 0.2.10-next.2 ### Patch Changes diff --git a/plugins/firehydrant/package.json b/plugins/firehydrant/package.json index 6c514bfae3..9747592e0c 100644 --- a/plugins/firehydrant/package.json +++ b/plugins/firehydrant/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-firehydrant", "description": "A Backstage plugin that integrates towards FireHydrant", - "version": "0.2.10-next.2", + "version": "0.2.13", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,10 +34,8 @@ "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.61", "@types/react": "^16.13.1 || ^17.0.0", "luxon": "^3.0.0", "react-use": "^17.2.4" @@ -54,9 +52,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "msw": "^1.0.0" + "@testing-library/react": "^14.0.0" }, "files": [ "dist" diff --git a/plugins/fossa/CHANGELOG.md b/plugins/fossa/CHANGELOG.md index fa67b4b78b..61721a6600 100644 --- a/plugins/fossa/CHANGELOG.md +++ b/plugins/fossa/CHANGELOG.md @@ -1,5 +1,122 @@ # @backstage/plugin-fossa +## 0.2.61 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.2.61-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.2.61-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.2.61-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + +## 0.2.60 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.2.60-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## 0.2.60-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + +## 0.2.60-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## 0.2.60-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.2.58 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + ## 0.2.58-next.2 ### Patch Changes diff --git a/plugins/fossa/package.json b/plugins/fossa/package.json index d86bf620de..83af637994 100644 --- a/plugins/fossa/package.json +++ b/plugins/fossa/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-fossa", "description": "A Backstage plugin that integrates towards FOSSA", - "version": "0.2.58-next.2", + "version": "0.2.61", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -39,9 +39,7 @@ "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", - "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", "@types/react": "^16.13.1 || ^17.0.0", "cross-fetch": "^4.0.0", @@ -62,7 +60,6 @@ "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, "files": [ diff --git a/plugins/gcalendar/CHANGELOG.md b/plugins/gcalendar/CHANGELOG.md index 54b342f86c..cb9865d96c 100644 --- a/plugins/gcalendar/CHANGELOG.md +++ b/plugins/gcalendar/CHANGELOG.md @@ -1,5 +1,97 @@ # @backstage/plugin-gcalendar +## 0.3.22 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/errors@1.2.3 + +## 0.3.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/errors@1.2.3 + +## 0.3.22-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + +## 0.3.21 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/errors@1.2.3 + +## 0.3.21-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + +## 0.3.21-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + +## 0.3.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## 0.3.21-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/errors@1.2.3 + +## 0.3.20 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- 62b5922916: Internal theme type updates +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/errors@1.2.3 + ## 0.3.20-next.2 ### Patch Changes diff --git a/plugins/gcalendar/package.json b/plugins/gcalendar/package.json index 13fb61f36f..c8a5b0bd0a 100644 --- a/plugins/gcalendar/package.json +++ b/plugins/gcalendar/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-gcalendar", - "version": "0.3.20-next.2", + "version": "0.3.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,15 +32,12 @@ "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.61", "@maxim_mazurok/gapi.client.calendar": "^3.0.20220408", "@tanstack/react-query": "^4.1.3", "@types/react": "^16.13.1 || ^17.0.0", "classnames": "^2.3.1", - "cross-fetch": "^4.0.0", "dompurify": "^2.3.6", "lodash": "^4.17.21", "luxon": "^3.0.0", @@ -54,16 +51,13 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", "@backstage/dev-utils": "workspace:^", "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", "@types/dompurify": "^2.3.3", - "@types/sanitize-html": "^2.6.2", - "msw": "^1.0.0" + "@types/sanitize-html": "^2.6.2" }, "files": [ "dist" diff --git a/plugins/gcp-projects/CHANGELOG.md b/plugins/gcp-projects/CHANGELOG.md index 7b0dd8c033..bcdc653349 100644 --- a/plugins/gcp-projects/CHANGELOG.md +++ b/plugins/gcp-projects/CHANGELOG.md @@ -1,5 +1,90 @@ # @backstage/plugin-gcp-projects +## 0.3.45 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + +## 0.3.45-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + +## 0.3.45-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/core-plugin-api@1.8.1 + +## 0.3.44 + +### Patch Changes + +- a518c5a: Updated dependency `@react-hookz/web` to `^23.0.0`. +- d2f5662: Fix query parameter for project details page which should point to projectId rather than project name +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + +## 0.3.44-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + +## 0.3.44-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## 0.3.44-next.1 + +### Patch Changes + +- a518c5a25b: Updated dependency `@react-hookz/web` to `^23.0.0`. +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.0 + +## 0.3.44-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + +## 0.3.43 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + ## 0.3.43-next.2 ### Patch Changes diff --git a/plugins/gcp-projects/package.json b/plugins/gcp-projects/package.json index f2a86624ce..571267216c 100644 --- a/plugins/gcp-projects/package.json +++ b/plugins/gcp-projects/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-gcp-projects", "description": "A Backstage plugin that helps you manage projects in GCP", - "version": "0.3.43-next.2", + "version": "0.3.45", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -36,11 +36,8 @@ "dependencies": { "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", - "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.61", - "@react-hookz/web": "^20.0.0", + "@react-hookz/web": "^23.0.0", "@types/react": "^16.13.1 || ^17.0.0" }, "peerDependencies": { @@ -50,15 +47,10 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", "@backstage/dev-utils": "workspace:^", - "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "cross-fetch": "^4.0.0", - "msw": "^1.0.0" + "@testing-library/react": "^14.0.0" }, "files": [ "dist" diff --git a/plugins/gcp-projects/src/components/ProjectDetailsPage/ProjectDetailsPage.tsx b/plugins/gcp-projects/src/components/ProjectDetailsPage/ProjectDetailsPage.tsx index 364033ce73..2982cbbd42 100644 --- a/plugins/gcp-projects/src/components/ProjectDetailsPage/ProjectDetailsPage.tsx +++ b/plugins/gcp-projects/src/components/ProjectDetailsPage/ProjectDetailsPage.tsx @@ -23,7 +23,6 @@ import { TableBody, TableCell, TableRow, - Theme, Typography, } from '@material-ui/core'; import React from 'react'; @@ -43,7 +42,7 @@ import { import { useApi, useRouteRef } from '@backstage/core-plugin-api'; import { rootRouteRef } from '../../routes'; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles(theme => ({ root: { maxWidth: 720, margin: theme.spacing(2), @@ -127,7 +126,7 @@ const DetailsPage = () => { {details?.name && ( + } + /> + ) : ( + + + + {projectName} + + + + + + } + > + + + )} + + ); +}; + +export default WorkflowRunsCard; diff --git a/plugins/github-actions/src/components/WorkflowRunsCard/index.ts b/plugins/github-actions/src/components/WorkflowRunsCard/index.ts new file mode 100644 index 0000000000..77b4c85664 --- /dev/null +++ b/plugins/github-actions/src/components/WorkflowRunsCard/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { WorkflowRunsCard, WorkflowRunsCardView } from './WorkflowRunsCard'; diff --git a/plugins/github-actions/src/components/useWorkflowRuns.ts b/plugins/github-actions/src/components/useWorkflowRuns.ts index 9ffbdad452..aacfabbe2f 100644 --- a/plugins/github-actions/src/components/useWorkflowRuns.ts +++ b/plugins/github-actions/src/components/useWorkflowRuns.ts @@ -17,6 +17,7 @@ import { useState } from 'react'; import useAsyncRetry from 'react-use/lib/useAsyncRetry'; import { githubActionsApiRef } from '../api/GithubActionsApi'; import { useApi, errorApiRef } from '@backstage/core-plugin-api'; +import { Branch } from '../api'; export type WorkflowRun = { workflowName?: string; @@ -41,12 +42,12 @@ export function useWorkflowRuns({ owner, repo, branch, - initialPageSize = 5, + initialPageSize = 6, }: { hostname?: string; owner: string; repo: string; - branch?: string; + branch?: string | undefined; initialPageSize?: number; }) { const api = useApi(githubActionsApiRef); @@ -56,6 +57,8 @@ export function useWorkflowRuns({ const [total, setTotal] = useState(0); const [page, setPage] = useState(0); const [pageSize, setPageSize] = useState(initialPageSize); + const [branches, setBranches] = useState([]); + const [defaultBranch, setDefaultBranch] = useState(''); const { loading, @@ -63,6 +66,43 @@ export function useWorkflowRuns({ retry, error, } = useAsyncRetry(async () => { + const fetchedDefaultBranch = await api.getDefaultBranch({ + hostname, + owner, + repo, + }); + + setDefaultBranch(fetchedDefaultBranch); + let selectedBranch = branch; + if (branch === 'default') { + selectedBranch = fetchedDefaultBranch; + } + + const fetchBranches = async () => { + let next = true; + let iteratePage = 0; + const branchSet: Branch[] = []; + + while (next) { + const branchesData = await api.listBranches({ + hostname, + owner, + repo, + page: iteratePage, + }); + if (branchesData.length === 0) { + next = false; + } + iteratePage++; + branchSet.push(...branchesData); + } + + return branchSet; + }; + + const branchSet = await fetchBranches(); + setBranches(branchSet); + // GitHub API pagination count starts from 1 const workflowRunsData = await api.listWorkflowRuns({ hostname, @@ -70,7 +110,7 @@ export function useWorkflowRuns({ repo, pageSize, page: page + 1, - branch, + branch: selectedBranch, }); setTotal(workflowRunsData.total_count); // Transformation here @@ -88,7 +128,7 @@ export function useWorkflowRuns({ }); } catch (e) { errorApi.post( - new Error(`Failed to rerun the workflow: ${e.message}`), + new Error(`Failed to rerun the workflow: ${(e as Error).message}`), ); } }, @@ -115,6 +155,8 @@ export function useWorkflowRuns({ pageSize, loading, runs, + branches, + defaultBranch, projectName: `${owner}/${repo}`, total, error, diff --git a/plugins/github-deployments/CHANGELOG.md b/plugins/github-deployments/CHANGELOG.md index cbc4bb9664..b09bb8d5db 100644 --- a/plugins/github-deployments/CHANGELOG.md +++ b/plugins/github-deployments/CHANGELOG.md @@ -1,5 +1,140 @@ # @backstage/plugin-github-deployments +## 0.1.60 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## 0.1.60-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + - @backstage/integration-react@1.1.23-next.0 + +## 0.1.60-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/integration-react@1.1.23-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/integration@1.8.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.1.60-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/integration-react@1.1.22 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## 0.1.59 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/integration@1.8.0 + - @backstage/integration-react@1.1.22 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.1.59-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## 0.1.59-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-react@1.1.22-next.1 + +## 0.1.59-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## 0.1.59-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/integration-react@1.1.22-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.1.57 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/integration@1.7.2 + - @backstage/integration-react@1.1.21 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + ## 0.1.57-next.2 ### Patch Changes diff --git a/plugins/github-deployments/package.json b/plugins/github-deployments/package.json index 33725f44ff..1869e04595 100644 --- a/plugins/github-deployments/package.json +++ b/plugins/github-deployments/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-github-deployments", "description": "A Backstage plugin that integrates towards GitHub Deployments", - "version": "0.1.57-next.2", + "version": "0.1.60", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -37,10 +37,8 @@ "@backstage/integration": "workspace:^", "@backstage/integration-react": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.61", "@octokit/graphql": "^5.0.0", "@types/react": "^16.13.1 || ^17.0.0", "luxon": "^3.0.0", @@ -59,7 +57,6 @@ "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, "files": [ diff --git a/plugins/github-issues/CHANGELOG.md b/plugins/github-issues/CHANGELOG.md index e257a8f7e8..3d15c6b6a9 100644 --- a/plugins/github-issues/CHANGELOG.md +++ b/plugins/github-issues/CHANGELOG.md @@ -1,5 +1,131 @@ # @backstage/plugin-github-issues +## 0.2.18 + +### Patch Changes + +- bf92ae3: Updated dependency `octokit` to `^3.0.0`. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## 0.2.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.2.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/integration@1.8.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.2.18-next.0 + +### Patch Changes + +- bf92ae3: Updated dependency `octokit` to `^3.0.0`. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## 0.2.17 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/integration@1.8.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.2.17-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## 0.2.17-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + +## 0.2.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## 0.2.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.2.15 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/integration@1.7.2 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + ## 0.2.15-next.2 ### Patch Changes diff --git a/plugins/github-issues/package.json b/plugins/github-issues/package.json index fb2001630a..de3b02f53b 100644 --- a/plugins/github-issues/package.json +++ b/plugins/github-issues/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-github-issues", - "version": "0.2.15-next.2", + "version": "0.2.18", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,13 +35,12 @@ "@backstage/errors": "workspace:^", "@backstage/integration": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.4", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", "@types/react": "^16.13.1 || ^17.0.0", "luxon": "^3.0.0", - "octokit": "^2.0.4", + "octokit": "^3.0.0", "react-use": "^17.4.0" }, "peerDependencies": { @@ -51,14 +50,11 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", "@backstage/dev-utils": "workspace:^", "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "msw": "^1.0.0" + "@testing-library/react": "^14.0.0" }, "files": [ "dist" diff --git a/plugins/github-issues/src/setupTests.ts b/plugins/github-issues/src/setupTests.ts index 326d2ed212..2f91bcb7b3 100644 --- a/plugins/github-issues/src/setupTests.ts +++ b/plugins/github-issues/src/setupTests.ts @@ -13,4 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import '@testing-library/jest-dom'; +import { Settings } from 'luxon'; + +Settings.defaultLocale = 'en'; diff --git a/plugins/github-pull-requests-board/CHANGELOG.md b/plugins/github-pull-requests-board/CHANGELOG.md index 9a5c5af99e..8fc568d310 100644 --- a/plugins/github-pull-requests-board/CHANGELOG.md +++ b/plugins/github-pull-requests-board/CHANGELOG.md @@ -1,5 +1,120 @@ # @backstage/plugin-github-pull-requests-board +## 0.1.23 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/integration@1.8.0 + +## 0.1.23-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.1.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/integration@1.8.0 + - @backstage/catalog-model@1.4.3 + +## 0.1.23-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/integration@1.8.0 + +## 0.1.22 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/integration@1.8.0 + - @backstage/catalog-model@1.4.3 + +## 0.1.22-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## 0.1.22-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/integration@1.8.0-next.1 + +## 0.1.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## 0.1.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + +## 0.1.20 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/integration@1.7.2 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + ## 0.1.20-next.2 ### Patch Changes diff --git a/plugins/github-pull-requests-board/package.json b/plugins/github-pull-requests-board/package.json index 34a2abfea2..aa086c0848 100644 --- a/plugins/github-pull-requests-board/package.json +++ b/plugins/github-pull-requests-board/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-github-pull-requests-board", "description": "A Backstage plugin that allows you to see all open Pull Requests for all the repositories owned by your team", - "version": "0.1.20-next.2", + "version": "0.1.23", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -40,15 +40,13 @@ "@backstage/core-plugin-api": "workspace:^", "@backstage/integration": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", "@octokit/rest": "^19.0.3", "@types/react": "^16.13.1 || ^17.0.0", "luxon": "^3.0.0", - "p-limit": "^4.0.0", - "react-use": "^17.2.4" + "p-limit": "^4.0.0" }, "peerDependencies": { "react": "^16.13.1 || ^17.0.0 || ^18.0.0", @@ -57,13 +55,10 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/dev-utils": "workspace:^", "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "msw": "^1.0.0" + "@testing-library/react": "^14.0.0" }, "files": [ "dist" diff --git a/plugins/gitops-profiles/CHANGELOG.md b/plugins/gitops-profiles/CHANGELOG.md index cabd28e242..cd312c04bf 100644 --- a/plugins/gitops-profiles/CHANGELOG.md +++ b/plugins/gitops-profiles/CHANGELOG.md @@ -1,5 +1,93 @@ # @backstage/plugin-gitops-profiles +## 0.3.44 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + +## 0.3.44-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + +## 0.3.44-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/core-plugin-api@1.8.1 + +## 0.3.43 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/config@1.1.1 + +## 0.3.43-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + +## 0.3.43-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/config@1.1.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## 0.3.43-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + +## 0.3.43-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/config@1.1.1 + +## 0.3.42 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/config@1.1.1 + ## 0.3.42-next.2 ### Patch Changes diff --git a/plugins/gitops-profiles/package.json b/plugins/gitops-profiles/package.json index 764bda7eb5..d9e509a49b 100644 --- a/plugins/gitops-profiles/package.json +++ b/plugins/gitops-profiles/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-gitops-profiles", "description": "A Backstage plugin that helps you manage GitOps profiles", - "version": "0.3.42-next.2", + "version": "0.3.44", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,10 +34,8 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/config": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", @@ -56,10 +54,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "cross-fetch": "^4.0.0", - "msw": "^1.0.0" + "@testing-library/react": "^14.0.0" }, "files": [ "dist" diff --git a/plugins/gocd/CHANGELOG.md b/plugins/gocd/CHANGELOG.md index 925bd3bae1..884a6fc295 100644 --- a/plugins/gocd/CHANGELOG.md +++ b/plugins/gocd/CHANGELOG.md @@ -1,5 +1,121 @@ # @backstage/plugin-gocd +## 0.1.35 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.1.35-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.1.35-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.1.35-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + +## 0.1.34 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.1.34-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## 0.1.34-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + +## 0.1.34-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## 0.1.34-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.1.32 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + ## 0.1.32-next.2 ### Patch Changes diff --git a/plugins/gocd/package.json b/plugins/gocd/package.json index fc441891b3..ec25c9f7e0 100644 --- a/plugins/gocd/package.json +++ b/plugins/gocd/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-gocd", "description": "A Backstage plugin that integrates towards GoCD", - "version": "0.1.32-next.2", + "version": "0.1.35", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,7 +35,6 @@ "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", @@ -60,8 +59,7 @@ "@testing-library/user-event": "^14.0.0", "@types/lodash": "^4.14.173", "@types/luxon": "^3.0.0", - "@types/react": "^16.13.1 || ^17.0.0", - "msw": "^1.0.0" + "@types/react": "^16.13.1 || ^17.0.0" }, "files": [ "dist", diff --git a/plugins/graphiql/CHANGELOG.md b/plugins/graphiql/CHANGELOG.md index 8bf0f7557a..14ce2b20fb 100644 --- a/plugins/graphiql/CHANGELOG.md +++ b/plugins/graphiql/CHANGELOG.md @@ -1,5 +1,134 @@ # @backstage/plugin-graphiql +## 0.3.2 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-compat-api@0.1.1 + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + +## 0.3.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.1.1-next.2 + - @backstage/frontend-plugin-api@0.4.1-next.2 + +## 0.3.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/core-compat-api@0.1.1-next.1 + - @backstage/frontend-plugin-api@0.4.1-next.1 + +## 0.3.2-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/frontend-plugin-api@0.4.1-next.0 + - @backstage/core-compat-api@0.1.1-next.0 + - @backstage/core-plugin-api@1.8.1 + +## 0.3.1 + +### Patch Changes + +- 03d0b6d: The `convertLegacyRouteRef` utility used by the alpha exports is now imported from `@backstage/core-compat-api`. +- a1227cc: Wrap `/alpha` export extension elements in backwards compatibility wrapper. +- 5814122: Updated `/alpha` exports to fit new naming patterns. +- 8f5d6c1: Updates to the `/alpha` exports to match the extension input wrapping change. +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- Updated dependencies + - @backstage/core-compat-api@0.1.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/frontend-plugin-api@0.4.0 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + +## 0.3.1-next.4 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/core-compat-api@0.1.0-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/frontend-plugin-api@0.4.0-next.3 + - @backstage/theme@0.5.0-next.1 + +## 0.3.1-next.3 + +### Patch Changes + +- a1227cc: Wrap `/alpha` export extension elements in backwards compatibility wrapper. +- 8f5d6c1: Updates to the `/alpha` exports to match the extension input wrapping change. +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.2 + - @backstage/theme@0.5.0-next.1 + - @backstage/core-compat-api@0.1.0-next.2 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## 0.3.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/core-compat-api@0.0.1-next.1 + - @backstage/theme@0.5.0-next.0 + +## 0.3.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.0.1-next.0 + +## 0.3.1-next.0 + +### Patch Changes + +- 03d0b6dcdc: The `convertLegacyRouteRef` utility used by the alpha exports is now imported from `@backstage/core-compat-api`. +- Updated dependencies + - @backstage/core-compat-api@0.0.2-next.0 + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/frontend-plugin-api@0.3.1-next.0 + +## 0.3.0 + +### Minor Changes + +- 57fda44b90: Upgrade to GraphiQL to 3.0.6 + +### Patch Changes + +- 68fc9dc60e: Updated alpha exports according to routing changes in `@backstage/frontend-plugin-api`. +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- 77f009b35d: Internal updates to match changes in the experimental `@backstage/frontend-plugin-api`. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/frontend-plugin-api@0.3.0 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + ## 0.3.0-next.2 ### Patch Changes diff --git a/plugins/graphiql/alpha-api-report.md b/plugins/graphiql/api-report-alpha.md similarity index 70% rename from plugins/graphiql/alpha-api-report.md rename to plugins/graphiql/api-report-alpha.md index 3362cf0a59..e642425463 100644 --- a/plugins/graphiql/alpha-api-report.md +++ b/plugins/graphiql/api-report-alpha.md @@ -4,20 +4,21 @@ ```ts import { BackstagePlugin } from '@backstage/frontend-plugin-api'; -import { Extension } from '@backstage/frontend-plugin-api'; +import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { GraphQLEndpoint } from '@backstage/plugin-graphiql'; import { PortableSchema } from '@backstage/frontend-plugin-api'; import { RouteRef } from '@backstage/frontend-plugin-api'; // @alpha (undocumented) -export function createEndpointExtension(options: { - id: string; +export function createGraphiQLEndpointExtension(options: { + namespace?: string; + name?: string; configSchema?: PortableSchema; disabled?: boolean; factory: (options: { config: TConfig }) => { endpoint: GraphQLEndpoint; }; -}): Extension; +}): ExtensionDefinition; // @alpha (undocumented) const _default: BackstagePlugin< @@ -29,16 +30,16 @@ const _default: BackstagePlugin< export default _default; // @alpha (undocumented) -export const graphiqlBrowseApi: Extension<{}>; +export const graphiqlBrowseApi: ExtensionDefinition<{}>; // @alpha (undocumented) -export const GraphiqlPage: Extension<{ - path: string; +export const graphiqlNavItem: ExtensionDefinition<{ + title: string; }>; // @alpha (undocumented) -export const graphiqlPageSidebarItem: Extension<{ - title: string; +export const graphiqlPage: ExtensionDefinition<{ + path: string; }>; // (No @packageDocumentation comment for this package) diff --git a/plugins/graphiql/package.json b/plugins/graphiql/package.json index 03e9f497c2..254356550f 100644 --- a/plugins/graphiql/package.json +++ b/plugins/graphiql/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-graphiql", "description": "Backstage plugin for browsing GraphQL APIs", - "version": "0.3.0-next.2", + "version": "0.3.2", "publishConfig": { "access": "public" }, @@ -46,13 +46,11 @@ "clean": "backstage-cli package clean" }, "dependencies": { + "@backstage/core-compat-api": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/frontend-plugin-api": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", - "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.61", "@types/react": "^16.13.1 || ^17.0.0", "graphiql": "^3.0.6", "graphql": "^16.0.0", @@ -66,16 +64,12 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", "@backstage/dev-utils": "workspace:^", "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "@types/codemirror": "^5.0.0", - "cross-fetch": "^4.0.0", - "msw": "^1.0.0" + "@types/codemirror": "^5.0.0" }, "files": [ "dist" diff --git a/plugins/graphiql/src/alpha.tsx b/plugins/graphiql/src/alpha.tsx index 8b2b962355..fdd343020d 100644 --- a/plugins/graphiql/src/alpha.tsx +++ b/plugins/graphiql/src/alpha.tsx @@ -34,19 +34,21 @@ import { } from '@backstage/plugin-graphiql'; import { createApiFactory, IconComponent } from '@backstage/core-plugin-api'; import { graphiQLRouteRef } from './route-refs'; -import { convertLegacyRouteRef } from '@backstage/core-plugin-api/alpha'; +import { + compatWrapper, + convertLegacyRouteRef, +} from '@backstage/core-compat-api'; /** @alpha */ -export const GraphiqlPage = createPageExtension({ - id: 'plugin.graphiql.page', +export const graphiqlPage = createPageExtension({ defaultPath: '/graphiql', routeRef: convertLegacyRouteRef(graphiQLRouteRef), - loader: () => import('./components').then(m => ), + loader: () => + import('./components').then(m => compatWrapper()), }); /** @alpha */ -export const graphiqlPageSidebarItem = createNavItemExtension({ - id: 'plugin.graphiql.nav.index', +export const graphiqlNavItem = createNavItemExtension({ title: 'GraphiQL', icon: GraphiQLIcon as IconComponent, routeRef: convertLegacyRouteRef(graphiQLRouteRef), @@ -54,12 +56,12 @@ export const graphiqlPageSidebarItem = createNavItemExtension({ /** @internal */ const endpointDataRef = createExtensionDataRef( - 'plugin.graphiql.endpoint', + 'graphiql.graphiql-endpoint', ); /** @alpha */ export const graphiqlBrowseApi = createApiExtension({ - api: graphQlBrowseApiRef, // apis.plugin.graphiql.browse + api: graphQlBrowseApiRef, inputs: { endpoints: createExtensionInput({ endpoint: endpointDataRef, @@ -68,21 +70,24 @@ export const graphiqlBrowseApi = createApiExtension({ factory({ inputs }) { return createApiFactory( graphQlBrowseApiRef, - GraphQLEndpoints.from(inputs.endpoints.map(i => i.endpoint)), + GraphQLEndpoints.from(inputs.endpoints.map(i => i.output.endpoint)), ); }, }); /** @alpha */ -export function createEndpointExtension(options: { - id: string; +export function createGraphiQLEndpointExtension(options: { + namespace?: string; + name?: string; configSchema?: PortableSchema; disabled?: boolean; factory: (options: { config: TConfig }) => { endpoint: GraphQLEndpoint }; }) { return createExtension({ - id: `apis.plugin.graphiql.browse.${options.id}`, - attachTo: { id: 'apis.plugin.graphiql.browse', input: 'endpoints' }, + kind: 'graphiql-endpoint', + namespace: options.namespace, + name: options.name, + attachTo: { id: 'api:graphiql/browse', input: 'endpoints' }, configSchema: options.configSchema, disabled: options.disabled ?? false, output: { @@ -97,29 +102,31 @@ export function createEndpointExtension(options: { } /** @alpha */ -const gitlabGraphiQLBrowseExtension = createEndpointExtension({ - id: 'gitlab', - disabled: true, - configSchema: createSchemaFromZod(z => - z - .object({ - id: z.string().default('gitlab'), - title: z.string().default('GitLab'), - url: z.string().default('https://gitlab.com/api/graphql'), - }) - .default({}), - ), - factory: ({ config }) => ({ endpoint: GraphQLEndpoints.create(config) }), -}); +const graphiqlGitlabGraphiQLEndpointExtension = createGraphiQLEndpointExtension( + { + name: 'gitlab', + disabled: true, + configSchema: createSchemaFromZod(z => + z + .object({ + id: z.string().default('gitlab'), + title: z.string().default('GitLab'), + url: z.string().default('https://gitlab.com/api/graphql'), + }) + .default({}), + ), + factory: ({ config }) => ({ endpoint: GraphQLEndpoints.create(config) }), + }, +); /** @alpha */ export default createPlugin({ id: 'graphiql', extensions: [ - GraphiqlPage, + graphiqlPage, graphiqlBrowseApi, - gitlabGraphiQLBrowseExtension, - graphiqlPageSidebarItem, + graphiqlGitlabGraphiQLEndpointExtension, + graphiqlNavItem, ], routes: { root: convertLegacyRouteRef(graphiQLRouteRef), diff --git a/plugins/graphiql/src/components/GraphiQLBrowser/GraphiQLBrowser.tsx b/plugins/graphiql/src/components/GraphiQLBrowser/GraphiQLBrowser.tsx index 40c2c168a8..cdd924a6d1 100644 --- a/plugins/graphiql/src/components/GraphiQLBrowser/GraphiQLBrowser.tsx +++ b/plugins/graphiql/src/components/GraphiQLBrowser/GraphiQLBrowser.tsx @@ -19,14 +19,13 @@ import { Tabs, Tab, makeStyles, Typography, Divider } from '@material-ui/core'; import 'graphiql/graphiql.css'; import { StorageBucket } from '../../lib/storage'; import { GraphQLEndpoint } from '../../lib/api'; -import { BackstageTheme } from '@backstage/theme'; import { Progress } from '@backstage/core-components'; const GraphiQL = React.lazy(() => import('graphiql').then(m => ({ default: m.GraphiQL })), ); -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles(theme => ({ root: { height: '100%', display: 'flex', diff --git a/plugins/graphql-backend/CHANGELOG.md b/plugins/graphql-backend/CHANGELOG.md deleted file mode 100644 index 85418706c1..0000000000 --- a/plugins/graphql-backend/CHANGELOG.md +++ /dev/null @@ -1,893 +0,0 @@ -# @backstage/plugin-graphql-backend - -## 0.2.1-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.19.9-next.2 - -## 0.2.1-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.19.9-next.1 - - @backstage/config@1.1.1 - - @backstage/plugin-catalog-graphql@0.4.1-next.0 - -## 0.2.1-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-graphql@0.4.1-next.0 - - @backstage/backend-common@0.19.9-next.0 - - @backstage/config@1.1.1 - -## 0.2.0 - -### Minor Changes - -- 9def1e95ab: This package has been deprecated, consider using [@frontside/backstage-plugin-graphql-backend](https://www.npmjs.com/package/@frontside/backstage-plugin-graphql-backend) instead. - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.19.8 - - @backstage/plugin-catalog-graphql@0.4.0 - - @backstage/config@1.1.1 - -## 0.1.44-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.19.8-next.2 - - @backstage/config@1.1.1-next.0 - - @backstage/plugin-catalog-graphql@0.3.24-next.0 - -## 0.1.43-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.19.7-next.1 - - @backstage/config@1.1.0 - - @backstage/plugin-catalog-graphql@0.3.23 - -## 0.1.43-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.19.7-next.0 - - @backstage/config@1.1.0 - - @backstage/plugin-catalog-graphql@0.3.23 - -## 0.1.41 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.19.5 - - @backstage/config@1.1.0 - - @backstage/plugin-catalog-graphql@0.3.23 - -## 0.1.41-next.3 - -### Patch Changes - -- Updated dependencies - - @backstage/config@1.1.0-next.2 - - @backstage/backend-common@0.19.5-next.3 - - @backstage/plugin-catalog-graphql@0.3.23-next.2 - -## 0.1.41-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/config@1.1.0-next.1 - - @backstage/backend-common@0.19.5-next.2 - - @backstage/plugin-catalog-graphql@0.3.23-next.1 - -## 0.1.41-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/config@1.1.0-next.0 - - @backstage/backend-common@0.19.5-next.1 - - @backstage/plugin-catalog-graphql@0.3.23-next.0 - -## 0.1.40-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.19.4-next.0 - - @backstage/config@1.0.8 - - @backstage/plugin-catalog-graphql@0.3.22 - -## 0.1.38 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.19.2 - - @backstage/config@1.0.8 - - @backstage/plugin-catalog-graphql@0.3.22 - -## 0.1.38-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.19.2-next.2 - -## 0.1.38-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.19.2-next.1 - - @backstage/config@1.0.8 - - @backstage/plugin-catalog-graphql@0.3.22 - -## 0.1.38-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.19.2-next.0 - - @backstage/config@1.0.8 - - @backstage/plugin-catalog-graphql@0.3.22 - -## 0.1.37 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.19.1 - - @backstage/config@1.0.8 - - @backstage/plugin-catalog-graphql@0.3.22 - -## 0.1.37-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.19.1-next.0 - - @backstage/config@1.0.8 - - @backstage/plugin-catalog-graphql@0.3.22-next.0 - -## 0.1.36 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.19.0 - - @backstage/config@1.0.8 - - @backstage/plugin-catalog-graphql@0.3.21 - -## 0.1.36-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.19.0-next.2 - - @backstage/config@1.0.7 - - @backstage/plugin-catalog-graphql@0.3.21-next.1 - -## 0.1.36-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.19.0-next.1 - - @backstage/plugin-catalog-graphql@0.3.21-next.0 - - @backstage/config@1.0.7 - -## 0.1.36-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.18.6-next.0 - - @backstage/config@1.0.7 - - @backstage/plugin-catalog-graphql@0.3.20 - -## 0.1.35 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.18.5 - - @backstage/config@1.0.7 - - @backstage/plugin-catalog-graphql@0.3.20 - -## 0.1.35-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.18.5-next.1 - - @backstage/config@1.0.7 - - @backstage/plugin-catalog-graphql@0.3.20 - -## 0.1.35-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.18.5-next.0 - - @backstage/config@1.0.7 - - @backstage/plugin-catalog-graphql@0.3.20 - -## 0.1.34 - -### Patch Changes - -- e47e69eadf0: Updated dependency `@apollo/server` to `^4.0.0`. -- Updated dependencies - - @backstage/backend-common@0.18.4 - - @backstage/plugin-catalog-graphql@0.3.20 - - @backstage/config@1.0.7 - -## 0.1.34-next.3 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.18.4-next.2 - - @backstage/config@1.0.7 - - @backstage/plugin-catalog-graphql@0.3.20-next.2 - -## 0.1.34-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.18.4-next.2 - - @backstage/config@1.0.7 - - @backstage/plugin-catalog-graphql@0.3.20-next.1 - -## 0.1.34-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-graphql@0.3.20-next.1 - - @backstage/backend-common@0.18.4-next.1 - - @backstage/config@1.0.7 - -## 0.1.34-next.0 - -### Patch Changes - -- e47e69eadf0: Updated dependency `@apollo/server` to `^4.0.0`. -- Updated dependencies - - @backstage/plugin-catalog-graphql@0.3.20-next.0 - - @backstage/backend-common@0.18.4-next.0 - - @backstage/config@1.0.7 - -## 0.1.33 - -### Patch Changes - -- 52b0022dab7: Updated dependency `msw` to `^1.0.0`. -- Updated dependencies - - @backstage/backend-common@0.18.3 - - @backstage/plugin-catalog-graphql@0.3.19 - - @backstage/config@1.0.7 - -## 0.1.33-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.18.3-next.2 - - @backstage/config@1.0.7-next.0 - - @backstage/plugin-catalog-graphql@0.3.19-next.1 - -## 0.1.33-next.1 - -### Patch Changes - -- 52b0022dab7: Updated dependency `msw` to `^1.0.0`. -- Updated dependencies - - @backstage/plugin-catalog-graphql@0.3.19-next.1 - - @backstage/backend-common@0.18.3-next.1 - - @backstage/config@1.0.7-next.0 - -## 0.1.33-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.18.3-next.0 - - @backstage/config@1.0.6 - - @backstage/plugin-catalog-graphql@0.3.19-next.0 - -## 0.1.32 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.18.2 - - @backstage/config@1.0.6 - - @backstage/plugin-catalog-graphql@0.3.18 - -## 0.1.32-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.18.2-next.2 - - @backstage/config@1.0.6 - - @backstage/plugin-catalog-graphql@0.3.18-next.1 - -## 0.1.32-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.18.2-next.1 - - @backstage/config@1.0.6 - - @backstage/plugin-catalog-graphql@0.3.18-next.0 - -## 0.1.32-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.18.2-next.0 - - @backstage/plugin-catalog-graphql@0.3.18-next.0 - -## 0.1.30 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.18.0 - - @backstage/config@1.0.6 - - @backstage/plugin-catalog-graphql@0.3.17 - -## 0.1.30-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.18.0-next.1 - - @backstage/config@1.0.6-next.0 - - @backstage/plugin-catalog-graphql@0.3.17-next.1 - -## 0.1.30-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.18.0-next.0 - - @backstage/config@1.0.6-next.0 - - @backstage/plugin-catalog-graphql@0.3.17-next.1 - -## 0.1.30-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.17.0 - - @backstage/config@1.0.5 - - @backstage/plugin-catalog-graphql@0.3.17-next.0 - -## 0.1.29 - -### Patch Changes - -- 3280711113: Updated dependency `msw` to `^0.49.0`. -- Updated dependencies - - @backstage/backend-common@0.17.0 - - @backstage/plugin-catalog-graphql@0.3.16 - - @backstage/config@1.0.5 - -## 0.1.29-next.3 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.17.0-next.3 - - @backstage/config@1.0.5-next.1 - - @backstage/plugin-catalog-graphql@0.3.16-next.1 - -## 0.1.29-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.17.0-next.2 - - @backstage/config@1.0.5-next.1 - - @backstage/plugin-catalog-graphql@0.3.16-next.1 - -## 0.1.29-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.17.0-next.1 - - @backstage/config@1.0.5-next.1 - - @backstage/plugin-catalog-graphql@0.3.16-next.1 - -## 0.1.29-next.0 - -### Patch Changes - -- 3280711113: Updated dependency `msw` to `^0.49.0`. -- Updated dependencies - - @backstage/backend-common@0.16.1-next.0 - - @backstage/plugin-catalog-graphql@0.3.16-next.0 - - @backstage/config@1.0.5-next.0 - -## 0.1.28 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.16.0 - - @backstage/config@1.0.4 - - @backstage/plugin-catalog-graphql@0.3.15 - -## 0.1.28-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.16.0-next.1 - - @backstage/config@1.0.4-next.0 - - @backstage/plugin-catalog-graphql@0.3.15-next.0 - -## 0.1.28-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.16.0-next.0 - - @backstage/config@1.0.4-next.0 - - @backstage/plugin-catalog-graphql@0.3.15-next.0 - -## 0.1.27 - -### Patch Changes - -- 2d3a5f09ab: Use `response.json` rather than `response.send` where appropriate, as outlined in `SECURITY.md` -- Updated dependencies - - @backstage/backend-common@0.15.2 - - @backstage/plugin-catalog-graphql@0.3.14 - - @backstage/config@1.0.3 - -## 0.1.27-next.2 - -### Patch Changes - -- 2d3a5f09ab: Use `response.json` rather than `response.send` where appropriate, as outlined in `SECURITY.md` -- Updated dependencies - - @backstage/backend-common@0.15.2-next.2 - - @backstage/config@1.0.3-next.2 - - @backstage/plugin-catalog-graphql@0.3.14-next.2 - -## 0.1.27-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.15.2-next.1 - - @backstage/config@1.0.3-next.1 - - @backstage/plugin-catalog-graphql@0.3.14-next.1 - -## 0.1.27-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-graphql@0.3.14-next.0 - - @backstage/backend-common@0.15.2-next.0 - - @backstage/config@1.0.3-next.0 - -## 0.1.26 - -### Patch Changes - -- d669d89206: Minor API signatures cleanup -- 60b85d8ade: Updated dependency `helmet` to `^6.0.0`. - - Please note that these policies are no longer applied by default: - - helmet.contentSecurityPolicy no longer sets block-all-mixed-content directive by default - helmet.expectCt is no longer set by default. It can, however, be explicitly enabled. It will be removed in Helmet 7. - -- 667d917488: Updated dependency `msw` to `^0.47.0`. -- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. -- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. -- Updated dependencies - - @backstage/backend-common@0.15.1 - - @backstage/config@1.0.2 - - @backstage/plugin-catalog-graphql@0.3.13 - -## 0.1.26-next.3 - -### Patch Changes - -- Updated dependencies - - @backstage/config@1.0.2-next.0 - - @backstage/backend-common@0.15.1-next.3 - - @backstage/plugin-catalog-graphql@0.3.13-next.3 - -## 0.1.26-next.2 - -### Patch Changes - -- 667d917488: Updated dependency `msw` to `^0.47.0`. -- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. -- Updated dependencies - - @backstage/backend-common@0.15.1-next.2 - - @backstage/plugin-catalog-graphql@0.3.13-next.2 - -## 0.1.26-next.1 - -### Patch Changes - -- d669d89206: Minor API signatures cleanup -- 60b85d8ade: Updated dependency `helmet` to `^6.0.0`. - - Please note that these policies are no longer applied by default: - - helmet.contentSecurityPolicy no longer sets block-all-mixed-content directive by default - helmet.expectCt is no longer set by default. It can, however, be explicitly enabled. It will be removed in Helmet 7. - -- Updated dependencies - - @backstage/backend-common@0.15.1-next.1 - - @backstage/plugin-catalog-graphql@0.3.13-next.1 - -## 0.1.26-next.0 - -### Patch Changes - -- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. -- Updated dependencies - - @backstage/backend-common@0.15.1-next.0 - - @backstage/plugin-catalog-graphql@0.3.13-next.0 - -## 0.1.25 - -### Patch Changes - -- fa3eeee92d: Updated dependency `@graphql-tools/schema` to `^9.0.0`. -- Updated dependencies - - @backstage/backend-common@0.15.0 - - @backstage/plugin-catalog-graphql@0.3.12 - -## 0.1.25-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.15.0-next.0 - -## 0.1.24 - -### Patch Changes - -- a70869e775: Updated dependency `msw` to `^0.43.0`. -- 8006d0f9bf: Updated dependency `msw` to `^0.44.0`. -- Updated dependencies - - @backstage/backend-common@0.14.1 - - @backstage/plugin-catalog-graphql@0.3.11 - -## 0.1.24-next.1 - -### Patch Changes - -- a70869e775: Updated dependency `msw` to `^0.43.0`. -- Updated dependencies - - @backstage/backend-common@0.14.1-next.3 - - @backstage/plugin-catalog-graphql@0.3.11-next.1 - -## 0.1.24-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.14.1-next.0 - - @backstage/plugin-catalog-graphql@0.3.11-next.0 - -## 0.1.23 - -### Patch Changes - -- 8f7b1835df: Updated dependency `msw` to `^0.41.0`. -- Updated dependencies - - @backstage/backend-common@0.14.0 - - @backstage/plugin-catalog-graphql@0.3.10 - -## 0.1.23-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.14.0-next.2 - -## 0.1.23-next.1 - -### Patch Changes - -- 8f7b1835df: Updated dependency `msw` to `^0.41.0`. -- Updated dependencies - - @backstage/backend-common@0.13.6-next.1 - - @backstage/plugin-catalog-graphql@0.3.10-next.0 - -## 0.1.23-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.13.6-next.0 - -## 0.1.22 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.13.3 - - @backstage/config@1.0.1 - - @backstage/plugin-catalog-graphql@0.3.9 - -## 0.1.22-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.13.3-next.2 - - @backstage/config@1.0.1-next.0 - - @backstage/plugin-catalog-graphql@0.3.9-next.0 - -## 0.1.22-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.13.3-next.0 - -## 0.1.21 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.13.2 - - @backstage/plugin-catalog-graphql@0.3.8 - -## 0.1.21-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.13.2-next.0 - - @backstage/plugin-catalog-graphql@0.3.8-next.0 - -## 0.1.20 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.13.1 - - @backstage/plugin-catalog-graphql@0.3.7 - - @backstage/config@1.0.0 - -## 0.1.19 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.13.0 - - @backstage/plugin-catalog-graphql@0.3.6 - -## 0.1.19-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.13.0-next.0 - - @backstage/plugin-catalog-graphql@0.3.6-next.0 - -## 0.1.18 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.12.0 - - @backstage/plugin-catalog-graphql@0.3.5 - -## 0.1.17 - -### Patch Changes - -- 68913af4ff: chore(deps): bump `graphql-modules` from 1.4.4 to 2.0.0 -- Updated dependencies - - @backstage/backend-common@0.11.0 - - @backstage/plugin-catalog-graphql@0.3.4 - -## 0.1.16 - -### Patch Changes - -- Fix for the previous release with missing type declarations. -- Updated dependencies - - @backstage/backend-common@0.10.9 - - @backstage/config@0.1.15 - - @backstage/plugin-catalog-graphql@0.3.3 - -## 0.1.15 - -### Patch Changes - -- c77c5c7eb6: Added `backstage.role` to `package.json` -- 0107c9aa08: chore(deps): bump `helmet` from 4.4.1 to 5.0.2 -- Updated dependencies - - @backstage/backend-common@0.10.8 - - @backstage/plugin-catalog-graphql@0.3.2 - - @backstage/config@0.1.14 - -## 0.1.14 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.10.7 - -## 0.1.14-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.10.7-next.0 - -## 0.1.13 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.10.6 - -## 0.1.13-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.10.6-next.0 - -## 0.1.12 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.10.4 - - @backstage/config@0.1.13 - - @backstage/plugin-catalog-graphql@0.3.1 - -## 0.1.12-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.10.4-next.0 - - @backstage/config@0.1.13-next.0 - - @backstage/plugin-catalog-graphql@0.3.1-next.0 - -## 0.1.11 - -### Patch Changes - -- 0fb17da164: chore: bumping dependencies in the GraphQL modules and bringing them up to date with the latest `graphql-modules` library -- Updated dependencies - - @backstage/config@0.1.12 - - @backstage/backend-common@0.10.3 - - @backstage/plugin-catalog-graphql@0.3.0 - -## 0.1.10 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.10.0 - -## 0.1.9 - -### Patch Changes - -- Updated dependencies - - @backstage/backend-common@0.9.0 - - @backstage/config@0.1.8 - - @backstage/plugin-catalog-graphql@0.2.12 - -## 0.1.8 - -### Patch Changes - -- Updated dependencies [3be844496] -- Updated dependencies [22fd8ce2a] -- Updated dependencies [f9fb4a205] - - @backstage/plugin-catalog-graphql@0.2.9 - - @backstage/backend-common@0.8.0 - -## 0.1.7 - -### Patch Changes - -- Updated dependencies [e0bfd3d44] -- Updated dependencies [38ca05168] -- Updated dependencies [d8b81fd28] - - @backstage/backend-common@0.7.0 - - @backstage/config@0.1.5 - - @backstage/plugin-catalog-graphql@0.2.8 - -## 0.1.6 - -### Patch Changes - -- Updated dependencies [8686eb38c] -- Updated dependencies [0434853a5] -- Updated dependencies [8686eb38c] - - @backstage/backend-common@0.6.0 - - @backstage/config@0.1.4 - - @backstage/plugin-catalog-graphql@0.2.7 - -## 0.1.5 - -### Patch Changes - -- Updated dependencies [0b135e7e0] -- Updated dependencies [294a70cab] -- Updated dependencies [0ea032763] -- Updated dependencies [5345a1f98] -- Updated dependencies [09a370426] - - @backstage/backend-common@0.5.0 - - @backstage/plugin-catalog-graphql@0.2.6 - -## 0.1.4 - -### Patch Changes - -- Updated dependencies [38e24db00] -- Updated dependencies [e3bd9fc2f] -- Updated dependencies [12bbd748c] -- Updated dependencies [e3bd9fc2f] - - @backstage/backend-common@0.4.0 - - @backstage/config@0.1.2 - - @backstage/plugin-catalog-graphql@0.2.4 - -## 0.1.3 - -### Patch Changes - -- Updated dependencies [1722cb53c] -- Updated dependencies [1722cb53c] -- Updated dependencies [7b37e6834] -- Updated dependencies [8e2effb53] - - @backstage/backend-common@0.3.0 - - @backstage/plugin-catalog-graphql@0.2.1 - -## 0.1.2 - -### Patch Changes - -- Updated dependencies [28edd7d29] -- Updated dependencies [5249594c5] -- Updated dependencies [56e4eb589] -- Updated dependencies [e37c0a005] -- Updated dependencies [f00ca3cb8] -- Updated dependencies [6579769df] -- Updated dependencies [8c2b76e45] -- Updated dependencies [440a17b39] -- Updated dependencies [8afce088a] -- Updated dependencies [7bbeb049f] - - @backstage/plugin-catalog-graphql@0.2.0 - - @backstage/backend-common@0.2.0 diff --git a/plugins/graphql-backend/README.md b/plugins/graphql-backend/README.md deleted file mode 100644 index 7e9f6c772e..0000000000 --- a/plugins/graphql-backend/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# GraphQL Backend - -This package has been deprecated, consider using [@frontside/backstage-plugin-graphql-backend](https://www.npmjs.com/package/@frontside/backstage-plugin-graphql-backend) instead. diff --git a/plugins/graphql-backend/api-report.md b/plugins/graphql-backend/api-report.md deleted file mode 100644 index a787c4f209..0000000000 --- a/plugins/graphql-backend/api-report.md +++ /dev/null @@ -1,20 +0,0 @@ -## API Report File for "@backstage/plugin-graphql-backend" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts -import { Config } from '@backstage/config'; -import express from 'express'; -import { Logger } from 'winston'; - -// @public (undocumented) -export function createRouter(options: RouterOptions): Promise; - -// @public (undocumented) -export interface RouterOptions { - // (undocumented) - config: Config; - // (undocumented) - logger: Logger; -} -``` diff --git a/plugins/graphql-backend/catalog-info.yaml b/plugins/graphql-backend/catalog-info.yaml deleted file mode 100644 index 4545c0def5..0000000000 --- a/plugins/graphql-backend/catalog-info.yaml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: backstage.io/v1alpha1 -kind: Component -metadata: - name: backstage-plugin-graphql-backend - title: '@backstage/plugin-graphql-backend' - description: An experimental Backstage backend plugin for GraphQL -spec: - lifecycle: experimental - type: backstage-backend-plugin - owner: maintainers diff --git a/plugins/graphql-backend/package.json b/plugins/graphql-backend/package.json deleted file mode 100644 index 9d849bf9f2..0000000000 --- a/plugins/graphql-backend/package.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "name": "@backstage/plugin-graphql-backend", - "description": "Deprecated, consider using @frontside/backstage-plugin-graphql-backend instead", - "version": "0.2.1-next.2", - "main": "src/index.ts", - "types": "src/index.ts", - "license": "Apache-2.0", - "publishConfig": { - "access": "public", - "main": "dist/index.cjs.js", - "types": "dist/index.d.ts" - }, - "backstage": { - "role": "backend-plugin" - }, - "homepage": "https://backstage.io", - "repository": { - "type": "git", - "url": "https://github.com/backstage/backstage", - "directory": "plugins/graphql-backend" - }, - "keywords": [ - "backstage", - "graphql" - ], - "scripts": { - "start": "backstage-cli package start", - "build": "backstage-cli package build", - "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" - }, - "dependencies": { - "@apollo/server": "^4.0.0", - "@backstage/backend-common": "workspace:^", - "@backstage/config": "workspace:^", - "@backstage/plugin-catalog-graphql": "workspace:^", - "@graphql-tools/schema": "^9.0.0", - "@types/express": "^4.17.6", - "express": "^4.17.1", - "express-promise-router": "^4.1.0", - "graphql": "^16.0.0", - "graphql-modules": "^2.0.0", - "helmet": "^6.0.0", - "reflect-metadata": "^0.1.13", - "winston": "^3.2.1", - "yn": "^4.0.0" - }, - "devDependencies": { - "@backstage/cli": "workspace:^", - "@types/supertest": "^2.0.8", - "msw": "^1.0.0", - "supertest": "^6.1.3" - }, - "files": [ - "dist", - "schema.gql" - ] -} diff --git a/plugins/graphql-backend/schema.gql b/plugins/graphql-backend/schema.gql deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/plugins/graphql-backend/src/service/router.test.ts b/plugins/graphql-backend/src/service/router.test.ts deleted file mode 100644 index 37dc25ebc6..0000000000 --- a/plugins/graphql-backend/src/service/router.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import { createRouter } from './router'; -import supertest from 'supertest'; -import { ConfigReader } from '@backstage/config'; -import { createLogger } from 'winston'; -import express from 'express'; - -describe('Router', () => { - describe('/health', () => { - it('should return ok', async () => { - const config = new ConfigReader({ backend: { baseUrl: 'lol' } }); - - const router = await createRouter({ config, logger: createLogger() }); - const app = express().use(router); - - const { body } = await supertest(app).get('/health'); - - expect(body).toEqual({ status: 'ok' }); - }); - }); -}); diff --git a/plugins/graphql-backend/src/service/router.ts b/plugins/graphql-backend/src/service/router.ts deleted file mode 100644 index fbddee435f..0000000000 --- a/plugins/graphql-backend/src/service/router.ts +++ /dev/null @@ -1,78 +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 { errorHandler } from '@backstage/backend-common'; -import express from 'express'; -import Router from 'express-promise-router'; -import { Logger } from 'winston'; -import { createApplication } from 'graphql-modules'; -import { ApolloServer } from '@apollo/server'; -import { expressMiddleware } from '@apollo/server/express4'; -import { createModule as createCatalogModule } from '@backstage/plugin-catalog-graphql'; -import { Config } from '@backstage/config'; -import helmet from 'helmet'; -import { makeExecutableSchema } from '@graphql-tools/schema'; - -/** @public */ -export interface RouterOptions { - logger: Logger; - config: Config; -} - -/** @public */ -export async function createRouter( - options: RouterOptions, -): Promise { - const catalogModule = await createCatalogModule(options); - - const { createSchemaForApollo } = createApplication({ - modules: [catalogModule], - schemaBuilder(input) { - return makeExecutableSchema({ - ...input, - inheritResolversFromInterfaces: true, - }); - }, - }); - - const server = new ApolloServer({ - schema: createSchemaForApollo(), - logger: options.logger, - introspection: true, - }); - - await server.start(); - - const router = Router(); - - router.get('/health', (_, response) => { - response.json({ status: 'ok' }); - }); - - if (process.env.NODE_ENV === 'development') - router.use( - helmet.contentSecurityPolicy({ - directives: { - defaultSrc: ["'self'", "'unsafe-inline'", 'http://*'], - }, - }), - ); - - router.use(expressMiddleware(server)); - router.use(errorHandler()); - - return router; -} diff --git a/plugins/graphql-voyager/CHANGELOG.md b/plugins/graphql-voyager/CHANGELOG.md index 2ef077cf11..f65e23b8bb 100644 --- a/plugins/graphql-voyager/CHANGELOG.md +++ b/plugins/graphql-voyager/CHANGELOG.md @@ -1,5 +1,86 @@ # @backstage/plugin-graphql-voyager +## 0.1.11 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + +## 0.1.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + +## 0.1.11-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/core-plugin-api@1.8.1 + +## 0.1.10 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + +## 0.1.10-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + +## 0.1.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## 0.1.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.0 + +## 0.1.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + +## 0.1.9 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + ## 0.1.9-next.2 ### Patch Changes diff --git a/plugins/graphql-voyager/package.json b/plugins/graphql-voyager/package.json index 44c0ec551f..2a2941b033 100644 --- a/plugins/graphql-voyager/package.json +++ b/plugins/graphql-voyager/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-graphql-voyager", "description": "Backstage plugin for GraphQL Voyager", - "version": "0.1.9-next.2", + "version": "0.1.11", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,10 +32,7 @@ "dependencies": { "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", - "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.61", "@types/react": "^16.13.1 || ^17.0.0", "graphql-voyager": "^1.0.0-rc.31", "react-use": "^17.2.4" @@ -47,14 +44,10 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", - "@backstage/dev-utils": "workspace:^", "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "msw": "^1.0.0" + "@testing-library/react": "^14.0.0" }, "files": [ "dist" diff --git a/plugins/graphql-voyager/src/components/GraphQLVoyagerBrowser/GraphQLVoyagerBrowser.tsx b/plugins/graphql-voyager/src/components/GraphQLVoyagerBrowser/GraphQLVoyagerBrowser.tsx index d2f9262983..772c70b0fa 100644 --- a/plugins/graphql-voyager/src/components/GraphQLVoyagerBrowser/GraphQLVoyagerBrowser.tsx +++ b/plugins/graphql-voyager/src/components/GraphQLVoyagerBrowser/GraphQLVoyagerBrowser.tsx @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { GraphQLVoyagerEndpoint, introspectionQuery, @@ -20,18 +21,17 @@ import { import { useState } from 'react'; import { makeStyles, Tab, Tabs, Typography } from '@material-ui/core'; import React, { Suspense } from 'react'; -import { BackstageTheme } from '@backstage/theme'; import { Content, ErrorPanel, Progress } from '@backstage/core-components'; import { Voyager } from 'graphql-voyager'; import useAsync from 'react-use/lib/useAsync'; -const useStyles = makeStyles(() => ({ +const useStyles = makeStyles({ root: { height: '100%', display: 'flex', flexFlow: 'column nowrap', }, -})); +}); type GraphQLVoyagerBrowserProps = { endpoints: GraphQLVoyagerEndpoint[]; diff --git a/plugins/home-react/CHANGELOG.md b/plugins/home-react/CHANGELOG.md index b3dfb1bf11..3e877e8a5d 100644 --- a/plugins/home-react/CHANGELOG.md +++ b/plugins/home-react/CHANGELOG.md @@ -1,5 +1,130 @@ # @backstage/plugin-home-react +## 0.1.7 + +### Patch Changes + +- 98ac5ab: Updated dependency `@rjsf/utils` to `5.15.1`. + Updated dependency `@rjsf/core` to `5.15.1`. + Updated dependency `@rjsf/material-ui` to `5.15.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.1`. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + +## 0.1.7-next.2 + +### Patch Changes + +- 98ac5ab: Updated dependency `@rjsf/utils` to `5.15.1`. + Updated dependency `@rjsf/core` to `5.15.1`. + Updated dependency `@rjsf/material-ui` to `5.15.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.1`. + +## 0.1.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + +## 0.1.7-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/core-plugin-api@1.8.1 + +## 0.1.6 + +### Patch Changes + +- 2b72591: Updated dependency `@rjsf/utils` to `5.14.3`. + Updated dependency `@rjsf/core` to `5.14.3`. + Updated dependency `@rjsf/material-ui` to `5.14.3`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.3`. +- 6cd12f2: Updated dependency `@rjsf/utils` to `5.14.1`. + Updated dependency `@rjsf/core` to `5.14.1`. + Updated dependency `@rjsf/material-ui` to `5.14.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.1`. +- 64301d3: Updated dependency `@rjsf/utils` to `5.15.0`. + Updated dependency `@rjsf/core` to `5.15.0`. + Updated dependency `@rjsf/material-ui` to `5.15.0`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.0`. +- 63c494e: Updated dependency `@rjsf/utils` to `5.14.2`. + Updated dependency `@rjsf/core` to `5.14.2`. + Updated dependency `@rjsf/material-ui` to `5.14.2`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.2`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + +## 0.1.6-next.3 + +### Patch Changes + +- 64301d3: Updated dependency `@rjsf/utils` to `5.15.0`. + Updated dependency `@rjsf/core` to `5.15.0`. + Updated dependency `@rjsf/material-ui` to `5.15.0`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.0`. +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + +## 0.1.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## 0.1.6-next.1 + +### Patch Changes + +- 2b725913c1: Updated dependency `@rjsf/utils` to `5.14.3`. + Updated dependency `@rjsf/core` to `5.14.3`. + Updated dependency `@rjsf/material-ui` to `5.14.3`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.3`. +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + +## 0.1.6-next.0 + +### Patch Changes + +- 6cd12f277b: Updated dependency `@rjsf/utils` to `5.14.1`. + Updated dependency `@rjsf/core` to `5.14.1`. + Updated dependency `@rjsf/material-ui` to `5.14.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.1`. +- 63c494ef22: Updated dependency `@rjsf/utils` to `5.14.2`. + Updated dependency `@rjsf/core` to `5.14.2`. + Updated dependency `@rjsf/material-ui` to `5.14.2`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.2`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + +## 0.1.5 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- c838da0edd: Updated dependency `@rjsf/utils` to `5.13.6`. + Updated dependency `@rjsf/core` to `5.13.6`. + Updated dependency `@rjsf/material-ui` to `5.13.6`. + Updated dependency `@rjsf/validator-ajv8` to `5.13.6`. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + ## 0.1.5-next.2 ### Patch Changes diff --git a/plugins/home-react/package.json b/plugins/home-react/package.json index 5173d11d00..896d9e46f2 100644 --- a/plugins/home-react/package.json +++ b/plugins/home-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-home-react", "description": "A Backstage plugin that contains react components helps you build a home page", - "version": "0.1.5-next.2", + "version": "0.1.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -38,7 +38,7 @@ "@backstage/core-plugin-api": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@rjsf/utils": "5.13.6", + "@rjsf/utils": "5.15.1", "@types/react": "^16.13.1 || ^17.0.0" }, "peerDependencies": { @@ -48,16 +48,7 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", - "@backstage/dev-utils": "workspace:^", - "@backstage/test-utils": "workspace:^", - "@testing-library/dom": "^9.0.0", - "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "@types/react-grid-layout": "^1.3.2", - "cross-fetch": "^4.0.0", - "msw": "^1.0.0" + "@types/react-grid-layout": "^1.3.2" }, "files": [ "dist" diff --git a/plugins/home/CHANGELOG.md b/plugins/home/CHANGELOG.md index 2d4074bab6..200ccd0aca 100644 --- a/plugins/home/CHANGELOG.md +++ b/plugins/home/CHANGELOG.md @@ -1,5 +1,260 @@ # @backstage/plugin-home +## 0.6.1 + +### Patch Changes + +- 98ac5ab: Updated dependency `@rjsf/utils` to `5.15.1`. + Updated dependency `@rjsf/core` to `5.15.1`. + Updated dependency `@rjsf/material-ui` to `5.15.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.1`. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-compat-api@0.1.1 + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-home-react@0.1.7 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-app-api@1.11.3 + - @backstage/theme@0.5.0 + +## 0.6.1-next.2 + +### Patch Changes + +- 98ac5ab: Updated dependency `@rjsf/utils` to `5.15.1`. + Updated dependency `@rjsf/core` to `5.15.1`. + Updated dependency `@rjsf/material-ui` to `5.15.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.1`. +- Updated dependencies + - @backstage/core-compat-api@0.1.1-next.2 + - @backstage/frontend-plugin-api@0.4.1-next.2 + - @backstage/plugin-home-react@0.1.7-next.2 + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.6.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/core-app-api@1.11.3-next.0 + - @backstage/core-compat-api@0.1.1-next.1 + - @backstage/frontend-plugin-api@0.4.1-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/plugin-home-react@0.1.7-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0 + +## 0.6.1-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/frontend-plugin-api@0.4.1-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/plugin-home-react@0.1.7-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-app-api@1.11.2 + - @backstage/core-compat-api@0.1.1-next.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/theme@0.5.0 + +## 0.6.0 + +### Minor Changes + +- 5a317f5: Added view of entities grouped by kind to make it easier to distinguish entities with different kind but same name + +### Patch Changes + +- 2633d64: Change user settings backend plugin id and fix when using user setting backend home page first will cause edit page loop render +- a1227cc: Wrap `/alpha` export extension elements in backwards compatibility wrapper. +- 5814122: Updated `/alpha` exports to fit new naming patterns. +- 8f5d6c1: Updates to the `/alpha` exports to match the extension input wrapping change. +- 2b72591: Updated dependency `@rjsf/utils` to `5.14.3`. + Updated dependency `@rjsf/core` to `5.14.3`. + Updated dependency `@rjsf/material-ui` to `5.14.3`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.3`. +- 6cd12f2: Updated dependency `@rjsf/utils` to `5.14.1`. + Updated dependency `@rjsf/core` to `5.14.1`. + Updated dependency `@rjsf/material-ui` to `5.14.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.1`. +- 64301d3: Updated dependency `@rjsf/utils` to `5.15.0`. + Updated dependency `@rjsf/core` to `5.15.0`. + Updated dependency `@rjsf/material-ui` to `5.15.0`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.0`. +- 63c494e: Updated dependency `@rjsf/utils` to `5.14.2`. + Updated dependency `@rjsf/core` to `5.14.2`. + Updated dependency `@rjsf/material-ui` to `5.14.2`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.2`. +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- 54cef27: StarredEntities component calls `getEntitiesByRefs` instead of `getEntities` to improve performance since we have the `entityRefs` +- c8908d4: Use new option from RJSF 5.15 +- 0cbb03b: Fixing regular expression ReDoS with zod packages. Upgrading to latest. ref: https://security.snyk.io/vuln/SNYK-JS-ZOD-5925617 +- Updated dependencies + - @backstage/core-compat-api@0.1.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/frontend-plugin-api@0.4.0 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-client@1.5.0 + - @backstage/core-app-api@1.11.2 + - @backstage/plugin-home-react@0.1.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## 0.6.0-next.3 + +### Patch Changes + +- 2633d64: Change user settings backend plugin id and fix when using user setting backend home page first will cause edit page loop render +- 64301d3: Updated dependency `@rjsf/utils` to `5.15.0`. + Updated dependency `@rjsf/core` to `5.15.0`. + Updated dependency `@rjsf/material-ui` to `5.15.0`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.0`. +- 54cef27: StarredEntities component calls `getEntitiesByRefs` instead of `getEntities` to improve performance since we have the `entityRefs` +- c8908d4: Use new option from RJSF 5.15 +- Updated dependencies + - @backstage/plugin-home-react@0.1.6-next.3 + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-compat-api@0.1.0-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/frontend-plugin-api@0.4.0-next.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## 0.6.0-next.2 + +### Patch Changes + +- a1227cc: Wrap `/alpha` export extension elements in backwards compatibility wrapper. +- 8f5d6c1: Updates to the `/alpha` exports to match the extension input wrapping change. +- 36c94b8: Refactor of the alpha exports due to API change in how extension IDs are constructed. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.2 + - @backstage/theme@0.5.0-next.1 + - @backstage/core-compat-api@0.1.0-next.2 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-home-react@0.1.6-next.2 + +## 0.6.0-next.1 + +### Minor Changes + +- 5a317f59c0: Added view of entities grouped by kind to make it easier to distinguish entities with different kind but same name + +### Patch Changes + +- 2b725913c1: Updated dependency `@rjsf/utils` to `5.14.3`. + Updated dependency `@rjsf/core` to `5.14.3`. + Updated dependency `@rjsf/material-ui` to `5.14.3`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.3`. +- Updated dependencies + - @backstage/frontend-plugin-api@0.4.0-next.1 + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/core-app-api@1.11.2-next.1 + - @backstage/plugin-home-react@0.1.6-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + +## 0.5.12-next.0 + +### Patch Changes + +- 6cd12f277b: Updated dependency `@rjsf/utils` to `5.14.1`. + Updated dependency `@rjsf/core` to `5.14.1`. + Updated dependency `@rjsf/material-ui` to `5.14.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.1`. +- 63c494ef22: Updated dependency `@rjsf/utils` to `5.14.2`. + Updated dependency `@rjsf/core` to `5.14.2`. + Updated dependency `@rjsf/material-ui` to `5.14.2`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.2`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/plugin-home-react@0.1.6-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/frontend-plugin-api@0.3.1-next.0 + - @backstage/core-app-api@1.11.2-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## 0.5.10 + +### Patch Changes + +- d86b2acec4: Fix bug where `retrieveAll` method wasn't fetching visits +- 3fdffbb699: Remove the duplicate versions of `@rjsf/*` as they're no longer needed +- 6c2b872153: Add official support for React 18. +- 5b364984bf: Added experimental support for declarative integration via the `/alpha` subpath. +- c838da0edd: Updated dependency `@rjsf/utils` to `5.13.6`. + Updated dependency `@rjsf/core` to `5.13.6`. + Updated dependency `@rjsf/material-ui` to `5.13.6`. + Updated dependency `@rjsf/validator-ajv8` to `5.13.6`. +- cc0e8d0b51: Temporarily pin the `react-grid-layout` sub-dependency to version `1.3.4` while the horizontal resizing of the latest version is not fixed. For more details, see [#20712](https://github.com/backstage/backstage/issues/20712). +- 302316d231: Added a new Featured Docs component to `plugin-home`, which can display any entity given a filter. + + ``` + import { FeaturedDocsCard } from '@backstage/plugin-home'; + + + ``` + + See the [storybook examples](https://backstage.io/storybook/?path=/story/plugins-home-components-featureddocs--default) + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/frontend-plugin-api@0.3.0 + - @backstage/core-plugin-api@1.8.0 + - @backstage/core-app-api@1.11.1 + - @backstage/plugin-home-react@0.1.5 + - @backstage/theme@0.4.4 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + ## 0.5.10-next.2 ### Patch Changes diff --git a/plugins/home/alpha-api-report.md b/plugins/home/api-report-alpha.md similarity index 100% rename from plugins/home/alpha-api-report.md rename to plugins/home/api-report-alpha.md diff --git a/plugins/home/api-report.md b/plugins/home/api-report.md index 14f685cfc1..dd6e22c57d 100644 --- a/plugins/home/api-report.md +++ b/plugins/home/api-report.md @@ -14,6 +14,7 @@ import { CardSettings as CardSettings_2 } from '@backstage/plugin-home-react'; import { ComponentParts as ComponentParts_2 } from '@backstage/plugin-home-react'; import { ComponentRenderer as ComponentRenderer_2 } from '@backstage/plugin-home-react'; import { createCardExtension as createCardExtension_2 } from '@backstage/plugin-home-react'; +import { EntityFilterQuery } from '@backstage/catalog-client'; import { ErrorApi } from '@backstage/core-plugin-api'; import { IdentityApi } from '@backstage/core-plugin-api'; import { JSX as JSX_2 } from 'react'; @@ -101,6 +102,20 @@ export type CustomHomepageGridProps = { preventCollision?: boolean; }; +// @public +export const FeaturedDocsCard: ( + props: CardExtensionProps_2, +) => JSX_2.Element; + +// @public +export type FeaturedDocsCardProps = { + filter: EntityFilterQuery; + emptyState?: React_2.JSX.Element; + linkDestination?: string; + responseLimit?: number; + subLinkText?: string; +}; + // @public export const HeaderWorldClock: (props: { clockConfigs: ClockConfig[]; @@ -133,7 +148,7 @@ export const HomePageRecentlyVisited: ( // @public export const HomePageStarredEntities: ( - props: CardExtensionProps_2, + props: CardExtensionProps_2>, ) => JSX_2.Element; // @public @@ -177,6 +192,12 @@ export const SettingsModal: (props: { children: JSX.Element; }) => JSX_2.Element; +// @public +export type StarredEntitiesProps = { + noStarredEntitiesMessage?: React_2.ReactNode | undefined; + groupByKind?: boolean; +}; + // @public (undocumented) export const TemplateBackstageLogo: (props: { classes: { diff --git a/plugins/home/package.json b/plugins/home/package.json index 4112e9a30b..9eff9d6110 100644 --- a/plugins/home/package.json +++ b/plugins/home/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-home", "description": "A Backstage plugin that helps you build a home page", - "version": "0.5.10-next.2", + "version": "0.6.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -47,30 +47,30 @@ "clean": "backstage-cli package clean" }, "dependencies": { + "@backstage/catalog-client": "workspace:^", "@backstage/catalog-model": "workspace:^", - "@backstage/config": "workspace:^", "@backstage/core-app-api": "workspace:^", + "@backstage/core-compat-api": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/frontend-plugin-api": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", "@backstage/plugin-home-react": "workspace:^", "@backstage/theme": "workspace:^", - "@backstage/types": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", - "@rjsf/core": "5.13.6", - "@rjsf/material-ui": "5.13.6", - "@rjsf/utils": "5.13.6", - "@rjsf/validator-ajv8": "5.13.6", + "@rjsf/core": "5.15.1", + "@rjsf/material-ui": "5.15.1", + "@rjsf/utils": "5.15.1", + "@rjsf/validator-ajv8": "5.15.1", "@types/react": "^16.13.1 || ^17.0.0", "lodash": "^4.17.21", "luxon": "^3.4.3", "react-grid-layout": "1.3.4", "react-resizable": "^3.0.4", "react-use": "^17.2.4", - "zod": "^3.21.4" + "zod": "^3.22.4" }, "peerDependencies": { "react": "^16.13.1 || ^17.0.0 || ^18.0.0", @@ -85,8 +85,7 @@ "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", - "@types/react-grid-layout": "^1.3.2", - "msw": "^1.0.0" + "@types/react-grid-layout": "^1.3.2" }, "files": [ "dist" diff --git a/plugins/home/src/alpha.tsx b/plugins/home/src/alpha.tsx index c8308f7c0a..e9ff26c9e1 100644 --- a/plugins/home/src/alpha.tsx +++ b/plugins/home/src/alpha.tsx @@ -24,6 +24,7 @@ import { createPlugin, createRouteRef, } from '@backstage/frontend-plugin-api'; +import { compatWrapper } from '@backstage/core-compat-api'; const rootRouteRef = createRouteRef(); @@ -32,8 +33,7 @@ const rootRouteRef = createRouteRef(); */ export const titleExtensionDataRef = createExtensionDataRef('title'); -const HomepageCompositionRootExtension = createPageExtension({ - id: 'home', +const homePage = createPageExtension({ defaultPath: '/home', routeRef: rootRouteRef, inputs: { @@ -50,12 +50,14 @@ const HomepageCompositionRootExtension = createPageExtension({ ), }, loader: ({ inputs }) => - import('./components/').then(m => ( - - )), + import('./components/').then(m => + compatWrapper( + , + ), + ), }); /** @@ -63,5 +65,5 @@ const HomepageCompositionRootExtension = createPageExtension({ */ export default createPlugin({ id: 'home', - extensions: [HomepageCompositionRootExtension], + extensions: [homePage], }); diff --git a/plugins/home/src/components/CustomHomepage/CustomHomepageGrid.tsx b/plugins/home/src/components/CustomHomepage/CustomHomepageGrid.tsx index 590a96bf09..07e21ff8e2 100644 --- a/plugins/home/src/components/CustomHomepage/CustomHomepageGrid.tsx +++ b/plugins/home/src/components/CustomHomepage/CustomHomepageGrid.tsx @@ -206,10 +206,11 @@ export const CustomHomepageGrid = (props: CustomHomepageGridProps) => { availableWidgetsFilter, [props], ); - - const defaultLayout = props.config - ? convertConfigToDefaultWidgets(props.config, availableWidgets) - : []; + const defaultLayout = useMemo(() => { + return props.config + ? convertConfigToDefaultWidgets(props.config, availableWidgets) + : []; + }, [props.config, availableWidgets]); const [widgets, setWidgets] = useHomeStorage(defaultLayout); const [addWidgetDialogOpen, setAddWidgetDialogOpen] = React.useState(false); const editModeOn = widgets.find(w => w.layout.isResizable) !== undefined; diff --git a/plugins/home/src/components/CustomHomepage/WidgetSettingsOverlay.tsx b/plugins/home/src/components/CustomHomepage/WidgetSettingsOverlay.tsx index aec4b3dcf2..735720ac13 100644 --- a/plugins/home/src/components/CustomHomepage/WidgetSettingsOverlay.tsx +++ b/plugins/home/src/components/CustomHomepage/WidgetSettingsOverlay.tsx @@ -91,6 +91,9 @@ export const WidgetSettingsOverlay = (props: WidgetSettingsOverlayProps) => { setSettingsDialogOpen(false); } }} + experimental_defaultFormStateBehavior={{ + allOf: 'populateDefaults', + }} /> diff --git a/plugins/home/src/components/StarredEntityListItem/StarredEntityListItem.tsx b/plugins/home/src/components/StarredEntityListItem/StarredEntityListItem.tsx new file mode 100644 index 0000000000..2a8960e469 --- /dev/null +++ b/plugins/home/src/components/StarredEntityListItem/StarredEntityListItem.tsx @@ -0,0 +1,60 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { Entity, stringifyEntityRef } from '@backstage/catalog-model'; +import { entityRouteParams } from '@backstage/plugin-catalog-react'; +import { + ListItem, + ListItemIcon, + Tooltip, + IconButton, + ListItemText, +} from '@material-ui/core'; +import React from 'react'; +import { Link } from 'react-router-dom'; +import { entityRouteRef } from '@backstage/plugin-catalog-react'; +import { useRouteRef } from '@backstage/core-plugin-api'; +import StarIcon from '@material-ui/icons/Star'; + +type EntityListItemProps = { + entity: Entity; + onToggleStarredEntity: (entity: Entity) => void; +}; + +export const StarredEntityListItem = ({ + entity, + onToggleStarredEntity, +}: EntityListItemProps) => { + const catalogEntityRoute = useRouteRef(entityRouteRef); + + return ( + + + + onToggleStarredEntity(entity)} + > + + + + + + + + + ); +}; diff --git a/plugins/home/src/components/StarredEntityListItem/index.ts b/plugins/home/src/components/StarredEntityListItem/index.ts new file mode 100644 index 0000000000..5419e0cdf7 --- /dev/null +++ b/plugins/home/src/components/StarredEntityListItem/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { StarredEntityListItem } from './StarredEntityListItem'; diff --git a/plugins/home/src/homePageComponents/FeaturedDocsCard/Content.test.tsx b/plugins/home/src/homePageComponents/FeaturedDocsCard/Content.test.tsx new file mode 100644 index 0000000000..427a1484d5 --- /dev/null +++ b/plugins/home/src/homePageComponents/FeaturedDocsCard/Content.test.tsx @@ -0,0 +1,73 @@ +/* + * 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 { Content } from './Content'; +import React from 'react'; +import { catalogApiRef, entityRouteRef } from '@backstage/plugin-catalog-react'; +import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; + +const docsEntities = [ + { + apiVersion: '1', + kind: 'Location', + metadata: { + name: 'getting-started-with-idp', + title: 'Getting Started Docs', + }, + spec: { + type: 'documentation', + }, + }, +]; + +describe('', () => { + const mockCatalogApi = { + getEntities: jest + .fn() + .mockImplementation(async () => ({ items: docsEntities })), + }; + let Wrapper: React.ComponentType>; + + beforeAll(() => { + Wrapper = ({ children }: { children?: React.ReactNode }) => ( + + {children} + + ); + }); + it('should show expected featured doc and title', async () => { + const { getByTestId, getByText } = await renderInTestApp( + + + , + { + mountedRoutes: { + '/home': entityRouteRef, + }, + }, + ); + const docsCardContent = getByTestId('docs-card-content'); + const docsEntity = getByText('Getting Started Docs'); + + expect(docsCardContent).toContainElement(docsEntity); + }); +}); diff --git a/plugins/home/src/homePageComponents/FeaturedDocsCard/Content.tsx b/plugins/home/src/homePageComponents/FeaturedDocsCard/Content.tsx new file mode 100644 index 0000000000..eb8d78b0cc --- /dev/null +++ b/plugins/home/src/homePageComponents/FeaturedDocsCard/Content.tsx @@ -0,0 +1,158 @@ +/* + * 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 React from 'react'; +import useAsync from 'react-use/lib/useAsync'; +import { + LinkButton, + EmptyState, + Link, + Progress, + ErrorPanel, +} from '@backstage/core-components'; +import { catalogApiRef, CatalogApi } from '@backstage/plugin-catalog-react'; +import { useApi } from '@backstage/core-plugin-api'; +import { EntityFilterQuery } from '@backstage/catalog-client'; + +import { makeStyles, Typography } from '@material-ui/core'; + +/** + * Props customizing the component. + * + * @public + */ +export type FeaturedDocsCardProps = { + /** The entity filter used to display only the intended item/s */ + filter: EntityFilterQuery; + /** An optional ReactNode for empty states */ + emptyState?: React.JSX.Element; + /** An optional linkDestination to set for the Featured Doc */ + linkDestination?: string; + /** An optional limit to set for link destination */ + responseLimit?: number; + /** An optional string to customize sublink text */ + subLinkText?: string; +}; + +const useStyles = makeStyles( + theme => ({ + docDescription: { + fontSize: theme.typography.body1.fontSize, + fontWeight: theme.typography.body1.fontWeight, + marginBottom: theme.spacing(2), + marginTop: theme.spacing(2), + }, + docSubLink: { + fontSize: theme.typography.subtitle1.fontSize, + fontWeight: theme.typography.subtitle1.fontWeight, + lineHeight: theme.typography.subtitle1.lineHeight, + }, + docsTitleLink: { + fontSize: theme.typography.h6.fontSize, + fontWeight: theme.typography.h6.fontWeight, + lineHeight: theme.typography.h6.lineHeight, + }, + }), + { name: 'HomeFeaturedDocsCard' }, +); + +/** + * A component to display specific Featured Docs. + * + * @public + */ +export const Content = (props: FeaturedDocsCardProps): JSX.Element => { + const { emptyState, filter, linkDestination, responseLimit, subLinkText } = + props; + const linkText = subLinkText || 'LEARN MORE'; + const styles = useStyles(); + const catalogApi: CatalogApi = useApi(catalogApiRef); + const { + value: entities, + loading, + error, + } = useAsync(async () => { + const response = await catalogApi.getEntities({ + filter: filter, + limit: responseLimit || 10, + }); + return response.items; + }); + + if (loading) { + return ; + } + if (error) { + return ; + } + + return entities?.length ? ( + <> + {entities.map(d => ( +
    + + {d.metadata.title} + + {d.metadata.description && ( + + {d.metadata.description} + + )} + + {linkText} + +
    + ))} + + ) : ( + emptyState || ( + + DOCS + + } + /> + ) + ); +}; diff --git a/plugins/home/src/homePageComponents/FeaturedDocsCard/FeaturedDocsCard.stories.tsx b/plugins/home/src/homePageComponents/FeaturedDocsCard/FeaturedDocsCard.stories.tsx new file mode 100644 index 0000000000..91f0dbf27e --- /dev/null +++ b/plugins/home/src/homePageComponents/FeaturedDocsCard/FeaturedDocsCard.stories.tsx @@ -0,0 +1,71 @@ +/* + * 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 { FeaturedDocsCard } from '../../plugin'; +import React, { ComponentType, PropsWithChildren } from 'react'; +import { wrapInTestApp, TestApiProvider } from '@backstage/test-utils'; +import { catalogApiRef, entityRouteRef } from '@backstage/plugin-catalog-react'; +import { Grid } from '@material-ui/core'; + +const docsEntities = [ + { + apiVersion: '1', + kind: 'Location', + metadata: { + name: 'getting-started-with-backstage', + title: 'Getting Started Docs', + description: + 'An awesome doc you want to feature to help out your customers. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis pretium magna ut molestie lacinia. Nullam eget bibendum est, vitae finibus neque.', + }, + spec: { + type: 'documentation', + }, + }, +]; + +const mockCatalogApi = { + getEntities: async () => ({ items: docsEntities }), +}; + +export default { + title: 'Plugins/Home/Components/FeaturedDocsCard', + decorators: [ + (Story: ComponentType>) => + wrapInTestApp( + + + , + { + mountedRoutes: { + '/catalog/:namespace/:kind/:name': entityRouteRef, + }, + }, + ), + ], +}; + +export const Default = () => { + return ( + + + + ); +}; diff --git a/plugins/home/src/homePageComponents/FeaturedDocsCard/index.ts b/plugins/home/src/homePageComponents/FeaturedDocsCard/index.ts new file mode 100644 index 0000000000..5151fa370c --- /dev/null +++ b/plugins/home/src/homePageComponents/FeaturedDocsCard/index.ts @@ -0,0 +1,18 @@ +/* + * 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. + */ + +export { Content } from './Content'; +export type { FeaturedDocsCardProps } from './Content'; diff --git a/plugins/home/src/homePageComponents/StarredEntities/Content.test.tsx b/plugins/home/src/homePageComponents/StarredEntities/Content.test.tsx index 695406aab5..c41d7f586c 100644 --- a/plugins/home/src/homePageComponents/StarredEntities/Content.test.tsx +++ b/plugins/home/src/homePageComponents/StarredEntities/Content.test.tsx @@ -49,7 +49,7 @@ describe('StarredEntitiesContent', () => { mockedApi.toggleStarred('component:default/mock-starred-entity-3'); const mockCatalogApi = { - getEntities: jest + getEntitiesByRefs: jest .fn() .mockImplementation(async () => ({ items: entities })), }; @@ -87,7 +87,7 @@ describe('StarredEntitiesContent', () => { const mockedApi = new MockStarredEntitiesApi(); const mockCatalogApi = { - getEntities: jest + getEntitiesByRefs: jest .fn() .mockImplementation(async () => ({ items: entities })), }; @@ -117,7 +117,7 @@ describe('StarredEntitiesContent', () => { const mockedApi = new MockStarredEntitiesApi(); const mockCatalogApi = { - getEntities: jest + getEntitiesByRefs: jest .fn() .mockImplementation(async () => ({ items: entities })), }; diff --git a/plugins/home/src/homePageComponents/StarredEntities/Content.tsx b/plugins/home/src/homePageComponents/StarredEntities/Content.tsx index 4654a7f860..b3d4caf44e 100644 --- a/plugins/home/src/homePageComponents/StarredEntities/Content.tsx +++ b/plugins/home/src/homePageComponents/StarredEntities/Content.tsx @@ -17,24 +17,14 @@ import { catalogApiRef, useStarredEntities, - entityRouteParams, - entityRouteRef, } from '@backstage/plugin-catalog-react'; -import { parseEntityRef, stringifyEntityRef } from '@backstage/catalog-model'; -import { useApi, useRouteRef } from '@backstage/core-plugin-api'; -import { Link, Progress, ResponseErrorPanel } from '@backstage/core-components'; -import { - List, - ListItem, - ListItemSecondaryAction, - IconButton, - ListItemText, - Tooltip, - Typography, -} from '@material-ui/core'; -import StarIcon from '@material-ui/icons/Star'; +import { Entity, stringifyEntityRef } from '@backstage/catalog-model'; +import { useApi } from '@backstage/core-plugin-api'; +import { Progress, ResponseErrorPanel } from '@backstage/core-components'; +import { List, Typography, Tabs, Tab } from '@material-ui/core'; import React from 'react'; import useAsync from 'react-use/lib/useAsync'; +import { StarredEntityListItem } from '../../components/StarredEntityListItem/StarredEntityListItem'; /** * A component to display a list of starred entities for the user. @@ -42,12 +32,18 @@ import useAsync from 'react-use/lib/useAsync'; * @public */ -export const Content = (props: { +export type StarredEntitiesProps = { noStarredEntitiesMessage?: React.ReactNode | undefined; -}) => { + groupByKind?: boolean; +}; + +export const Content = ({ + noStarredEntitiesMessage, + groupByKind, +}: StarredEntitiesProps) => { const catalogApi = useApi(catalogApiRef); - const catalogEntityRoute = useRouteRef(entityRouteRef); const { starredEntities, toggleStarredEntity } = useStarredEntities(); + const [activeTab, setActiveTab] = React.useState(0); // Grab starred entities from catalog to ensure they still exist and also retrieve display titles const entities = useAsync(async () => { @@ -55,17 +51,9 @@ export const Content = (props: { return []; } - const filter = [...starredEntities] - .map(ent => parseEntityRef(ent)) - .map(ref => ({ - kind: ref.kind, - 'metadata.namespace': ref.namespace, - 'metadata.name': ref.name, - })); - return ( - await catalogApi.getEntities({ - filter, + await catalogApi.getEntitiesByRefs({ + entityRefs: [...starredEntities], fields: [ 'kind', 'metadata.namespace', @@ -73,13 +61,13 @@ export const Content = (props: { 'metadata.title', ], }) - ).items; + ).items.filter((e): e is Entity => !!e); }, [catalogApi, starredEntities]); if (starredEntities.size === 0) return ( - {props.noStarredEntitiesMessage || + {noStarredEntitiesMessage || 'Click the star beside an entity name to add it to this list!'} ); @@ -88,36 +76,73 @@ export const Content = (props: { return ; } + const groupedEntities: { [kind: string]: Entity[] } = {}; + entities.value?.forEach(entity => { + const kind = entity.kind; + if (!groupedEntities[kind]) { + groupedEntities[kind] = []; + } + groupedEntities[kind].push(entity); + }); + + const groupByKindEntries = Object.entries(groupedEntities); + return entities.error ? ( ) : ( - - {entities.value - ?.sort((a, b) => - (a.metadata.title ?? a.metadata.name).localeCompare( - b.metadata.title ?? b.metadata.name, - ), - ) - .map(entity => ( - - - + {!groupByKind && ( + + {entities.value + ?.sort((a, b) => + (a.metadata.title ?? a.metadata.name).localeCompare( + b.metadata.title ?? b.metadata.name, + ), + ) + .map(entity => ( + - - - - toggleStarredEntity(entity)} - > - - - - - + ))} + + )} + + {groupByKind && ( + setActiveTab(newValue)} + variant="scrollable" + scrollButtons="auto" + aria-label="entity-tabs" + > + {groupByKindEntries.map(([kind]) => ( + + ))} + + )} + + {groupByKind && + groupByKindEntries.map(([kind, entitiesByKind], index) => ( + ))} - + ); }; diff --git a/plugins/home/src/homePageComponents/StarredEntities/index.ts b/plugins/home/src/homePageComponents/StarredEntities/index.ts index 1faa9a2426..32e9213ea6 100644 --- a/plugins/home/src/homePageComponents/StarredEntities/index.ts +++ b/plugins/home/src/homePageComponents/StarredEntities/index.ts @@ -13,5 +13,5 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - export { Content } from './Content'; +export type { StarredEntitiesProps } from './Content'; diff --git a/plugins/home/src/homePageComponents/index.ts b/plugins/home/src/homePageComponents/index.ts index 9149afa295..e260982e8e 100644 --- a/plugins/home/src/homePageComponents/index.ts +++ b/plugins/home/src/homePageComponents/index.ts @@ -18,3 +18,5 @@ export type { ToolkitContentProps, Tool } from './Toolkit'; export type { ClockConfig } from './HeaderWorldClock'; export type { WelcomeTitleLanguageProps } from './WelcomeTitle'; export type { VisitedByTypeProps, VisitedByTypeKind } from './VisitedByType'; +export type { FeaturedDocsCardProps } from './FeaturedDocsCard'; +export type { StarredEntitiesProps } from './StarredEntities'; diff --git a/plugins/home/src/index.ts b/plugins/home/src/index.ts index a80f8bd93d..154186f169 100644 --- a/plugins/home/src/index.ts +++ b/plugins/home/src/index.ts @@ -34,6 +34,7 @@ export { HeaderWorldClock, HomePageTopVisited, HomePageRecentlyVisited, + FeaturedDocsCard, } from './plugin'; export * from './components'; export * from './assets'; diff --git a/plugins/home/src/plugin.ts b/plugins/home/src/plugin.ts index ab8c46baa1..cb9f129a72 100644 --- a/plugins/home/src/plugin.ts +++ b/plugins/home/src/plugin.ts @@ -23,9 +23,14 @@ import { storageApiRef, } from '@backstage/core-plugin-api'; import { createCardExtension } from '@backstage/plugin-home-react'; -import { ToolkitContentProps, VisitedByTypeProps } from './homePageComponents'; +import { + ToolkitContentProps, + VisitedByTypeProps, + FeaturedDocsCardProps, +} from './homePageComponents'; import { rootRouteRef } from './routes'; import { VisitsStorageApi, visitsApiRef } from './api'; +import { StarredEntitiesProps } from './homePageComponents/StarredEntities/Content'; /** @public */ export const homePlugin = createPlugin({ @@ -164,7 +169,7 @@ export const HomePageToolkit = homePlugin.provide( * @public */ export const HomePageStarredEntities = homePlugin.provide( - createCardExtension({ + createCardExtension>({ name: 'HomePageStarredEntities', title: 'Your Starred Entities', components: () => import('./homePageComponents/StarredEntities'), @@ -210,3 +215,16 @@ export const HomePageRecentlyVisited = homePlugin.provide( import('./homePageComponents/VisitedByType/RecentlyVisited'), }), ); + +/** + * A component to display specific Featured Docs. + * + * @public + */ +export const FeaturedDocsCard = homePlugin.provide( + createCardExtension({ + name: 'FeaturedDocsCard', + title: 'Featured Docs', + components: () => import('./homePageComponents/FeaturedDocsCard'), + }), +); diff --git a/plugins/home/src/setupTests.ts b/plugins/home/src/setupTests.ts index 7435872609..d56608cdc8 100644 --- a/plugins/home/src/setupTests.ts +++ b/plugins/home/src/setupTests.ts @@ -13,4 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import '@testing-library/jest-dom'; +import { Settings } from 'luxon'; + +Settings.defaultLocale = 'en'; diff --git a/plugins/ilert/CHANGELOG.md b/plugins/ilert/CHANGELOG.md index 8346c31b23..e2a55dbc2a 100644 --- a/plugins/ilert/CHANGELOG.md +++ b/plugins/ilert/CHANGELOG.md @@ -1,5 +1,120 @@ # @backstage/plugin-ilert +## 0.2.18 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.2.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.2.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.2.18-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + +## 0.2.17 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.2.17-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## 0.2.17-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + +## 0.2.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## 0.2.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.2.15 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + ## 0.2.15-next.2 ### Patch Changes diff --git a/plugins/ilert/package.json b/plugins/ilert/package.json index c852ca5652..7ef998cc64 100644 --- a/plugins/ilert/package.json +++ b/plugins/ilert/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-ilert", "description": "A Backstage plugin that integrates towards iLert", - "version": "0.2.15-next.2", + "version": "0.2.18", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,7 +35,6 @@ "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", - "@backstage/theme": "workspace:^", "@date-io/luxon": "1.x", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -53,14 +52,10 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", "@backstage/dev-utils": "workspace:^", - "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "msw": "^1.0.0" + "@testing-library/react": "^14.0.0" }, "files": [ "dist", diff --git a/plugins/ilert/src/components/ILertCard/ILertCardEmptyState.tsx b/plugins/ilert/src/components/ILertCard/ILertCardEmptyState.tsx index 966caea079..f81cfbc0a4 100644 --- a/plugins/ilert/src/components/ILertCard/ILertCardEmptyState.tsx +++ b/plugins/ilert/src/components/ILertCard/ILertCardEmptyState.tsx @@ -14,7 +14,6 @@ * limitations under the License. */ -import { BackstageTheme } from '@backstage/theme'; import Card from '@material-ui/core/Card'; import CardContent from '@material-ui/core/CardContent'; import CardHeader from '@material-ui/core/CardHeader'; @@ -37,7 +36,7 @@ spec: lifecycle: production owner: guest`; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles(theme => ({ code: { borderRadius: 6, margin: theme.spacing(2, 0), diff --git a/plugins/jenkins-backend/CHANGELOG.md b/plugins/jenkins-backend/CHANGELOG.md index b47d26f6fb..04645c8b31 100644 --- a/plugins/jenkins-backend/CHANGELOG.md +++ b/plugins/jenkins-backend/CHANGELOG.md @@ -1,5 +1,172 @@ # @backstage/plugin-jenkins-backend +## 0.3.3 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-jenkins-common@0.1.23 + +## 0.3.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/plugin-permission-node@0.7.20-next.2 + +## 0.3.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/plugin-permission-node@0.7.20-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-node@1.6.1-next.1 + - @backstage/plugin-jenkins-common@0.1.22 + - @backstage/plugin-permission-common@0.7.11 + +## 0.3.3-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/plugin-catalog-node@1.6.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.3-next.0 + - @backstage/plugin-jenkins-common@0.1.22 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.20-next.0 + +## 0.3.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/catalog-client@1.5.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.19 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-jenkins-common@0.1.22 + +## 0.3.2-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + - @backstage/plugin-catalog-node@1.6.0-next.3 + - @backstage/plugin-jenkins-common@0.1.21 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.3 + +## 0.3.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.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/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-jenkins-common@0.1.21 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.2 + +## 0.3.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-jenkins-common@0.1.21 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + +## 0.3.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/plugin-permission-node@0.7.19-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-jenkins-common@0.1.21 + - @backstage/plugin-permission-common@0.7.10 + +## 0.3.1 + +### Patch Changes + +- 4bfb878807: Updated dependency `@types/jenkins` to `^1.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/catalog-client@1.4.6 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.1 + - @backstage/plugin-jenkins-common@0.1.21 + - @backstage/plugin-permission-node@0.7.18 + ## 0.3.1-next.2 ### Patch Changes diff --git a/plugins/jenkins-backend/package.json b/plugins/jenkins-backend/package.json index bcfa73720d..0310169606 100644 --- a/plugins/jenkins-backend/package.json +++ b/plugins/jenkins-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-jenkins-backend", "description": "A Backstage backend plugin that integrates towards Jenkins", - "version": "0.3.1-next.2", + "version": "0.3.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -52,9 +52,7 @@ "devDependencies": { "@backstage/cli": "workspace:^", "@types/jenkins": "^1.0.0", - "@types/supertest": "^2.0.8", - "msw": "^1.0.0", - "supertest": "^6.1.6" + "@types/supertest": "^2.0.8" }, "files": [ "dist", diff --git a/plugins/jenkins-common/CHANGELOG.md b/plugins/jenkins-common/CHANGELOG.md index f91ea5074c..6d364dc40b 100644 --- a/plugins/jenkins-common/CHANGELOG.md +++ b/plugins/jenkins-common/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-jenkins-common +## 0.1.23 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-catalog-common@1.0.20 + +## 0.1.22 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-catalog-common@1.0.19 + +## 0.1.21 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-catalog-common@1.0.18 + ## 0.1.20 ### Patch Changes diff --git a/plugins/jenkins-common/package.json b/plugins/jenkins-common/package.json index 0856d27ad0..d61bd6cede 100644 --- a/plugins/jenkins-common/package.json +++ b/plugins/jenkins-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-jenkins-common", - "version": "0.1.20", + "version": "0.1.23", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/jenkins/CHANGELOG.md b/plugins/jenkins/CHANGELOG.md index f47d2c12c5..f69387fbdf 100644 --- a/plugins/jenkins/CHANGELOG.md +++ b/plugins/jenkins/CHANGELOG.md @@ -1,5 +1,131 @@ # @backstage/plugin-jenkins +## 0.9.4 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-jenkins-common@0.1.23 + +## 0.9.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.9.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-jenkins-common@0.1.22 + +## 0.9.4-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-jenkins-common@0.1.22 + +## 0.9.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-jenkins-common@0.1.22 + +## 0.9.3-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + - @backstage/plugin-jenkins-common@0.1.21 + +## 0.9.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-jenkins-common@0.1.21 + +## 0.9.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-jenkins-common@0.1.21 + +## 0.9.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-jenkins-common@0.1.21 + +## 0.9.1 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-jenkins-common@0.1.21 + ## 0.9.1-next.2 ### Patch Changes diff --git a/plugins/jenkins/package.json b/plugins/jenkins/package.json index a481772422..87181ac37c 100644 --- a/plugins/jenkins/package.json +++ b/plugins/jenkins/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-jenkins", "description": "A Backstage plugin that integrates towards Jenkins", - "version": "0.9.1-next.2", + "version": "0.9.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -40,10 +40,8 @@ "@backstage/errors": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", "@backstage/plugin-jenkins-common": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.61", "@types/react": "^16.13.1 || ^17.0.0", "luxon": "^3.0.0", "react-use": "^17.2.4" @@ -55,16 +53,12 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", "@backstage/dev-utils": "workspace:^", "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "@types/testing-library__jest-dom": "^5.9.1", - "cross-fetch": "^4.0.0", - "msw": "^1.0.0" + "@types/testing-library__jest-dom": "^5.9.1" }, "files": [ "dist" diff --git a/plugins/jenkins/src/components/Cards/Cards.tsx b/plugins/jenkins/src/components/Cards/Cards.tsx index 44bbc06f65..1cbc3e5d9f 100644 --- a/plugins/jenkins/src/components/Cards/Cards.tsx +++ b/plugins/jenkins/src/components/Cards/Cards.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { LinearProgress, makeStyles, Theme } from '@material-ui/core'; +import { LinearProgress, makeStyles } from '@material-ui/core'; import ExternalLinkIcon from '@material-ui/icons/Launch'; import { DateTime, Duration } from 'luxon'; import React from 'react'; @@ -29,7 +29,7 @@ import { } from '@backstage/core-components'; import { Project } from '../../api/JenkinsApi'; -const useStyles = makeStyles({ +const useStyles = makeStyles({ externalLinkIcon: { fontSize: 'inherit', verticalAlign: 'bottom', diff --git a/plugins/kafka-backend/CHANGELOG.md b/plugins/kafka-backend/CHANGELOG.md index 0fb9b6c92d..17a3a277e9 100644 --- a/plugins/kafka-backend/CHANGELOG.md +++ b/plugins/kafka-backend/CHANGELOG.md @@ -1,5 +1,112 @@ # @backstage/plugin-kafka-backend +## 0.3.7 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.3.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + +## 0.3.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/errors@1.2.3 + +## 0.3.7-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.3.6 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.3.6-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.3.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.3.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.3.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.3.5 + +### Patch Changes + +- 8613ba3928: Switched to using `"exports"` field for `/alpha` subpath export. +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + ## 0.3.5-next.2 ### Patch Changes diff --git a/plugins/kafka-backend/alpha-api-report.md b/plugins/kafka-backend/api-report-alpha.md similarity index 100% rename from plugins/kafka-backend/alpha-api-report.md rename to plugins/kafka-backend/api-report-alpha.md diff --git a/plugins/kafka-backend/package.json b/plugins/kafka-backend/package.json index 17237a69e7..5b8130fa91 100644 --- a/plugins/kafka-backend/package.json +++ b/plugins/kafka-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kafka-backend", "description": "A Backstage backend plugin that integrates towards Kafka", - "version": "0.3.5-next.2", + "version": "0.3.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -49,7 +49,6 @@ "dependencies": { "@backstage/backend-common": "workspace:^", "@backstage/backend-plugin-api": "workspace:^", - "@backstage/catalog-model": "workspace:^", "@backstage/config": "workspace:^", "@backstage/errors": "workspace:^", "@types/express": "^4.17.6", diff --git a/plugins/kafka/CHANGELOG.md b/plugins/kafka/CHANGELOG.md index 527d244872..4b6a8eda9b 100644 --- a/plugins/kafka/CHANGELOG.md +++ b/plugins/kafka/CHANGELOG.md @@ -1,5 +1,118 @@ # @backstage/plugin-kafka +## 0.3.29 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## 0.3.29-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.3.29-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + +## 0.3.29-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + +## 0.3.28 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + +## 0.3.28-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## 0.3.28-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## 0.3.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + +## 0.3.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + +## 0.3.26 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + ## 0.3.26-next.2 ### Patch Changes diff --git a/plugins/kafka/package.json b/plugins/kafka/package.json index 2c2afada94..ffbeb1c761 100644 --- a/plugins/kafka/package.json +++ b/plugins/kafka/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kafka", "description": "A Backstage plugin that integrates towards Kafka", - "version": "0.3.26-next.2", + "version": "0.3.29", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,14 +32,11 @@ }, "dependencies": { "@backstage/catalog-model": "workspace:^", - "@backstage/config": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.61", "@types/react": "^16.13.1 || ^17.0.0", "react-use": "^17.2.4" }, @@ -50,15 +47,12 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", "@backstage/dev-utils": "workspace:^", "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "jest-when": "^3.1.0", - "msw": "^1.0.0" + "jest-when": "^3.1.0" }, "files": [ "dist", diff --git a/plugins/kubernetes-backend/CHANGELOG.md b/plugins/kubernetes-backend/CHANGELOG.md index a419085051..d19054eb6b 100644 --- a/plugins/kubernetes-backend/CHANGELOG.md +++ b/plugins/kubernetes-backend/CHANGELOG.md @@ -1,5 +1,251 @@ # @backstage/plugin-kubernetes-backend +## 0.14.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-kubernetes-common@0.7.3 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + - @backstage/plugin-kubernetes-node@0.1.3 + +## 0.14.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/plugin-kubernetes-node@0.1.3-next.2 + - @backstage/plugin-permission-node@0.7.20-next.2 + +## 0.14.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration-aws-node@0.1.8 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/plugin-permission-node@0.7.20-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-node@1.6.1-next.1 + - @backstage/plugin-kubernetes-common@0.7.3-next.0 + - @backstage/plugin-kubernetes-node@0.1.3-next.1 + - @backstage/plugin-permission-common@0.7.11 + +## 0.14.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/plugin-kubernetes-common@0.7.3-next.0 + - @backstage/plugin-catalog-node@1.6.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.0 + - @backstage/plugin-kubernetes-node@0.1.3-next.0 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.20-next.0 + +## 0.14.0 + +### Minor Changes + +- 52050ad: You can now select `single` kubernetes cluster that the entity is part-of from all your defined kubernetes clusters, by passing `backstage.io/kubernetes-cluster` annotation with the defined cluster name. + + If you do not specify the annotation by `default it fetches all` defined kubernetes cluster. + + To apply + + catalog-info.yaml + + ```diff + annotations: + 'backstage.io/kubernetes-id': dice-roller + 'backstage.io/kubernetes-namespace': dice-space + + 'backstage.io/kubernetes-cluster': dice-cluster + 'backstage.io/kubernetes-label-selector': 'app=my-app,component=front-end' + ``` + +### Patch Changes + +- 6010564: The `kubernetes-node` plugin has been modified to house a new extension points for Kubernetes backend plugin; + `KubernetesClusterSupplierExtensionPoint` is introduced . + `kubernetesAuthStrategyExtensionPoint` is introduced . + `kubernetesFetcherExtensionPoint` is introduced . + `kubernetesServiceLocatorExtensionPoint` is introduced . + + The `kubernetes-backend` plugin was modified to use this new extension point. + +- 706fc3a: Updated dependency `@kubernetes/client-node` to `0.20.0`. +- ae94d3c: Updated dependency `@aws-crypto/sha256-js` to `^5.0.0`. +- 99fb541: Updated dependency `@azure/identity` to `^4.0.0`. +- 42c1aee: Updated dependency `@google-cloud/container` to `^5.0.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/catalog-client@1.5.0 + - @backstage/plugin-kubernetes-node@0.1.2 + - @backstage/plugin-kubernetes-common@0.7.2 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.19 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + +## 0.14.0-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.3 + - @backstage/plugin-catalog-node@1.6.0-next.3 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + - @backstage/plugin-kubernetes-node@0.1.2-next.3 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.3 + +## 0.14.0-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.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/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + - @backstage/plugin-kubernetes-node@0.1.2-next.2 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.2 + +## 0.14.0-next.1 + +### Patch Changes + +- ae94d3ce6f: Updated dependency `@aws-crypto/sha256-js` to `^5.0.0`. +- 99fb54183b: Updated dependency `@azure/identity` to `^4.0.0`. +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-kubernetes-node@0.1.2-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + +## 0.14.0-next.0 + +### Minor Changes + +- 52050ada6e: You can now select `single` kubernetes cluster that the entity is part-of from all your defined kubernetes clusters, by passing `backstage.io/kubernetes-cluster` annotation with the defined cluster name. + + If you do not specify the annotation by `default it fetches all` defined kubernetes cluster. + + To apply + + catalog-info.yaml + + ```diff + annotations: + 'backstage.io/kubernetes-id': dice-roller + 'backstage.io/kubernetes-namespace': dice-space + + 'backstage.io/kubernetes-cluster': dice-cluster + 'backstage.io/kubernetes-label-selector': 'app=my-app,component=front-end' + ``` + +### Patch Changes + +- 706fc3a7e1: Updated dependency `@kubernetes/client-node` to `0.20.0`. +- 42c1aee741: Updated dependency `@google-cloud/container` to `^5.0.0`. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-kubernetes-common@0.7.2-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/plugin-permission-node@0.7.19-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + - @backstage/plugin-kubernetes-node@0.1.2-next.0 + - @backstage/plugin-permission-common@0.7.10 + +## 0.13.1 + +### Patch Changes + +- 62180df4ee: Allow storing dashboard parameters for kubernetes in catalog +- df40b067e1: Fixed the lack of `resourcequotas` as part of the Default Objects to fetch from the kubernetes api +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/plugin-kubernetes-common@0.7.1 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/integration-aws-node@0.1.8 + - @backstage/catalog-client@1.4.6 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.1 + - @backstage/plugin-kubernetes-node@0.1.1 + - @backstage/plugin-permission-node@0.7.18 + ## 0.13.1-next.2 ### Patch Changes diff --git a/plugins/kubernetes-backend/alpha-api-report.md b/plugins/kubernetes-backend/api-report-alpha.md similarity index 100% rename from plugins/kubernetes-backend/alpha-api-report.md rename to plugins/kubernetes-backend/api-report-alpha.md diff --git a/plugins/kubernetes-backend/api-report.md b/plugins/kubernetes-backend/api-report.md index 0ed5a31d9d..e6996484dd 100644 --- a/plugins/kubernetes-backend/api-report.md +++ b/plugins/kubernetes-backend/api-report.md @@ -3,21 +3,20 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { AuthenticationStrategy as AuthenticationStrategy_2 } from '@backstage/plugin-kubernetes-node'; import { CatalogApi } from '@backstage/catalog-client'; +import { ClusterDetails as ClusterDetails_2 } from '@backstage/plugin-kubernetes-node'; import { Config } from '@backstage/config'; -import type { CustomResourceMatcher } from '@backstage/plugin-kubernetes-common'; -import { CustomResourcesByEntity } from '@backstage/plugin-kubernetes-node'; +import { CustomResource as CustomResource_2 } from '@backstage/plugin-kubernetes-node'; import { Duration } from 'luxon'; -import { Entity } from '@backstage/catalog-model'; import express from 'express'; -import type { FetchResponse } from '@backstage/plugin-kubernetes-common'; -import type { JsonObject } from '@backstage/types'; -import type { KubernetesFetchError } from '@backstage/plugin-kubernetes-common'; -import { KubernetesObjectsByEntity } from '@backstage/plugin-kubernetes-node'; -import { KubernetesObjectsProvider } from '@backstage/plugin-kubernetes-node'; +import * as k8sAuthTypes from '@backstage/plugin-kubernetes-node'; +import { KubernetesClustersSupplier as KubernetesClustersSupplier_2 } from '@backstage/plugin-kubernetes-node'; +import { KubernetesObjectsProvider as KubernetesObjectsProvider_2 } from '@backstage/plugin-kubernetes-node'; import { KubernetesRequestAuth } from '@backstage/plugin-kubernetes-common'; import type { KubernetesRequestBody } from '@backstage/plugin-kubernetes-common'; import { Logger } from 'winston'; +import { ObjectToFetch as ObjectToFetch_2 } from '@backstage/plugin-kubernetes-node'; import { PermissionEvaluator } from '@backstage/plugin-permission-common'; import { PluginEndpointDiscovery } from '@backstage/backend-common'; import { RequestHandler } from 'http-proxy-middleware'; @@ -42,19 +41,11 @@ export class AnonymousStrategy implements AuthenticationStrategy { validateCluster(): Error[]; } -// @public (undocumented) -export interface AuthenticationStrategy { - // (undocumented) - getCredential( - clusterDetails: ClusterDetails, - authConfig: KubernetesRequestAuth, - ): Promise; - // (undocumented) - validateCluster(authMetadata: AuthMetadata): Error[]; -} +// @public @deprecated (undocumented) +export type AuthenticationStrategy = k8sAuthTypes.AuthenticationStrategy; -// @public -export type AuthMetadata = Record; +// @public @deprecated (undocumented) +export type AuthMetadata = k8sAuthTypes.AuthMetadata; // @public (undocumented) export class AwsIamStrategy implements AuthenticationStrategy { @@ -74,36 +65,17 @@ export class AzureIdentityStrategy implements AuthenticationStrategy { validateCluster(): Error[]; } -// @public (undocumented) -export interface ClusterDetails { - // (undocumented) - authMetadata: AuthMetadata; - // (undocumented) - caData?: string | undefined; - // (undocumented) - caFile?: string | undefined; - customResources?: CustomResourceMatcher[]; - dashboardApp?: string; - dashboardParameters?: JsonObject; - dashboardUrl?: string; - name: string; - skipMetricsLookup?: boolean; - // (undocumented) - skipTLSVerify?: boolean; - // (undocumented) - url: string; -} +// @public @deprecated (undocumented) +export type ClusterDetails = k8sAuthTypes.ClusterDetails; // @public @deprecated export function createRouter(options: RouterOptions): Promise; -// @public (undocumented) -export interface CustomResource extends ObjectToFetch { - // (undocumented) - objectType: 'customresources'; -} +// @public @deprecated (undocumented) +export type CustomResource = k8sAuthTypes.CustomResource; -export { CustomResourcesByEntity }; +// @public @deprecated (undocumented) +export type CustomResourcesByEntity = k8sAuthTypes.CustomResourcesByEntity; // @public (undocumented) export const DEFAULT_OBJECTS: ObjectToFetch[]; @@ -127,13 +99,8 @@ export type DispatchStrategyOptions = { }; }; -// @public (undocumented) -export interface FetchResponseWrapper { - // (undocumented) - errors: KubernetesFetchError[]; - // (undocumented) - responses: FetchResponse[]; -} +// @public @deprecated (undocumented) +export type FetchResponseWrapper = k8sAuthTypes.FetchResponseWrapper; // @public (undocumented) export class GoogleServiceAccountStrategy implements AuthenticationStrategy { @@ -169,37 +136,37 @@ export class KubernetesBuilder { build(): KubernetesBuilderReturn; // (undocumented) protected buildAuthStrategyMap(): { - [key: string]: AuthenticationStrategy; + [key: string]: AuthenticationStrategy_2; }; // (undocumented) protected buildClusterSupplier( refreshInterval: Duration, - ): KubernetesClustersSupplier; + ): KubernetesClustersSupplier_2; // (undocumented) - protected buildCustomResources(): CustomResource[]; + protected buildCustomResources(): CustomResource_2[]; // (undocumented) protected buildFetcher(): KubernetesFetcher; // (undocumented) protected buildHttpServiceLocator( - _clusterSupplier: KubernetesClustersSupplier, + _clusterSupplier: KubernetesClustersSupplier_2, ): KubernetesServiceLocator; // (undocumented) protected buildMultiTenantServiceLocator( - clusterSupplier: KubernetesClustersSupplier, + clusterSupplier: KubernetesClustersSupplier_2, ): KubernetesServiceLocator; // (undocumented) protected buildObjectsProvider( options: KubernetesObjectsProviderOptions, - ): KubernetesObjectsProvider; + ): KubernetesObjectsProvider_2; // (undocumented) protected buildProxy( logger: Logger, - clusterSupplier: KubernetesClustersSupplier, + clusterSupplier: KubernetesClustersSupplier_2, ): KubernetesProxy; // (undocumented) protected buildRouter( - objectsProvider: KubernetesObjectsProvider, - clusterSupplier: KubernetesClustersSupplier, + objectsProvider: KubernetesObjectsProvider_2, + clusterSupplier: KubernetesClustersSupplier_2, catalogApi: CatalogApi, proxy: KubernetesProxy, permissionApi: PermissionEvaluator, @@ -207,7 +174,11 @@ export class KubernetesBuilder { // (undocumented) protected buildServiceLocator( method: ServiceLocatorMethod, - clusterSupplier: KubernetesClustersSupplier, + clusterSupplier: KubernetesClustersSupplier_2, + ): KubernetesServiceLocator; + // (undocumented) + protected buildSingleTenantServiceLocator( + clusterSupplier: KubernetesClustersSupplier_2, ): KubernetesServiceLocator; // (undocumented) static createBuilder(env: KubernetesEnvironment): KubernetesBuilder; @@ -215,26 +186,26 @@ export class KubernetesBuilder { protected readonly env: KubernetesEnvironment; // (undocumented) protected fetchClusterDetails( - clusterSupplier: KubernetesClustersSupplier, - ): Promise; + clusterSupplier: KubernetesClustersSupplier_2, + ): Promise; // (undocumented) protected getAuthStrategyMap(): { - [key: string]: AuthenticationStrategy; + [key: string]: AuthenticationStrategy_2; }; // (undocumented) - protected getClusterSupplier(): KubernetesClustersSupplier; + protected getClusterSupplier(): KubernetesClustersSupplier_2; // (undocumented) protected getFetcher(): KubernetesFetcher; // (undocumented) protected getObjectsProvider( options: KubernetesObjectsProviderOptions, - ): KubernetesObjectsProvider; + ): KubernetesObjectsProvider_2; // (undocumented) - protected getObjectTypesToFetch(): ObjectToFetch[] | undefined; + protected getObjectTypesToFetch(): ObjectToFetch_2[] | undefined; // (undocumented) protected getProxy( logger: Logger, - clusterSupplier: KubernetesClustersSupplier, + clusterSupplier: KubernetesClustersSupplier_2, ): KubernetesProxy; // (undocumented) protected getServiceLocator(): KubernetesServiceLocator; @@ -245,13 +216,13 @@ export class KubernetesBuilder { [key: string]: AuthenticationStrategy; }): void; // (undocumented) - setClusterSupplier(clusterSupplier?: KubernetesClustersSupplier): this; + setClusterSupplier(clusterSupplier?: KubernetesClustersSupplier_2): this; // (undocumented) setDefaultClusterRefreshInterval(refreshInterval: Duration): this; // (undocumented) setFetcher(fetcher?: KubernetesFetcher): this; // (undocumented) - setObjectsProvider(objectsProvider?: KubernetesObjectsProvider): this; + setObjectsProvider(objectsProvider?: KubernetesObjectsProvider_2): this; // (undocumented) setProxy(proxy?: KubernetesProxy): this; // (undocumented) @@ -261,31 +232,23 @@ export class KubernetesBuilder { // @public export type KubernetesBuilderReturn = Promise<{ router: express.Router; - clusterSupplier: KubernetesClustersSupplier; + clusterSupplier: KubernetesClustersSupplier_2; customResources: CustomResource[]; fetcher: KubernetesFetcher; proxy: KubernetesProxy; - objectsProvider: KubernetesObjectsProvider; + objectsProvider: KubernetesObjectsProvider_2; serviceLocator: KubernetesServiceLocator; authStrategyMap: { [key: string]: AuthenticationStrategy; }; }>; -// @public -export interface KubernetesClustersSupplier { - getClusters(): Promise; -} +// @public @deprecated (undocumented) +export type KubernetesClustersSupplier = + k8sAuthTypes.KubernetesClustersSupplier; -// @public -export type KubernetesCredential = - | { - type: 'bearer token'; - token: string; - } - | { - type: 'anonymous'; - }; +// @public @deprecated (undocumented) +export type KubernetesCredential = k8sAuthTypes.KubernetesCredential; // @public (undocumented) export interface KubernetesEnvironment { @@ -299,57 +262,30 @@ export interface KubernetesEnvironment { permissions: PermissionEvaluator; } -// @public -export interface KubernetesFetcher { - // (undocumented) - fetchObjectsForService( - params: ObjectFetchParams, - ): Promise; - // (undocumented) - fetchPodMetricsByNamespaces( - clusterDetails: ClusterDetails, - credential: KubernetesCredential, - namespaces: Set, - labelSelector?: string, - ): Promise; -} +// @public @deprecated (undocumented) +export type KubernetesFetcher = k8sAuthTypes.KubernetesFetcher; -export { KubernetesObjectsByEntity }; - -export { KubernetesObjectsProvider }; +// @public @deprecated (undocumented) +export type KubernetesObjectsProvider = k8sAuthTypes.KubernetesObjectsProvider; // @public (undocumented) export interface KubernetesObjectsProviderOptions { // (undocumented) config: Config; // (undocumented) - customResources: CustomResource[]; + customResources: k8sAuthTypes.CustomResource[]; // (undocumented) - fetcher: KubernetesFetcher; + fetcher: k8sAuthTypes.KubernetesFetcher; // (undocumented) logger: Logger; // (undocumented) - objectTypesToFetch?: ObjectToFetch[]; + objectTypesToFetch?: k8sAuthTypes.ObjectToFetch[]; // (undocumented) - serviceLocator: KubernetesServiceLocator; + serviceLocator: k8sAuthTypes.KubernetesServiceLocator; } -// @public (undocumented) -export type KubernetesObjectTypes = - | 'pods' - | 'services' - | 'configmaps' - | 'deployments' - | 'limitranges' - | 'resourcequotas' - | 'replicasets' - | 'horizontalpodautoscalers' - | 'jobs' - | 'cronjobs' - | 'ingresses' - | 'customresources' - | 'statefulsets' - | 'daemonsets'; +// @public @deprecated (undocumented) +export type KubernetesObjectTypes = k8sAuthTypes.KubernetesObjectTypes; // @public export class KubernetesProxy { @@ -372,49 +308,17 @@ export type KubernetesProxyOptions = { authStrategy: AuthenticationStrategy; }; -// @public -export interface KubernetesServiceLocator { - // (undocumented) - getClustersByEntity( - entity: Entity, - requestContext: ServiceLocatorRequestContext, - ): Promise<{ - clusters: ClusterDetails[]; - }>; -} +// @public @deprecated (undocumented) +export type KubernetesServiceLocator = k8sAuthTypes.KubernetesServiceLocator; -// @public (undocumented) -export interface ObjectFetchParams { - // (undocumented) - clusterDetails: ClusterDetails; - // (undocumented) - credential: KubernetesCredential; - // (undocumented) - customResources: CustomResource[]; - // (undocumented) - labelSelector?: string; - // (undocumented) - namespace?: string; - // (undocumented) - objectTypesToFetch: Set; - // (undocumented) - serviceId: string; -} +// @public @deprecated (undocumented) +export type ObjectFetchParams = k8sAuthTypes.ObjectFetchParams; // @public (undocumented) export type ObjectsByEntityRequest = KubernetesRequestBody; -// @public (undocumented) -export interface ObjectToFetch { - // (undocumented) - apiVersion: string; - // (undocumented) - group: string; - // (undocumented) - objectType: KubernetesObjectTypes; - // (undocumented) - plural: string; -} +// @public @deprecated (undocumented) +export type ObjectToFetch = k8sAuthTypes.ObjectToFetch; // @public (undocumented) export class OidcStrategy implements AuthenticationStrategy { @@ -452,15 +356,11 @@ export class ServiceAccountStrategy implements AuthenticationStrategy { } // @public (undocumented) -export type ServiceLocatorMethod = 'multiTenant' | 'http'; +export type ServiceLocatorMethod = 'multiTenant' | 'singleTenant' | 'http'; -// @public (undocumented) -export interface ServiceLocatorRequestContext { - // (undocumented) - customResources: CustomResourceMatcher[]; - // (undocumented) - objectTypesToFetch: Set; -} +// @public @deprecated (undocumented) +export type ServiceLocatorRequestContext = + k8sAuthTypes.ServiceLocatorRequestContext; // @public (undocumented) export type SigningCreds = { diff --git a/plugins/kubernetes-backend/package.json b/plugins/kubernetes-backend/package.json index b653cd347e..6e80fef004 100644 --- a/plugins/kubernetes-backend/package.json +++ b/plugins/kubernetes-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes-backend", "description": "A Backstage backend plugin that integrates towards Kubernetes", - "version": "0.13.1-next.2", + "version": "0.14.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -47,10 +47,10 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@aws-crypto/sha256-js": "^3.0.0", + "@aws-crypto/sha256-js": "^5.0.0", "@aws-sdk/credential-providers": "^3.350.0", "@aws-sdk/signature-v4": "^3.347.0", - "@azure/identity": "^3.2.1", + "@azure/identity": "^4.0.0", "@backstage/backend-common": "workspace:^", "@backstage/backend-plugin-api": "workspace:^", "@backstage/catalog-client": "workspace:^", @@ -65,9 +65,9 @@ "@backstage/plugin-permission-common": "workspace:^", "@backstage/plugin-permission-node": "workspace:^", "@backstage/types": "workspace:^", - "@google-cloud/container": "^4.0.0", + "@google-cloud/container": "^5.0.0", "@jest-mock/express": "^2.0.1", - "@kubernetes/client-node": "0.19.0", + "@kubernetes/client-node": "0.20.0", "@types/express": "^4.17.6", "@types/http-proxy-middleware": "^0.19.3", "@types/luxon": "^3.0.0", @@ -90,6 +90,8 @@ "@backstage/backend-app-api": "workspace:^", "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", + "@backstage/plugin-permission-backend": "workspace:^", + "@backstage/plugin-permission-backend-module-allow-all-policy": "workspace:^", "@types/aws4": "^1.5.1", "msw": "^1.0.0", "supertest": "^6.1.3", diff --git a/plugins/kubernetes-backend/src/auth/types.ts b/plugins/kubernetes-backend/src/auth/types.ts index fff9952bae..9b33265448 100644 --- a/plugins/kubernetes-backend/src/auth/types.ts +++ b/plugins/kubernetes-backend/src/auth/types.ts @@ -14,25 +14,15 @@ * limitations under the License. */ -import { AuthMetadata, ClusterDetails } from '../types/types'; -import { KubernetesRequestAuth } from '@backstage/plugin-kubernetes-common'; +import * as k8sAuthTypes from '@backstage/plugin-kubernetes-node'; + +// TODO remove this re-export as a breaking change after a couple of releases +/** + * @public @deprecated Import it from \@backstage/plugin-kubernetes-node instead + */ +export type AuthenticationStrategy = k8sAuthTypes.AuthenticationStrategy; /** - * Authentication data used to make a request to Kubernetes - * @public + * @public @deprecated Import it from \@backstage/plugin-kubernetes-node instead */ -export type KubernetesCredential = - | { type: 'bearer token'; token: string } - | { type: 'anonymous' }; - -/** - * - * @public - */ -export interface AuthenticationStrategy { - getCredential( - clusterDetails: ClusterDetails, - authConfig: KubernetesRequestAuth, - ): Promise; - validateCluster(authMetadata: AuthMetadata): Error[]; -} +export type KubernetesCredential = k8sAuthTypes.KubernetesCredential; diff --git a/plugins/kubernetes-backend/src/plugin.ts b/plugins/kubernetes-backend/src/plugin.ts index 83dbae15a0..1b4aca4160 100644 --- a/plugins/kubernetes-backend/src/plugin.ts +++ b/plugins/kubernetes-backend/src/plugin.ts @@ -26,6 +26,20 @@ import { KubernetesObjectsProviderExtensionPoint, kubernetesObjectsProviderExtensionPoint, KubernetesObjectsProvider, + KubernetesClusterSupplierExtensionPoint, + kubernetesClusterSupplierExtensionPoint, + KubernetesClustersSupplier, + KubernetesAuthStrategyExtensionPoint, + AuthenticationStrategy, + kubernetesAuthStrategyExtensionPoint, + KubernetesFetcher, + KubernetesServiceLocatorExtensionPoint, + KubernetesServiceLocator, + kubernetesServiceLocatorExtensionPoint, +} from '@backstage/plugin-kubernetes-node'; +import { + KubernetesFetcherExtensionPoint, + kubernetesFetcherExtensionPoint, } from '@backstage/plugin-kubernetes-node'; class ObjectsProvider implements KubernetesObjectsProviderExtensionPoint { @@ -45,6 +59,86 @@ class ObjectsProvider implements KubernetesObjectsProviderExtensionPoint { } } +class ClusterSuplier implements KubernetesClusterSupplierExtensionPoint { + private clusterSupplier: KubernetesClustersSupplier | undefined; + + getClusterSupplier() { + return this.clusterSupplier; + } + + addClusterSupplier(clusterSupplier: KubernetesClustersSupplier) { + if (this.clusterSupplier) { + throw new Error( + 'Multiple Kubernetes Cluster Suppliers is not supported at this time', + ); + } + this.clusterSupplier = clusterSupplier; + } +} + +class Fetcher implements KubernetesFetcherExtensionPoint { + private fetcher: KubernetesFetcher | undefined; + + getFetcher() { + return this.fetcher; + } + + addFetcher(fetcher: KubernetesFetcher) { + if (this.fetcher) { + throw new Error( + 'Multiple Kubernetes Fetchers is not supported at this time', + ); + } + this.fetcher = fetcher; + } +} + +class ServiceLocator implements KubernetesServiceLocatorExtensionPoint { + private serviceLocator: KubernetesServiceLocator | undefined; + + getServiceLocator() { + return this.serviceLocator; + } + + addServiceLocator(serviceLocator: KubernetesServiceLocator) { + if (this.serviceLocator) { + throw new Error( + 'Multiple Kubernetes Service Locators is not supported at this time', + ); + } + this.serviceLocator = serviceLocator; + } +} + +class AuthStrategy implements KubernetesAuthStrategyExtensionPoint { + private authStrategies: Array<{ + key: string; + strategy: AuthenticationStrategy; + }>; + + constructor() { + this.authStrategies = new Array<{ + key: string; + strategy: AuthenticationStrategy; + }>(); + } + + static addAuthStrategiesFromArray( + authStrategies: Array<{ key: string; strategy: AuthenticationStrategy }>, + builder: KubernetesBuilder, + ) { + authStrategies.forEach(st => builder.addAuthStrategy(st.key, st.strategy)); + } + + getAuthenticationStrategies() { + return this.authStrategies; + } + + addAuthStrategy(key: string, authStrategy: AuthenticationStrategy) { + this.authStrategies.push({ key, strategy: authStrategy }); + } +} + /** * This is the backend plugin that provides the Kubernetes integration. * @alpha @@ -53,10 +147,31 @@ class ObjectsProvider implements KubernetesObjectsProviderExtensionPoint { export const kubernetesPlugin = createBackendPlugin({ pluginId: 'kubernetes', register(env) { - const extensionPoint = new ObjectsProvider(); + const extPointObjectsProvider = new ObjectsProvider(); + const extPointClusterSuplier = new ClusterSuplier(); + const extPointAuthStrategy = new AuthStrategy(); + const extPointFetcher = new Fetcher(); + const extPointServiceLocator = new ServiceLocator(); + env.registerExtensionPoint( kubernetesObjectsProviderExtensionPoint, - extensionPoint, + extPointObjectsProvider, + ); + env.registerExtensionPoint( + kubernetesClusterSupplierExtensionPoint, + extPointClusterSuplier, + ); + env.registerExtensionPoint( + kubernetesAuthStrategyExtensionPoint, + extPointAuthStrategy, + ); + env.registerExtensionPoint( + kubernetesFetcherExtensionPoint, + extPointFetcher, + ); + env.registerExtensionPoint( + kubernetesServiceLocatorExtensionPoint, + extPointServiceLocator, ); env.registerInit({ @@ -70,14 +185,22 @@ export const kubernetesPlugin = createBackendPlugin({ async init({ http, logger, config, catalogApi, permissions }) { const winstonLogger = loggerToWinstonLogger(logger); // TODO: expose all of the customization & extension points of the builder here - const { router } = await KubernetesBuilder.createBuilder({ + const builder: KubernetesBuilder = KubernetesBuilder.createBuilder({ logger: winstonLogger, config, catalogApi, permissions, }) - .setObjectsProvider(extensionPoint.getObjectsProvider()) - .build(); + .setObjectsProvider(extPointObjectsProvider.getObjectsProvider()) + .setClusterSupplier(extPointClusterSuplier.getClusterSupplier()) + .setFetcher(extPointFetcher.getFetcher()) + .setServiceLocator(extPointServiceLocator.getServiceLocator()); + + AuthStrategy.addAuthStrategiesFromArray( + extPointAuthStrategy.getAuthenticationStrategies(), + builder, + ); + const { router } = await builder.build(); http.use(router); }, }); diff --git a/plugins/kubernetes-backend/src/routes/resourceRoutes.test.ts b/plugins/kubernetes-backend/src/routes/resourceRoutes.test.ts index b8254d781c..6d69606316 100644 --- a/plugins/kubernetes-backend/src/routes/resourceRoutes.test.ts +++ b/plugins/kubernetes-backend/src/routes/resourceRoutes.test.ts @@ -107,7 +107,7 @@ describe('resourcesRoutes', () => { import('@backstage/plugin-kubernetes-backend/alpha'), createBackendModule({ pluginId: 'kubernetes', - moduleId: 'testObjectsProvider', + moduleId: 'test-objects-provider', register(env) { env.registerInit({ deps: { extension: kubernetesObjectsProviderExtensionPoint }, diff --git a/plugins/kubernetes-backend/src/service-locator/SingleTenantServiceLocator.test.ts b/plugins/kubernetes-backend/src/service-locator/SingleTenantServiceLocator.test.ts new file mode 100644 index 0000000000..7e66ab96ea --- /dev/null +++ b/plugins/kubernetes-backend/src/service-locator/SingleTenantServiceLocator.test.ts @@ -0,0 +1,151 @@ +/* + * 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 '@backstage/backend-common'; +import { Entity } from '@backstage/catalog-model'; +import { ServiceLocatorRequestContext } from '../types/types'; +import { SingleTenantServiceLocator } from './SingleTenantServiceLocator'; + +describe('SingleTenantConfigClusterLocator', () => { + it('empty clusters returns empty cluster details', async () => { + const sut = new SingleTenantServiceLocator({ + getClusters: async () => [], + }); + + const result = await sut.getClustersByEntity( + {} as Entity, + {} as ServiceLocatorRequestContext, + ); + + expect(result).toStrictEqual({ clusters: [] }); + }); + + it('one cluster return from two clusters', async () => { + const sut = new SingleTenantServiceLocator({ + getClusters: async () => { + return [ + { + name: 'cluster1', + url: 'http://localhost:8080', + authMetadata: {}, + }, + { + name: 'cluster2', + url: 'http://localhost:8081', + authMetadata: {}, + }, + ]; + }, + }); + + const testEntity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + namespace: 'default', + name: 'testEntity', + annotations: { + 'backstage.io/kubernetes-cluster': 'cluster1', + }, + }, + }; + + const result = await sut.getClustersByEntity( + testEntity as Entity, + {} as ServiceLocatorRequestContext, + ); + + expect(result).toStrictEqual({ + clusters: [ + { + name: 'cluster1', + url: 'http://localhost:8080', + authMetadata: {}, + }, + ], + }); + }); + + it('no annotation return all cluster', async () => { + const definedClusters = [ + { + name: 'cluster1', + url: 'http://localhost:8080', + authMetadata: {}, + }, + { + name: 'cluster2', + url: 'http://localhost:8081', + authMetadata: {}, + }, + ]; + + const sut = new SingleTenantServiceLocator({ + getClusters: async () => { + return definedClusters; + }, + }); + + const result = await sut.getClustersByEntity( + {} as Entity, + {} as ServiceLocatorRequestContext, + ); + + expect(result).toStrictEqual({ + clusters: definedClusters, + }); + }); + + it('wrong annotation returns empty cluster', async () => { + const sut = new SingleTenantServiceLocator({ + getClusters: async () => { + return [ + { + name: 'cluster1', + url: 'http://localhost:8080', + authMetadata: {}, + }, + { + name: 'cluster2', + url: 'http://localhost:8081', + authMetadata: {}, + }, + ]; + }, + }); + + const testEntity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + namespace: 'default', + name: 'testEntity', + annotations: { + 'backstage.io/kubernetes-cluster': 'cluster3', + }, + }, + }; + + const result = await sut.getClustersByEntity( + testEntity as Entity, + {} as ServiceLocatorRequestContext, + ); + + expect(result).toStrictEqual({ + clusters: [], + }); + }); +}); diff --git a/plugins/kubernetes-backend/src/service-locator/SingleTenantServiceLocator.ts b/plugins/kubernetes-backend/src/service-locator/SingleTenantServiceLocator.ts new file mode 100644 index 0000000000..e94d95776c --- /dev/null +++ b/plugins/kubernetes-backend/src/service-locator/SingleTenantServiceLocator.ts @@ -0,0 +1,54 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { Entity } from '@backstage/catalog-model'; +import { + ClusterDetails, + KubernetesClustersSupplier, + KubernetesServiceLocator, + ServiceLocatorRequestContext, +} from '../types/types'; + +// This locator assumes that service is located on one cluster +// Therefore it will always return specified cluster provided in backstage.io/kubernetes-cluster annotation +// If backstage.io/kubernetes-cluster annotation not provided will always return all cluster provided +export class SingleTenantServiceLocator implements KubernetesServiceLocator { + private readonly clusterSupplier: KubernetesClustersSupplier; + + constructor(clusterSupplier: KubernetesClustersSupplier) { + this.clusterSupplier = clusterSupplier; + } + + // As this implementation always returns all clusters serviceId is ignored here + getClustersByEntity( + _entity: Entity, + _requestContext: ServiceLocatorRequestContext, + ): Promise<{ clusters: ClusterDetails[] }> { + return this.clusterSupplier.getClusters().then(clusters => { + if (_entity.metadata?.annotations?.['backstage.io/kubernetes-cluster']) { + return { + clusters: clusters.filter( + c => + c.name === + _entity.metadata?.annotations?.[ + 'backstage.io/kubernetes-cluster' + ], + ), + }; + } + return { clusters }; + }); + } +} diff --git a/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts b/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts index c676cc6246..77d02a032a 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts @@ -14,106 +14,181 @@ * limitations under the License. */ -import { getVoidLogger } from '@backstage/backend-common'; import { Entity } from '@backstage/catalog-model'; -import { Config, ConfigReader } from '@backstage/config'; import { ANNOTATION_KUBERNETES_AUTH_PROVIDER, ANNOTATION_KUBERNETES_OIDC_TOKEN_PROVIDER, ObjectsByEntityResponse, KubernetesRequestAuth, } from '@backstage/plugin-kubernetes-common'; -import express from 'express'; import request from 'supertest'; import { ClusterDetails, FetchResponseWrapper, - KubernetesClustersSupplier, KubernetesFetcher, KubernetesServiceLocator, ObjectFetchParams, } from '../types/types'; import { KubernetesCredential } from '../auth/types'; -import { KubernetesBuilder } from './KubernetesBuilder'; -import { KubernetesFanOutHandler } from './KubernetesFanOutHandler'; -import { CatalogApi } from '@backstage/catalog-client'; import { HEADER_KUBERNETES_CLUSTER, HEADER_KUBERNETES_AUTH, } from './KubernetesProxy'; import { setupServer } from 'msw/node'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { + ServiceMock, + mockServices, + setupRequestMockHandlers, + startTestBackend, +} from '@backstage/backend-test-utils'; import { rest } from 'msw'; import { AuthorizeResult, PermissionEvaluator, } from '@backstage/plugin-permission-common'; +import { + PermissionsService, + createBackendModule, +} from '@backstage/backend-plugin-api'; +import { + KubernetesObjectsProvider, + kubernetesAuthStrategyExtensionPoint, + kubernetesClusterSupplierExtensionPoint, + kubernetesObjectsProviderExtensionPoint, + kubernetesFetcherExtensionPoint, + kubernetesServiceLocatorExtensionPoint, +} from '@backstage/plugin-kubernetes-node'; +import { ExtendedHttpServer } from '@backstage/backend-app-api'; describe('KubernetesBuilder', () => { - let app: express.Express; - let kubernetesFanOutHandler: jest.Mocked; - let config: Config; - let catalogApi: CatalogApi; - let permissions: jest.Mocked; + let app: ExtendedHttpServer; + let objectsProviderMock: KubernetesObjectsProvider; + const happyK8SResult = { + items: [ + { + clusterOne: { + pods: [ + { + metadata: { + name: 'pod1', + }, + }, + ], + }, + }, + ], + } as any; + const policyMock: jest.Mocked = { + authorize: jest.fn(), + authorizeConditional: jest.fn(), + }; + const permissionsMock: ServiceMock = + mockServices.permissions.mock(policyMock); beforeEach(async () => { jest.resetAllMocks(); - const logger = getVoidLogger(); - config = new ConfigReader({ - kubernetes: { - serviceLocatorMethod: { type: 'multiTenant' }, - clusterLocatorMethods: [{ type: 'config', clusters: [] }], - }, + + objectsProviderMock = { + getKubernetesObjectsByEntity: jest.fn().mockImplementation(_ => { + return Promise.resolve(happyK8SResult); + }), + getCustomResourcesByEntity: jest.fn().mockImplementation(_ => { + return Promise.resolve(happyK8SResult); + }), + }; + + const clusterSupplierMock = { + getClusters: jest.fn().mockImplementation(_ => { + return Promise.resolve([ + { + name: 'some-cluster', + url: 'https://localhost:1234', + authMetadata: { + [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'serviceAccount', + }, + }, + { + name: 'some-other-cluster', + url: 'https://localhost:1235', + authMetadata: { + [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'oidc', + [ANNOTATION_KUBERNETES_OIDC_TOKEN_PROVIDER]: 'google', + }, + }, + ]); + }), + }; + + jest.mock('@backstage/catalog-client', () => ({ + CatalogClient: jest.fn().mockImplementation(() => ({ + getEntityByRef: jest.fn().mockImplementation(entityRef => { + if (entityRef.name === 'noentity') { + return Promise.resolve(undefined); + } + return Promise.resolve({ + kind: entityRef.kind, + metadata: { + name: entityRef.name, + namespace: entityRef.namespace, + }, + } as Entity); + }), + })), + })); + + const { server } = await startTestBackend({ + features: [ + mockServices.rootConfig.factory({ + data: { + kubernetes: { + serviceLocatorMethod: { + type: 'multiTenant', + }, + clusterLocatorMethods: [ + { + type: 'config', + clusters: [], + }, + ], + }, + }, + }), + import('@backstage/plugin-kubernetes-backend/alpha'), + import('@backstage/plugin-permission-backend/alpha'), + import('@backstage/plugin-permission-backend-module-allow-all-policy'), + createBackendModule({ + pluginId: 'kubernetes', + moduleId: 'testObjectsProvider', + register(env) { + env.registerInit({ + deps: { extension: kubernetesObjectsProviderExtensionPoint }, + async init({ extension }) { + extension.addObjectsProvider(objectsProviderMock); + }, + }); + }, + }), + createBackendModule({ + pluginId: 'kubernetes', + moduleId: 'testClusterSupplier', + register(env) { + env.registerInit({ + deps: { extension: kubernetesClusterSupplierExtensionPoint }, + async init({ extension }) { + extension.addClusterSupplier(clusterSupplierMock); + }, + }); + }, + }), + ], }); - const clusters: ClusterDetails[] = [ - { - name: 'some-cluster', - url: 'https://localhost:1234', - authMetadata: { - [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'serviceAccount', - }, - }, - { - name: 'some-other-cluster', - url: 'https://localhost:1235', - authMetadata: { - [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'oidc', - [ANNOTATION_KUBERNETES_OIDC_TOKEN_PROVIDER]: 'google', - }, - }, - ]; - const clusterSupplier: KubernetesClustersSupplier = { - async getClusters() { - return clusters; - }, - }; - - kubernetesFanOutHandler = { - getKubernetesObjectsByEntity: jest.fn(), - } as any; - - permissions = { - authorize: jest.fn(), - authorizeConditional: jest.fn(), - }; - - const { router } = await KubernetesBuilder.createBuilder({ - config, - logger, - catalogApi, - permissions, - }) - .setObjectsProvider(kubernetesFanOutHandler) - .setClusterSupplier(clusterSupplier) - .build(); - - app = express().use(router); + app = server; }); describe('get /clusters', () => { it('happy path: lists clusters', async () => { - const response = await request(app).get('/clusters'); + const response = await request(app).get('/api/kubernetes/clusters'); expect(response.status).toEqual(200); expect(response.body).toStrictEqual({ @@ -133,70 +208,41 @@ describe('KubernetesBuilder', () => { }); describe('post /services/:serviceId', () => { it('happy path: lists kubernetes objects without auth in request body', async () => { - const result = { - clusterOne: { - pods: [ - { - metadata: { - name: 'pod1', - }, - }, - ], - }, - } as any; - kubernetesFanOutHandler.getKubernetesObjectsByEntity.mockReturnValueOnce( - Promise.resolve(result), + const response = await request(app).post( + '/api/kubernetes/services/test-service', ); - - const response = await request(app).post('/services/test-service'); - expect(response.status).toEqual(200); - expect(response.body).toEqual(result); + expect(response.body).toEqual(happyK8SResult); }); it('happy path: lists kubernetes objects with auth in request body', async () => { - const result = { - clusterOne: { - pods: [ - { - metadata: { - name: 'pod1', - }, - }, - ], - }, - } as any; - kubernetesFanOutHandler.getKubernetesObjectsByEntity.mockReturnValueOnce( - Promise.resolve(result), - ); - const response = await request(app) - .post('/services/test-service') + .post('/api/kubernetes/services/test-service') .send({ auth: { google: 'google_token_123', }, }) .set('Content-Type', 'application/json'); - expect(response.status).toEqual(200); - expect(response.body).toEqual(result); + expect(response.body).toEqual(happyK8SResult); }); it('internal error: lists kubernetes objects', async () => { - kubernetesFanOutHandler.getKubernetesObjectsByEntity.mockRejectedValue( - Error('some internal error'), - ); + objectsProviderMock.getKubernetesObjectsByEntity = jest + .fn() + .mockRejectedValue(Error('some internal error')); - const response = await request(app).post('/services/test-service'); + const response = await request(app).post( + '/api/kubernetes/services/test-service', + ); expect(response.status).toEqual(500); expect(response.body).toEqual({ error: 'some internal error' }); }); it('custom service locator', async () => { - const logger = getVoidLogger(); - const someCluster: ClusterDetails = { + const someCluster = { name: 'some-cluster', url: 'https://localhost:1234', authMetadata: { @@ -212,11 +258,13 @@ describe('KubernetesBuilder', () => { authMetadata: { [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'google' }, }, ]; - const clusterSupplier: KubernetesClustersSupplier = { - async getClusters() { - return clusters; - }, + + const clusterSupplierMock = { + getClusters: jest.fn().mockImplementation(_ => { + return Promise.resolve(clusters); + }), }; + const pod = { metadata: { name: 'pod1', @@ -240,7 +288,7 @@ describe('KubernetesBuilder', () => { ], }; - const serviceLocator: KubernetesServiceLocator = { + const mockServiceLocator: KubernetesServiceLocator = { getClustersByEntity( _entity: Entity, ): Promise<{ clusters: ClusterDetails[] }> { @@ -248,7 +296,7 @@ describe('KubernetesBuilder', () => { }, }; - const fetcher: KubernetesFetcher = { + const mockFetcher: KubernetesFetcher = { fetchPodMetricsByNamespaces( _clusterDetails: ClusterDetails, _credential: KubernetesCredential, @@ -271,20 +319,67 @@ describe('KubernetesBuilder', () => { }, }; - const { router } = await KubernetesBuilder.createBuilder({ - logger, - config, - catalogApi, - permissions, - }) - .setClusterSupplier(clusterSupplier) - .setServiceLocator(serviceLocator) - .setFetcher(fetcher) - .build(); - app = express().use(router); + const { server } = await startTestBackend({ + features: [ + mockServices.rootConfig.factory({ + data: { + kubernetes: { + serviceLocatorMethod: { + type: 'multiTenant', + }, + clusterLocatorMethods: [ + { + type: 'config', + clusters: [], + }, + ], + }, + }, + }), + import('@backstage/plugin-kubernetes-backend/alpha'), + createBackendModule({ + pluginId: 'kubernetes', + moduleId: 'testClusterSupplier', + register(env) { + env.registerInit({ + deps: { extension: kubernetesClusterSupplierExtensionPoint }, + async init({ extension }) { + extension.addClusterSupplier(clusterSupplierMock); + }, + }); + }, + }), + createBackendModule({ + pluginId: 'kubernetes', + moduleId: 'testFetcher', + register(env) { + env.registerInit({ + deps: { extension: kubernetesFetcherExtensionPoint }, + async init({ extension }) { + extension.addFetcher(mockFetcher); + }, + }); + }, + }), + createBackendModule({ + pluginId: 'kubernetes', + moduleId: 'testServiceLocator', + register(env) { + env.registerInit({ + deps: { extension: kubernetesServiceLocatorExtensionPoint }, + async init({ extension }) { + extension.addServiceLocator(mockServiceLocator); + }, + }); + }, + }), + ], + }); + + app = server; const response = await request(app) - .post('/services/test-service') + .post('/api/kubernetes/services/test-service') .send({ entity: { metadata: { @@ -298,9 +393,6 @@ describe('KubernetesBuilder', () => { }); it('reads auth data for custom strategy', async () => { - permissions.authorize.mockResolvedValue([ - { result: AuthorizeResult.ALLOW }, - ]); const mockFetcher = { fetchPodMetricsByNamespaces: jest .fn() @@ -312,43 +404,93 @@ describe('KubernetesBuilder', () => { ], }), }; - const { router } = await KubernetesBuilder.createBuilder({ - logger: getVoidLogger(), - config, - catalogApi, - permissions, - }) - .addAuthStrategy('custom', { - getCredential: jest - .fn< - Promise, - [ClusterDetails, KubernetesRequestAuth] - >() - .mockImplementation(async (_, requestAuth) => ({ - type: 'bearer token', - token: requestAuth.custom as string, - })), - validateCluster: jest.fn().mockReturnValue([]), - }) - .setClusterSupplier({ - getClusters: jest - .fn, []>() - .mockResolvedValue([ - { - name: 'custom-cluster', - url: 'http://my.cluster.url', - authMetadata: { - [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'custom', - }, + + const clusterSupplierMock = { + getClusters: jest.fn().mockImplementation(_ => { + return Promise.resolve([ + { + name: 'custom-cluster', + url: 'http://my.cluster.url', + authMetadata: { + [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'custom', }, - ]), - }) - .setFetcher(mockFetcher) - .build(); - app = express().use(router); + }, + ]); + }), + }; + + const { server } = await startTestBackend({ + features: [ + mockServices.rootConfig.factory({ + data: { + kubernetes: { + serviceLocatorMethod: { + type: 'multiTenant', + }, + clusterLocatorMethods: [ + { + type: 'config', + clusters: [], + }, + ], + }, + }, + }), + import('@backstage/plugin-kubernetes-backend/alpha'), + createBackendModule({ + pluginId: 'kubernetes', + moduleId: 'testClusterSupplier', + register(env) { + env.registerInit({ + deps: { extension: kubernetesClusterSupplierExtensionPoint }, + async init({ extension }) { + extension.addClusterSupplier(clusterSupplierMock); + }, + }); + }, + }), + createBackendModule({ + pluginId: 'kubernetes', + moduleId: 'testAuthStrategy', + register(env) { + env.registerInit({ + deps: { extension: kubernetesAuthStrategyExtensionPoint }, + async init({ extension }) { + extension.addAuthStrategy('custom', { + getCredential: jest + .fn< + Promise, + [ClusterDetails, KubernetesRequestAuth] + >() + .mockImplementation(async (_, requestAuth) => ({ + type: 'bearer token', + token: requestAuth.custom as string, + })), + validateCluster: jest.fn().mockReturnValue([]), + }); + }, + }); + }, + }), + createBackendModule({ + pluginId: 'kubernetes', + moduleId: 'testFetcher', + register(env) { + env.registerInit({ + deps: { extension: kubernetesFetcherExtensionPoint }, + async init({ extension }) { + extension.addFetcher(mockFetcher); + }, + }); + }, + }), + ], + }); + + app = server; await request(app) - .post('/services/test-service') + .post('/api/kubernetes/services/test-service') .send({ entity: { metadata: { @@ -400,12 +542,8 @@ describe('KubernetesBuilder', () => { }, }; - permissions.authorize.mockReturnValue( - Promise.resolve([{ result: AuthorizeResult.ALLOW }]), - ); - const proxyEndpointRequest = request(app) - .post('/proxy/api/v1/namespaces') + .post('/api/kubernetes/proxy/api/v1/namespaces') .set(HEADER_KUBERNETES_CLUSTER, 'some-cluster') .set(HEADER_KUBERNETES_AUTH, 'randomtoken') .send(requestBody); @@ -425,12 +563,8 @@ metadata: name: new-ns `; - permissions.authorize.mockReturnValue( - Promise.resolve([{ result: AuthorizeResult.ALLOW }]), - ); - const proxyEndpointRequest = request(app) - .post('/proxy/api/v1/namespaces') + .post('/api/kubernetes/proxy/api/v1/namespaces') .set(HEADER_KUBERNETES_CLUSTER, 'some-cluster') .set(HEADER_KUBERNETES_AUTH, 'randomtoken') .set('content-type', 'application/yaml') @@ -451,12 +585,35 @@ metadata: }, }; - permissions.authorize.mockReturnValue( - Promise.resolve([{ result: AuthorizeResult.DENY }]), - ); + permissionsMock.authorize.mockResolvedValue([ + { result: AuthorizeResult.DENY }, + ]); - const proxyEndpointRequest = request(app) - .post('/proxy/api/v1/namespaces') + const { server } = await startTestBackend({ + features: [ + mockServices.rootConfig.factory({ + data: { + kubernetes: { + serviceLocatorMethod: { + type: 'multiTenant', + }, + clusterLocatorMethods: [ + { + type: 'config', + clusters: [], + }, + ], + }, + }, + }), + permissionsMock.factory, + import('@backstage/plugin-kubernetes-backend/alpha'), + // import('@backstage/plugin-permission-backend/alpha'), + ], + }); + + const proxyEndpointRequest = request(server) + .post('/api/kubernetes/proxy/api/v1/namespaces') .set(HEADER_KUBERNETES_CLUSTER, 'some-cluster') .set(HEADER_KUBERNETES_AUTH, 'randomtoken') .send(requestBody); @@ -477,42 +634,90 @@ metadata: return res(ctx.json({ items: [] })); }), ); - permissions.authorize.mockResolvedValue([ - { result: AuthorizeResult.ALLOW }, - ]); - const { router } = await KubernetesBuilder.createBuilder({ - logger: getVoidLogger(), - config, - catalogApi, - permissions, - }) - .addAuthStrategy('custom', { - getCredential: jest - .fn< - Promise, - [ClusterDetails, KubernetesRequestAuth] - >() - .mockResolvedValue({ type: 'anonymous' }), - validateCluster: jest.fn().mockReturnValue([]), - }) - .setClusterSupplier({ - getClusters: jest - .fn, []>() - .mockResolvedValue([ - { - name: 'custom-cluster', - url: 'http://my.cluster.url', - authMetadata: { - [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'custom', - }, + + const clusterSupplierMock = { + getClusters: jest.fn().mockImplementation(_ => { + return Promise.resolve([ + { + name: 'custom-cluster', + url: 'http://my.cluster.url', + authMetadata: { + [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'custom', }, - ]), - }) - .build(); - app = express().use(router); + }, + ]); + }), + }; + + const { server } = await startTestBackend({ + features: [ + mockServices.rootConfig.factory({ + data: { + kubernetes: { + serviceLocatorMethod: { + type: 'multiTenant', + }, + clusterLocatorMethods: [ + { + type: 'config', + clusters: [], + }, + ], + }, + }, + }), + import('@backstage/plugin-kubernetes-backend/alpha'), + createBackendModule({ + pluginId: 'kubernetes', + moduleId: 'testObjectsProvider', + register(env) { + env.registerInit({ + deps: { extension: kubernetesObjectsProviderExtensionPoint }, + async init({ extension }) { + extension.addObjectsProvider(objectsProviderMock); + }, + }); + }, + }), + createBackendModule({ + pluginId: 'kubernetes', + moduleId: 'testClusterSupplier', + register(env) { + env.registerInit({ + deps: { extension: kubernetesClusterSupplierExtensionPoint }, + async init({ extension }) { + extension.addClusterSupplier(clusterSupplierMock); + }, + }); + }, + }), + createBackendModule({ + pluginId: 'kubernetes', + moduleId: 'testAuthStrategy', + register(env) { + env.registerInit({ + deps: { extension: kubernetesAuthStrategyExtensionPoint }, + async init({ extension }) { + extension.addAuthStrategy('custom', { + getCredential: jest + .fn< + Promise, + [ClusterDetails, KubernetesRequestAuth] + >() + .mockResolvedValue({ type: 'anonymous' }), + validateCluster: jest.fn().mockReturnValue([]), + }); + }, + }); + }, + }), + ], + }); + + app = server; const proxyEndpointRequest = request(app) - .get('/proxy/api/v1/namespaces') + .get('/api/kubernetes/proxy/api/v1/namespaces') .set(HEADER_KUBERNETES_CLUSTER, 'custom-cluster') .set(HEADER_KUBERNETES_AUTH, 'custom-token'); worker.use(rest.all(proxyEndpointRequest.url, req => req.passthrough())); @@ -522,29 +727,44 @@ metadata: }); it('should not permit custom auth strategies with dashes', async () => { - const throwError = () => - KubernetesBuilder.createBuilder({ - logger: getVoidLogger(), - config, - catalogApi, - permissions, - }).addAuthStrategy('custom-strategy', { - getCredential: jest - .fn< - Promise, - [ClusterDetails, KubernetesRequestAuth] - >() - .mockResolvedValue({ type: 'anonymous' }), - validateCluster: jest.fn().mockReturnValue([]), + const throwError = async () => { + await startTestBackend({ + features: [ + import('@backstage/plugin-kubernetes-backend/alpha'), + createBackendModule({ + pluginId: 'kubernetes', + moduleId: 'testAuthStrategy', + register(env) { + env.registerInit({ + deps: { extension: kubernetesAuthStrategyExtensionPoint }, + async init({ extension }) { + extension.addAuthStrategy('custom-strategy', { + getCredential: jest + .fn< + Promise, + [ClusterDetails, KubernetesRequestAuth] + >() + .mockResolvedValue({ type: 'anonymous' }), + validateCluster: jest.fn().mockReturnValue([]), + }); + }, + }); + }, + }), + ], }); + }; - expect(throwError).toThrow('Strategy name can not include dashes'); + await expect(throwError).rejects.toThrow( + 'Strategy name can not include dashes', + ); }); }); + describe('get /.well-known/backstage/permissions/metadata', () => { it('lists permissions supported by the kubernetes plugin', async () => { const response = await request(app).get( - '/.well-known/backstage/permissions/metadata', + '/api/kubernetes/.well-known/backstage/permissions/metadata', ); expect(response.status).toEqual(200); diff --git a/plugins/kubernetes-backend/src/service/KubernetesBuilder.ts b/plugins/kubernetes-backend/src/service/KubernetesBuilder.ts index b05db36398..c1ff4688e7 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesBuilder.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesBuilder.ts @@ -43,9 +43,9 @@ import { import { addResourceRoutesToRouter } from '../routes/resourcesRoutes'; import { MultiTenantServiceLocator } from '../service-locator/MultiTenantServiceLocator'; +import { SingleTenantServiceLocator } from '../service-locator/SingleTenantServiceLocator'; import { CustomResource, - KubernetesClustersSupplier, KubernetesFetcher, KubernetesObjectsProviderOptions, KubernetesObjectTypes, @@ -53,7 +53,10 @@ import { ObjectsByEntityRequest, ServiceLocatorMethod, } from '../types/types'; -import { KubernetesObjectsProvider } from '@backstage/plugin-kubernetes-node'; +import { + KubernetesClustersSupplier, + KubernetesObjectsProvider, +} from '@backstage/plugin-kubernetes-node'; import { DEFAULT_OBJECTS, KubernetesFanOutHandler, @@ -276,6 +279,10 @@ export class KubernetesBuilder { this.serviceLocator = this.buildMultiTenantServiceLocator(clusterSupplier); break; + case 'singleTenant': + this.serviceLocator = + this.buildSingleTenantServiceLocator(clusterSupplier); + break; case 'http': this.serviceLocator = this.buildHttpServiceLocator(clusterSupplier); break; @@ -294,6 +301,12 @@ export class KubernetesBuilder { return new MultiTenantServiceLocator(clusterSupplier); } + protected buildSingleTenantServiceLocator( + clusterSupplier: KubernetesClustersSupplier, + ): KubernetesServiceLocator { + return new SingleTenantServiceLocator(clusterSupplier); + } + protected buildHttpServiceLocator( _clusterSupplier: KubernetesClustersSupplier, ): KubernetesServiceLocator { diff --git a/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.ts b/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.ts index 3ea06e061e..7a8ff1bf2d 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.ts @@ -17,7 +17,6 @@ import { Entity } from '@backstage/catalog-model'; import { Logger } from 'winston'; import { - ClusterDetails, KubernetesFetcher, KubernetesObjectsProviderOptions, KubernetesServiceLocator, @@ -26,7 +25,6 @@ import { ObjectToFetch, CustomResource, } from '../types/types'; -import { AuthenticationStrategy, KubernetesCredential } from '../auth/types'; import { ClientContainerStatus, ClientCurrentResourceUsage, @@ -45,7 +43,10 @@ import { PodStatus, } from '@kubernetes/client-node'; import { + AuthenticationStrategy, + ClusterDetails, CustomResourcesByEntity, + KubernetesCredential, KubernetesObjectsByEntity, } from '@backstage/plugin-kubernetes-node'; diff --git a/plugins/kubernetes-backend/src/service/KubernetesFetcher.ts b/plugins/kubernetes-backend/src/service/KubernetesFetcher.ts index d5c945a864..99501c48c6 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesFetcher.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesFetcher.ts @@ -26,12 +26,10 @@ import { import lodash, { Dictionary } from 'lodash'; import { Logger } from 'winston'; import { - ClusterDetails, FetchResponseWrapper, KubernetesFetcher, ObjectFetchParams, } from '../types/types'; -import { KubernetesCredential } from '../auth/types'; import { ANNOTATION_KUBERNETES_AUTH_PROVIDER, FetchResponse, @@ -43,6 +41,10 @@ import fetch, { RequestInit, Response } from 'node-fetch'; import * as https from 'https'; import fs from 'fs-extra'; import { JsonObject } from '@backstage/types'; +import { + ClusterDetails, + KubernetesCredential, +} from '@backstage/plugin-kubernetes-node'; export interface KubernetesClientBasedFetcherOptions { logger: Logger; diff --git a/plugins/kubernetes-backend/src/types/index.ts b/plugins/kubernetes-backend/src/types/index.ts index c8413c1aa9..db229eae34 100644 --- a/plugins/kubernetes-backend/src/types/index.ts +++ b/plugins/kubernetes-backend/src/types/index.ts @@ -15,9 +15,3 @@ */ export * from './types'; - -export type { - CustomResourcesByEntity, - KubernetesObjectsByEntity, - KubernetesObjectsProvider, -} from '@backstage/plugin-kubernetes-node'; diff --git a/plugins/kubernetes-backend/src/types/types.ts b/plugins/kubernetes-backend/src/types/types.ts index 597984591f..57a12bb58a 100644 --- a/plugins/kubernetes-backend/src/types/types.ts +++ b/plugins/kubernetes-backend/src/types/types.ts @@ -14,201 +14,16 @@ * limitations under the License. */ -import { Entity } from '@backstage/catalog-model'; import { Logger } from 'winston'; -import type { JsonObject } from '@backstage/types'; -import type { - CustomResourceMatcher, - FetchResponse, - KubernetesFetchError, - KubernetesRequestBody, -} from '@backstage/plugin-kubernetes-common'; +import type { KubernetesRequestBody } from '@backstage/plugin-kubernetes-common'; import { Config } from '@backstage/config'; -import { KubernetesCredential } from '../auth/types'; +import * as k8sTypes from '@backstage/plugin-kubernetes-node'; /** * * @public */ -export interface ObjectFetchParams { - serviceId: string; - clusterDetails: ClusterDetails; - credential: KubernetesCredential; - objectTypesToFetch: Set; - labelSelector?: string; - customResources: CustomResource[]; - namespace?: string; -} - -/** - * Fetches information from a kubernetes cluster using the cluster details object to target a specific cluster - * - * @public - */ -export interface KubernetesFetcher { - fetchObjectsForService( - params: ObjectFetchParams, - ): Promise; - fetchPodMetricsByNamespaces( - clusterDetails: ClusterDetails, - credential: KubernetesCredential, - namespaces: Set, - labelSelector?: string, - ): Promise; -} - -/** - * - * @public - */ -export interface FetchResponseWrapper { - errors: KubernetesFetchError[]; - responses: FetchResponse[]; -} - -/** - * - * @public - */ -export interface ObjectToFetch { - objectType: KubernetesObjectTypes; - group: string; - apiVersion: string; - plural: string; -} - -/** - * - * @public - */ -export interface CustomResource extends ObjectToFetch { - objectType: 'customresources'; -} - -/** - * - * @public - */ -export type KubernetesObjectTypes = - | 'pods' - | 'services' - | 'configmaps' - | 'deployments' - | 'limitranges' - | 'resourcequotas' - | 'replicasets' - | 'horizontalpodautoscalers' - | 'jobs' - | 'cronjobs' - | 'ingresses' - | 'customresources' - | 'statefulsets' - | 'daemonsets'; -// If updating this list, also make sure to update -// `objectTypes` and `apiVersionOverrides` in config.d.ts! - -/** - * Used to load cluster details from different sources - * @public - */ -export interface KubernetesClustersSupplier { - /** - * Returns the cached list of clusters. - * - * Implementations _should_ cache the clusters and refresh them periodically, - * as getClusters is called whenever the list of clusters is needed. - */ - getClusters(): Promise; -} - -/** - * @public - */ -export interface ServiceLocatorRequestContext { - objectTypesToFetch: Set; - customResources: CustomResourceMatcher[]; -} - -/** - * Used to locate which cluster(s) a service is running on - * @public - */ -export interface KubernetesServiceLocator { - getClustersByEntity( - entity: Entity, - requestContext: ServiceLocatorRequestContext, - ): Promise<{ clusters: ClusterDetails[] }>; -} - -/** - * - * @public - */ -export type ServiceLocatorMethod = 'multiTenant' | 'http'; // TODO implement http - -/** - * Provider-specific authentication configuration - * @public - */ -export type AuthMetadata = Record; - -/** - * - * @public - */ -export interface ClusterDetails { - /** - * Specifies the name of the Kubernetes cluster. - */ - name: string; - url: string; - authMetadata: AuthMetadata; - skipTLSVerify?: boolean; - /** - * Whether to skip the lookup to the metrics server to retrieve pod resource usage. - * It is not guaranteed that the Kubernetes distro has the metrics server installed. - */ - skipMetricsLookup?: boolean; - caData?: string | undefined; - caFile?: string | undefined; - /** - * Specifies the link to the Kubernetes dashboard managing this cluster. - * @remarks - * Note that you should specify the app used for the dashboard - * using the dashboardApp property, in order to properly format - * links to kubernetes resources, otherwise it will assume that you're running the standard one. - * @see dashboardApp - * @see dashboardParameters - */ - dashboardUrl?: string; - /** - * Specifies the app that provides the Kubernetes dashboard. - * This will be used for formatting links to kubernetes objects inside the dashboard. - * @remarks - * The existing apps are: standard, rancher, openshift, gke, aks, eks - * Note that it will default to the regular dashboard provided by the Kubernetes project (standard). - * Note that you can add your own formatter by registering it to the clusterLinksFormatters dictionary. - * @defaultValue standard - * @see dashboardUrl - * @example - * ```ts - * import { clusterLinksFormatters } from '@backstage/plugin-kubernetes'; - * clusterLinksFormatters.myDashboard = (options) => ...; - * ``` - */ - dashboardApp?: string; - /** - * Specifies specific parameters used by some dashboard URL formatters. - * This is used by the GKE formatter which requires the project, region and cluster name. - * @see dashboardApp - */ - dashboardParameters?: JsonObject; - /** - * Specifies which custom resources to look for when returning an entity's - * Kubernetes resources. - */ - customResources?: CustomResourceMatcher[]; -} +export type ServiceLocatorMethod = 'multiTenant' | 'singleTenant' | 'http'; // TODO implement http /** * @@ -217,10 +32,10 @@ export interface ClusterDetails { export interface KubernetesObjectsProviderOptions { logger: Logger; config: Config; - fetcher: KubernetesFetcher; - serviceLocator: KubernetesServiceLocator; - customResources: CustomResource[]; - objectTypesToFetch?: ObjectToFetch[]; + fetcher: k8sTypes.KubernetesFetcher; + serviceLocator: k8sTypes.KubernetesServiceLocator; + customResources: k8sTypes.CustomResource[]; + objectTypesToFetch?: k8sTypes.ObjectToFetch[]; } /** @@ -228,3 +43,73 @@ export interface KubernetesObjectsProviderOptions { * @public */ export type ObjectsByEntityRequest = KubernetesRequestBody; + +// TODO remove this re-export as a breaking change after a couple of releases +/** + * @public @deprecated Import it from \@backstage/plugin-kubernetes-node instead + */ +export type KubernetesObjectsProvider = k8sTypes.KubernetesObjectsProvider; + +/** + * @public @deprecated Import it from \@backstage/plugin-kubernetes-node instead + */ +export type CustomResourcesByEntity = k8sTypes.CustomResourcesByEntity; + +/** + * @public + * @deprecated Import it from \@backstage/plugin-kubernetes-node instead + */ +export type AuthMetadata = k8sTypes.AuthMetadata; + +/** + * @public + * @deprecated Import it from \@backstage/plugin-kubernetes-node instead + */ +export type ClusterDetails = k8sTypes.ClusterDetails; + +/** + * @public + * @deprecated Import it from \@backstage/plugin-kubernetes-node instead + */ +export type KubernetesClustersSupplier = k8sTypes.KubernetesClustersSupplier; + +/** + * @public @deprecated Import it from \@backstage/plugin-kubernetes-node instead + */ +export type KubernetesObjectTypes = k8sTypes.KubernetesObjectTypes; + +/** + * @public @deprecated Import it from \@backstage/plugin-kubernetes-node instead + */ +export type ObjectToFetch = k8sTypes.ObjectToFetch; + +/** + * @public @deprecated Import it from \@backstage/plugin-kubernetes-node instead + */ +export type CustomResource = k8sTypes.CustomResource; + +/** + * @public @deprecated Import it from \@backstage/plugin-kubernetes-node instead + */ +export type ObjectFetchParams = k8sTypes.ObjectFetchParams; + +/** + * @public @deprecated Import it from \@backstage/plugin-kubernetes-node instead + */ +export type FetchResponseWrapper = k8sTypes.FetchResponseWrapper; + +/** + * @public @deprecated Import it from \@backstage/plugin-kubernetes-node instead + */ +export type KubernetesFetcher = k8sTypes.KubernetesFetcher; + +/** + * @public @deprecated Import it from \@backstage/plugin-kubernetes-node instead + */ +export type ServiceLocatorRequestContext = + k8sTypes.ServiceLocatorRequestContext; + +/** + * @public @deprecated Import it from \@backstage/plugin-kubernetes-node instead + */ +export type KubernetesServiceLocator = k8sTypes.KubernetesServiceLocator; diff --git a/plugins/kubernetes-cluster/CHANGELOG.md b/plugins/kubernetes-cluster/CHANGELOG.md index 0f700d4768..e24b987e07 100644 --- a/plugins/kubernetes-cluster/CHANGELOG.md +++ b/plugins/kubernetes-cluster/CHANGELOG.md @@ -1,5 +1,142 @@ # @backstage/plugin-kubernetes-cluster +## 0.0.5 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-kubernetes-react@0.2.1 + - @backstage/plugin-kubernetes-common@0.7.3 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## 0.0.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.0.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/plugin-kubernetes-react@0.2.1-next.1 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-kubernetes-common@0.7.3-next.0 + +## 0.0.5-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-kubernetes-common@0.7.3-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/plugin-kubernetes-react@0.2.1-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + +## 0.0.4 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/plugin-kubernetes-react@0.2.0 + - @backstage/plugin-kubernetes-common@0.7.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.0.4-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + - @backstage/plugin-kubernetes-react@0.2.0-next.3 + +## 0.0.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-kubernetes-react@0.2.0-next.2 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + +## 0.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + - @backstage/plugin-kubernetes-react@0.1.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## 0.0.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/plugin-kubernetes-react@0.1.2-next.0 + - @backstage/plugin-kubernetes-common@0.7.2-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.0.2 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/plugin-kubernetes-common@0.7.1 + - @backstage/plugin-kubernetes-react@0.1.1 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + ## 0.0.2-next.2 ### Patch Changes diff --git a/plugins/kubernetes-cluster/package.json b/plugins/kubernetes-cluster/package.json index 18f47b47af..cf4d5abdea 100644 --- a/plugins/kubernetes-cluster/package.json +++ b/plugins/kubernetes-cluster/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes-cluster", "description": "A Backstage plugin that shows details of Kubernetes clusters", - "version": "0.0.2-next.2", + "version": "0.0.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,18 +35,14 @@ }, "dependencies": { "@backstage/catalog-model": "workspace:^", - "@backstage/config": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", - "@backstage/errors": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", "@backstage/plugin-kubernetes-common": "workspace:^", "@backstage/plugin-kubernetes-react": "workspace:^", - "@backstage/theme": "workspace:^", "@kubernetes-models/apimachinery": "^1.1.0", "@kubernetes-models/base": "^4.0.1", "@material-ui/core": "^4.12.2", - "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", "@types/react": "^16.13.1 || ^17.0.0", "cronstrue": "^2.2.0", @@ -63,15 +59,11 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", - "@backstage/dev-utils": "workspace:^", "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "@types/node": "^16.11.26", - "msw": "^1.0.0" + "@types/node": "^16.11.26" }, "files": [ "dist" diff --git a/plugins/kubernetes-common/CHANGELOG.md b/plugins/kubernetes-common/CHANGELOG.md index ec818f3d00..c49d14f2a8 100644 --- a/plugins/kubernetes-common/CHANGELOG.md +++ b/plugins/kubernetes-common/CHANGELOG.md @@ -1,5 +1,73 @@ # @backstage/plugin-kubernetes-common +## 0.7.3 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/plugin-permission-common@0.7.12 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + +## 0.7.3-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.11 + +## 0.7.2 + +### Patch Changes + +- 706fc3a: Updated dependency `@kubernetes/client-node` to `0.20.0`. +- 5d79682: Remove unused dependency +- Updated dependencies + - @backstage/plugin-permission-common@0.7.11 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.7.2-next.1 + +### Patch Changes + +- 5d796829bb: Remove unused dependency +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.10 + +## 0.7.2-next.0 + +### Patch Changes + +- 706fc3a7e1: Updated dependency `@kubernetes/client-node` to `0.20.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.10 + +## 0.7.1 + +### Patch Changes + +- 62180df4ee: Allow storing dashboard parameters for kubernetes in catalog +- df40b067e1: Fixed the lack of `resourcequotas` as part of the Default Objects to fetch from the kubernetes api +- Updated dependencies + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + ## 0.7.1-next.1 ### Patch Changes diff --git a/plugins/kubernetes-common/package.json b/plugins/kubernetes-common/package.json index d63265ddea..994c8e3f88 100644 --- a/plugins/kubernetes-common/package.json +++ b/plugins/kubernetes-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes-common", "description": "Common functionalities for kubernetes, to be shared between kubernetes and kubernetes-backend plugin", - "version": "0.7.1-next.1", + "version": "0.7.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -40,20 +40,15 @@ }, "dependencies": { "@backstage/catalog-model": "workspace:^", - "@backstage/core-plugin-api": "workspace:^", - "@backstage/errors": "workspace:^", "@backstage/plugin-permission-common": "workspace:^", "@backstage/types": "workspace:^", - "@kubernetes/client-node": "0.19.0", + "@kubernetes/client-node": "0.20.0", "kubernetes-models": "^4.3.1", "lodash": "^4.17.21", "luxon": "^3.0.0" }, "devDependencies": { - "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", - "@backstage/test-utils": "workspace:^", - "msw": "^1.3.1" + "@backstage/cli": "workspace:^" }, "jest": { "roots": [ diff --git a/plugins/kubernetes-node/CHANGELOG.md b/plugins/kubernetes-node/CHANGELOG.md index e10683b110..1de200a3f3 100644 --- a/plugins/kubernetes-node/CHANGELOG.md +++ b/plugins/kubernetes-node/CHANGELOG.md @@ -1,5 +1,105 @@ # @backstage/plugin-kubernetes-node +## 0.1.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-kubernetes-common@0.7.3 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + +## 0.1.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + +## 0.1.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + - @backstage/plugin-kubernetes-common@0.7.3-next.0 + +## 0.1.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes-common@0.7.3-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + +## 0.1.2 + +### Patch Changes + +- 6010564: The `kubernetes-node` plugin has been modified to house a new extension points for Kubernetes backend plugin; + `KubernetesClusterSupplierExtensionPoint` is introduced . + `kubernetesAuthStrategyExtensionPoint` is introduced . + `kubernetesFetcherExtensionPoint` is introduced . + `kubernetesServiceLocatorExtensionPoint` is introduced . + + The `kubernetes-backend` plugin was modified to use this new extension point. + +- Updated dependencies + - @backstage/plugin-kubernetes-common@0.7.2 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + +## 0.1.2-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + +## 0.1.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + +## 0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + +## 0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes-common@0.7.2-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-model@1.4.3 + +## 0.1.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes-common@0.7.1 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/catalog-model@1.4.3 + ## 0.1.1-next.2 ### Patch Changes diff --git a/plugins/kubernetes-node/api-report.md b/plugins/kubernetes-node/api-report.md index d2981b32d1..2272035742 100644 --- a/plugins/kubernetes-node/api-report.md +++ b/plugins/kubernetes-node/api-report.md @@ -3,19 +3,131 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { AuthenticationStrategy as AuthenticationStrategy_2 } from '@backstage/plugin-kubernetes-node'; import { CustomResourceMatcher } from '@backstage/plugin-kubernetes-common'; import { Entity } from '@backstage/catalog-model'; import { ExtensionPoint } from '@backstage/backend-plugin-api'; +import { FetchResponse } from '@backstage/plugin-kubernetes-common'; +import { JsonObject } from '@backstage/types'; +import { KubernetesClustersSupplier as KubernetesClustersSupplier_2 } from '@backstage/plugin-kubernetes-node'; +import { KubernetesFetcher as KubernetesFetcher_2 } from '@backstage/plugin-kubernetes-node'; +import { KubernetesFetchError } from '@backstage/plugin-kubernetes-common'; import { KubernetesObjectsProvider as KubernetesObjectsProvider_2 } from '@backstage/plugin-kubernetes-node'; import { KubernetesRequestAuth } from '@backstage/plugin-kubernetes-common'; +import { KubernetesServiceLocator as KubernetesServiceLocator_2 } from '@backstage/plugin-kubernetes-node'; import { ObjectsByEntityResponse } from '@backstage/plugin-kubernetes-common'; +// @public (undocumented) +export interface AuthenticationStrategy { + // (undocumented) + getCredential( + clusterDetails: ClusterDetails, + authConfig: KubernetesRequestAuth, + ): Promise; + // (undocumented) + validateCluster(authMetadata: AuthMetadata): Error[]; +} + +// @public +export type AuthMetadata = Record; + +// @public (undocumented) +export interface ClusterDetails { + // (undocumented) + authMetadata: AuthMetadata; + // (undocumented) + caData?: string | undefined; + // (undocumented) + caFile?: string | undefined; + customResources?: CustomResourceMatcher[]; + dashboardApp?: string; + dashboardParameters?: JsonObject; + dashboardUrl?: string; + name: string; + skipMetricsLookup?: boolean; + // (undocumented) + skipTLSVerify?: boolean; + // (undocumented) + url: string; +} + +// @public (undocumented) +export interface CustomResource extends ObjectToFetch { + // (undocumented) + objectType: 'customresources'; +} + // @public (undocumented) export interface CustomResourcesByEntity extends KubernetesObjectsByEntity { // (undocumented) customResources: CustomResourceMatcher[]; } +// @public (undocumented) +export interface FetchResponseWrapper { + // (undocumented) + errors: KubernetesFetchError[]; + // (undocumented) + responses: FetchResponse[]; +} + +// @public +export interface KubernetesAuthStrategyExtensionPoint { + // (undocumented) + addAuthStrategy(key: string, strategy: AuthenticationStrategy_2): void; +} + +// @public +export const kubernetesAuthStrategyExtensionPoint: ExtensionPoint; + +// @public +export interface KubernetesClustersSupplier { + getClusters(): Promise; +} + +// @public +export interface KubernetesClusterSupplierExtensionPoint { + // (undocumented) + addClusterSupplier(clusterSupplier: KubernetesClustersSupplier_2): void; +} + +// @public +export const kubernetesClusterSupplierExtensionPoint: ExtensionPoint; + +// @public +export type KubernetesCredential = + | { + type: 'bearer token'; + token: string; + } + | { + type: 'anonymous'; + }; + +// @public +export interface KubernetesFetcher { + // (undocumented) + fetchObjectsForService( + params: ObjectFetchParams, + ): Promise; + // (undocumented) + fetchPodMetricsByNamespaces( + clusterDetails: ClusterDetails, + credential: KubernetesCredential, + namespaces: Set, + labelSelector?: string, + ): Promise; +} + +// @public +export interface KubernetesFetcherExtensionPoint { + // (undocumented) + addFetcher(fetcher: KubernetesFetcher_2): void; +} + +// @public +export const kubernetesFetcherExtensionPoint: ExtensionPoint; + // @public (undocumented) export interface KubernetesObjectsByEntity { // (undocumented) @@ -44,4 +156,79 @@ export interface KubernetesObjectsProviderExtensionPoint { // @public export const kubernetesObjectsProviderExtensionPoint: ExtensionPoint; + +// @public (undocumented) +export type KubernetesObjectTypes = + | 'pods' + | 'services' + | 'configmaps' + | 'deployments' + | 'limitranges' + | 'resourcequotas' + | 'replicasets' + | 'horizontalpodautoscalers' + | 'jobs' + | 'cronjobs' + | 'ingresses' + | 'customresources' + | 'statefulsets' + | 'daemonsets'; + +// @public +export interface KubernetesServiceLocator { + // (undocumented) + getClustersByEntity( + entity: Entity, + requestContext: ServiceLocatorRequestContext, + ): Promise<{ + clusters: ClusterDetails[]; + }>; +} + +// @public +export interface KubernetesServiceLocatorExtensionPoint { + // (undocumented) + addServiceLocator(serviceLocator: KubernetesServiceLocator_2): void; +} + +// @public +export const kubernetesServiceLocatorExtensionPoint: ExtensionPoint; + +// @public (undocumented) +export interface ObjectFetchParams { + // (undocumented) + clusterDetails: ClusterDetails; + // (undocumented) + credential: KubernetesCredential; + // (undocumented) + customResources: CustomResource[]; + // (undocumented) + labelSelector?: string; + // (undocumented) + namespace?: string; + // (undocumented) + objectTypesToFetch: Set; + // (undocumented) + serviceId: string; +} + +// @public (undocumented) +export interface ObjectToFetch { + // (undocumented) + apiVersion: string; + // (undocumented) + group: string; + // (undocumented) + objectType: KubernetesObjectTypes; + // (undocumented) + plural: string; +} + +// @public (undocumented) +export interface ServiceLocatorRequestContext { + // (undocumented) + customResources: CustomResourceMatcher[]; + // (undocumented) + objectTypesToFetch: Set; +} ``` diff --git a/plugins/kubernetes-node/package.json b/plugins/kubernetes-node/package.json index 993eb3b574..317f75063d 100644 --- a/plugins/kubernetes-node/package.json +++ b/plugins/kubernetes-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes-node", "description": "Node.js library for the kubernetes plugin", - "version": "0.1.1-next.2", + "version": "0.1.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,6 +30,7 @@ "dependencies": { "@backstage/backend-plugin-api": "workspace:^", "@backstage/catalog-model": "workspace:^", - "@backstage/plugin-kubernetes-common": "workspace:^" + "@backstage/plugin-kubernetes-common": "workspace:^", + "@backstage/types": "workspace:^" } } diff --git a/plugins/kubernetes-node/src/extensions.ts b/plugins/kubernetes-node/src/extensions.ts index 152622cf96..d898244161 100644 --- a/plugins/kubernetes-node/src/extensions.ts +++ b/plugins/kubernetes-node/src/extensions.ts @@ -14,7 +14,13 @@ * limitations under the License. */ import { createExtensionPoint } from '@backstage/backend-plugin-api'; -import { KubernetesObjectsProvider } from '@backstage/plugin-kubernetes-node'; +import { + AuthenticationStrategy, + KubernetesClustersSupplier, + KubernetesFetcher, + KubernetesObjectsProvider, + KubernetesServiceLocator, +} from '@backstage/plugin-kubernetes-node'; /** * The interface for {@link kubernetesObjectsProviderExtensionPoint}. @@ -34,3 +40,79 @@ export const kubernetesObjectsProviderExtensionPoint = createExtensionPoint({ id: 'kubernetes.objects-provider', }); + +/** + * The interface for {@link kubernetesClusterSupplierExtensionPoint}. + * + * @public + */ +export interface KubernetesClusterSupplierExtensionPoint { + addClusterSupplier(clusterSupplier: KubernetesClustersSupplier): void; +} + +/** + * An extension point the exposes the ability to configure a cluster supplier. + * + * @public + */ +export const kubernetesClusterSupplierExtensionPoint = + createExtensionPoint({ + id: 'kubernetes.cluster-supplier', + }); + +/** + * The interface for {@link kubernetesAuthStrategyExtensionPoint}. + * + * @public + */ +export interface KubernetesAuthStrategyExtensionPoint { + addAuthStrategy(key: string, strategy: AuthenticationStrategy): void; +} + +/** + * An extension point the exposes the ability to add an Auth Strategy. + * + * @public + */ +export const kubernetesAuthStrategyExtensionPoint = + createExtensionPoint({ + id: 'kubernetes.auth-strategy', + }); + +/** + * The interface for {@link kubernetesFetcherExtensionPoint}. + * + * @public + */ +export interface KubernetesFetcherExtensionPoint { + addFetcher(fetcher: KubernetesFetcher): void; +} + +/** + * An extension point the exposes the ability to configure a kubernetes fetcher. + * + * @public + */ +export const kubernetesFetcherExtensionPoint = + createExtensionPoint({ + id: 'kubernetes.fetcher', + }); + +/** + * The interface for {@link kubernetesServiceLocatorExtensionPoint}. + * + * @public + */ +export interface KubernetesServiceLocatorExtensionPoint { + addServiceLocator(serviceLocator: KubernetesServiceLocator): void; +} + +/** + * An extension point the exposes the ability to configure a kubernetes service locator. + * + * @public + */ +export const kubernetesServiceLocatorExtensionPoint = + createExtensionPoint({ + id: 'kubernetes.service-locator', + }); diff --git a/plugins/kubernetes-node/src/index.ts b/plugins/kubernetes-node/src/index.ts index 09ea4123ce..162d5baf26 100644 --- a/plugins/kubernetes-node/src/index.ts +++ b/plugins/kubernetes-node/src/index.ts @@ -29,9 +29,5 @@ * @packageDocumentation */ -export { - kubernetesObjectsProviderExtensionPoint, - type KubernetesObjectsProviderExtensionPoint, -} from './extensions'; - +export * from './extensions'; export * from './types'; diff --git a/plugins/kubernetes-node/src/types/types.ts b/plugins/kubernetes-node/src/types/types.ts index 182f3ecfeb..a0f48d0c26 100644 --- a/plugins/kubernetes-node/src/types/types.ts +++ b/plugins/kubernetes-node/src/types/types.ts @@ -16,9 +16,12 @@ import { Entity } from '@backstage/catalog-model'; import { CustomResourceMatcher, + FetchResponse, + KubernetesFetchError, KubernetesRequestAuth, ObjectsByEntityResponse, } from '@backstage/plugin-kubernetes-common'; +import { JsonObject } from '@backstage/types'; /** * @@ -51,3 +54,200 @@ export interface KubernetesObjectsByEntity { export interface CustomResourcesByEntity extends KubernetesObjectsByEntity { customResources: CustomResourceMatcher[]; } + +/** + * Provider-specific authentication configuration + * @public + */ +export type AuthMetadata = Record; + +/** + * + * @public + */ +export interface ClusterDetails { + /** + * Specifies the name of the Kubernetes cluster. + */ + name: string; + url: string; + authMetadata: AuthMetadata; + skipTLSVerify?: boolean; + /** + * Whether to skip the lookup to the metrics server to retrieve pod resource usage. + * It is not guaranteed that the Kubernetes distro has the metrics server installed. + */ + skipMetricsLookup?: boolean; + caData?: string | undefined; + caFile?: string | undefined; + /** + * Specifies the link to the Kubernetes dashboard managing this cluster. + * @remarks + * Note that you should specify the app used for the dashboard + * using the dashboardApp property, in order to properly format + * links to kubernetes resources, otherwise it will assume that you're running the standard one. + * @see dashboardApp + * @see dashboardParameters + */ + dashboardUrl?: string; + /** + * Specifies the app that provides the Kubernetes dashboard. + * This will be used for formatting links to kubernetes objects inside the dashboard. + * @remarks + * The existing apps are: standard, rancher, openshift, gke, aks, eks + * Note that it will default to the regular dashboard provided by the Kubernetes project (standard). + * Note that you can add your own formatter by registering it to the clusterLinksFormatters dictionary. + * @defaultValue standard + * @see dashboardUrl + * @example + * ```ts + * import { clusterLinksFormatters } from '@backstage/plugin-kubernetes'; + * clusterLinksFormatters.myDashboard = (options) => ...; + * ``` + */ + dashboardApp?: string; + /** + * Specifies specific parameters used by some dashboard URL formatters. + * This is used by the GKE formatter which requires the project, region and cluster name. + * @see dashboardApp + */ + dashboardParameters?: JsonObject; + /** + * Specifies which custom resources to look for when returning an entity's + * Kubernetes resources. + */ + customResources?: CustomResourceMatcher[]; +} + +/** + * Used to load cluster details from different sources + * @public + */ +export interface KubernetesClustersSupplier { + /** + * Returns the cached list of clusters. + * + * Implementations _should_ cache the clusters and refresh them periodically, + * as getClusters is called whenever the list of clusters is needed. + */ + getClusters(): Promise; +} + +/** + * Authentication data used to make a request to Kubernetes + * @public + */ +export type KubernetesCredential = + | { type: 'bearer token'; token: string } + | { type: 'anonymous' }; + +/** + * + * @public + */ +export interface AuthenticationStrategy { + getCredential( + clusterDetails: ClusterDetails, + authConfig: KubernetesRequestAuth, + ): Promise; + validateCluster(authMetadata: AuthMetadata): Error[]; +} + +/** + * + * @public + */ +export type KubernetesObjectTypes = + | 'pods' + | 'services' + | 'configmaps' + | 'deployments' + | 'limitranges' + | 'resourcequotas' + | 'replicasets' + | 'horizontalpodautoscalers' + | 'jobs' + | 'cronjobs' + | 'ingresses' + | 'customresources' + | 'statefulsets' + | 'daemonsets'; +// If updating this list, also make sure to update +// `objectTypes` and `apiVersionOverrides` in config.d.ts on @backstage/plugin-kubernetes-backend! + +/** + * + * @public + */ +export interface ObjectToFetch { + objectType: KubernetesObjectTypes; // TODO - Review + group: string; + apiVersion: string; + plural: string; +} + +/** + * + * @public + */ +export interface CustomResource extends ObjectToFetch { + objectType: 'customresources'; +} + +/** + * + * @public + */ +export interface ObjectFetchParams { + serviceId: string; + clusterDetails: ClusterDetails; + credential: KubernetesCredential; + objectTypesToFetch: Set; + labelSelector?: string; + customResources: CustomResource[]; + namespace?: string; +} + +/** + * + * @public + */ +export interface FetchResponseWrapper { + errors: KubernetesFetchError[]; + responses: FetchResponse[]; +} + +/** + * Fetches information from a kubernetes cluster using the cluster details object to target a specific cluster + * + * @public + */ +export interface KubernetesFetcher { + fetchObjectsForService( + params: ObjectFetchParams, + ): Promise; + fetchPodMetricsByNamespaces( + clusterDetails: ClusterDetails, + credential: KubernetesCredential, + namespaces: Set, + labelSelector?: string, + ): Promise; +} +/** + * @public + */ +export interface ServiceLocatorRequestContext { + objectTypesToFetch: Set; + customResources: CustomResourceMatcher[]; +} + +/** + * Used to locate which cluster(s) a service is running on + * @public + */ +export interface KubernetesServiceLocator { + getClustersByEntity( + entity: Entity, + requestContext: ServiceLocatorRequestContext, + ): Promise<{ clusters: ClusterDetails[] }>; +} diff --git a/plugins/kubernetes-react/CHANGELOG.md b/plugins/kubernetes-react/CHANGELOG.md index 11cff887ec..12e4f42147 100644 --- a/plugins/kubernetes-react/CHANGELOG.md +++ b/plugins/kubernetes-react/CHANGELOG.md @@ -1,5 +1,146 @@ # @backstage/plugin-kubernetes-react +## 0.2.1 + +### Patch Changes + +- d5d2c67: Add `authuser` search parameter to GKE cluster link formatter in k8s plugin + + Thanks to this, people with multiple simultaneously logged-in accounts in their GCP console will automatically view objects with the same email as the one signed in to the Google auth provider in Backstage. + +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-kubernetes-common@0.7.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.2.1-next.1 + +### Patch Changes + +- d5d2c67: Add `authuser` search parameter to GKE cluster link formatter in k8s plugin + + Thanks to this, people with multiple simultaneously logged-in accounts in their GCP console will automatically view objects with the same email as the one signed in to the Google auth provider in Backstage. + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-kubernetes-common@0.7.3-next.0 + +## 0.2.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-kubernetes-common@0.7.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.2.0 + +### Minor Changes + +- 899d71a: Change `formatClusterLink` to be an API and make it async for further customization possibilities. + + **BREAKING** + If you have a custom k8s page and used `formatClusterLink` directly, you need to migrate to new `kubernetesClusterLinkFormatterApiRef` + +### Patch Changes + +- b5ae2e5: Add ID property to the table displaying kubernetes pods to avoid closing the info sidebar when the data reloads and needs to rerender. +- 706fc3a: Updated dependency `@kubernetes/client-node` to `0.20.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/plugin-kubernetes-common@0.7.2 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.2.0-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + +## 0.2.0-next.2 + +### Minor Changes + +- 899d71a: Change `formatClusterLink` to be an API and make it async for further customization possibilities. + + **BREAKING** + If you have a custom k8s page and used `formatClusterLink` directly, you need to migrate to new `kubernetesClusterLinkFormatterApiRef` + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + +## 0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.1.2-next.0 + +### Patch Changes + +- b5ae2e5a62: Add ID property to the table displaying kubernetes pods to avoid closing the info sidebar when the data reloads and needs to rerender. +- 706fc3a7e1: Updated dependency `@kubernetes/client-node` to `0.20.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/plugin-kubernetes-common@0.7.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.1.1 + +### Patch Changes + +- 0f4cad6da0: Internal refactor to avoid a null pointer problem +- 6c2b872153: Add official support for React 18. +- b52f576f48: Make sure types exported by other `kubernetes` plugins in the past are exported again after the creation + of the react package. + + Some types have been moved to this new package but the export was missing, so they were not available anymore for developers. + +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/plugin-kubernetes-common@0.7.1 + - @backstage/core-plugin-api@1.8.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + ## 0.1.1-next.2 ### Patch Changes diff --git a/plugins/kubernetes-react/api-report.md b/plugins/kubernetes-react/api-report.md index ca1df34b40..7e9c2fbd61 100644 --- a/plugins/kubernetes-react/api-report.md +++ b/plugins/kubernetes-react/api-report.md @@ -22,13 +22,14 @@ import { IContainerStatus } from 'kubernetes-models/v1'; import { IdentityApi } from '@backstage/core-plugin-api'; import { IIoK8sApimachineryPkgApisMetaV1ObjectMeta } from '@kubernetes-models/apimachinery/apis/meta/v1/ObjectMeta'; import { IObjectMeta } from '@kubernetes-models/apimachinery/apis/meta/v1/ObjectMeta'; -import type { JsonObject } from '@backstage/types'; +import { JsonObject } from '@backstage/types'; import { KubernetesRequestBody } from '@backstage/plugin-kubernetes-common'; import { OAuthApi } from '@backstage/core-plugin-api'; import { ObjectsByEntityResponse } from '@backstage/plugin-kubernetes-common'; import { OpenIdConnectApi } from '@backstage/core-plugin-api'; import { Pod } from 'kubernetes-models/v1'; import { Pod as Pod_2 } from 'kubernetes-models/v1/Pod'; +import { ProfileInfoApi } from '@backstage/core-plugin-api'; import { default as React_2 } from 'react'; import * as React_3 from 'react'; import { TypeMeta } from '@kubernetes-models/base'; @@ -38,6 +39,12 @@ import { V1ObjectMeta } from '@kubernetes/client-node'; import { V1Pod } from '@kubernetes/client-node'; import { WorkloadsByEntityRequest } from '@backstage/plugin-kubernetes-common'; +// @public (undocumented) +export class AksClusterLinksFormatter implements ClusterLinksFormatter { + // (undocumented) + formatClusterLink(options: ClusterLinksFormatterOptions): Promise; +} + // @public (undocumented) export class AksKubernetesAuthProvider implements KubernetesAuthProvider { constructor(microsoftAuthApi: OAuthApi); @@ -61,9 +68,10 @@ export const Cluster: ({ export const ClusterContext: React_2.Context; // @public (undocumented) -export type ClusterLinksFormatter = ( - options: ClusterLinksFormatterOptions, -) => URL; +export interface ClusterLinksFormatter { + // (undocumented) + formatClusterLink(options: ClusterLinksFormatterOptions): Promise; +} // @public (undocumented) export interface ClusterLinksFormatterOptions { @@ -77,9 +85,6 @@ export interface ClusterLinksFormatterOptions { object: any; } -// @public (undocumented) -export const clusterLinksFormatters: Record; - // @public export type ClusterProps = { clusterObjects: ClusterObjects; @@ -125,9 +130,18 @@ export interface CustomResourcesProps { children?: React_2.ReactNode; } +// @public (undocumented) +export const DEFAULT_FORMATTER_NAME = 'standard'; + // @public export const DetectedErrorsContext: React_2.Context; +// @public (undocumented) +export class EksClusterLinksFormatter implements ClusterLinksFormatter { + // (undocumented) + formatClusterLink(_options: ClusterLinksFormatterOptions): Promise; +} + // @public export const ErrorList: ({ podAndErrors, @@ -228,11 +242,6 @@ export interface FixDialogProps { pod: Pod_2; } -// @public (undocumented) -export function formatClusterLink( - options: FormatClusterLinkOptions, -): string | undefined; - // @public (undocumented) export type FormatClusterLinkOptions = { dashboardUrl?: string; @@ -242,6 +251,18 @@ export type FormatClusterLinkOptions = { kind: string; }; +// @public (undocumented) +export function getDefaultFormatters(deps: { + googleAuthApi: ProfileInfoApi; +}): Record; + +// @public (undocumented) +export class GkeClusterLinksFormatter implements ClusterLinksFormatter { + constructor(googleAuthApi: ProfileInfoApi | undefined); + // (undocumented) + formatClusterLink(options: ClusterLinksFormatterOptions): Promise; +} + // @public (undocumented) export class GoogleKubernetesAuthProvider implements KubernetesAuthProvider { constructor(authProvider: OAuthApi); @@ -415,6 +436,31 @@ export class KubernetesBackendClient implements KubernetesApi { }): Promise; } +// @public (undocumented) +export class KubernetesClusterLinkFormatter + implements KubernetesClusterLinkFormatterApi +{ + constructor(options: { + formatters: Record; + defaultFormatterName: string; + }); + // (undocumented) + formatClusterLink( + options: FormatClusterLinkOptions, + ): Promise; +} + +// @public (undocumented) +export interface KubernetesClusterLinkFormatterApi { + // (undocumented) + formatClusterLink( + options: FormatClusterLinkOptions, + ): Promise; +} + +// @public (undocumented) +export const kubernetesClusterLinkFormatterApiRef: ApiRef; + // @public export const KubernetesDrawer: ({ open, @@ -587,6 +633,12 @@ export class OidcKubernetesAuthProvider implements KubernetesAuthProvider { providerName: string; } +// @public (undocumented) +export class OpenshiftClusterLinksFormatter { + // (undocumented) + formatClusterLink(options: ClusterLinksFormatterOptions): Promise; +} + // @public export const PendingPodContent: ({ pod, @@ -716,6 +768,12 @@ export type PodsTablesProps = { children?: React_2.ReactNode; }; +// @public (undocumented) +export class RancherClusterLinksFormatter implements ClusterLinksFormatter { + // (undocumented) + formatClusterLink(options: ClusterLinksFormatterOptions): Promise; +} + // @public (undocumented) export const READY_COLUMNS: PodColumns; @@ -763,6 +821,12 @@ export const ServicesAccordions: ({}: ServicesAccordionsProps) => React_2.JSX.El // @public (undocumented) export type ServicesAccordionsProps = {}; +// @public (undocumented) +export class StandardClusterLinksFormatter implements ClusterLinksFormatter { + // (undocumented) + formatClusterLink(options: ClusterLinksFormatterOptions): Promise; +} + // @public export const useCustomResources: ( entity: Entity, diff --git a/plugins/kubernetes-react/package.json b/plugins/kubernetes-react/package.json index bddd793b97..8389b4d2a9 100644 --- a/plugins/kubernetes-react/package.json +++ b/plugins/kubernetes-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes-react", "description": "Web library for the kubernetes-react plugin", - "version": "0.1.1-next.2", + "version": "0.2.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,7 +32,7 @@ "@backstage/types": "workspace:^", "@kubernetes-models/apimachinery": "^1.1.0", "@kubernetes-models/base": "^4.0.1", - "@kubernetes/client-node": "^0.19.0", + "@kubernetes/client-node": "^0.20.0", "@material-ui/core": "^4.9.13", "@material-ui/icons": "^4.11.3", "@material-ui/lab": "^4.0.0-alpha.61", diff --git a/plugins/kubernetes-react/src/api/KubernetesClusterLinkFormatter.test.ts b/plugins/kubernetes-react/src/api/KubernetesClusterLinkFormatter.test.ts new file mode 100644 index 0000000000..05b1709c75 --- /dev/null +++ b/plugins/kubernetes-react/src/api/KubernetesClusterLinkFormatter.test.ts @@ -0,0 +1,76 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { KubernetesClusterLinkFormatter } from './KubernetesClusterLinkFormatter'; + +const dashboardUrl = new URL('http://dashboard/url'); +describe('KubernetesClusterLinkFormatter', () => { + const formatter = new KubernetesClusterLinkFormatter({ + formatters: { + standard: { formatClusterLink: async _ => dashboardUrl }, + }, + defaultFormatterName: 'standard', + }); + describe('formatter.formatClusterLink', () => { + it('should not return an url when there is no dashboard url', async () => { + const url = await formatter.formatClusterLink({ + object: {}, + kind: 'foo', + }); + expect(url).toBeUndefined(); + }); + it('should return an url even when there is no object', async () => { + const url = await formatter.formatClusterLink({ + dashboardUrl: 'https://k8s.foo.com', + object: undefined, + kind: 'foo', + }); + expect(url).toBe('https://k8s.foo.com'); + }); + it('should throw when the app is not recognized', async () => { + await expect( + formatter.formatClusterLink({ + dashboardUrl: 'https://k8s.foo.com', + dashboardApp: 'unknownapp', + object: { + metadata: { + name: 'foobar', + namespace: 'bar', + }, + }, + kind: 'Deployment', + }), + ).rejects.toThrow( + "Could not find Kubernetes dashboard app named 'unknownapp'", + ); + }); + + describe('default app', () => { + it('should use default app', async () => { + const url = await formatter.formatClusterLink({ + dashboardUrl: 'https://k8s.foo.com/', + object: { + metadata: { + name: 'foobar', + namespace: 'bar', + }, + }, + kind: 'Deployment', + }); + expect(url).toBe(dashboardUrl.toString()); + }); + }); + }); +}); diff --git a/plugins/kubernetes-react/src/api/KubernetesClusterLinkFormatter.ts b/plugins/kubernetes-react/src/api/KubernetesClusterLinkFormatter.ts new file mode 100644 index 0000000000..45dd6e6fa1 --- /dev/null +++ b/plugins/kubernetes-react/src/api/KubernetesClusterLinkFormatter.ts @@ -0,0 +1,59 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + KubernetesClusterLinkFormatterApi, + FormatClusterLinkOptions, +} from './types'; +import { ClusterLinksFormatter } from '../types'; + +/** @public */ +export class KubernetesClusterLinkFormatter + implements KubernetesClusterLinkFormatterApi +{ + private readonly formatters: Record; + private readonly defaultFormatterName: string; + + constructor(options: { + formatters: Record; + defaultFormatterName: string; + }) { + this.formatters = options.formatters; + this.defaultFormatterName = options.defaultFormatterName; + } + async formatClusterLink(options: FormatClusterLinkOptions) { + if (!options.dashboardUrl && !options.dashboardParameters) { + return undefined; + } + if (options.dashboardUrl && !options.object) { + return options.dashboardUrl; + } + const app = options.dashboardApp ?? this.defaultFormatterName; + const formatter = this.formatters[app]; + if (!formatter) { + throw new Error(`Could not find Kubernetes dashboard app named '${app}'`); + } + const url = await formatter.formatClusterLink({ + dashboardUrl: options.dashboardUrl + ? new URL(options.dashboardUrl) + : undefined, + dashboardParameters: options.dashboardParameters, + object: options.object, + kind: options.kind, + }); + return url.toString(); + } +} diff --git a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/aks.test.ts b/plugins/kubernetes-react/src/api/formatters/AksClusterLinksFormatter.test.ts similarity index 82% rename from plugins/kubernetes-react/src/utils/clusterLinks/formatters/aks.test.ts rename to plugins/kubernetes-react/src/api/formatters/AksClusterLinksFormatter.test.ts index 18db618686..b7bdc3d7e8 100644 --- a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/aks.test.ts +++ b/plugins/kubernetes-react/src/api/formatters/AksClusterLinksFormatter.test.ts @@ -13,12 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { aksFormatter } from './aks'; +import { AksClusterLinksFormatter } from './AksClusterLinksFormatter'; describe('clusterLinks - AKS formatter', () => { - it('should provide a dashboardParameters in the options', () => { - expect(() => - aksFormatter({ + const formatter = new AksClusterLinksFormatter(); + it('should provide a dashboardParameters in the options', async () => { + await expect(() => + formatter.formatClusterLink({ object: { metadata: { name: 'foobar', @@ -27,11 +28,11 @@ describe('clusterLinks - AKS formatter', () => { }, kind: 'Deployment', }), - ).toThrow('AKS dashboard requires a dashboardParameters option'); + ).rejects.toThrow('AKS dashboard requires a dashboardParameters option'); }); - it('should provide a subscriptionId in the dashboardParameters options', () => { - expect(() => - aksFormatter({ + it('should provide a subscriptionId in the dashboardParameters options', async () => { + await expect( + formatter.formatClusterLink({ dashboardParameters: { resourceGroup: 'rg-1', clusterName: 'cluster-1', @@ -44,13 +45,13 @@ describe('clusterLinks - AKS formatter', () => { }, kind: 'Deployment', }), - ).toThrow( + ).rejects.toThrow( 'AKS dashboard requires a "subscriptionId" of type string in the dashboardParameters option', ); }); - it('should provide a resourceGroup in the dashboardParameters options', () => { - expect(() => - aksFormatter({ + it('should provide a resourceGroup in the dashboardParameters options', async () => { + await expect( + formatter.formatClusterLink({ dashboardParameters: { subscriptionId: '1234-GUID-5678', clusterName: 'cluster-1', @@ -63,13 +64,13 @@ describe('clusterLinks - AKS formatter', () => { }, kind: 'Deployment', }), - ).toThrow( + ).rejects.toThrow( 'AKS dashboard requires a "resourceGroup" of type string in the dashboardParameters option', ); }); - it('should provide a clusterName in the dashboardParameters options', () => { - expect(() => - aksFormatter({ + it('should provide a clusterName in the dashboardParameters options', async () => { + await expect( + formatter.formatClusterLink({ dashboardParameters: { subscriptionId: '1234-GUID-5678', resourceGroup: 'us-east1-c', @@ -82,12 +83,12 @@ describe('clusterLinks - AKS formatter', () => { }, kind: 'Deployment', }), - ).toThrow( + ).rejects.toThrow( 'AKS dashboard requires a "clusterName" of type string in the dashboardParameters option', ); }); - it('should return an url on the cluster with object details', () => { - const url = aksFormatter({ + it('should return an url on the cluster with object details', async () => { + const url = await formatter.formatClusterLink({ dashboardParameters: { subscriptionId: '1234-GUID-5678', resourceGroup: 'rg-1', diff --git a/plugins/kubernetes-react/src/api/formatters/AksClusterLinksFormatter.ts b/plugins/kubernetes-react/src/api/formatters/AksClusterLinksFormatter.ts new file mode 100644 index 0000000000..1e7bb0ff9e --- /dev/null +++ b/plugins/kubernetes-react/src/api/formatters/AksClusterLinksFormatter.ts @@ -0,0 +1,59 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + ClusterLinksFormatter, + ClusterLinksFormatterOptions, +} from '../../types'; + +const basePath = + 'https://portal.azure.com/#blade/Microsoft_Azure_ContainerService/AksK8ResourceMenuBlade/overview-Deployment/aksClusterId'; + +const requiredParams = ['subscriptionId', 'resourceGroup', 'clusterName']; + +/** @public */ +export class AksClusterLinksFormatter implements ClusterLinksFormatter { + async formatClusterLink(options: ClusterLinksFormatterOptions) { + if (!options.dashboardParameters) { + throw new Error('AKS dashboard requires a dashboardParameters option'); + } + const args = options.dashboardParameters; + for (const param of requiredParams) { + if (typeof args[param] !== 'string') { + throw new Error( + `AKS dashboard requires a "${param}" of type string in the dashboardParameters option`, + ); + } + } + + const path = `/subscriptions/${args.subscriptionId}/resourceGroups/${args.resourceGroup}/providers/Microsoft.ContainerService/managedClusters/${args.clusterName}`; + + const { name, namespace, uid } = options.object.metadata; + const { selector } = options.object.spec; + const params = { + kind: options.kind, + metadata: { name, namespace, uid }, + spec: { + selector, + }, + }; + + return new URL( + `${basePath}/${encodeURIComponent(path)}/resource/${encodeURIComponent( + JSON.stringify(params), + )}`, + ); + } +} diff --git a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/eks.test.ts b/plugins/kubernetes-react/src/api/formatters/EksClusterLinksFormatter.test.ts similarity index 75% rename from plugins/kubernetes-react/src/utils/clusterLinks/formatters/eks.test.ts rename to plugins/kubernetes-react/src/api/formatters/EksClusterLinksFormatter.test.ts index d0ae73753f..738da9fb94 100644 --- a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/eks.test.ts +++ b/plugins/kubernetes-react/src/api/formatters/EksClusterLinksFormatter.test.ts @@ -13,12 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { eksFormatter } from './eks'; + +import { EksClusterLinksFormatter } from './EksClusterLinksFormatter'; describe('clusterLinks - EKS formatter', () => { - it('should return an url on the workloads when there is a namespace only', () => { - expect(() => - eksFormatter({ + const formatter = new EksClusterLinksFormatter(); + it('should return an url on the workloads when there is a namespace only', async () => { + await expect( + formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com'), object: { metadata: { @@ -28,6 +30,8 @@ describe('clusterLinks - EKS formatter', () => { }, kind: 'Deployment', }), - ).toThrow('EKS formatter is not yet implemented. Please, contribute!'); + ).rejects.toThrow( + 'EKS formatter is not yet implemented. Please, contribute!', + ); }); }); diff --git a/plugins/kubernetes-react/src/api/formatters/EksClusterLinksFormatter.ts b/plugins/kubernetes-react/src/api/formatters/EksClusterLinksFormatter.ts new file mode 100644 index 0000000000..d65b619639 --- /dev/null +++ b/plugins/kubernetes-react/src/api/formatters/EksClusterLinksFormatter.ts @@ -0,0 +1,30 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + ClusterLinksFormatter, + ClusterLinksFormatterOptions, +} from '../../types'; + +/** @public */ +export class EksClusterLinksFormatter implements ClusterLinksFormatter { + async formatClusterLink( + _options: ClusterLinksFormatterOptions, + ): Promise { + throw new Error( + 'EKS formatter is not yet implemented. Please, contribute!', + ); + } +} diff --git a/plugins/kubernetes-react/src/api/formatters/GkeClusterLinksFormatter.test.ts b/plugins/kubernetes-react/src/api/formatters/GkeClusterLinksFormatter.test.ts new file mode 100644 index 0000000000..9b9e707a6c --- /dev/null +++ b/plugins/kubernetes-react/src/api/formatters/GkeClusterLinksFormatter.test.ts @@ -0,0 +1,264 @@ +/* + * 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 { GkeClusterLinksFormatter } from './GkeClusterLinksFormatter'; + +describe('clusterLinks - GKE formatter', () => { + describe('without googleAuthApi provided', () => { + const formatter = new GkeClusterLinksFormatter(undefined); + + it('should provide a dashboardParameters in the options', async () => { + await expect( + formatter.formatClusterLink({ + object: { + metadata: { + name: 'foobar', + namespace: 'bar', + }, + }, + kind: 'Deployment', + }), + ).rejects.toThrow('GKE dashboard requires a dashboardParameters option'); + }); + it('should provide a projectId in the dashboardParameters options', async () => { + await expect( + formatter.formatClusterLink({ + dashboardParameters: { + region: 'us-east1-c', + clusterName: 'cluster-1', + }, + object: { + metadata: { + name: 'foobar', + namespace: 'bar', + }, + }, + kind: 'Deployment', + }), + ).rejects.toThrow( + 'GKE dashboard requires a "projectId" of type string in the dashboardParameters option', + ); + }); + it('should provide a region in the dashboardParameters options', async () => { + await expect( + formatter.formatClusterLink({ + dashboardParameters: { + projectId: 'foobar-333614', + clusterName: 'cluster-1', + }, + object: { + metadata: { + name: 'foobar', + namespace: 'bar', + }, + }, + kind: 'Deployment', + }), + ).rejects.toThrow( + 'GKE dashboard requires a "region" of type string in the dashboardParameters option', + ); + }); + it('should provide a clusterName in the dashboardParameters options', async () => { + await expect(() => + formatter.formatClusterLink({ + dashboardParameters: { + projectId: 'foobar-333614', + region: 'us-east1-c', + }, + object: { + metadata: { + name: 'foobar', + namespace: 'bar', + }, + }, + kind: 'Deployment', + }), + ).rejects.toThrow( + 'GKE dashboard requires a "clusterName" of type string in the dashboardParameters option', + ); + }); + it('should return an url on the cluster when there is a namespace only', async () => { + const url = await formatter.formatClusterLink({ + dashboardParameters: { + projectId: 'foobar-333614', + region: 'us-east1-c', + clusterName: 'cluster-1', + }, + object: { + metadata: { + namespace: 'bar', + }, + }, + kind: 'foo', + }); + expect(url.href).toBe( + 'https://console.cloud.google.com/kubernetes/clusters/details/us-east1-c/cluster-1/details?project=foobar-333614', + ); + }); + it('should return an url on the cluster when the kind is not recognized', async () => { + const url = await formatter.formatClusterLink({ + dashboardParameters: { + projectId: 'foobar-333614', + region: 'us-east1-c', + clusterName: 'cluster-1', + }, + object: { + metadata: { + name: 'foobar', + namespace: 'bar', + }, + }, + kind: 'UnknownKind', + }); + expect(url.href).toBe( + 'https://console.cloud.google.com/kubernetes/clusters/details/us-east1-c/cluster-1/details?project=foobar-333614', + ); + }); + it('should return an url on the deployment', async () => { + const url = await formatter.formatClusterLink({ + dashboardParameters: { + projectId: 'foobar-333614', + region: 'us-east1-c', + clusterName: 'cluster-1', + }, + object: { + metadata: { + name: 'foobar', + namespace: 'bar', + }, + }, + kind: 'Deployment', + }); + expect(url.href).toBe( + 'https://console.cloud.google.com/kubernetes/deployment/us-east1-c/cluster-1/bar/foobar/overview?project=foobar-333614', + ); + }); + + it('should return an url on the service', async () => { + const url = await formatter.formatClusterLink({ + dashboardParameters: { + projectId: 'foobar-333614', + region: 'us-east1-c', + clusterName: 'cluster-1', + }, + object: { + metadata: { + name: 'foobar', + namespace: 'bar', + }, + }, + kind: 'Service', + }); + expect(url.href).toBe( + 'https://console.cloud.google.com/kubernetes/service/us-east1-c/cluster-1/bar/foobar/overview?project=foobar-333614', + ); + }); + it('should return an url on the pod', async () => { + const url = await formatter.formatClusterLink({ + dashboardParameters: { + projectId: 'foobar-333614', + region: 'us-east1-c', + clusterName: 'cluster-1', + }, + object: { + metadata: { + name: 'foobar', + namespace: 'bar', + }, + }, + kind: 'Pod', + }); + expect(url.href).toBe( + 'https://console.cloud.google.com/kubernetes/pod/us-east1-c/cluster-1/bar/foobar/details?project=foobar-333614', + ); + }); + it('should return an url on the ingress', async () => { + const url = await formatter.formatClusterLink({ + dashboardParameters: { + projectId: 'foobar-333614', + region: 'us-east1-c', + clusterName: 'cluster-1', + }, + object: { + metadata: { + name: 'foobar', + namespace: 'bar', + }, + }, + kind: 'Ingress', + }); + expect(url.href).toBe( + 'https://console.cloud.google.com/kubernetes/ingress/us-east1-c/cluster-1/bar/foobar/details?project=foobar-333614', + ); + }); + it('should return an url on the deployment for a hpa', async () => { + const url = await formatter.formatClusterLink({ + dashboardParameters: { + projectId: 'foobar-333614', + region: 'us-east1-c', + clusterName: 'cluster-1', + }, + object: { + metadata: { + name: 'foobar', + namespace: 'bar', + }, + }, + kind: 'HorizontalPodAutoscaler', + }); + expect(url.href).toBe( + 'https://console.cloud.google.com/kubernetes/deployment/us-east1-c/cluster-1/bar/foobar/overview?project=foobar-333614', + ); + }); + }); + describe('with googleAuthApi provided', () => { + const object = { + dashboardParameters: { + projectId: 'foobar-333614', + region: 'us-east1-c', + clusterName: 'cluster-1', + }, + object: { + metadata: { + namespace: 'bar', + }, + }, + kind: 'foo', + }; + it('should not fail, when undefined is returned as profile', async () => { + const formatter = new GkeClusterLinksFormatter({ + getProfile: async _ => undefined, + }); + const url = await formatter.formatClusterLink(object); + expect(url.searchParams.has('authuser')).toBeFalsy(); + }); + it('should not fail, when profile returns no email', async () => { + const formatter = new GkeClusterLinksFormatter({ + getProfile: async _ => ({ email: undefined }), + }); + const url = await formatter.formatClusterLink(object); + expect(url.searchParams.has('authuser')).toBeFalsy(); + }); + it('should add authuser with email when provided', async () => { + const email = 'email@example.com'; + const formatter = new GkeClusterLinksFormatter({ + getProfile: async _ => ({ email }), + }); + const url = await formatter.formatClusterLink(object); + expect(url.searchParams.get('authuser')).toBe(email); + }); + }); +}); diff --git a/plugins/kubernetes-react/src/api/formatters/GkeClusterLinksFormatter.ts b/plugins/kubernetes-react/src/api/formatters/GkeClusterLinksFormatter.ts new file mode 100644 index 0000000000..4bf3c28f45 --- /dev/null +++ b/plugins/kubernetes-react/src/api/formatters/GkeClusterLinksFormatter.ts @@ -0,0 +1,81 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + ClusterLinksFormatter, + ClusterLinksFormatterOptions, +} from '../../types'; +import { ProfileInfoApi } from '@backstage/core-plugin-api'; + +const kindMappings: Record = { + deployment: 'deployment', + pod: 'pod', + ingress: 'ingress', + service: 'service', + horizontalpodautoscaler: 'deployment', +}; + +/** @public */ +export class GkeClusterLinksFormatter implements ClusterLinksFormatter { + constructor(private readonly googleAuthApi: ProfileInfoApi | undefined) {} + async formatClusterLink(options: ClusterLinksFormatterOptions): Promise { + if (!options.dashboardParameters) { + throw new Error('GKE dashboard requires a dashboardParameters option'); + } + const args = options.dashboardParameters; + if (typeof args.projectId !== 'string') { + throw new Error( + 'GKE dashboard requires a "projectId" of type string in the dashboardParameters option', + ); + } + if (typeof args.region !== 'string') { + throw new Error( + 'GKE dashboard requires a "region" of type string in the dashboardParameters option', + ); + } + if (typeof args.clusterName !== 'string') { + throw new Error( + 'GKE dashboard requires a "clusterName" of type string in the dashboardParameters option', + ); + } + const basePath = new URL('https://console.cloud.google.com/'); + const region = encodeURIComponent(args.region); + const clusterName = encodeURIComponent(args.clusterName); + const name = encodeURIComponent(options.object.metadata?.name ?? ''); + const namespace = encodeURIComponent( + options.object.metadata?.namespace ?? '', + ); + const validKind = kindMappings[options.kind.toLocaleLowerCase('en-US')]; + let path: string; + if (namespace && name && validKind) { + const kindsWithDetails = ['ingress', 'pod']; + const landingPage = kindsWithDetails.includes(validKind) + ? 'details' + : 'overview'; + path = `kubernetes/${validKind}/${region}/${clusterName}/${namespace}/${name}/${landingPage}`; + } else { + path = `kubernetes/clusters/details/${region}/${clusterName}/details`; + } + const result = new URL(path, basePath); + result.searchParams.set('project', args.projectId); + if (this.googleAuthApi) { + const profile = await this.googleAuthApi.getProfile({ optional: true }); + if (profile?.email) { + result.searchParams.set('authuser', profile.email); + } + } + return result; + } +} diff --git a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/openshift.test.ts b/plugins/kubernetes-react/src/api/formatters/OpenshiftClusterLinksFormatter.test.ts similarity index 75% rename from plugins/kubernetes-react/src/utils/clusterLinks/formatters/openshift.test.ts rename to plugins/kubernetes-react/src/api/formatters/OpenshiftClusterLinksFormatter.test.ts index 945553e340..1adb688757 100644 --- a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/openshift.test.ts +++ b/plugins/kubernetes-react/src/api/formatters/OpenshiftClusterLinksFormatter.test.ts @@ -13,12 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { openshiftFormatter } from './openshift'; + +import { OpenshiftClusterLinksFormatter } from './OpenshiftClusterLinksFormatter'; describe('clusterLinks - OpenShift formatter', () => { - it('should provide a dashboardUrl in the options', () => { - expect(() => - openshiftFormatter({ + const formatter = new OpenshiftClusterLinksFormatter(); + it('should provide a dashboardUrl in the options', async () => { + await expect(() => + formatter.formatClusterLink({ object: { metadata: { name: 'foobar', @@ -27,10 +29,10 @@ describe('clusterLinks - OpenShift formatter', () => { }, kind: 'Deployment', }), - ).toThrow('OpenShift dashboard requires a dashboardUrl option'); + ).rejects.toThrow('OpenShift dashboard requires a dashboardUrl option'); }); - it('should return an url on the workloads when there is a namespace only', () => { - const url = openshiftFormatter({ + it('should return an url on the workloads when there is a namespace only', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com'), object: { metadata: { @@ -41,8 +43,8 @@ describe('clusterLinks - OpenShift formatter', () => { }); expect(url.href).toBe('https://k8s.foo.com/k8s/cluster/projects/bar'); }); - it('should return an url on the workloads when the kind is not recognizeed', () => { - const url = openshiftFormatter({ + it('should return an url on the workloads when the kind is not recognizeed', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com'), object: { metadata: { @@ -54,8 +56,8 @@ describe('clusterLinks - OpenShift formatter', () => { }); expect(url.href).toBe('https://k8s.foo.com/k8s/cluster/projects/bar'); }); - it('should return an url on the deployment', () => { - const url = openshiftFormatter({ + it('should return an url on the deployment', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/'), object: { metadata: { @@ -67,8 +69,8 @@ describe('clusterLinks - OpenShift formatter', () => { }); expect(url.href).toBe('https://k8s.foo.com/k8s/ns/bar/deployments/foobar'); }); - it('should return an url on the deployment and keep the path prefix 1', () => { - const url = openshiftFormatter({ + it('should return an url on the deployment and keep the path prefix 1', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/some/prefix/'), object: { metadata: { @@ -82,8 +84,8 @@ describe('clusterLinks - OpenShift formatter', () => { 'https://k8s.foo.com/some/prefix/k8s/ns/bar/deployments/foobar', ); }); - it('should return an url on the deployment and keep the path prefix 2', () => { - const url = openshiftFormatter({ + it('should return an url on the deployment and keep the path prefix 2', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/some/prefix'), object: { metadata: { @@ -97,8 +99,8 @@ describe('clusterLinks - OpenShift formatter', () => { 'https://k8s.foo.com/some/prefix/k8s/ns/bar/deployments/foobar', ); }); - it('should return an url on the service', () => { - const url = openshiftFormatter({ + it('should return an url on the service', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/'), object: { metadata: { @@ -110,8 +112,8 @@ describe('clusterLinks - OpenShift formatter', () => { }); expect(url.href).toBe('https://k8s.foo.com/k8s/ns/bar/services/foobar'); }); - it('should return an url on the ingress', () => { - const url = openshiftFormatter({ + it('should return an url on the ingress', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/'), object: { metadata: { @@ -123,8 +125,8 @@ describe('clusterLinks - OpenShift formatter', () => { }); expect(url.href).toBe('https://k8s.foo.com/k8s/ns/bar/ingresses/foobar'); }); - it('should return an url on the deployment for a hpa', () => { - const url = openshiftFormatter({ + it('should return an url on the deployment for a hpa', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/'), object: { metadata: { @@ -138,8 +140,8 @@ describe('clusterLinks - OpenShift formatter', () => { 'https://k8s.foo.com/k8s/ns/bar/horizontalpodautoscalers/foobar', ); }); - it('should return an url on the PV', () => { - const url = openshiftFormatter({ + it('should return an url on the PV', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/'), object: { metadata: { diff --git a/plugins/kubernetes-react/src/api/formatters/OpenshiftClusterLinksFormatter.ts b/plugins/kubernetes-react/src/api/formatters/OpenshiftClusterLinksFormatter.ts new file mode 100644 index 0000000000..228ff3d1ac --- /dev/null +++ b/plugins/kubernetes-react/src/api/formatters/OpenshiftClusterLinksFormatter.ts @@ -0,0 +1,60 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { ClusterLinksFormatterOptions } from '../../types'; + +const kindMappings: Record = { + deployment: 'deployments', + ingress: 'ingresses', + service: 'services', + horizontalpodautoscaler: 'horizontalpodautoscalers', + persistentvolume: 'persistentvolumes', +}; + +/** @public */ +export class OpenshiftClusterLinksFormatter { + async formatClusterLink(options: ClusterLinksFormatterOptions): Promise { + if (!options.dashboardUrl) { + throw new Error('OpenShift dashboard requires a dashboardUrl option'); + } + const basePath = new URL(options.dashboardUrl.href); + const name = encodeURIComponent(options.object.metadata?.name ?? ''); + const namespace = encodeURIComponent( + options.object.metadata?.namespace ?? '', + ); + const validKind = kindMappings[options.kind.toLocaleLowerCase('en-US')]; + if (!basePath.pathname.endsWith('/')) { + // a dashboard url with a path should end with a slash otherwise + // the new combined URL will replace the last segment with the appended path! + // https://foobar.com/abc/def + k8s/cluster/projects/test --> https://foobar.com/abc/k8s/cluster/projects/test + // https://foobar.com/abc/def/ + k8s/cluster/projects/test --> https://foobar.com/abc/def/k8s/cluster/projects/test + basePath.pathname += '/'; + } + let path = ''; + if (namespace) { + if (name && validKind) { + path = `k8s/ns/${namespace}/${validKind}/${name}`; + } else { + path = `k8s/cluster/projects/${namespace}`; + } + } else if (validKind) { + path = `k8s/cluster/${validKind}`; + if (name) { + path += `/${name}`; + } + } + return new URL(path, basePath); + } +} diff --git a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/rancher.test.ts b/plugins/kubernetes-react/src/api/formatters/RancherClusterLinksFormatter.test.ts similarity index 74% rename from plugins/kubernetes-react/src/utils/clusterLinks/formatters/rancher.test.ts rename to plugins/kubernetes-react/src/api/formatters/RancherClusterLinksFormatter.test.ts index bb26da3ab0..228340eb16 100644 --- a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/rancher.test.ts +++ b/plugins/kubernetes-react/src/api/formatters/RancherClusterLinksFormatter.test.ts @@ -13,12 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { rancherFormatter } from './rancher'; + +import { RancherClusterLinksFormatter } from './RancherClusterLinksFormatter'; describe('clusterLinks - rancher formatter', () => { - it('should provide a dashboardUrl in the options', () => { - expect(() => - rancherFormatter({ + const formatter = new RancherClusterLinksFormatter(); + it('should provide a dashboardUrl in the options', async () => { + await expect(() => + formatter.formatClusterLink({ object: { metadata: { name: 'foobar', @@ -27,10 +29,10 @@ describe('clusterLinks - rancher formatter', () => { }, kind: 'Deployment', }), - ).toThrow('Rancher dashboard requires a dashboardUrl option'); + ).rejects.toThrow('Rancher dashboard requires a dashboardUrl option'); }); - it('should return a url on the workloads when there is a namespace only', () => { - const url = rancherFormatter({ + it('should return a url on the workloads when there is a namespace only', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com'), object: { metadata: { @@ -41,8 +43,8 @@ describe('clusterLinks - rancher formatter', () => { }); expect(url.href).toBe('https://k8s.foo.com/explorer/workload'); }); - it('should return a url on the workloads when the kind is not recognized', () => { - const url = rancherFormatter({ + it('should return a url on the workloads when the kind is not recognized', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com'), object: { metadata: { @@ -54,8 +56,8 @@ describe('clusterLinks - rancher formatter', () => { }); expect(url.href).toBe('https://k8s.foo.com/explorer/workload'); }); - it('should return a url on the deployment', () => { - const url = rancherFormatter({ + it('should return a url on the deployment', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/'), object: { metadata: { @@ -69,8 +71,8 @@ describe('clusterLinks - rancher formatter', () => { 'https://k8s.foo.com/explorer/apps.deployment/bar/foobar', ); }); - it('should return a url on the service', () => { - const url = rancherFormatter({ + it('should return a url on the service', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/'), object: { metadata: { @@ -82,8 +84,8 @@ describe('clusterLinks - rancher formatter', () => { }); expect(url.href).toBe('https://k8s.foo.com/explorer/service/bar/foobar'); }); - it('should return a url on the ingress', () => { - const url = rancherFormatter({ + it('should return a url on the ingress', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/'), object: { metadata: { @@ -97,8 +99,8 @@ describe('clusterLinks - rancher formatter', () => { 'https://k8s.foo.com/explorer/networking.k8s.io.ingress/bar/foobar', ); }); - it('should return a url on the deployment for a hpa', () => { - const url = rancherFormatter({ + it('should return a url on the deployment for a hpa', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/'), object: { metadata: { @@ -112,8 +114,8 @@ describe('clusterLinks - rancher formatter', () => { 'https://k8s.foo.com/explorer/autoscaling.horizontalpodautoscaler/bar/foobar', ); }); - it('should support subpaths in dashboardUrl', () => { - const url = rancherFormatter({ + it('should support subpaths in dashboardUrl', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/dashboard/c/c-28a4b/'), object: { metadata: { diff --git a/plugins/kubernetes-react/src/api/formatters/RancherClusterLinksFormatter.ts b/plugins/kubernetes-react/src/api/formatters/RancherClusterLinksFormatter.ts new file mode 100644 index 0000000000..e607d98972 --- /dev/null +++ b/plugins/kubernetes-react/src/api/formatters/RancherClusterLinksFormatter.ts @@ -0,0 +1,55 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + ClusterLinksFormatter, + ClusterLinksFormatterOptions, +} from '../../types'; + +const kindMappings: Record = { + deployment: 'apps.deployment', + ingress: 'networking.k8s.io.ingress', + service: 'service', + horizontalpodautoscaler: 'autoscaling.horizontalpodautoscaler', +}; + +/** @public */ +export class RancherClusterLinksFormatter implements ClusterLinksFormatter { + async formatClusterLink(options: ClusterLinksFormatterOptions): Promise { + if (!options.dashboardUrl) { + throw new Error('Rancher dashboard requires a dashboardUrl option'); + } + const basePath = new URL(options.dashboardUrl.href); + const name = encodeURIComponent(options.object.metadata?.name ?? ''); + const namespace = encodeURIComponent( + options.object.metadata?.namespace ?? '', + ); + const validKind = kindMappings[options.kind.toLocaleLowerCase('en-US')]; + if (!basePath.pathname.endsWith('/')) { + // a dashboard url with a path should end with a slash otherwise + // the new combined URL will replace the last segment with the appended path! + // https://foobar.com/abc/def + explorer/service/test --> https://foobar.com/abc/explorer/service/test + // https://foobar.com/abc/def/ + explorer/service/test --> https://foobar.com/abc/def/explorer/service/test + basePath.pathname += '/'; + } + let path = ''; + if (validKind && name && namespace) { + path = `explorer/${validKind}/${namespace}/${name}`; + } else if (namespace) { + path = 'explorer/workload'; + } + return new URL(path, basePath); + } +} diff --git a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/standard.test.ts b/plugins/kubernetes-react/src/api/formatters/StandardClusterLinksFormatter.test.ts similarity index 76% rename from plugins/kubernetes-react/src/utils/clusterLinks/formatters/standard.test.ts rename to plugins/kubernetes-react/src/api/formatters/StandardClusterLinksFormatter.test.ts index 280de6bfde..fe1b2be4f5 100644 --- a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/standard.test.ts +++ b/plugins/kubernetes-react/src/api/formatters/StandardClusterLinksFormatter.test.ts @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { standardFormatter } from './standard'; + +import { StandardClusterLinksFormatter } from './StandardClusterLinksFormatter'; function formatUrl(url: URL) { // Note that we can't rely on 'url.href' since it will put the search before the hash @@ -23,9 +24,10 @@ function formatUrl(url: URL) { } describe('clusterLinks - standard formatter', () => { - it('should provide a dashboardUrl in the options', () => { - expect(() => - standardFormatter({ + const formatter = new StandardClusterLinksFormatter(); + it('should provide a dashboardUrl in the options', async () => { + await expect(() => + formatter.formatClusterLink({ object: { metadata: { name: 'foobar', @@ -34,10 +36,10 @@ describe('clusterLinks - standard formatter', () => { }, kind: 'Deployment', }), - ).toThrow('standard dashboard requires a dashboardUrl option'); + ).rejects.toThrow('standard dashboard requires a dashboardUrl option'); }); - it('should return an url on the workloads when there is a namespace only', () => { - const url = standardFormatter({ + it('should return an url on the workloads when there is a namespace only', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com'), object: { metadata: { @@ -50,8 +52,8 @@ describe('clusterLinks - standard formatter', () => { 'https://k8s.foo.com/#/workloads?namespace=bar', ); }); - it('should return an url on the workloads when the kind is not recognizeed', () => { - const url = standardFormatter({ + it('should return an url on the workloads when the kind is not recognizeed', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com'), object: { metadata: { @@ -65,8 +67,8 @@ describe('clusterLinks - standard formatter', () => { 'https://k8s.foo.com/#/workloads?namespace=bar', ); }); - it('should return an url on the deployment', () => { - const url = standardFormatter({ + it('should return an url on the deployment', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/'), object: { metadata: { @@ -80,8 +82,8 @@ describe('clusterLinks - standard formatter', () => { 'https://k8s.foo.com/#/deployment/bar/foobar?namespace=bar', ); }); - it('should return an url on the pod', () => { - const url = standardFormatter({ + it('should return an url on the pod', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/'), object: { metadata: { @@ -95,8 +97,8 @@ describe('clusterLinks - standard formatter', () => { 'https://k8s.foo.com/#/pod/bar/foobar?namespace=bar', ); }); - it('should return an url on the deployment with a prefix 1', () => { - const url = standardFormatter({ + it('should return an url on the deployment with a prefix 1', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/some/prefix'), object: { metadata: { @@ -110,8 +112,8 @@ describe('clusterLinks - standard formatter', () => { 'https://k8s.foo.com/some/prefix/#/deployment/bar/foobar?namespace=bar', ); }); - it('should return an url on the deployment with a prefix 2', () => { - const url = standardFormatter({ + it('should return an url on the deployment with a prefix 2', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/some/prefix/'), object: { metadata: { @@ -125,8 +127,8 @@ describe('clusterLinks - standard formatter', () => { 'https://k8s.foo.com/some/prefix/#/deployment/bar/foobar?namespace=bar', ); }); - it('should return an url on the deployment properly url encoded', () => { - const url = standardFormatter({ + it('should return an url on the deployment properly url encoded', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/'), object: { metadata: { @@ -140,8 +142,8 @@ describe('clusterLinks - standard formatter', () => { 'https://k8s.foo.com/#/deployment/bar%20bar/foobar?namespace=bar%20bar', ); }); - it('should return an url on the service', () => { - const url = standardFormatter({ + it('should return an url on the service', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/'), object: { metadata: { @@ -155,8 +157,8 @@ describe('clusterLinks - standard formatter', () => { 'https://k8s.foo.com/#/service/bar/foobar?namespace=bar', ); }); - it('should return an url on the ingress', () => { - const url = standardFormatter({ + it('should return an url on the ingress', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/'), object: { metadata: { @@ -170,8 +172,8 @@ describe('clusterLinks - standard formatter', () => { 'https://k8s.foo.com/#/ingress/bar/foobar?namespace=bar', ); }); - it('should return an url on the deployment for a hpa', () => { - const url = standardFormatter({ + it('should return an url on the deployment for a hpa', async () => { + const url = await formatter.formatClusterLink({ dashboardUrl: new URL('https://k8s.foo.com/'), object: { metadata: { diff --git a/plugins/kubernetes-react/src/api/formatters/StandardClusterLinksFormatter.ts b/plugins/kubernetes-react/src/api/formatters/StandardClusterLinksFormatter.ts new file mode 100644 index 0000000000..76537c5a4e --- /dev/null +++ b/plugins/kubernetes-react/src/api/formatters/StandardClusterLinksFormatter.ts @@ -0,0 +1,56 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + ClusterLinksFormatter, + ClusterLinksFormatterOptions, +} from '../../types'; + +const kindMappings: Record = { + deployment: 'deployment', + pod: 'pod', + ingress: 'ingress', + service: 'service', + horizontalpodautoscaler: 'deployment', + statefulset: 'statefulset', +}; + +/** @public */ +export class StandardClusterLinksFormatter implements ClusterLinksFormatter { + async formatClusterLink(options: ClusterLinksFormatterOptions): Promise { + if (!options.dashboardUrl) { + throw new Error('standard dashboard requires a dashboardUrl option'); + } + const result = new URL(options.dashboardUrl.href); + const name = encodeURIComponent(options.object.metadata?.name ?? ''); + const namespace = encodeURIComponent( + options.object.metadata?.namespace ?? '', + ); + const validKind = kindMappings[options.kind.toLocaleLowerCase('en-US')]; + if (!result.pathname.endsWith('/')) { + result.pathname += '/'; + } + if (validKind && name && namespace) { + result.hash = `/${validKind}/${namespace}/${name}`; + } else if (namespace) { + result.hash = '/workloads'; + } + if (namespace) { + // Note that Angular SPA requires a hash and the query parameter should be part of it + result.hash += `?namespace=${namespace}`; + } + return result; + } +} diff --git a/plugins/kubernetes-react/src/api/formatters/index.ts b/plugins/kubernetes-react/src/api/formatters/index.ts new file mode 100644 index 0000000000..c4bf52d181 --- /dev/null +++ b/plugins/kubernetes-react/src/api/formatters/index.ts @@ -0,0 +1,50 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { AksClusterLinksFormatter } from './AksClusterLinksFormatter'; +import { ClusterLinksFormatter } from '../../types'; +import { EksClusterLinksFormatter } from './EksClusterLinksFormatter'; +import { GkeClusterLinksFormatter } from './GkeClusterLinksFormatter'; +import { StandardClusterLinksFormatter } from './StandardClusterLinksFormatter'; +import { OpenshiftClusterLinksFormatter } from './OpenshiftClusterLinksFormatter'; +import { RancherClusterLinksFormatter } from './RancherClusterLinksFormatter'; +import { ProfileInfoApi } from '@backstage/core-plugin-api'; + +export { + StandardClusterLinksFormatter, + AksClusterLinksFormatter, + EksClusterLinksFormatter, + GkeClusterLinksFormatter, + OpenshiftClusterLinksFormatter, + RancherClusterLinksFormatter, +}; + +/** @public */ +export const DEFAULT_FORMATTER_NAME = 'standard'; + +/** @public */ +export function getDefaultFormatters(deps: { + googleAuthApi: ProfileInfoApi; +}): Record { + return { + standard: new StandardClusterLinksFormatter(), + aks: new AksClusterLinksFormatter(), + eks: new EksClusterLinksFormatter(), + gke: new GkeClusterLinksFormatter(deps.googleAuthApi), + openshift: new OpenshiftClusterLinksFormatter(), + rancher: new RancherClusterLinksFormatter(), + }; +} diff --git a/plugins/kubernetes-react/src/api/index.ts b/plugins/kubernetes-react/src/api/index.ts index ec8843937a..42fbcf1618 100644 --- a/plugins/kubernetes-react/src/api/index.ts +++ b/plugins/kubernetes-react/src/api/index.ts @@ -14,7 +14,18 @@ * limitations under the License. */ -export { kubernetesApiRef, kubernetesProxyApiRef } from './types'; -export type { KubernetesApi, KubernetesProxyApi } from './types'; +export { + kubernetesApiRef, + kubernetesProxyApiRef, + kubernetesClusterLinkFormatterApiRef, +} from './types'; +export type { + KubernetesApi, + KubernetesProxyApi, + FormatClusterLinkOptions, + KubernetesClusterLinkFormatterApi, +} from './types'; export { KubernetesBackendClient } from './KubernetesBackendClient'; +export { KubernetesClusterLinkFormatter } from './KubernetesClusterLinkFormatter'; export { KubernetesProxyClient } from './KubernetesProxyClient'; +export * from './formatters'; diff --git a/plugins/kubernetes-react/src/api/types.ts b/plugins/kubernetes-react/src/api/types.ts index 28cf2dde55..cc27bf9dd4 100644 --- a/plugins/kubernetes-react/src/api/types.ts +++ b/plugins/kubernetes-react/src/api/types.ts @@ -22,6 +22,7 @@ import { } from '@backstage/plugin-kubernetes-common'; import { createApiRef } from '@backstage/core-plugin-api'; import { Event } from 'kubernetes-models/v1'; +import { JsonObject } from '@backstage/types'; /** @public */ export const kubernetesApiRef = createApiRef({ @@ -33,6 +34,12 @@ export const kubernetesProxyApiRef = createApiRef({ id: 'plugin.kubernetes.proxy-service', }); +/** @public */ +export const kubernetesClusterLinkFormatterApiRef = + createApiRef({ + id: 'plugin.kubernetes.cluster-link-formatter-service', + }); + /** @public */ export interface KubernetesApi { getObjectsByEntity( @@ -82,3 +89,21 @@ export interface KubernetesProxyApi { namespace: string; }): Promise; } + +/** + * @public + */ +export type FormatClusterLinkOptions = { + dashboardUrl?: string; + dashboardApp?: string; + dashboardParameters?: JsonObject; + object: any; + kind: string; +}; + +/** @public */ +export interface KubernetesClusterLinkFormatterApi { + formatClusterLink( + options: FormatClusterLinkOptions, + ): Promise; +} diff --git a/plugins/kubernetes-react/src/components/CronJobsAccordions/CronJobsDrawer.test.tsx b/plugins/kubernetes-react/src/components/CronJobsAccordions/CronJobsDrawer.test.tsx index b16e83ee50..75506476ea 100644 --- a/plugins/kubernetes-react/src/components/CronJobsAccordions/CronJobsDrawer.test.tsx +++ b/plugins/kubernetes-react/src/components/CronJobsAccordions/CronJobsDrawer.test.tsx @@ -15,16 +15,20 @@ */ import React from 'react'; import * as oneCronJobsFixture from '../../__fixtures__/1-cronjobs.json'; -import { renderInTestApp } from '@backstage/test-utils'; +import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; import { CronJobDrawer } from './CronJobsDrawer'; +import { kubernetesClusterLinkFormatterApiRef } from '../../api'; describe('CronJobDrawer', () => { it('should render cronJob drawer', async () => { const { getByText, getAllByText } = await renderInTestApp( - , + + + , + , ); expect(getAllByText('dice-roller-cronjob')).toHaveLength(2); diff --git a/plugins/kubernetes-react/src/components/DeploymentsAccordions/DeploymentDrawer.test.tsx b/plugins/kubernetes-react/src/components/DeploymentsAccordions/DeploymentDrawer.test.tsx index f221a36cee..1e8515f81a 100644 --- a/plugins/kubernetes-react/src/components/DeploymentsAccordions/DeploymentDrawer.test.tsx +++ b/plugins/kubernetes-react/src/components/DeploymentsAccordions/DeploymentDrawer.test.tsx @@ -16,16 +16,24 @@ import React from 'react'; import * as deployments from '../../__fixtures__/2-deployments.json'; -import { renderInTestApp, textContentMatcher } from '@backstage/test-utils'; +import { + renderInTestApp, + TestApiProvider, + textContentMatcher, +} from '@backstage/test-utils'; import { DeploymentDrawer } from './DeploymentDrawer'; +import { kubernetesClusterLinkFormatterApiRef } from '../../api'; describe('DeploymentDrawer', () => { it('should render deployment drawer', async () => { const { getByText, getAllByText } = await renderInTestApp( - , + + + , + , ); expect(getAllByText('dice-roller')).toHaveLength(2); @@ -53,13 +61,16 @@ describe('DeploymentDrawer', () => { it('should render deployment drawer without namespace', async () => { const deployment = (deployments as any).deployments[0]; const { queryByText } = await renderInTestApp( - , + + + , + , ); expect(queryByText('namespace: default')).not.toBeInTheDocument(); diff --git a/plugins/kubernetes-react/src/components/HorizontalPodAutoscalers/HorizontalPodAutoscalerDrawer.test.tsx b/plugins/kubernetes-react/src/components/HorizontalPodAutoscalers/HorizontalPodAutoscalerDrawer.test.tsx index beb0db1e2b..6599a2041f 100644 --- a/plugins/kubernetes-react/src/components/HorizontalPodAutoscalers/HorizontalPodAutoscalerDrawer.test.tsx +++ b/plugins/kubernetes-react/src/components/HorizontalPodAutoscalers/HorizontalPodAutoscalerDrawer.test.tsx @@ -17,15 +17,18 @@ import React from 'react'; import { screen } from '@testing-library/react'; import * as hpas from './__fixtures__/horizontalpodautoscalers.json'; -import { renderInTestApp } from '@backstage/test-utils'; +import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; import { HorizontalPodAutoscalerDrawer } from './HorizontalPodAutoscalerDrawer'; +import { kubernetesClusterLinkFormatterApiRef } from '../../api'; describe('HorizontalPodAutoscalersDrawer', () => { it('should render hpa drawer', async () => { await renderInTestApp( - -

    CHILD

    -
    , + + +

    CHILD

    +
    +
    , ); expect(screen.getByText('dice-roller')).toBeInTheDocument(); diff --git a/plugins/kubernetes-react/src/components/IngressesAccordions/IngressDrawer.test.tsx b/plugins/kubernetes-react/src/components/IngressesAccordions/IngressDrawer.test.tsx index 8619e362b7..cfacb24ee4 100644 --- a/plugins/kubernetes-react/src/components/IngressesAccordions/IngressDrawer.test.tsx +++ b/plugins/kubernetes-react/src/components/IngressesAccordions/IngressDrawer.test.tsx @@ -14,16 +14,23 @@ * limitations under the License. */ -import { renderInTestApp, textContentMatcher } from '@backstage/test-utils'; +import { + renderInTestApp, + TestApiProvider, + textContentMatcher, +} from '@backstage/test-utils'; import { screen } from '@testing-library/react'; import React from 'react'; import { IngressDrawer } from './IngressDrawer'; import * as ingresses from './__fixtures__/2-ingresses.json'; +import { kubernetesClusterLinkFormatterApiRef } from '../../api'; describe('IngressDrawer', () => { it('should render ingress drawer', async () => { await renderInTestApp( - , + + + , ); expect(screen.getAllByText('awesome-service')).toHaveLength(4); diff --git a/plugins/kubernetes-react/src/components/JobsAccordions/JobsDrawer.test.tsx b/plugins/kubernetes-react/src/components/JobsAccordions/JobsDrawer.test.tsx index 48a4e6fe7e..23f49a2118 100644 --- a/plugins/kubernetes-react/src/components/JobsAccordions/JobsDrawer.test.tsx +++ b/plugins/kubernetes-react/src/components/JobsAccordions/JobsDrawer.test.tsx @@ -15,13 +15,16 @@ */ import React from 'react'; import * as oneCronJobsFixture from '../../__fixtures__/1-cronjobs.json'; -import { renderInTestApp } from '@backstage/test-utils'; +import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; import { JobDrawer } from './JobsDrawer'; +import { kubernetesClusterLinkFormatterApiRef } from '../../api'; describe('JobDrawer', () => { it('should render job drawer', async () => { const { getByText, getAllByText } = await renderInTestApp( - , + + , + , ); expect(getAllByText('dice-roller-cronjob-1637025000')).toHaveLength(2); diff --git a/plugins/kubernetes-react/src/components/KubernetesDrawer/KubernetesStructuredMetadataTableDrawer.tsx b/plugins/kubernetes-react/src/components/KubernetesDrawer/KubernetesStructuredMetadataTableDrawer.tsx index 65001c658e..0b6cfa26b4 100644 --- a/plugins/kubernetes-react/src/components/KubernetesDrawer/KubernetesStructuredMetadataTableDrawer.tsx +++ b/plugins/kubernetes-react/src/components/KubernetesDrawer/KubernetesStructuredMetadataTableDrawer.tsx @@ -37,10 +37,11 @@ import { WarningPanel, } from '@backstage/core-components'; import { ClusterContext } from '../../hooks'; -import { formatClusterLink } from '../../utils/clusterLinks'; import { ClusterAttributes } from '@backstage/plugin-kubernetes-common'; -import { FormatClusterLinkOptions } from '../../utils/clusterLinks/formatClusterLink'; import { ManifestYaml } from './ManifestYaml'; +import { useApi } from '@backstage/core-plugin-api'; +import { kubernetesClusterLinkFormatterApiRef } from '../../api'; +import useAsync from 'react-use/lib/useAsync'; const useDrawerStyles = makeStyles((theme: Theme) => createStyles({ @@ -147,20 +148,6 @@ function replaceNullsWithUndefined(someObj: any) { return JSON.parse(JSON.stringify(someObj, replacer)); } -function tryFormatClusterLink(options: FormatClusterLinkOptions) { - try { - return { - clusterLink: formatClusterLink(options), - errorMessage: '', - }; - } catch (err) { - return { - clusterLink: '', - errorMessage: err.message || err.toString(), - }; - } -} - const KubernetesStructuredMetadataTableDrawerContent = < T extends KubernetesDrawerable, >({ @@ -171,15 +158,20 @@ const KubernetesStructuredMetadataTableDrawerContent = < }: KubernetesStructuredMetadataTableDrawerContentProps) => { const [isYaml, setIsYaml] = useState(false); + const formatter = useApi(kubernetesClusterLinkFormatterApiRef); const classes = useDrawerContentStyles(); const cluster = useContext(ClusterContext); - const { clusterLink, errorMessage } = tryFormatClusterLink({ - dashboardUrl: cluster.dashboardUrl, - dashboardApp: cluster.dashboardApp, - dashboardParameters: cluster.dashboardParameters, - object, - kind, - }); + const { value: clusterLink, error } = useAsync( + async () => + formatter.formatClusterLink({ + dashboardUrl: cluster.dashboardUrl, + dashboardApp: cluster.dashboardApp, + dashboardParameters: cluster.dashboardParameters, + object, + kind, + }), + [cluster, object, kind, formatter], + ); return ( <> @@ -221,9 +213,12 @@ const KubernetesStructuredMetadataTableDrawerContent = < - {errorMessage && ( + {error && (
    - +
    )}
    diff --git a/plugins/kubernetes-react/src/components/Pods/PodsTable.tsx b/plugins/kubernetes-react/src/components/Pods/PodsTable.tsx index f7c2660c84..d83aebb210 100644 --- a/plugins/kubernetes-react/src/components/Pods/PodsTable.tsx +++ b/plugins/kubernetes-react/src/components/Pods/PodsTable.tsx @@ -125,6 +125,11 @@ const Memory = ({ clusterName, pod }: { clusterName: string; pod: Pod }) => { export const PodsTable = ({ pods, extraColumns = [] }: PodsTablesProps) => { const cluster = useContext(ClusterContext); const defaultColumns: TableColumn[] = [ + { + title: 'ID', + field: 'metadata.uid', + hidden: true, + }, { title: 'name', highlight: true, @@ -176,7 +181,14 @@ export const PodsTable = ({ pods, extraColumns = [] }: PodsTablesProps) => {
    ({ + ...pod, + id: pod?.metadata?.uid, + })) as any as Pod[] + } columns={columns} /> diff --git a/plugins/kubernetes-react/src/components/ServicesAccordions/ServiceDrawer.test.tsx b/plugins/kubernetes-react/src/components/ServicesAccordions/ServiceDrawer.test.tsx index dda5e300eb..7eec2926c4 100644 --- a/plugins/kubernetes-react/src/components/ServicesAccordions/ServiceDrawer.test.tsx +++ b/plugins/kubernetes-react/src/components/ServicesAccordions/ServiceDrawer.test.tsx @@ -17,13 +17,20 @@ import React from 'react'; import { screen } from '@testing-library/react'; import * as services from './__fixtures__/2-services.json'; -import { textContentMatcher, renderInTestApp } from '@backstage/test-utils'; +import { + textContentMatcher, + renderInTestApp, + TestApiProvider, +} from '@backstage/test-utils'; import { ServiceDrawer } from './ServiceDrawer'; +import { kubernetesClusterLinkFormatterApiRef } from '../../api'; describe('ServiceDrawer', () => { it('should render deployment drawer', async () => { await renderInTestApp( - , + + , + , ); expect(screen.getAllByText('awesome-service-grpc')).toHaveLength(2); diff --git a/plugins/kubernetes-react/src/components/StatefulSetsAccordions/StatefulSetDrawer.test.tsx b/plugins/kubernetes-react/src/components/StatefulSetsAccordions/StatefulSetDrawer.test.tsx index c187c7d05d..d69ab15f1a 100644 --- a/plugins/kubernetes-react/src/components/StatefulSetsAccordions/StatefulSetDrawer.test.tsx +++ b/plugins/kubernetes-react/src/components/StatefulSetsAccordions/StatefulSetDrawer.test.tsx @@ -16,16 +16,24 @@ import React from 'react'; import * as statefulsets from '../../__fixtures__/2-statefulsets.json'; -import { renderInTestApp, textContentMatcher } from '@backstage/test-utils'; +import { + renderInTestApp, + TestApiProvider, + textContentMatcher, +} from '@backstage/test-utils'; import { StatefulSetDrawer } from './StatefulSetDrawer'; +import { kubernetesClusterLinkFormatterApiRef } from '../../api'; describe('StatefulSetDrawer', () => { it('should render statefulset drawer', async () => { const { getByText, getAllByText } = await renderInTestApp( - , + + + , + , ); expect(getAllByText('dice-roller')).toHaveLength(4); @@ -55,13 +63,16 @@ describe('StatefulSetDrawer', () => { it('should render statefulset drawer without namespace', async () => { const statefulset = (statefulsets as any).statefulsets[0]; const { queryByText } = await renderInTestApp( - , + + + , + , ); expect(queryByText('namespace: default')).not.toBeInTheDocument(); diff --git a/plugins/kubernetes-react/src/index.ts b/plugins/kubernetes-react/src/index.ts index 4fb8614091..326b363b05 100644 --- a/plugins/kubernetes-react/src/index.ts +++ b/plugins/kubernetes-react/src/index.ts @@ -27,5 +27,4 @@ export * from './hooks'; export * from './api'; export * from './kubernetes-auth-provider'; export * from './components'; -export * from './utils'; export * from './types'; diff --git a/plugins/kubernetes-react/src/setupTests.ts b/plugins/kubernetes-react/src/setupTests.ts index 865308e634..609118cd07 100644 --- a/plugins/kubernetes-react/src/setupTests.ts +++ b/plugins/kubernetes-react/src/setupTests.ts @@ -13,4 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import '@testing-library/jest-dom'; +import { Settings } from 'luxon'; + +Settings.defaultLocale = 'en'; diff --git a/plugins/kubernetes-react/src/types/types.ts b/plugins/kubernetes-react/src/types/types.ts index ad8df040ac..5db2e281f4 100644 --- a/plugins/kubernetes-react/src/types/types.ts +++ b/plugins/kubernetes-react/src/types/types.ts @@ -29,6 +29,6 @@ export interface ClusterLinksFormatterOptions { /** * @public */ -export type ClusterLinksFormatter = ( - options: ClusterLinksFormatterOptions, -) => URL; +export interface ClusterLinksFormatter { + formatClusterLink(options: ClusterLinksFormatterOptions): Promise; +} diff --git a/plugins/kubernetes-react/src/utils/clusterLinks/formatClusterLink.test.ts b/plugins/kubernetes-react/src/utils/clusterLinks/formatClusterLink.test.ts deleted file mode 100644 index 254b9fc51b..0000000000 --- a/plugins/kubernetes-react/src/utils/clusterLinks/formatClusterLink.test.ts +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import { formatClusterLink } from './formatClusterLink'; - -describe('clusterLinks', () => { - describe('formatClusterLink', () => { - it('should not return an url when there is no dashboard url', () => { - const url = formatClusterLink({ object: {}, kind: 'foo' }); - expect(url).toBeUndefined(); - }); - it('should return an url even when there is no object', () => { - const url = formatClusterLink({ - dashboardUrl: 'https://k8s.foo.com', - object: undefined, - kind: 'foo', - }); - expect(url).toBe('https://k8s.foo.com'); - }); - it('should throw when the app is not recognized', () => { - expect(() => - formatClusterLink({ - dashboardUrl: 'https://k8s.foo.com', - dashboardApp: 'unknownapp', - object: { - metadata: { - name: 'foobar', - namespace: 'bar', - }, - }, - kind: 'Deployment', - }), - ).toThrow("Could not find Kubernetes dashboard app named 'unknownapp'"); - }); - - describe('default app', () => { - it('should return an url on the deployment', () => { - const url = formatClusterLink({ - dashboardUrl: 'https://k8s.foo.com/', - object: { - metadata: { - name: 'foobar', - namespace: 'bar', - }, - }, - kind: 'Deployment', - }); - expect(url).toBe( - 'https://k8s.foo.com/#/deployment/bar/foobar?namespace=bar', - ); - }); - it('should return an url on the service', () => { - const url = formatClusterLink({ - dashboardUrl: 'https://k8s.foo.com/', - object: { - metadata: { - name: 'foobar', - namespace: 'bar', - }, - }, - kind: 'Service', - }); - expect(url).toBe( - 'https://k8s.foo.com/#/service/bar/foobar?namespace=bar', - ); - }); - }); - - describe('standard app', () => { - it('should return an url on the deployment', () => { - const url = formatClusterLink({ - dashboardUrl: 'https://k8s.foo.com/', - dashboardApp: 'standard', - object: { - metadata: { - name: 'foobar', - namespace: 'bar', - }, - }, - kind: 'Deployment', - }); - expect(url).toBe( - 'https://k8s.foo.com/#/deployment/bar/foobar?namespace=bar', - ); - }); - it('should return an url on the service', () => { - const url = formatClusterLink({ - dashboardUrl: 'https://k8s.foo.com/', - dashboardApp: 'standard', - object: { - metadata: { - name: 'foobar', - namespace: 'bar', - }, - }, - kind: 'Service', - }); - expect(url).toBe( - 'https://k8s.foo.com/#/service/bar/foobar?namespace=bar', - ); - }); - }); - describe('GKE app', () => { - it('should return an url on the deployment', () => { - const url = formatClusterLink({ - dashboardApp: 'gke', - dashboardParameters: { - projectId: 'foobar-333614', - region: 'us-east1-c', - clusterName: 'cluster-1', - }, - object: { - metadata: { - name: 'foobar', - namespace: 'bar', - }, - }, - kind: 'Deployment', - }); - expect(url).toBe( - 'https://console.cloud.google.com/kubernetes/deployment/us-east1-c/cluster-1/bar/foobar/overview?project=foobar-333614', - ); - }); - it('should return an url on the service', () => { - const url = formatClusterLink({ - dashboardApp: 'gke', - dashboardParameters: { - projectId: 'foobar-333614', - region: 'us-east1-c', - clusterName: 'cluster-1', - }, - object: { - metadata: { - name: 'foobar', - namespace: 'bar', - }, - }, - kind: 'Service', - }); - expect(url).toBe( - 'https://console.cloud.google.com/kubernetes/service/us-east1-c/cluster-1/bar/foobar/overview?project=foobar-333614', - ); - }); - }); - }); -}); diff --git a/plugins/kubernetes-react/src/utils/clusterLinks/formatClusterLink.ts b/plugins/kubernetes-react/src/utils/clusterLinks/formatClusterLink.ts deleted file mode 100644 index 8f7e43a121..0000000000 --- a/plugins/kubernetes-react/src/utils/clusterLinks/formatClusterLink.ts +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { JsonObject } from '@backstage/types'; -import { defaultFormatterName, clusterLinksFormatters } from './formatters'; - -/** - * @public - */ -export type FormatClusterLinkOptions = { - dashboardUrl?: string; - dashboardApp?: string; - dashboardParameters?: JsonObject; - object: any; - kind: string; -}; - -/** - * @public - */ -export function formatClusterLink(options: FormatClusterLinkOptions) { - if (!options.dashboardUrl && !options.dashboardParameters) { - return undefined; - } - if (options.dashboardUrl && !options.object) { - return options.dashboardUrl; - } - const app = options.dashboardApp || defaultFormatterName; - const formatter = clusterLinksFormatters[app]; - if (!formatter) { - throw new Error(`Could not find Kubernetes dashboard app named '${app}'`); - } - const url = formatter({ - dashboardUrl: options.dashboardUrl - ? new URL(options.dashboardUrl) - : undefined, - dashboardParameters: options.dashboardParameters, - object: options.object, - kind: options.kind, - }); - return url.toString(); -} diff --git a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/aks.ts b/plugins/kubernetes-react/src/utils/clusterLinks/formatters/aks.ts deleted file mode 100644 index 71fffb00e6..0000000000 --- a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/aks.ts +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import { ClusterLinksFormatterOptions } from '../../../types/types'; - -const basePath = - 'https://portal.azure.com/#blade/Microsoft_Azure_ContainerService/AksK8ResourceMenuBlade/overview-Deployment/aksClusterId'; - -const requiredParams = ['subscriptionId', 'resourceGroup', 'clusterName']; - -export function aksFormatter(options: ClusterLinksFormatterOptions): URL { - if (!options.dashboardParameters) { - throw new Error('AKS dashboard requires a dashboardParameters option'); - } - const args = options.dashboardParameters; - for (const param of requiredParams) { - if (typeof args[param] !== 'string') { - throw new Error( - `AKS dashboard requires a "${param}" of type string in the dashboardParameters option`, - ); - } - } - - const path = `/subscriptions/${args.subscriptionId}/resourceGroups/${args.resourceGroup}/providers/Microsoft.ContainerService/managedClusters/${args.clusterName}`; - - const { name, namespace, uid } = options.object.metadata; - const { selector } = options.object.spec; - const params = { - kind: options.kind, - metadata: { name, namespace, uid }, - spec: { - selector, - }, - }; - - return new URL( - `${basePath}/${encodeURIComponent(path)}/resource/${encodeURIComponent( - JSON.stringify(params), - )}`, - ); -} diff --git a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/gke.test.ts b/plugins/kubernetes-react/src/utils/clusterLinks/formatters/gke.test.ts deleted file mode 100644 index 7fd0814267..0000000000 --- a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/gke.test.ts +++ /dev/null @@ -1,222 +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 { gkeFormatter } from './gke'; - -describe('clusterLinks - GKE formatter', () => { - it('should provide a dashboardParameters in the options', () => { - expect(() => - gkeFormatter({ - object: { - metadata: { - name: 'foobar', - namespace: 'bar', - }, - }, - kind: 'Deployment', - }), - ).toThrow('GKE dashboard requires a dashboardParameters option'); - }); - it('should provide a projectId in the dashboardParameters options', () => { - expect(() => - gkeFormatter({ - dashboardParameters: { - region: 'us-east1-c', - clusterName: 'cluster-1', - }, - object: { - metadata: { - name: 'foobar', - namespace: 'bar', - }, - }, - kind: 'Deployment', - }), - ).toThrow( - 'GKE dashboard requires a "projectId" of type string in the dashboardParameters option', - ); - }); - it('should provide a region in the dashboardParameters options', () => { - expect(() => - gkeFormatter({ - dashboardParameters: { - projectId: 'foobar-333614', - clusterName: 'cluster-1', - }, - object: { - metadata: { - name: 'foobar', - namespace: 'bar', - }, - }, - kind: 'Deployment', - }), - ).toThrow( - 'GKE dashboard requires a "region" of type string in the dashboardParameters option', - ); - }); - it('should provide a clusterName in the dashboardParameters options', () => { - expect(() => - gkeFormatter({ - dashboardParameters: { - projectId: 'foobar-333614', - region: 'us-east1-c', - }, - object: { - metadata: { - name: 'foobar', - namespace: 'bar', - }, - }, - kind: 'Deployment', - }), - ).toThrow( - 'GKE dashboard requires a "clusterName" of type string in the dashboardParameters option', - ); - }); - it('should return an url on the cluster when there is a namespace only', () => { - const url = gkeFormatter({ - dashboardParameters: { - projectId: 'foobar-333614', - region: 'us-east1-c', - clusterName: 'cluster-1', - }, - object: { - metadata: { - namespace: 'bar', - }, - }, - kind: 'foo', - }); - expect(url.href).toBe( - 'https://console.cloud.google.com/kubernetes/clusters/details/us-east1-c/cluster-1/details?project=foobar-333614', - ); - }); - it('should return an url on the cluster when the kind is not recognizeed', () => { - const url = gkeFormatter({ - dashboardParameters: { - projectId: 'foobar-333614', - region: 'us-east1-c', - clusterName: 'cluster-1', - }, - object: { - metadata: { - name: 'foobar', - namespace: 'bar', - }, - }, - kind: 'UnknownKind', - }); - expect(url.href).toBe( - 'https://console.cloud.google.com/kubernetes/clusters/details/us-east1-c/cluster-1/details?project=foobar-333614', - ); - }); - it('should return an url on the deployment', () => { - const url = gkeFormatter({ - dashboardParameters: { - projectId: 'foobar-333614', - region: 'us-east1-c', - clusterName: 'cluster-1', - }, - object: { - metadata: { - name: 'foobar', - namespace: 'bar', - }, - }, - kind: 'Deployment', - }); - expect(url.href).toBe( - 'https://console.cloud.google.com/kubernetes/deployment/us-east1-c/cluster-1/bar/foobar/overview?project=foobar-333614', - ); - }); - - it('should return an url on the service', () => { - const url = gkeFormatter({ - dashboardParameters: { - projectId: 'foobar-333614', - region: 'us-east1-c', - clusterName: 'cluster-1', - }, - object: { - metadata: { - name: 'foobar', - namespace: 'bar', - }, - }, - kind: 'Service', - }); - expect(url.href).toBe( - 'https://console.cloud.google.com/kubernetes/service/us-east1-c/cluster-1/bar/foobar/overview?project=foobar-333614', - ); - }); - it('should return an url on the pod', () => { - const url = gkeFormatter({ - dashboardParameters: { - projectId: 'foobar-333614', - region: 'us-east1-c', - clusterName: 'cluster-1', - }, - object: { - metadata: { - name: 'foobar', - namespace: 'bar', - }, - }, - kind: 'Pod', - }); - expect(url.href).toBe( - 'https://console.cloud.google.com/kubernetes/pod/us-east1-c/cluster-1/bar/foobar/details?project=foobar-333614', - ); - }); - it('should return an url on the ingress', () => { - const url = gkeFormatter({ - dashboardParameters: { - projectId: 'foobar-333614', - region: 'us-east1-c', - clusterName: 'cluster-1', - }, - object: { - metadata: { - name: 'foobar', - namespace: 'bar', - }, - }, - kind: 'Ingress', - }); - expect(url.href).toBe( - 'https://console.cloud.google.com/kubernetes/ingress/us-east1-c/cluster-1/bar/foobar/details?project=foobar-333614', - ); - }); - it('should return an url on the deployment for a hpa', () => { - const url = gkeFormatter({ - dashboardParameters: { - projectId: 'foobar-333614', - region: 'us-east1-c', - clusterName: 'cluster-1', - }, - object: { - metadata: { - name: 'foobar', - namespace: 'bar', - }, - }, - kind: 'HorizontalPodAutoscaler', - }); - expect(url.href).toBe( - 'https://console.cloud.google.com/kubernetes/deployment/us-east1-c/cluster-1/bar/foobar/overview?project=foobar-333614', - ); - }); -}); diff --git a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/gke.ts b/plugins/kubernetes-react/src/utils/clusterLinks/formatters/gke.ts deleted file mode 100644 index 957032e6e2..0000000000 --- a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/gke.ts +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import { ClusterLinksFormatterOptions } from '../../../types/types'; - -const kindMappings: Record = { - deployment: 'deployment', - pod: 'pod', - ingress: 'ingress', - service: 'service', - horizontalpodautoscaler: 'deployment', -}; - -export function gkeFormatter(options: ClusterLinksFormatterOptions): URL { - if (!options.dashboardParameters) { - throw new Error('GKE dashboard requires a dashboardParameters option'); - } - const args = options.dashboardParameters; - if (typeof args.projectId !== 'string') { - throw new Error( - 'GKE dashboard requires a "projectId" of type string in the dashboardParameters option', - ); - } - if (typeof args.region !== 'string') { - throw new Error( - 'GKE dashboard requires a "region" of type string in the dashboardParameters option', - ); - } - if (typeof args.clusterName !== 'string') { - throw new Error( - 'GKE dashboard requires a "clusterName" of type string in the dashboardParameters option', - ); - } - const basePath = new URL('https://console.cloud.google.com/'); - const region = encodeURIComponent(args.region); - const clusterName = encodeURIComponent(args.clusterName); - const name = encodeURIComponent(options.object.metadata?.name ?? ''); - const namespace = encodeURIComponent( - options.object.metadata?.namespace ?? '', - ); - const validKind = kindMappings[options.kind.toLocaleLowerCase('en-US')]; - let path = ''; - if (namespace && name && validKind) { - const kindsWithDetails = ['ingress', 'pod']; - const landingPage = kindsWithDetails.includes(validKind) - ? 'details' - : 'overview'; - path = `kubernetes/${validKind}/${region}/${clusterName}/${namespace}/${name}/${landingPage}`; - } else { - path = `kubernetes/clusters/details/${region}/${clusterName}/details`; - } - const result = new URL(path, basePath); - result.searchParams.set('project', args.projectId); - return result; -} diff --git a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/index.ts b/plugins/kubernetes-react/src/utils/clusterLinks/formatters/index.ts deleted file mode 100644 index b75e45cc7f..0000000000 --- a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/index.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import { ClusterLinksFormatter } from '../../../types/types'; -import { standardFormatter } from './standard'; -import { rancherFormatter } from './rancher'; -import { openshiftFormatter } from './openshift'; -import { aksFormatter } from './aks'; -import { eksFormatter } from './eks'; -import { gkeFormatter } from './gke'; - -/** - * @public - */ -export const clusterLinksFormatters: Record = { - standard: standardFormatter, - rancher: rancherFormatter, - openshift: openshiftFormatter, - aks: aksFormatter, - eks: eksFormatter, - gke: gkeFormatter, -}; -export const defaultFormatterName = 'standard'; diff --git a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/openshift.ts b/plugins/kubernetes-react/src/utils/clusterLinks/formatters/openshift.ts deleted file mode 100644 index c5b7313061..0000000000 --- a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/openshift.ts +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import { ClusterLinksFormatterOptions } from '../../../types/types'; - -const kindMappings: Record = { - deployment: 'deployments', - ingress: 'ingresses', - service: 'services', - horizontalpodautoscaler: 'horizontalpodautoscalers', - persistentvolume: 'persistentvolumes', -}; - -export function openshiftFormatter(options: ClusterLinksFormatterOptions): URL { - if (!options.dashboardUrl) { - throw new Error('OpenShift dashboard requires a dashboardUrl option'); - } - const basePath = new URL(options.dashboardUrl.href); - const name = encodeURIComponent(options.object.metadata?.name ?? ''); - const namespace = encodeURIComponent( - options.object.metadata?.namespace ?? '', - ); - const validKind = kindMappings[options.kind.toLocaleLowerCase('en-US')]; - if (!basePath.pathname.endsWith('/')) { - // a dashboard url with a path should end with a slash otherwise - // the new combined URL will replace the last segment with the appended path! - // https://foobar.com/abc/def + k8s/cluster/projects/test --> https://foobar.com/abc/k8s/cluster/projects/test - // https://foobar.com/abc/def/ + k8s/cluster/projects/test --> https://foobar.com/abc/def/k8s/cluster/projects/test - basePath.pathname += '/'; - } - let path = ''; - if (namespace) { - if (name && validKind) { - path = `k8s/ns/${namespace}/${validKind}/${name}`; - } else { - path = `k8s/cluster/projects/${namespace}`; - } - } else if (validKind) { - path = `k8s/cluster/${validKind}`; - if (name) { - path += `/${name}`; - } - } - return new URL(path, basePath); -} diff --git a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/rancher.ts b/plugins/kubernetes-react/src/utils/clusterLinks/formatters/rancher.ts deleted file mode 100644 index 6c72730181..0000000000 --- a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/rancher.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import { ClusterLinksFormatterOptions } from '../../../types/types'; - -const kindMappings: Record = { - deployment: 'apps.deployment', - ingress: 'networking.k8s.io.ingress', - service: 'service', - horizontalpodautoscaler: 'autoscaling.horizontalpodautoscaler', -}; - -export function rancherFormatter(options: ClusterLinksFormatterOptions): URL { - if (!options.dashboardUrl) { - throw new Error('Rancher dashboard requires a dashboardUrl option'); - } - const basePath = new URL(options.dashboardUrl.href); - const name = encodeURIComponent(options.object.metadata?.name ?? ''); - const namespace = encodeURIComponent( - options.object.metadata?.namespace ?? '', - ); - const validKind = kindMappings[options.kind.toLocaleLowerCase('en-US')]; - if (!basePath.pathname.endsWith('/')) { - // a dashboard url with a path should end with a slash otherwise - // the new combined URL will replace the last segment with the appended path! - // https://foobar.com/abc/def + explorer/service/test --> https://foobar.com/abc/explorer/service/test - // https://foobar.com/abc/def/ + explorer/service/test --> https://foobar.com/abc/def/explorer/service/test - basePath.pathname += '/'; - } - let path = ''; - if (validKind && name && namespace) { - path = `explorer/${validKind}/${namespace}/${name}`; - } else if (namespace) { - path = 'explorer/workload'; - } - return new URL(path, basePath); -} diff --git a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/standard.ts b/plugins/kubernetes-react/src/utils/clusterLinks/formatters/standard.ts deleted file mode 100644 index e26adf98e6..0000000000 --- a/plugins/kubernetes-react/src/utils/clusterLinks/formatters/standard.ts +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import { ClusterLinksFormatterOptions } from '../../../types/types'; - -const kindMappings: Record = { - deployment: 'deployment', - pod: 'pod', - ingress: 'ingress', - service: 'service', - horizontalpodautoscaler: 'deployment', - statefulset: 'statefulset', -}; - -export function standardFormatter(options: ClusterLinksFormatterOptions) { - if (!options.dashboardUrl) { - throw new Error('standard dashboard requires a dashboardUrl option'); - } - const result = new URL(options.dashboardUrl.href); - const name = encodeURIComponent(options.object.metadata?.name ?? ''); - const namespace = encodeURIComponent( - options.object.metadata?.namespace ?? '', - ); - const validKind = kindMappings[options.kind.toLocaleLowerCase('en-US')]; - if (!result.pathname.endsWith('/')) { - result.pathname += '/'; - } - if (validKind && name && namespace) { - result.hash = `/${validKind}/${namespace}/${name}`; - } else if (namespace) { - result.hash = '/workloads'; - } - if (namespace) { - // Note that Angular SPA requires a hash and the query parameter should be part of it - result.hash += `?namespace=${namespace}`; - } - return result; -} diff --git a/plugins/kubernetes/CHANGELOG.md b/plugins/kubernetes/CHANGELOG.md index 644af82b5a..6f2cc8a23d 100644 --- a/plugins/kubernetes/CHANGELOG.md +++ b/plugins/kubernetes/CHANGELOG.md @@ -1,5 +1,168 @@ # @backstage/plugin-kubernetes +## 0.11.4 + +### Patch Changes + +- d5d2c67: Add `authuser` search parameter to GKE cluster link formatter in k8s plugin + + Thanks to this, people with multiple simultaneously logged-in accounts in their GCP console will automatically view objects with the same email as the one signed in to the Google auth provider in Backstage. + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-kubernetes-react@0.2.1 + - @backstage/plugin-kubernetes-common@0.7.3 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## 0.11.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.11.4-next.1 + +### Patch Changes + +- d5d2c67: Add `authuser` search parameter to GKE cluster link formatter in k8s plugin + + Thanks to this, people with multiple simultaneously logged-in accounts in their GCP console will automatically view objects with the same email as the one signed in to the Google auth provider in Backstage. + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/plugin-kubernetes-react@0.2.1-next.1 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-kubernetes-common@0.7.3-next.0 + +## 0.11.4-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-kubernetes-common@0.7.3-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/plugin-kubernetes-react@0.2.1-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + +## 0.11.3 + +### Patch Changes + +- 899d71a: Change `formatClusterLink` to be an API and make it async for further customization possibilities. + + **BREAKING** + If you have a custom k8s page and used `formatClusterLink` directly, you need to migrate to new `kubernetesClusterLinkFormatterApiRef` + +- 706fc3a: Updated dependency `@kubernetes/client-node` to `0.20.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/plugin-kubernetes-react@0.2.0 + - @backstage/plugin-kubernetes-common@0.7.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.11.3-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + - @backstage/plugin-kubernetes-react@0.2.0-next.3 + +## 0.11.3-next.2 + +### Patch Changes + +- 899d71a: Change `formatClusterLink` to be an API and make it async for further customization possibilities. + + **BREAKING** + If you have a custom k8s page and used `formatClusterLink` directly, you need to migrate to new `kubernetesClusterLinkFormatterApiRef` + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-kubernetes-react@0.2.0-next.2 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + +## 0.11.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-kubernetes-common@0.7.2-next.1 + - @backstage/plugin-kubernetes-react@0.1.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + +## 0.11.3-next.0 + +### Patch Changes + +- 706fc3a7e1: Updated dependency `@kubernetes/client-node` to `0.20.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/plugin-kubernetes-react@0.1.2-next.0 + - @backstage/plugin-kubernetes-common@0.7.2-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.11.1 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/plugin-kubernetes-common@0.7.1 + - @backstage/plugin-kubernetes-react@0.1.1 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + ## 0.11.1-next.2 ### Patch Changes diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index 1ae47b383c..858cc7a3c4 100644 --- a/plugins/kubernetes/package.json +++ b/plugins/kubernetes/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes", "description": "A Backstage plugin that integrates towards Kubernetes", - "version": "0.11.1-next.2", + "version": "0.11.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,28 +35,21 @@ }, "dependencies": { "@backstage/catalog-model": "workspace:^", - "@backstage/config": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", - "@backstage/errors": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", "@backstage/plugin-kubernetes-common": "workspace:^", "@backstage/plugin-kubernetes-react": "workspace:^", - "@backstage/theme": "workspace:^", - "@backstage/types": "workspace:^", "@kubernetes-models/apimachinery": "^1.1.0", "@kubernetes-models/base": "^4.0.1", - "@kubernetes/client-node": "0.19.0", + "@kubernetes/client-node": "0.20.0", "@material-ui/core": "^4.12.2", - "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.61", "@types/react": "^16.13.1 || ^17.0.0", "cronstrue": "^2.2.0", "js-yaml": "^4.0.0", "kubernetes-models": "^4.1.0", "lodash": "^4.17.21", "luxon": "^3.0.0", - "react-use": "^17.2.4", "xterm": "^5.2.1", "xterm-addon-attach": "^0.9.0", "xterm-addon-fit": "^0.8.0" @@ -68,15 +61,11 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", "@backstage/dev-utils": "workspace:^", "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "jest-websocket-mock": "^2.4.1", - "msw": "^1.0.0" + "@testing-library/react": "^14.0.0" }, "files": [ "dist" diff --git a/plugins/kubernetes/src/plugin.ts b/plugins/kubernetes/src/plugin.ts index ac55dbbf23..afe2287633 100644 --- a/plugins/kubernetes/src/plugin.ts +++ b/plugins/kubernetes/src/plugin.ts @@ -20,6 +20,10 @@ import { kubernetesAuthProvidersApiRef, KubernetesAuthProviders, KubernetesProxyClient, + kubernetesClusterLinkFormatterApiRef, + getDefaultFormatters, + KubernetesClusterLinkFormatter, + DEFAULT_FORMATTER_NAME, } from '@backstage/plugin-kubernetes-react'; import { createApiFactory, @@ -97,6 +101,17 @@ export const kubernetesPlugin = createPlugin({ }); }, }), + createApiFactory({ + api: kubernetesClusterLinkFormatterApiRef, + deps: { googleAuthApi: googleAuthApiRef }, + factory: deps => { + const formatters = getDefaultFormatters(deps); + return new KubernetesClusterLinkFormatter({ + formatters, + defaultFormatterName: DEFAULT_FORMATTER_NAME, + }); + }, + }), ], routes: { entityContent: rootCatalogKubernetesRouteRef, diff --git a/plugins/lighthouse-backend/CHANGELOG.md b/plugins/lighthouse-backend/CHANGELOG.md index 7aeebf7d9d..c41667aab4 100644 --- a/plugins/lighthouse-backend/CHANGELOG.md +++ b/plugins/lighthouse-backend/CHANGELOG.md @@ -1,5 +1,158 @@ # @backstage/plugin-lighthouse-backend +## 0.4.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-lighthouse-common@0.1.4 + +## 0.4.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## 0.4.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-node@1.6.1-next.1 + - @backstage/plugin-lighthouse-common@0.1.4 + +## 0.4.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/plugin-catalog-node@1.6.1-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/types@1.1.1 + - @backstage/plugin-lighthouse-common@0.1.4 + +## 0.4.0 + +### Minor Changes + +- 7f0dbfd: Fixed crashes faced with custom schedule configuration. The configuration schema has been update to leverage the TaskScheduleDefinition interface. It is highly recommended to move the `lighthouse.shedule` and `lighthouse.timeout` respectively to `lighthouse.schedule.frequency` and `lighthouse.schedule.timeout`. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/catalog-client@1.5.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-lighthouse-common@0.1.4 + +## 0.4.0-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-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/types@1.1.1 + - @backstage/plugin-catalog-node@1.6.0-next.3 + - @backstage/plugin-lighthouse-common@0.1.4 + +## 0.4.0-next.2 + +### Minor Changes + +- 7f0dbfd: Fixed crashes faced with custom schedule configuration. The configuration schema has been update to leverage the TaskScheduleDefinition interface. It is highly recommended to move the `lighthouse.shedule` and `lighthouse.timeout` respectively to `lighthouse.schedule.frequency` and `lighthouse.schedule.timeout`. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.0-next.2 + - @backstage/backend-common@0.20.0-next.2 + - @backstage/catalog-client@1.5.0-next.1 + - @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/types@1.1.1 + - @backstage/plugin-lighthouse-common@0.1.4 + +## 0.3.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-lighthouse-common@0.1.4 + +## 0.3.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-lighthouse-common@0.1.4 + +## 0.3.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-lighthouse-common@0.1.4 + ## 0.3.4-next.2 ### Patch Changes diff --git a/plugins/lighthouse-backend/README.md b/plugins/lighthouse-backend/README.md index 28845d3c73..687467f1d5 100644 --- a/plugins/lighthouse-backend/README.md +++ b/plugins/lighthouse-backend/README.md @@ -19,13 +19,19 @@ import { PluginEnvironment } from '../types'; import { CatalogClient } from '@backstage/catalog-client'; export default async function createPlugin(env: PluginEnvironment) { - const { logger, scheduler, config } = env; + const { logger, scheduler, config, tokenManager } = env; const catalogClient = new CatalogClient({ discoveryApi: env.discovery, }); - await createScheduler({ logger, scheduler, config, catalogClient }); + await createScheduler({ + logger, + scheduler, + config, + catalogClient, + tokenManager, + }); } ``` @@ -80,5 +86,8 @@ You can define how often and when the scheduler should run the audits: ```yaml lighthouse: schedule: - days: 1 + frequency: + hours: 12 # Default: 1 day + timeout: + minutes: 30 # Default: 10 minutes ``` diff --git a/plugins/lighthouse-backend/config.d.ts b/plugins/lighthouse-backend/config.d.ts new file mode 100644 index 0000000000..2d49f188b6 --- /dev/null +++ b/plugins/lighthouse-backend/config.d.ts @@ -0,0 +1,30 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { TaskScheduleDefinitionConfig } from '@backstage/backend-tasks'; +import { HumanDuration } from '@backstage/types'; + +export interface Config { + /** + * Configuration options for the Lighthouse backend plugin. + */ + lighthouse?: { + /** + * Schedule of the audit + */ + schedule?: HumanDuration | TaskScheduleDefinitionConfig; + }; +} diff --git a/plugins/lighthouse-backend/package.json b/plugins/lighthouse-backend/package.json index d0828439f6..ac9c844456 100644 --- a/plugins/lighthouse-backend/package.json +++ b/plugins/lighthouse-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-lighthouse-backend", "description": "Backend functionalities for lighthouse", - "version": "0.3.4-next.2", + "version": "0.4.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -24,8 +24,10 @@ "lighthouse" ], "files": [ - "dist" + "dist", + "config.d.ts" ], + "configSchema": "config.d.ts", "scripts": { "build": "backstage-cli package build", "lint": "backstage-cli package lint", diff --git a/plugins/lighthouse-backend/src/config.ts b/plugins/lighthouse-backend/src/config.ts index bea1c35661..736a4e569d 100644 --- a/plugins/lighthouse-backend/src/config.ts +++ b/plugins/lighthouse-backend/src/config.ts @@ -13,56 +13,66 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { LoggerService } from '@backstage/backend-plugin-api'; +import { + TaskScheduleDefinition, + readTaskScheduleDefinitionFromConfig, +} from '@backstage/backend-tasks'; +import { Config, readDurationFromConfig } from '@backstage/config'; +import { HumanDuration } from '@backstage/types'; -import { Config } from '@backstage/config'; -import { HumanDuration as HumanDuration } from '@backstage/types'; - -export interface LighthouseAuditScheduleConfig { - schedule: HumanDuration; - timeout: HumanDuration; - auditDetail: HumanDuration; -} - -/** @public */ -export type LighthouseAuditSchedule = { - getSchedule: () => HumanDuration; - getTimeout: () => HumanDuration; +type Options = { + logger: LoggerService; }; /** @public */ -export class LighthouseAuditScheduleImpl implements LighthouseAuditSchedule { - static fromConfig(config: Config) { - const lighthouse = config.getOptionalConfig('lighthouse'); +export class LighthouseAuditScheduleImpl implements TaskScheduleDefinition { + /** + * Looks at the `lighthouse.schedule` section in the application configuration + * and returns a TaskScheduleDefinition. + * Defaults to `{ frequency: { days: 1 }, timeout: {}, initialDelay: { minutes; 15 } }` + * + * @returns a TaskScheduleDefinition + */ + static fromConfig(config: Config, options: Options): TaskScheduleDefinition { + const { logger } = options; - let schedule: HumanDuration = { days: 1 }; - let timeout: HumanDuration = {}; + let lighthouse: TaskScheduleDefinition = { + frequency: { days: 1 }, + timeout: { minutes: 10 }, + initialDelay: { minutes: 15 }, + }; - if (lighthouse) { - const scheduleConfig = lighthouse.getOptionalConfig('schedule'); - const timeoutConfig = lighthouse.getOptionalConfig('timeout'); + if (config.has('lighthouse.schedule.frequency')) { + lighthouse = readTaskScheduleDefinitionFromConfig( + config.getConfig('lighthouse.schedule'), + ); + } else if (config.has('lighthouse.schedule')) { + logger.warn( + `[Deprecation] Please migrate the schedule configuration to 'lighthouse.schedule.frequency'`, + ); - if (scheduleConfig) { - schedule = scheduleConfig as HumanDuration; - } - - if (timeoutConfig) { - timeout = timeoutConfig as HumanDuration; - } + lighthouse.frequency = readDurationFromConfig( + config.getConfig('lighthouse.schedule'), + ); } - return new LighthouseAuditScheduleImpl(schedule, timeout); + if (config.has('lighthouse.timeout')) { + logger.warn( + `[Deprecation] Please migrate the timeout configuration to 'lighthouse.schedule.timeout'`, + ); + + lighthouse.timeout = readDurationFromConfig( + config.getConfig('lighthouse.timeout'), + ); + } + + return lighthouse; } constructor( - private schedule: HumanDuration, - private timeout: HumanDuration, + public frequency: HumanDuration, + public timeout: HumanDuration, + public initialDelay: HumanDuration, ) {} - - getSchedule(): HumanDuration { - return this.schedule; - } - - getTimeout(): HumanDuration { - return this.timeout; - } } diff --git a/plugins/lighthouse-backend/src/service/createScheduler.ts b/plugins/lighthouse-backend/src/service/createScheduler.ts index 498e459a09..45a3e88149 100644 --- a/plugins/lighthouse-backend/src/service/createScheduler.ts +++ b/plugins/lighthouse-backend/src/service/createScheduler.ts @@ -39,7 +39,9 @@ export async function createScheduler( const { logger, scheduler, catalogClient, config, tokenManager } = options; const lighthouseApi = LighthouseRestApi.fromConfig(config); - const lighthouseAuditConfig = LighthouseAuditScheduleImpl.fromConfig(config); + const lighthouseAuditConfig = LighthouseAuditScheduleImpl.fromConfig(config, { + logger, + }); const formFactorToScreenEmulationMap = { // the default is mobile, so no need to override mobile: undefined, @@ -56,16 +58,16 @@ export async function createScheduler( logger.info( `Running with Scheduler Config ${JSON.stringify( - lighthouseAuditConfig.getSchedule(), - )} and timeout ${JSON.stringify(lighthouseAuditConfig.getTimeout())}`, + lighthouseAuditConfig.frequency, + )} and timeout ${JSON.stringify(lighthouseAuditConfig.timeout)}`, ); if (scheduler) { await scheduler.scheduleTask({ id: 'lighthouse_audit', - frequency: lighthouseAuditConfig.getSchedule(), - timeout: lighthouseAuditConfig.getTimeout(), - initialDelay: { minutes: 15 }, + frequency: lighthouseAuditConfig.frequency, + timeout: lighthouseAuditConfig.timeout, + initialDelay: lighthouseAuditConfig.initialDelay, fn: async () => { const filter: Record = { kind: 'Component', diff --git a/plugins/lighthouse/CHANGELOG.md b/plugins/lighthouse/CHANGELOG.md index bb711423da..92d919b657 100644 --- a/plugins/lighthouse/CHANGELOG.md +++ b/plugins/lighthouse/CHANGELOG.md @@ -1,5 +1,129 @@ # @backstage/plugin-lighthouse +## 0.4.14 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-lighthouse-common@0.1.4 + +## 0.4.14-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.4.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-lighthouse-common@0.1.4 + +## 0.4.14-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-lighthouse-common@0.1.4 + +## 0.4.13 + +### Patch Changes + +- ffbf656: Updated README +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-lighthouse-common@0.1.4 + +## 0.4.13-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + - @backstage/plugin-lighthouse-common@0.1.4 + +## 0.4.13-next.2 + +### Patch Changes + +- ffbf656: Updated README +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-lighthouse-common@0.1.4 + +## 0.4.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-lighthouse-common@0.1.4 + +## 0.4.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-lighthouse-common@0.1.4 + +## 0.4.11 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-lighthouse-common@0.1.4 + ## 0.4.11-next.2 ### Patch Changes diff --git a/plugins/lighthouse/README.md b/plugins/lighthouse/README.md index 1d2385e4c4..e834ad39c1 100644 --- a/plugins/lighthouse/README.md +++ b/plugins/lighthouse/README.md @@ -47,6 +47,10 @@ const routes = ( Then configure the `lighthouse-audit-service` URL in your [`app-config.yaml`](https://github.com/backstage/backstage/blob/master/app-config.yaml). ```yaml +backend: + csp: + frame-src: + - http://your-service-url lighthouse: baseUrl: http://your-service-url ``` diff --git a/plugins/lighthouse/package.json b/plugins/lighthouse/package.json index e14a58252b..b71039ce2e 100644 --- a/plugins/lighthouse/package.json +++ b/plugins/lighthouse/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-lighthouse", "description": "A Backstage plugin that integrates towards Lighthouse", - "version": "0.4.11-next.2", + "version": "0.4.14", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,12 +35,10 @@ }, "dependencies": { "@backstage/catalog-model": "workspace:^", - "@backstage/config": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", "@backstage/plugin-lighthouse-common": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", @@ -60,7 +58,6 @@ "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, "files": [ diff --git a/plugins/linguist-backend/CHANGELOG.md b/plugins/linguist-backend/CHANGELOG.md index 65ad934f6c..439c15066a 100644 --- a/plugins/linguist-backend/CHANGELOG.md +++ b/plugins/linguist-backend/CHANGELOG.md @@ -1,5 +1,172 @@ # @backstage/plugin-linguist-backend +## 0.5.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-linguist-common@0.1.2 + +## 0.5.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + +## 0.5.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-node@1.6.1-next.1 + - @backstage/plugin-linguist-common@0.1.2 + +## 0.5.6-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/plugin-catalog-node@1.6.1-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/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.0 + - @backstage/plugin-linguist-common@0.1.2 + +## 0.5.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/catalog-client@1.5.0 + - @backstage/backend-tasks@0.5.13 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-linguist-common@0.1.2 + +## 0.5.5-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-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/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.3 + - @backstage/plugin-catalog-node@1.6.0-next.3 + - @backstage/plugin-linguist-common@0.1.2 + +## 0.5.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.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/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/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-linguist-common@0.1.2 + +## 0.5.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-linguist-common@0.1.2 + +## 0.5.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/plugin-catalog-node@1.5.1-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-linguist-common@0.1.2 + +## 0.5.4 + +### Patch Changes + +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. +- Updated dependencies + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.1 + - @backstage/plugin-linguist-common@0.1.2 + ## 0.5.4-next.2 ### Patch Changes diff --git a/plugins/linguist-backend/package.json b/plugins/linguist-backend/package.json index a70f8f2e98..6f137ad5f6 100644 --- a/plugins/linguist-backend/package.json +++ b/plugins/linguist-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-linguist-backend", - "version": "0.5.4-next.2", + "version": "0.5.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -56,7 +56,6 @@ "@backstage/cli": "workspace:^", "@types/supertest": "^2.0.8", "js-yaml": "^4.1.0", - "msw": "^1.0.0", "supertest": "^6.2.4" }, "files": [ diff --git a/plugins/linguist/.eslintrc.js b/plugins/linguist/.eslintrc.js index e2a53a6ad2..e487f765b2 100644 --- a/plugins/linguist/.eslintrc.js +++ b/plugins/linguist/.eslintrc.js @@ -1 +1,5 @@ -module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, { + rules: { + '@backstage/no-top-level-material-ui-4-imports': 'error', + }, +}); diff --git a/plugins/linguist/CHANGELOG.md b/plugins/linguist/CHANGELOG.md index 455f329b82..7e96d237e6 100644 --- a/plugins/linguist/CHANGELOG.md +++ b/plugins/linguist/CHANGELOG.md @@ -1,5 +1,135 @@ # @backstage/plugin-linguist +## 0.1.14 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- 4f42918: Added alpha support for the New Frontend System (Declarative Integration) +- Updated dependencies + - @backstage/core-compat-api@0.1.1 + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-linguist-common@0.1.2 + +## 0.1.14-next.2 + +### Patch Changes + +- 4f42918: Added alpha support for the New Frontend System (Declarative Integration) +- Updated dependencies + - @backstage/core-compat-api@0.1.1-next.2 + - @backstage/frontend-plugin-api@0.4.1-next.2 + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.1.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-linguist-common@0.1.2 + +## 0.1.14-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-linguist-common@0.1.2 + +## 0.1.13 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-linguist-common@0.1.2 + +## 0.1.13-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + - @backstage/plugin-linguist-common@0.1.2 + +## 0.1.13-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-linguist-common@0.1.2 + +## 0.1.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-linguist-common@0.1.2 + +## 0.1.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-linguist-common@0.1.2 + +## 0.1.11 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-linguist-common@0.1.2 + ## 0.1.11-next.2 ### Patch Changes diff --git a/plugins/linguist/api-report-alpha.md b/plugins/linguist/api-report-alpha.md new file mode 100644 index 0000000000..418439d331 --- /dev/null +++ b/plugins/linguist/api-report-alpha.md @@ -0,0 +1,13 @@ +## API Report File for "@backstage/plugin-linguist" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { BackstagePlugin } from '@backstage/frontend-plugin-api'; + +// @alpha (undocumented) +const _default: BackstagePlugin<{}, {}>; +export default _default; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/linguist/package.json b/plugins/linguist/package.json index d47d695a49..ed38f881de 100644 --- a/plugins/linguist/package.json +++ b/plugins/linguist/package.json @@ -1,13 +1,26 @@ { "name": "@backstage/plugin-linguist", - "version": "0.1.11-next.2", + "version": "0.1.14", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", "publishConfig": { - "access": "public", - "main": "dist/index.esm.js", - "types": "dist/index.d.ts" + "access": "public" + }, + "exports": { + ".": "./src/index.ts", + "./alpha": "./src/alpha.ts", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "alpha": [ + "src/alpha.ts" + ], + "package.json": [ + "package.json" + ] + } }, "backstage": { "role": "frontend-plugin" @@ -30,14 +43,14 @@ }, "dependencies": { "@backstage/catalog-model": "workspace:^", + "@backstage/core-compat-api": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", + "@backstage/frontend-plugin-api": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", "@backstage/plugin-linguist-common": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.9.13", - "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", "@types/react": "^16.13.1 || ^17.0.0", "luxon": "^2.0.2", @@ -51,14 +64,10 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", "@backstage/dev-utils": "workspace:^", - "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "msw": "^1.0.0" + "@testing-library/react": "^14.0.0" }, "files": [ "dist" diff --git a/plugins/linguist/src/alpha.ts b/plugins/linguist/src/alpha.ts new file mode 100644 index 0000000000..e80f131817 --- /dev/null +++ b/plugins/linguist/src/alpha.ts @@ -0,0 +1,18 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './alpha/index'; +export { default } from './alpha/index'; diff --git a/plugins/linguist/src/alpha/index.ts b/plugins/linguist/src/alpha/index.ts new file mode 100644 index 0000000000..2f137f09ee --- /dev/null +++ b/plugins/linguist/src/alpha/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { default } from './plugin'; diff --git a/plugins/linguist/src/alpha/plugin.tsx b/plugins/linguist/src/alpha/plugin.tsx new file mode 100644 index 0000000000..36d635740f --- /dev/null +++ b/plugins/linguist/src/alpha/plugin.tsx @@ -0,0 +1,53 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { + createApiExtension, + createApiFactory, + createPlugin, + discoveryApiRef, + identityApiRef, +} from '@backstage/frontend-plugin-api'; + +import { LinguistClient, linguistApiRef } from '../api'; +import { compatWrapper } from '@backstage/core-compat-api'; +import { createEntityCardExtension } from '@backstage/plugin-catalog-react/alpha'; + +/** @alpha */ +export const entityLinguistCard = createEntityCardExtension({ + name: 'languages', + loader: async () => + import('../components/LinguistCard').then(m => + compatWrapper(), + ), +}); + +/** @alpha */ +export const linguistApi = createApiExtension({ + factory: createApiFactory({ + api: linguistApiRef, + deps: { discoveryApi: discoveryApiRef, identityApi: identityApiRef }, + factory: ({ discoveryApi, identityApi }) => + new LinguistClient({ discoveryApi, identityApi }), + }), +}); + +/** @alpha */ +export default createPlugin({ + id: 'linguist', + extensions: [linguistApi, entityLinguistCard], +}); diff --git a/plugins/linguist/src/components/LinguistCard/LinguistCard.tsx b/plugins/linguist/src/components/LinguistCard/LinguistCard.tsx index 6014487d30..6a07a958c2 100644 --- a/plugins/linguist/src/components/LinguistCard/LinguistCard.tsx +++ b/plugins/linguist/src/components/LinguistCard/LinguistCard.tsx @@ -14,15 +14,12 @@ * limitations under the License. */ -import { - Box, - Chip, - Tooltip, - Typography, - makeStyles, - Grid, - useTheme, -} from '@material-ui/core'; +import Box from '@material-ui/core/Box'; +import Chip from '@material-ui/core/Chip'; +import Tooltip from '@material-ui/core/Tooltip'; +import Typography from '@material-ui/core/Typography'; +import Grid from '@material-ui/core/Grid'; +import { makeStyles, useTheme } from '@material-ui/core/styles'; import { InfoCard, Progress } from '@backstage/core-components'; import Alert from '@material-ui/lab/Alert'; import { DateTime } from 'luxon'; diff --git a/plugins/microsoft-calendar/CHANGELOG.md b/plugins/microsoft-calendar/CHANGELOG.md index f1a6abe709..86ea39fcff 100644 --- a/plugins/microsoft-calendar/CHANGELOG.md +++ b/plugins/microsoft-calendar/CHANGELOG.md @@ -1,5 +1,96 @@ # @backstage/plugin-microsoft-calendar +## 0.1.11 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/errors@1.2.3 + +## 0.1.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/errors@1.2.3 + +## 0.1.11-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + +## 0.1.10 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/errors@1.2.3 + +## 0.1.10-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + +## 0.1.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + +## 0.1.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## 0.1.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/errors@1.2.3 + +## 0.1.9 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 62b5922916: Internal theme type updates +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/errors@1.2.3 + ## 0.1.9-next.2 ### Patch Changes diff --git a/plugins/microsoft-calendar/package.json b/plugins/microsoft-calendar/package.json index 0f8532b305..aec094c029 100644 --- a/plugins/microsoft-calendar/package.json +++ b/plugins/microsoft-calendar/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-microsoft-calendar", - "version": "0.1.9-next.2", + "version": "0.1.11", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -51,7 +51,6 @@ "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@microsoft/microsoft-graph-types": "^2.25.0", @@ -71,14 +70,10 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", "@backstage/dev-utils": "workspace:^", - "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "msw": "^1.0.0" + "@testing-library/react": "^14.0.0" }, "files": [ "dist" diff --git a/plugins/newrelic-dashboard/CHANGELOG.md b/plugins/newrelic-dashboard/CHANGELOG.md index d2b5291446..8b5a6e560a 100644 --- a/plugins/newrelic-dashboard/CHANGELOG.md +++ b/plugins/newrelic-dashboard/CHANGELOG.md @@ -1,5 +1,115 @@ # @backstage/plugin-newrelic-dashboard +## 0.3.4 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.3.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.3.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.3.4-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + +## 0.3.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.3.3-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## 0.3.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + +## 0.3.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.3.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.3.1 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + ## 0.3.1-next.2 ### Patch Changes diff --git a/plugins/newrelic-dashboard/package.json b/plugins/newrelic-dashboard/package.json index 618e43e1fd..981441b479 100644 --- a/plugins/newrelic-dashboard/package.json +++ b/plugins/newrelic-dashboard/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-newrelic-dashboard", - "version": "0.3.1-next.2", + "version": "0.3.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -36,7 +36,6 @@ "@backstage/plugin-catalog-react": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.61", "@types/react": "^16.13.1 || ^17.0.0", "react-use": "^17.2.4" }, diff --git a/plugins/newrelic/CHANGELOG.md b/plugins/newrelic/CHANGELOG.md index c4ea0fc8ea..8935f6c619 100644 --- a/plugins/newrelic/CHANGELOG.md +++ b/plugins/newrelic/CHANGELOG.md @@ -1,5 +1,87 @@ # @backstage/plugin-newrelic +## 0.3.44 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + +## 0.3.44-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + +## 0.3.44-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/core-plugin-api@1.8.1 + +## 0.3.43 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + +## 0.3.43-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + +## 0.3.43-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## 0.3.43-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.0 + +## 0.3.43-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + +## 0.3.42 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + ## 0.3.42-next.2 ### Patch Changes diff --git a/plugins/newrelic/package.json b/plugins/newrelic/package.json index 3aa34f0e50..a67a2203d5 100644 --- a/plugins/newrelic/package.json +++ b/plugins/newrelic/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-newrelic", "description": "A Backstage plugin that integrates towards New Relic", - "version": "0.3.42-next.2", + "version": "0.3.44", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -36,9 +36,7 @@ "dependencies": { "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", - "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", "@types/react": "^16.13.1 || ^17.0.0", "parse-link-header": "^2.0.0", @@ -50,17 +48,13 @@ "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", "@backstage/dev-utils": "workspace:^", "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", "@types/parse-link-header": "^2.0.1", - "cross-fetch": "^4.0.0", "msw": "^1.2.3" }, "files": [ diff --git a/plugins/nomad-backend/CHANGELOG.md b/plugins/nomad-backend/CHANGELOG.md index 1ae3d6c002..786da63c37 100644 --- a/plugins/nomad-backend/CHANGELOG.md +++ b/plugins/nomad-backend/CHANGELOG.md @@ -1,5 +1,105 @@ # @backstage/plugin-nomad-backend +## 0.1.11 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.1.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + +## 0.1.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/errors@1.2.3 + +## 0.1.11-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.1.10 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.1.10-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.1.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.1.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.1.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.1.9 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + ## 0.1.9-next.2 ### Patch Changes diff --git a/plugins/nomad-backend/package.json b/plugins/nomad-backend/package.json index 0e87e15999..d206b12398 100644 --- a/plugins/nomad-backend/package.json +++ b/plugins/nomad-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-nomad-backend", - "version": "0.1.9-next.2", + "version": "0.1.11", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -42,7 +42,6 @@ "devDependencies": { "@backstage/cli": "workspace:^", "@types/supertest": "^2.0.8", - "msw": "^1.0.0", "supertest": "^6.2.4" }, "files": [ diff --git a/plugins/nomad/CHANGELOG.md b/plugins/nomad/CHANGELOG.md index b16c1f918a..2640dca7bc 100644 --- a/plugins/nomad/CHANGELOG.md +++ b/plugins/nomad/CHANGELOG.md @@ -1,5 +1,119 @@ # @backstage/plugin-nomad +## 0.1.10 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## 0.1.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.1.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + +## 0.1.10-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + +## 0.1.9 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + +## 0.1.9-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## 0.1.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## 0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0-next.0 + +## 0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + +## 0.1.7 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + ## 0.1.7-next.2 ### Patch Changes diff --git a/plugins/nomad/package.json b/plugins/nomad/package.json index 9b174ebb7d..90df893a93 100644 --- a/plugins/nomad/package.json +++ b/plugins/nomad/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-nomad", - "version": "0.1.7-next.2", + "version": "0.1.10", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,14 +30,11 @@ }, "dependencies": { "@backstage/catalog-model": "workspace:^", - "@backstage/config": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.9.13", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "^4.0.0-alpha.60", "@types/react": "^16.13.1 || ^17.0.0", "luxon": "^3.3.0", "react-use": "^17.2.4" @@ -49,14 +46,10 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", "@backstage/dev-utils": "workspace:^", - "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "cross-fetch": "^4.0.0", - "msw": "^1.0.0" + "cross-fetch": "^4.0.0" }, "files": [ "dist" diff --git a/plugins/octopus-deploy/CHANGELOG.md b/plugins/octopus-deploy/CHANGELOG.md index 3ec6f12e74..2acdc81710 100644 --- a/plugins/octopus-deploy/CHANGELOG.md +++ b/plugins/octopus-deploy/CHANGELOG.md @@ -1,5 +1,114 @@ # @backstage/plugin-octopus-deploy +## 0.2.11 + +### Patch Changes + +- 7d96ba8: added install path and fixed import on plugin-octopus-deploy +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## 0.2.11-next.2 + +### Patch Changes + +- 7d96ba8: added install path and fixed import on plugin-octopus-deploy +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.2.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + +## 0.2.11-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + +## 0.2.10 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + +## 0.2.10-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## 0.2.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## 0.2.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## 0.2.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + +## 0.2.8 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4d2f72c572: Added Deep link into Octopus Deploy project from the Release Table. +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + ## 0.2.8-next.2 ### Patch Changes diff --git a/plugins/octopus-deploy/README.md b/plugins/octopus-deploy/README.md index e80bbf0fcd..3699b76678 100644 --- a/plugins/octopus-deploy/README.md +++ b/plugins/octopus-deploy/README.md @@ -8,6 +8,17 @@ Welcome to the octopus-deploy plugin! ## Getting started +### Installing + +To get started, first install the plugin with the following command: + +```bash +# From your Backstage root directory +yarn add --cwd packages/app @backstage/plugin-octopus-deploy +``` + +### Setup + This plugin (currently) uses the Backstage proxy to securely communicate with the Octopus Deploy API. To use it, you will need to generate an [API Key](https://octopus.com/docs/octopus-rest-api/how-to-create-an-api-key) within Octopus Deploy. @@ -23,12 +34,19 @@ proxy: X-Octopus-ApiKey: ${OCTOPUS_API_KEY} ``` +Optionally, also add the following section to your app-config.yaml if you wish to enable linking to the Project Release page in the Octopus Deploy UI from the footer of the Backstage Release Table. Typically this will be the server URL above without the /api postfix. + +``` +octopusdeploy: + webBaseUrl: "" +``` + 2. Add the following to `EntityPage.tsx` to display Octopus Releases ``` // In packages/app/src/components/catalog/EntityPage.tsx import { - isOctopusDeployAvailable + isOctopusDeployAvailable, EntityOctopusDeployContent } from '@backstage/plugin-octopus-deploy'; diff --git a/plugins/octopus-deploy/api-report.md b/plugins/octopus-deploy/api-report.md index 3d65e40c64..094cc0a7b0 100644 --- a/plugins/octopus-deploy/api-report.md +++ b/plugins/octopus-deploy/api-report.md @@ -7,6 +7,7 @@ import { ApiRef } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/core-plugin-api'; +import { ConfigApi } from '@backstage/core-plugin-api'; import { DiscoveryApi } from '@backstage/core-plugin-api'; import { Entity } from '@backstage/catalog-model'; import { FetchApi } from '@backstage/core-plugin-api'; @@ -25,6 +26,10 @@ export const OCTOPUS_DEPLOY_PROJECT_ID_ANNOTATION = 'octopus.com/project-id'; // @public (undocumented) export interface OctopusDeployApi { + // (undocumented) + getConfig(): Promise; + // (undocumented) + getProjectInfo(projectReference: ProjectReference): Promise; // (undocumented) getReleaseProgression(opts: { projectReference: ProjectReference; @@ -38,11 +43,16 @@ export const octopusDeployApiRef: ApiRef; // @public (undocumented) export class OctopusDeployClient implements OctopusDeployApi { constructor(options: { + configApi: ConfigApi; discoveryApi: DiscoveryApi; fetchApi: FetchApi; proxyPathBase?: string; }); // (undocumented) + getConfig(): Promise; + // (undocumented) + getProjectInfo(projectReference: ProjectReference): Promise; + // (undocumented) getReleaseProgression(opts: { projectReference: ProjectReference; releaseHistoryCount: number; @@ -63,12 +73,30 @@ export type OctopusEnvironment = { Name: string; }; +// @public (undocumented) +export type OctopusLinks = { + Self: string; + Web: string; +}; + +// @public (undocumented) +export type OctopusPluginConfig = { + WebUiBaseUrl: string; +}; + // @public (undocumented) export type OctopusProgression = { Environments: OctopusEnvironment[]; Releases: OctopusReleaseProgression[]; }; +// @public (undocumented) +export type OctopusProject = { + Name: string; + Slug: string; + Links: OctopusLinks; +}; + // @public (undocumented) export type OctopusRelease = { Id: string; diff --git a/plugins/octopus-deploy/config.d.ts b/plugins/octopus-deploy/config.d.ts new file mode 100644 index 0000000000..81d14f2921 --- /dev/null +++ b/plugins/octopus-deploy/config.d.ts @@ -0,0 +1,24 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export interface Config { + octopusdeploy?: { + /** + * Frontend Web UI Base URL for deep links to UI + * @visibility frontend + */ + webBaseUrl?: string; + }; +} diff --git a/plugins/octopus-deploy/package.json b/plugins/octopus-deploy/package.json index f71ee497ed..03dd65d5e8 100644 --- a/plugins/octopus-deploy/package.json +++ b/plugins/octopus-deploy/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-octopus-deploy", - "version": "0.2.8-next.2", + "version": "0.2.11", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,10 +33,7 @@ "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.9.13", - "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.61", "@types/react": "^16.13.1 || ^17.0.0", "react-use": "^17.2.4" }, @@ -47,16 +44,14 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", "@backstage/dev-utils": "workspace:^", - "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "msw": "^1.0.0" + "@testing-library/react": "^14.0.0" }, "files": [ - "dist" - ] + "dist", + "config.d.ts" + ], + "configSchema": "config.d.ts" } diff --git a/plugins/octopus-deploy/src/api/index.ts b/plugins/octopus-deploy/src/api/index.ts index 0364bed269..cb5d428308 100644 --- a/plugins/octopus-deploy/src/api/index.ts +++ b/plugins/octopus-deploy/src/api/index.ts @@ -17,6 +17,7 @@ import { createApiRef, DiscoveryApi, FetchApi, + ConfigApi, } from '@backstage/core-plugin-api'; import { ProjectReference } from '../utils/getAnnotationFromEntity'; @@ -48,6 +49,23 @@ export type OctopusRelease = { export type OctopusDeployment = { State: string; }; +/** @public */ +export type OctopusLinks = { + Self: string; + Web: string; +}; + +/** @public */ +export type OctopusProject = { + Name: string; + Slug: string; + Links: OctopusLinks; +}; + +/** @public */ +export type OctopusPluginConfig = { + WebUiBaseUrl: string; +}; /** @public */ export const octopusDeployApiRef = createApiRef({ @@ -55,6 +73,7 @@ export const octopusDeployApiRef = createApiRef({ }); const DEFAULT_PROXY_PATH_BASE = '/octopus-deploy'; +const WEB_UI_BASE_URL_CONFIG_KEY = 'octopusdeploy.webBaseUrl'; /** @public */ export interface OctopusDeployApi { @@ -62,19 +81,24 @@ export interface OctopusDeployApi { projectReference: ProjectReference; releaseHistoryCount: number; }): Promise; + getProjectInfo(projectReference: ProjectReference): Promise; + getConfig(): Promise; } /** @public */ export class OctopusDeployClient implements OctopusDeployApi { + private readonly configApi: ConfigApi; private readonly discoveryApi: DiscoveryApi; private readonly fetchApi: FetchApi; private readonly proxyPathBase: string; constructor(options: { + configApi: ConfigApi; discoveryApi: DiscoveryApi; fetchApi: FetchApi; proxyPathBase?: string; }) { + this.configApi = options.configApi; this.discoveryApi = options.discoveryApi; this.fetchApi = options.fetchApi; this.proxyPathBase = options.proxyPathBase ?? DEFAULT_PROXY_PATH_BASE; @@ -84,7 +108,7 @@ export class OctopusDeployClient implements OctopusDeployApi { projectReference: ProjectReference; releaseHistoryCount: number; }): Promise { - const url = await this.getApiUrl(opts); + const url = await this.getProgressionApiUrl(opts); const response = await this.fetchApi.fetch(url); @@ -107,24 +131,58 @@ export class OctopusDeployClient implements OctopusDeployApi { return responseJson; } - private async getApiUrl(opts: { + async getProjectInfo( + projectReference: ProjectReference, + ): Promise { + const url = await this.getProjectApiUrl(projectReference); + const response = await this.fetchApi.fetch(url); + + let responseJson; + + try { + responseJson = await response.json(); + } catch (e) { + responseJson = { releases: [] }; + } + + if (response.status !== 200) { + throw new Error( + `Error communicating with Octopus Deploy: ${ + responseJson?.error?.title || response.statusText + }`, + ); + } + + return responseJson; + } + + async getConfig(): Promise { + return { + WebUiBaseUrl: this.configApi.getString(WEB_UI_BASE_URL_CONFIG_KEY), + }; + } + + private async getProgressionApiUrl(opts: { projectReference: ProjectReference; releaseHistoryCount: number; }) { - const proxyUrl = await this.discoveryApi.getBaseUrl('proxy'); const queryParameters = new URLSearchParams({ releaseHistoryCount: opts.releaseHistoryCount.toString(), }); - if (opts.projectReference.spaceId !== undefined) { - return `${proxyUrl}${this.proxyPathBase}/${encodeURIComponent( - opts.projectReference.spaceId, - )}/projects/${encodeURIComponent( - opts.projectReference.projectId, - )}/progression?${queryParameters}`; - } + const projectUrl = await this.getProjectApiUrl(opts.projectReference); + + return `${projectUrl}/progression?${queryParameters}`; + } + + private async getProjectApiUrl(projectReference: ProjectReference) { + const proxyUrl = await this.discoveryApi.getBaseUrl('proxy'); + if (projectReference.spaceId !== undefined) + return `${proxyUrl}${this.proxyPathBase}/${encodeURIComponent( + projectReference.spaceId, + )}/projects/${encodeURIComponent(projectReference.projectId)}`; return `${proxyUrl}${this.proxyPathBase}/projects/${encodeURIComponent( - opts.projectReference.projectId, - )}/progression?${queryParameters}`; + projectReference.projectId, + )}`; } } diff --git a/plugins/octopus-deploy/src/components/EntityPageOctopusDeploy/EntityPageOctopusDeploy.tsx b/plugins/octopus-deploy/src/components/EntityPageOctopusDeploy/EntityPageOctopusDeploy.tsx index 21080cb408..d9352a414a 100644 --- a/plugins/octopus-deploy/src/components/EntityPageOctopusDeploy/EntityPageOctopusDeploy.tsx +++ b/plugins/octopus-deploy/src/components/EntityPageOctopusDeploy/EntityPageOctopusDeploy.tsx @@ -13,7 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { useConfig } from '../../hooks/useConfig'; import { useEntity } from '@backstage/plugin-catalog-react'; +import { useProject } from '../../hooks/useProject'; import { useReleases } from '../../hooks/useReleases'; import { getProjectReferenceAnnotationFromEntity } from '../../utils/getAnnotationFromEntity'; import React from 'react'; @@ -30,12 +32,22 @@ export const EntityPageOctopusDeploy = (props: { defaultLimit?: number }) => { projectReference.spaceId, ); + const { + project, + loading: projectLoading, + error: projectError, + } = useProject(projectReference.projectId, projectReference.spaceId); + + const { config, loading: configLoading, error: configError } = useConfig(); + return ( ); }; diff --git a/plugins/octopus-deploy/src/components/ReleaseTable/ReleaseTable.tsx b/plugins/octopus-deploy/src/components/ReleaseTable/ReleaseTable.tsx index bc185546b1..b61b533667 100644 --- a/plugins/octopus-deploy/src/components/ReleaseTable/ReleaseTable.tsx +++ b/plugins/octopus-deploy/src/components/ReleaseTable/ReleaseTable.tsx @@ -14,10 +14,17 @@ * limitations under the License. */ import { Box, Typography } from '@material-ui/core'; -import { OctopusEnvironment, OctopusReleaseProgression } from '../../api'; +import { + OctopusEnvironment, + OctopusProject, + OctopusReleaseProgression, + OctopusPluginConfig, +} from '../../api'; import React from 'react'; import { + BottomLink, + BottomLinkProps, ResponseErrorPanel, StatusAborted, StatusError, @@ -33,6 +40,8 @@ import { OctopusDeployIcon } from '../OctopusDeployIcon'; type ReleaseTableProps = { environments?: OctopusEnvironment[]; releases?: OctopusReleaseProgression[]; + project?: OctopusProject; + config?: OctopusPluginConfig; loading: boolean; error?: Error; }; @@ -93,6 +102,8 @@ export const getDeploymentStatusComponent = (state: string | undefined) => { export const ReleaseTable = ({ environments, releases, + project, + config, loading, error, }: ReleaseTableProps) => { @@ -130,24 +141,39 @@ export const ReleaseTable = ({ })) ?? []), ]; + const deepLink: BottomLinkProps | null = + project?.Links?.Web && config?.WebUiBaseUrl + ? { + link: `${config.WebUiBaseUrl}${project.Links.Web}`, + title: 'Go to project', + onClick: e => { + e.preventDefault(); + window.open(`${config?.WebUiBaseUrl}${project?.Links.Web}`); + }, + } + : null; + return ( -
    - - - Octopus Deploy - Releases ({releases ? releases.length : 0}) - - } - data={releases ?? []} - /> + +
    + + + Octopus Deploy - Releases ({releases ? releases.length : 0}) + + } + data={releases ?? []} + /> + {deepLink !== null && } + ); }; diff --git a/plugins/octopus-deploy/src/hooks/useConfig.ts b/plugins/octopus-deploy/src/hooks/useConfig.ts new file mode 100644 index 0000000000..7218bf1a2c --- /dev/null +++ b/plugins/octopus-deploy/src/hooks/useConfig.ts @@ -0,0 +1,36 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { useApi } from '@backstage/core-plugin-api'; +import useAsync from 'react-use/lib/useAsync'; +import { octopusDeployApiRef, OctopusPluginConfig } from '../api'; + +export function useConfig(): { + config?: OctopusPluginConfig; + loading: boolean; + error?: Error; +} { + const api = useApi(octopusDeployApiRef); + + const { value, loading, error } = useAsync(() => { + return api.getConfig(); + }, [api]); + + return { + config: value, + loading, + error, + }; +} diff --git a/plugins/octopus-deploy/src/hooks/useProject.ts b/plugins/octopus-deploy/src/hooks/useProject.ts new file mode 100644 index 0000000000..f4178fd3e0 --- /dev/null +++ b/plugins/octopus-deploy/src/hooks/useProject.ts @@ -0,0 +1,39 @@ +/* + * 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 { useApi } from '@backstage/core-plugin-api'; +import useAsync from 'react-use/lib/useAsync'; +import { octopusDeployApiRef, OctopusProject } from '../api'; + +export function useProject( + projectId: string, + spaceId?: string, +): { + project?: OctopusProject; + loading: boolean; + error?: Error; +} { + const api = useApi(octopusDeployApiRef); + + const { value, loading, error } = useAsync(() => { + return api.getProjectInfo({ projectId: projectId, spaceId: spaceId }); + }, [api, projectId, spaceId]); + + return { + project: value, + loading, + error, + }; +} diff --git a/plugins/octopus-deploy/src/plugin.ts b/plugins/octopus-deploy/src/plugin.ts index 9365f93bdb..39b2b49fb7 100644 --- a/plugins/octopus-deploy/src/plugin.ts +++ b/plugins/octopus-deploy/src/plugin.ts @@ -24,6 +24,7 @@ import { createRoutableExtension, discoveryApiRef, fetchApiRef, + configApiRef, } from '@backstage/core-plugin-api'; import { Entity } from '@backstage/catalog-model'; @@ -38,9 +39,13 @@ export const octopusDeployPlugin = createPlugin({ apis: [ createApiFactory({ api: octopusDeployApiRef, - deps: { discoveryApi: discoveryApiRef, fetchApi: fetchApiRef }, - factory: ({ discoveryApi, fetchApi }) => - new OctopusDeployClient({ discoveryApi, fetchApi }), + deps: { + discoveryApi: discoveryApiRef, + fetchApi: fetchApiRef, + configApi: configApiRef, + }, + factory: ({ discoveryApi, fetchApi, configApi }) => + new OctopusDeployClient({ discoveryApi, fetchApi, configApi }), }), ], }); diff --git a/plugins/opencost/CHANGELOG.md b/plugins/opencost/CHANGELOG.md index f2520046c8..16d73b63d2 100644 --- a/plugins/opencost/CHANGELOG.md +++ b/plugins/opencost/CHANGELOG.md @@ -1,5 +1,87 @@ # @backstage/plugin-opencost +## 0.2.4 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + +## 0.2.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + +## 0.2.4-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/core-plugin-api@1.8.1 + +## 0.2.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + +## 0.2.3-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + +## 0.2.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## 0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.0 + +## 0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + +## 0.2.2 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- Updated dependencies + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + ## 0.2.2-next.2 ### Patch Changes diff --git a/plugins/opencost/package.json b/plugins/opencost/package.json index de787343dc..1e1b4fb674 100644 --- a/plugins/opencost/package.json +++ b/plugins/opencost/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-opencost", - "version": "0.2.2-next.2", + "version": "0.2.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -25,18 +25,15 @@ "dependencies": { "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", - "@backstage/theme": "workspace:^", "@date-io/luxon": "1.x", "@material-ui/core": "^4.9.13", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "^4.0.0-alpha.60", "@material-ui/pickers": "^3.3.10", "@material-ui/styles": "^4.11.5", "@types/react": "^16.13.1 || ^17.0.0", "axios": "^1.4.0", "date-fns": "^2.30.0", "lodash": "^4.17.21", - "react-use": "^17.2.4", "recharts": "^2.5.0" }, "peerDependencies": { @@ -45,14 +42,8 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", "@backstage/dev-utils": "workspace:^", - "@backstage/test-utils": "workspace:^", - "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "cross-fetch": "^4.0.0", - "msw": "^1.0.0" + "@testing-library/jest-dom": "^6.0.0" }, "files": [ "dist", diff --git a/plugins/org-react/CHANGELOG.md b/plugins/org-react/CHANGELOG.md index 0ca09d2952..b56074f2cd 100644 --- a/plugins/org-react/CHANGELOG.md +++ b/plugins/org-react/CHANGELOG.md @@ -1,5 +1,121 @@ # @backstage/plugin-org-react +## 0.1.18 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## 0.1.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + +## 0.1.18-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + +## 0.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-client@1.5.0 + - @backstage/catalog-model@1.4.3 + +## 0.1.17-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## 0.1.17-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## 0.1.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## 0.1.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + +## 0.1.15 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 62b5922916: Internal theme type updates +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + ## 0.1.15-next.2 ### Patch Changes diff --git a/plugins/org-react/package.json b/plugins/org-react/package.json index 9551c415eb..07ae6b82b0 100644 --- a/plugins/org-react/package.json +++ b/plugins/org-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-org-react", - "version": "0.1.15-next.2", + "version": "0.1.18", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -37,7 +37,6 @@ "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", @@ -52,13 +51,11 @@ "devDependencies": { "@backstage/cli": "workspace:^", "@backstage/core-app-api": "workspace:^", - "@backstage/dev-utils": "workspace:^", "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "msw": "^1.0.0" + "@testing-library/user-event": "^14.0.0" }, "files": [ "dist" diff --git a/plugins/org/CHANGELOG.md b/plugins/org/CHANGELOG.md index 706a144c53..c36bf88714 100644 --- a/plugins/org/CHANGELOG.md +++ b/plugins/org/CHANGELOG.md @@ -1,5 +1,121 @@ # @backstage/plugin-org +## 0.6.19 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.20 + +## 0.6.19-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.6.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.19 + +## 0.6.19-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-common@1.0.19 + +## 0.6.18 + +### Patch Changes + +- 59c24b9: Fix issue where members inside of `` would be rendered as squished when the card itself was shrunk down. +- 3a65d9c: Support member list scrollable when parent has specified height +- 4785d05: Add permission check to catalog create and refresh button +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.19 + +## 0.6.18-next.3 + +### Patch Changes + +- 59c24b9: Fix issue where members inside of `` would be rendered as squished when the card itself was shrunk down. +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## 0.6.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## 0.6.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## 0.6.18-next.0 + +### Patch Changes + +- 3a65d9c4d7: Support member list scrollable when parent has specified height +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + +## 0.6.16 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 62b5922916: Internal theme type updates +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + ## 0.6.16-next.2 ### Patch Changes diff --git a/plugins/org/package.json b/plugins/org/package.json index 08213e43de..c4035a8498 100644 --- a/plugins/org/package.json +++ b/plugins/org/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-org", "description": "A Backstage plugin that helps you create entity pages for your organization", - "version": "0.6.16-next.2", + "version": "0.6.19", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,8 +33,8 @@ "@backstage/catalog-model": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", + "@backstage/plugin-catalog-common": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", @@ -56,14 +56,14 @@ "@backstage/core-app-api": "workspace:^", "@backstage/dev-utils": "workspace:^", "@backstage/plugin-catalog": "workspace:^", + "@backstage/plugin-permission-common": "workspace:^", "@backstage/plugin-permission-react": "workspace:^", "@backstage/test-utils": "workspace:^", "@backstage/types": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "msw": "^1.0.0" + "@testing-library/user-event": "^14.0.0" }, "files": [ "dist" diff --git a/plugins/org/src/__testUtils__/catalogMocks.ts b/plugins/org/src/__testUtils__/catalogMocks.ts index b14856e345..a97caa9971 100644 --- a/plugins/org/src/__testUtils__/catalogMocks.ts +++ b/plugins/org/src/__testUtils__/catalogMocks.ts @@ -208,8 +208,7 @@ export const groupAUserOne: Entity = { profile: { displayName: 'Group A User One', email: 'group-a-user-one@testing.email', - picture: - 'https://avatars.dicebear.com/api/avataaars/breanna-davison@example.com.svg', + picture: 'https://api.dicebear.com/7.x/avataaars/svg?seed=Buster', }, }, }; @@ -224,8 +223,7 @@ export const groupBUserOne: Entity = { profile: { displayName: 'Group B User One', email: 'group-b-user-one@testing.email', - picture: - 'https://avatars.dicebear.com/api/avataaars/breanna-davison@example.com.svg', + picture: 'https://api.dicebear.com/7.x/avataaars/svg?seed=Buster', }, }, }; @@ -240,8 +238,7 @@ export const groupDUserOne: Entity = { profile: { displayName: 'Group D User One', email: 'group-d-user-one@testing.email', - picture: - 'https://avatars.dicebear.com/api/avataaars/breanna-davison@example.com.svg', + picture: 'https://api.dicebear.com/7.x/avataaars/svg?seed=Buster', }, }, }; @@ -256,8 +253,7 @@ export const groupEUserOne: Entity = { profile: { displayName: 'Group E User One', email: 'group-e-user-one@testing.email', - picture: - 'https://avatars.dicebear.com/api/avataaars/breanna-davison@example.com.svg', + picture: 'https://api.dicebear.com/7.x/avataaars/svg?seed=Buster', }, }, }; @@ -272,8 +268,7 @@ export const groupFUserOne: Entity = { profile: { displayName: 'Group F User One', email: 'group-f-user-one@testing.email', - picture: - 'https://avatars.dicebear.com/api/avataaars/breanna-davison@example.com.svg', + picture: 'https://api.dicebear.com/7.x/avataaars/svg?seed=Buster', }, }, }; @@ -288,8 +283,7 @@ export const duplicatedUser: Entity = { profile: { displayName: 'Duplicated User', email: 'duplicated-user@testing.email', - picture: - 'https://avatars.dicebear.com/api/avataaars/breanna-davison@example.com.svg', + picture: 'https://api.dicebear.com/7.x/avataaars/svg?seed=Buster', }, }, }; diff --git a/plugins/org/src/components/Cards/Group/GroupProfile/GroupProfileCard.stories.tsx b/plugins/org/src/components/Cards/Group/GroupProfile/GroupProfileCard.stories.tsx index e10d6322e0..17f285c039 100644 --- a/plugins/org/src/components/Cards/Group/GroupProfile/GroupProfileCard.stories.tsx +++ b/plugins/org/src/components/Cards/Group/GroupProfile/GroupProfileCard.stories.tsx @@ -21,6 +21,8 @@ import { EntityProvider, entityRouteRef, } from '@backstage/plugin-catalog-react'; +import { permissionApiRef } from '@backstage/plugin-permission-react'; +import { AuthorizeResult } from '@backstage/plugin-permission-common'; import { TestApiProvider, wrapInTestApp } from '@backstage/test-utils'; import { Grid } from '@material-ui/core'; import React, { ComponentType, PropsWithChildren } from 'react'; @@ -48,7 +50,7 @@ const defaultEntity: GroupEntity = { displayName: 'Team A', email: 'team-a@example.com', picture: - 'https://avatars.dicebear.com/api/identicon/team-a@example.com.svg?background=%23fff&margin=25', + 'https://api.dicebear.com/7.x/identicon/svg?seed=Fluffy&backgroundType=solid,gradientLinear&backgroundColor=ffd5dc,b6e3f4', }, type: 'group', children: [], @@ -60,6 +62,10 @@ const catalogApi: Partial = { async refreshEntity() {}, }; +const permissionApi: typeof permissionApiRef.T = { + authorize: async () => ({ result: AuthorizeResult.ALLOW }), +}; + export const Default = () => ( @@ -76,7 +82,12 @@ export default { decorators: [ (Story: ComponentType>) => wrapInTestApp( - + , { @@ -111,7 +122,7 @@ const extraDetailsEntity: GroupEntity = { displayName: 'Team A', email: 'team-a@example.com', picture: - 'https://avatars.dicebear.com/api/identicon/team-a@example.com.svg?background=%23fff&margin=25', + 'https://api.dicebear.com/7.x/identicon/svg?seed=Fluffy&backgroundType=solid,gradientLinear&backgroundColor=ffd5dc,b6e3f4', }, type: 'group', children: [], @@ -141,7 +152,7 @@ const groupWithTitle: GroupEntity = { profile: { email: 'team-a@example.com', picture: - 'https://avatars.dicebear.com/api/identicon/team-a@example.com.svg?background=%23fff&margin=25', + 'https://api.dicebear.com/7.x/identicon/svg?seed=Fluffy&backgroundType=solid,gradientLinear&backgroundColor=ffd5dc,b6e3f4', }, type: 'group', children: [], diff --git a/plugins/org/src/components/Cards/Group/GroupProfile/GroupProfileCard.tsx b/plugins/org/src/components/Cards/Group/GroupProfile/GroupProfileCard.tsx index 76527362ff..33c6ee137a 100644 --- a/plugins/org/src/components/Cards/Group/GroupProfile/GroupProfileCard.tsx +++ b/plugins/org/src/components/Cards/Group/GroupProfile/GroupProfileCard.tsx @@ -54,6 +54,8 @@ import EditIcon from '@material-ui/icons/Edit'; import EmailIcon from '@material-ui/icons/Email'; import GroupIcon from '@material-ui/icons/Group'; import { LinksGroup } from '../../Meta'; +import { useEntityPermission } from '@backstage/plugin-catalog-react/alpha'; +import { catalogEntityRefreshPermission } from '@backstage/plugin-catalog-common/alpha'; const CardTitle = (props: { title: string }) => ( @@ -70,6 +72,9 @@ export const GroupProfileCard = (props: { const catalogApi = useApi(catalogApiRef); const alertApi = useApi(alertApiRef); const { entity: group } = useEntity(); + const { allowed: canRefresh } = useEntityPermission( + catalogEntityRefreshPermission, + ); const refreshEntity = useCallback(async () => { await catalogApi.refreshEntity(stringifyEntityRef(group)); @@ -127,7 +132,7 @@ export const GroupProfileCard = (props: { variant={props.variant} action={ <> - {allowRefresh && ( + {allowRefresh && canRefresh && ( = { }, }; +const rootRouteRef = catalogPlugin.routes.catalogIndex; + describe('MemberTab Test', () => { const groupEntity: GroupEntity = { apiVersion: 'backstage.io/v1alpha1', @@ -122,6 +124,7 @@ describe('MemberTab Test', () => { { mountedRoutes: { '/catalog/:namespace/:kind/:name': entityRouteRef, + '/catalog': rootRouteRef, }, }, ); @@ -151,6 +154,7 @@ describe('MemberTab Test', () => { { mountedRoutes: { '/catalog/:namespace/:kind/:name': entityRouteRef, + '/catalog': rootRouteRef, }, }, ); @@ -179,6 +183,7 @@ describe('MemberTab Test', () => { { mountedRoutes: { '/catalog/:namespace/:kind/:name': entityRouteRef, + '/catalog': rootRouteRef, }, }, ); @@ -206,6 +211,7 @@ describe('MemberTab Test', () => { { mountedRoutes: { '/catalog/:namespace/:kind/:name': entityRouteRef, + '/catalog': rootRouteRef, }, }, ); @@ -231,6 +237,7 @@ describe('MemberTab Test', () => { { mountedRoutes: { '/catalog/:namespace/:kind/:name': entityRouteRef, + '/catalog': rootRouteRef, }, }, ); @@ -265,6 +272,7 @@ describe('MemberTab Test', () => { { mountedRoutes: { '/catalog/:namespace/:kind/:name': entityRouteRef, + '/catalog': rootRouteRef, }, }, ); @@ -299,6 +307,7 @@ describe('MemberTab Test', () => { { mountedRoutes: { '/catalog/:namespace/:kind/:name': entityRouteRef, + '/catalog': rootRouteRef, }, }, ); diff --git a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx index 3716af5522..8967e7cdd7 100644 --- a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx +++ b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx @@ -73,52 +73,66 @@ const MemberComponent = (props: { member: UserEntity }) => { const displayName = profile?.displayName ?? metaName; return ( - - + + + - - - - - - {profile?.email && ( - - - - )} - {description && ( - {description} - )} - + + + + {profile?.email && ( + + + + )} + {description && ( + {description} + )} - + ); }; +const useListStyles = makeStyles(theme => ({ + root: { + height: '100%', + }, + cardContent: { + overflow: 'auto', + }, + memberList: { + display: 'grid', + gap: theme.spacing(1.5), + gridTemplateColumns: `repeat(auto-fit, minmax(auto, ${theme.spacing( + 34, + )}px))`, + }, +})); + /** @public */ export const MembersListCard = (props: { memberDisplayTitle?: string; @@ -130,6 +144,7 @@ export const MembersListCard = (props: { pageSize = 50, showAggregateMembersToggle, } = props; + const classes = useListStyles(); const { entity: groupEntity } = useEntity(); const { @@ -209,14 +224,35 @@ export const MembersListCard = (props: { /> ); + let memberList: React.JSX.Element; + if (members && members.length > 0) { + memberList = ( + + {members.slice(pageSize * (page - 1), pageSize * page).map(member => ( + + ))} + + ); + } else { + memberList = ( + + + This group has no {memberDisplayTitle.toLocaleLowerCase()}. + + + ); + } + return ( - + {showAggregateMembersToggle && ( <> @@ -235,21 +271,7 @@ export const MembersListCard = (props: { {showAggregateMembers && loadingDescendantMembers ? ( ) : ( - - {members && members.length > 0 ? ( - members - .slice(pageSize * (page - 1), pageSize * page) - .map(member => ( - - )) - ) : ( - - - This group has no {memberDisplayTitle.toLocaleLowerCase()}. - - - )} - + memberList )} diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.stories.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.stories.tsx index 390fff12a4..1f50dc33d8 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.stories.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.stories.tsx @@ -44,7 +44,7 @@ const defaultEntity: GroupEntity = { displayName: 'Team A', email: 'team-a@example.com', picture: - 'https://avatars.dicebear.com/api/identicon/team-a@example.com.svg?background=%23fff&margin=25', + 'https://api.dicebear.com/7.x/identicon/svg?seed=Fluffy&backgroundType=solid,gradientLinear&backgroundColor=ffd5dc,b6e3f4', }, type: 'group', children: [], diff --git a/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.stories.tsx b/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.stories.tsx index 02598691e0..6326a043bc 100644 --- a/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.stories.tsx +++ b/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.stories.tsx @@ -45,8 +45,6 @@ const defaultEntity: UserEntity = { profile: { displayName: 'Guest User', email: 'guest@example.com', - picture: - 'https://avatars.dicebear.com/api/avataaars/guest@example.com.svg?background=%23fff', }, memberOf: ['team-a'], }, @@ -125,8 +123,6 @@ const extraDetailsEntity: UserEntity = { profile: { displayName: 'Guest User', email: 'guest@example.com', - picture: - 'https://avatars.dicebear.com/api/avataaars/guest@example.com.svg?background=%23fff', }, memberOf: ['team-a'], }, diff --git a/plugins/pagerduty/CHANGELOG.md b/plugins/pagerduty/CHANGELOG.md index 6b9620a151..8e48fcf210 100644 --- a/plugins/pagerduty/CHANGELOG.md +++ b/plugins/pagerduty/CHANGELOG.md @@ -1,5 +1,138 @@ # @backstage/plugin-pagerduty +## 0.7.1 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-home-react@0.1.7 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.7.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-home-react@0.1.7-next.2 + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.7.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/plugin-home-react@0.1.7-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.7.1-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/plugin-home-react@0.1.7-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + +## 0.7.0 + +### Minor Changes + +- 5fca16f: This package has been deprecated, consider using [@pagerduty/backstage-plugin](https://github.com/pagerduty/backstage-plugin) instead. + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/plugin-home-react@0.1.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.7.0-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-home-react@0.1.6-next.3 + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## 0.7.0-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-home-react@0.1.6-next.2 + +## 0.7.0-next.1 + +### Minor Changes + +- 5fca16fdf6: This package has been deprecated, consider using [@pagerduty/backstage-plugin](https://github.com/pagerduty/backstage-plugin) instead. + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-home-react@0.1.6-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## 0.6.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/plugin-home-react@0.1.6-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.6.7 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-home-react@0.1.5 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + ## 0.6.7-next.2 ### Patch Changes diff --git a/plugins/pagerduty/README.md b/plugins/pagerduty/README.md index bf748439c9..c1079004e3 100644 --- a/plugins/pagerduty/README.md +++ b/plugins/pagerduty/README.md @@ -1,217 +1,3 @@ # PagerDuty + Backstage Integration Benefits -- Display relevant PagerDuty information about an entity within Backstage, such as the escalation policy, if there are any active incidents, and recent changes -- Trigger an incident to the currently on-call responder(s) for a service - -## How it Works - -- The Backstage PagerDuty plugin allows PagerDuty information about a Backstage entity to be displayed within Backstage. This includes active incidents, recent change events, as well as the current on-call responders' names, email addresses, and links to their profiles in PagerDuty. -- Incidents can be manually triggered via the plugin with a user-provided description, which will in turn notify the current on-call responders (Alternatively, the plugin can be configured with an optional `readOnly` property to suppress the ability to trigger incidents from the plugin). - - _Note: This feature is only available when providing the `pagerduty.com/integration-key` annotation_ -- Change events will be displayed in a separate tab. If the change event payload has additional links the first link only will be rendered. - -## Requirements - -- Setup of the PagerDuty plugin for Backstage requires a PagerDuty Admin role in order to generate the necessary authorizations, such as the API token. If you do not have this role, please reach out to an Admin or Account Owner within your organization to request configuration of this plugin. - -## Feature Overview - -### View any open incidents - -![PagerDuty plugin showing no incidents and the on-call rotation](doc/pd1.png) - -### Email link, and view contact information for staff on call - -![PagerDuty plugin showing on-call rotation contact information](doc/pd2.png) - -### Trigger an incident for a service - -![PagerDuty plugin popup modal for creating an incident](doc/pd3.png) - -![PagerDuty plugin showing an active incident](doc/pd4.png) - -## Support - -If you need help with this plugin, please reach out on the [Backstage Discord server](https://discord.gg/backstage-687207715902193673). - -## Integration Walk-through - -### In PagerDuty - -#### Integrating With a PagerDuty Service - -1. From the **Configuration** menu, select **Services**. -2. There are two ways to add an integration to a service: - - **If you are adding your integration to an existing service**: Click the **name** of the service you want to add the integration to. Then, select the **Integrations** tab and click the **New Integration** button. - - **If you are creating a new service for your integration**: Please read the documentation in section [Configuring Services and Integrations](https://support.pagerduty.com/docs/services-and-integrations#section-configuring-services-and-integrations) and follow the steps outlined in the [Create a New Service](https://support.pagerduty.com/docs/services-and-integrations#section-create-a-new-service) section, selecting **Backstage** as the **Integration Type** in step 4. Continue with the **In Backstage** section (below) once you have finished these steps. -3. Enter an **Integration Name** in the format `monitoring-tool-service-name` (e.g. `Backstage-Shopping-Cart`) and select **Backstage** from the Integration Type menu. -4. Click the **Add Integration** button to save your new integration. You will be redirected to the Integrations tab for your service. -5. An **Integration Key** will be generated on this screen. Keep this key saved in a safe place, as it will be used when you configure the integration with **Backstage** in the next section. - ![](https://pdpartner.s3.amazonaws.com/ig-template-copy-integration-key.png) - -### In Backstage - -#### Install the plugin - -The file paths mentioned in the following steps are relative to your app's root directory — for example, the directory created by following the [Getting Started](https://backstage.io/docs/getting-started/) guide and creating your app with `npx @backstage/create-app`. - -First, install the PagerDuty plugin via a CLI: - -```bash -# From your Backstage root directory -yarn add --cwd packages/app @backstage/plugin-pagerduty -``` - -Next, add the plugin to `EntityPage.tsx` in `packages/app/src/components/catalog` by adding the following code snippets. - -Add the following imports to the top of the file: - -```ts -import { - isPluginApplicableToEntity as isPagerDutyAvailable, - EntityPagerDutyCard, -} from '@backstage/plugin-pagerduty'; -``` - -Find `const overviewContent` in `EntityPage.tsx`, and add the following snippet inside the outermost `Grid` defined there, just before the closing `` tag: - -```ts - - - - - - - -``` - -When you're done, the `overviewContent` definition should look something like this: - -```ts -const overviewContent = ( - - ... - - - - - - - - -); -``` - -#### Configure the plugin - -First, [annotate](https://backstage.io/docs/features/software-catalog/descriptor-format#annotations-optional) the appropriate entity with the PagerDuty integration key in its `.yaml` configuration file: - -```yaml -annotations: - pagerduty.com/integration-key: [INTEGRATION_KEY] -``` - -#### The homepage component - -You may also add the component to the homepage of Backstage. Edit the `HomePage.tsx` file, import `PagerDutyHomepageCard` and add it to the home page. e.g. - -```typescript jsx -... -export const homePage = ( - - ... - - - ... - - - - -); -``` - -Next, provide the [API token](https://support.pagerduty.com/docs/generating-api-keys#generating-a-general-access-rest-api-key) that the client will use to make requests to the [PagerDuty API](https://developer.pagerduty.com/docs/rest-api-v2/rest-api/). - -Add the proxy configuration in `app-config.yaml`: - -```yaml -proxy: - ... - '/pagerduty': - target: https://api.pagerduty.com - headers: - Authorization: Token token=${PAGERDUTY_TOKEN} -``` - -Then, start the backend, passing the PagerDuty API token as an environment variable: - -```bash -$ PAGERDUTY_TOKEN='' yarn start -``` - -This will proxy the request by adding an `Authorization` header with the provided token. - -#### Optional configuration - -##### Annotating with Service ID - -If you want to integrate a PagerDuty service with Backstage but don't want to use an integration key, you can also [annotate](https://backstage.io/docs/features/software-catalog/descriptor-format#annotations-optional) the appropriate entity with a PagerDuty Service ID instead - -```yaml -annotations: - pagerduty.com/service-id: [SERVICE_ID] -``` - -This service ID can be found by navigating to a Service within PagerDuty and pulling the ID value out of the URL. - -1. From the **Configuration** menu within PagerDuty, select **Services**. -2. Click the **name** of the service you want to represent for your Entity. - -Your browser URL should now be located at `https://pagerduty.com/service-directory/[SERVICE_ID]`. - -_Note: When annotating with `pagerduty.com/service-id`, the feature to Create Incidents is not currently supported_ - -##### Custom Events URL - -If you want to override the default URL used for events, you can add it to `app-config.yaml`: - -```yaml -pagerDuty: - eventsBaseUrl: 'https://events.pagerduty.com/v2' -``` - -To suppress the rendering of the actionable incident-creation button, the `PagerDutyCard` can also be instantiated in `readOnly` mode: - -```ts - -``` - -**WARNING**: In current implementation, the PagerDuty plugin requires the `/pagerduty` proxy endpoint be exposed by the Backstage backend as an unprotected endpoint, in effect enabling PagerDuty API access using the configured `PAGERDUTY_TOKEN` for any user or process with access to the `/pagerduty` Backstage backend endpoint. If you regard this as problematic, consider using the plugin in `readOnly` mode (``) using the following proxy configuration: - -```yaml -proxy: - '/pagerduty': - target: https://api.pagerduty.com - headers: - Authorization: Token token=${PAGERDUTY_TOKEN} - # prohibit the `/pagerduty` proxy endpoint from servicing non-GET requests - allowedMethods: ['GET'] -``` - -## How to Uninstall - -1. Remove any configuration added in Backstage yaml files, such as the proxy configuration in `app-config.yaml` and the integration key in an entity's annotations. -2. Remove the added code snippets from `EntityPage.tsx` -3. Remove the plugin package: - -```bash -# From your Backstage root directory -yarn remove --cwd packages/app @backstage/plugin-pagerduty -``` - -4. [Delete the integration](https://support.pagerduty.com/docs/services-and-integrations#delete-an-integration-from-a-service) from the service in PagerDuty +This package has been deprecated, consider using [@pagerduty/backstage-plugin](https://github.com/pagerduty/backstage-plugin) instead. diff --git a/plugins/pagerduty/api-report.md b/plugins/pagerduty/api-report.md index db73259dd5..a96cab1af1 100644 --- a/plugins/pagerduty/api-report.md +++ b/plugins/pagerduty/api-report.md @@ -16,7 +16,7 @@ import { JSX as JSX_2 } from 'react'; import { default as React_2 } from 'react'; import { ReactNode } from 'react'; -// @public (undocumented) +// @public @deprecated (undocumented) export const EntityPagerDutyCard: ( props: EntityPagerDutyCardProps, ) => JSX_2.Element; @@ -27,7 +27,7 @@ export type EntityPagerDutyCardProps = { disableChangeEvents?: boolean; }; -// @public (undocumented) +// @public @deprecated (undocumented) export const HomePagePagerDutyCard: ( props: CardExtensionProps, ) => JSX_2.Element; @@ -138,7 +138,7 @@ export type PagerDutyClientApiDependencies = { fetchApi: FetchApi; }; -// @public (undocumented) +// @public @deprecated (undocumented) export type PagerDutyEntity = { integrationKey?: string; serviceId?: string; @@ -176,7 +176,7 @@ export type PagerDutyOnCallsResponse = { oncalls: PagerDutyOnCall[]; }; -// @public (undocumented) +// @public @deprecated (undocumented) const pagerDutyPlugin: BackstagePlugin<{}, {}>; export { pagerDutyPlugin }; export { pagerDutyPlugin as plugin }; diff --git a/plugins/pagerduty/package.json b/plugins/pagerduty/package.json index cbc5c1ed45..2526d7ca99 100644 --- a/plugins/pagerduty/package.json +++ b/plugins/pagerduty/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-pagerduty", - "description": "A Backstage plugin that integrates towards PagerDuty", - "version": "0.6.7-next.2", + "description": "This plugin has been deprecated, consider using [@pagerduty/backstage-plugin](https://github.com/pagerduty/backstage-plugin) instead.", + "version": "0.7.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -40,12 +40,10 @@ "@backstage/errors": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", "@backstage/plugin-home-react": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", "@types/react": "^16.13.1 || ^17.0.0", - "classnames": "^2.2.6", "luxon": "^3.0.0", "react-use": "^17.2.4" }, @@ -61,9 +59,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "msw": "^1.0.0" + "@testing-library/react": "^14.0.0" }, "files": [ "dist", diff --git a/plugins/pagerduty/src/components/ChangeEvents/ChangeEventListItem.tsx b/plugins/pagerduty/src/components/ChangeEvents/ChangeEventListItem.tsx index 7b531bf1de..8dc5bf1f33 100644 --- a/plugins/pagerduty/src/components/ChangeEvents/ChangeEventListItem.tsx +++ b/plugins/pagerduty/src/components/ChangeEvents/ChangeEventListItem.tsx @@ -28,9 +28,8 @@ import { import { DateTime, Duration } from 'luxon'; import { PagerDutyChangeEvent } from '../types'; import OpenInBrowserIcon from '@material-ui/icons/OpenInBrowser'; -import { BackstageTheme } from '@backstage/theme'; -const useStyles = makeStyles({ +const useStyles = makeStyles({ denseListIcon: { marginRight: 0, display: 'flex', diff --git a/plugins/pagerduty/src/components/Incident/IncidentListItem.tsx b/plugins/pagerduty/src/components/Incident/IncidentListItem.tsx index b23fcb8490..3ee92f1470 100644 --- a/plugins/pagerduty/src/components/Incident/IncidentListItem.tsx +++ b/plugins/pagerduty/src/components/Incident/IncidentListItem.tsx @@ -30,10 +30,9 @@ import Warning from '@material-ui/icons/Warning'; import { DateTime, Duration } from 'luxon'; import { PagerDutyIncident } from '../types'; import OpenInBrowserIcon from '@material-ui/icons/OpenInBrowser'; -import { BackstageTheme } from '@backstage/theme'; import { Link } from '@backstage/core-components'; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles(theme => ({ denseListIcon: { marginRight: 0, display: 'flex', diff --git a/plugins/pagerduty/src/components/TriggerButton/index.tsx b/plugins/pagerduty/src/components/TriggerButton/index.tsx index 1c12103d73..60adbd38c0 100644 --- a/plugins/pagerduty/src/components/TriggerButton/index.tsx +++ b/plugins/pagerduty/src/components/TriggerButton/index.tsx @@ -13,14 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import React, { useCallback, ReactNode, useState } from 'react'; import { makeStyles, Button } from '@material-ui/core'; -import { BackstageTheme } from '@backstage/theme'; - import { usePagerdutyEntity } from '../../hooks'; import { TriggerDialog } from '../TriggerDialog'; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles(theme => ({ buttonStyle: { backgroundColor: theme.palette.error.main, color: theme.palette.error.contrastText, diff --git a/plugins/pagerduty/src/plugin.ts b/plugins/pagerduty/src/plugin.ts index 59cc5cd8cc..4144eb5878 100644 --- a/plugins/pagerduty/src/plugin.ts +++ b/plugins/pagerduty/src/plugin.ts @@ -30,7 +30,10 @@ export const rootRouteRef = createRouteRef({ id: 'pagerduty', }); -/** @public */ +/** + * @public + * @deprecated This plugin will be removed in a future release. Please use \@pagerduty/backstage-plugin plugin instead (https://www.npmjs.com/package/\@pagerduty/backstage-plugin). + */ export const pagerDutyPlugin = createPlugin({ id: 'pagerduty', apis: [ @@ -47,7 +50,10 @@ export const pagerDutyPlugin = createPlugin({ ], }); -/** @public */ +/** + * @public + * @deprecated This plugin and it's cards will be removed in a future release. Please use \@pagerduty/backstage-plugin plugin instead (https://www.npmjs.com/package/\@pagerduty/backstage-plugin). + */ export const EntityPagerDutyCard = pagerDutyPlugin.provide( createComponentExtension({ name: 'EntityPagerDutyCard', @@ -60,7 +66,10 @@ export const EntityPagerDutyCard = pagerDutyPlugin.provide( }), ); -/** @public */ +/** + * @public + * @deprecated This plugin and it's cards will be removed in a future release. Please use \@pagerduty/backstage-plugin plugin instead (https://www.npmjs.com/package/\@pagerduty/backstage-plugin). + */ export const HomePagePagerDutyCard = pagerDutyPlugin.provide( createCardExtension({ name: 'HomePagePagerDutyCard', diff --git a/plugins/pagerduty/src/types.ts b/plugins/pagerduty/src/types.ts index 9f38b429ef..e026a6ffbe 100644 --- a/plugins/pagerduty/src/types.ts +++ b/plugins/pagerduty/src/types.ts @@ -14,7 +14,10 @@ * limitations under the License. */ -/** @public */ +/** + * @public + * @deprecated This plugin and it's types will be removed in a future release. Please use \@pagerduty/backstage-plugin plugin instead (https://www.npmjs.com/package/\@pagerduty/backstage-plugin). + */ export type PagerDutyEntity = { integrationKey?: string; serviceId?: string; diff --git a/plugins/periskop-backend/CHANGELOG.md b/plugins/periskop-backend/CHANGELOG.md index 6fc6dc094f..2a94efd57e 100644 --- a/plugins/periskop-backend/CHANGELOG.md +++ b/plugins/periskop-backend/CHANGELOG.md @@ -1,5 +1,97 @@ # @backstage/plugin-periskop-backend +## 0.2.7 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + +## 0.2.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + +## 0.2.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + +## 0.2.7-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/config@1.1.1 + +## 0.2.6 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + +## 0.2.6-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/config@1.1.1 + +## 0.2.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/config@1.1.1 + +## 0.2.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + +## 0.2.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + +## 0.2.5 + +### Patch Changes + +- 8613ba3928: Switched to using `"exports"` field for `/alpha` subpath export. +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/config@1.1.1 + ## 0.2.5-next.2 ### Patch Changes diff --git a/plugins/periskop-backend/alpha-api-report.md b/plugins/periskop-backend/api-report-alpha.md similarity index 100% rename from plugins/periskop-backend/alpha-api-report.md rename to plugins/periskop-backend/api-report-alpha.md diff --git a/plugins/periskop-backend/package.json b/plugins/periskop-backend/package.json index 545ac13a02..992e047346 100644 --- a/plugins/periskop-backend/package.json +++ b/plugins/periskop-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-periskop-backend", - "version": "0.2.5-next.2", + "version": "0.2.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -54,7 +54,6 @@ "devDependencies": { "@backstage/cli": "workspace:^", "@types/supertest": "^2.0.8", - "msw": "^1.0.0", "supertest": "^6.1.6" }, "files": [ diff --git a/plugins/periskop/CHANGELOG.md b/plugins/periskop/CHANGELOG.md index c15a85cc21..b29b672e96 100644 --- a/plugins/periskop/CHANGELOG.md +++ b/plugins/periskop/CHANGELOG.md @@ -1,5 +1,120 @@ # @backstage/plugin-periskop +## 0.1.27 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.1.27-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.1.27-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.1.27-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + +## 0.1.26 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.1.26-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## 0.1.26-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + +## 0.1.26-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## 0.1.26-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.1.24 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + ## 0.1.24-next.2 ### Patch Changes diff --git a/plugins/periskop/package.json b/plugins/periskop/package.json index 86063b596f..acb7a68241 100644 --- a/plugins/periskop/package.json +++ b/plugins/periskop/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-periskop", - "version": "0.1.24-next.2", + "version": "0.1.27", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,10 +34,6 @@ "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", - "@backstage/theme": "workspace:^", - "@material-ui/core": "^4.12.2", - "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.61", "@types/react": "^16.13.1 || ^17.0.0", "luxon": "^3.0.0", "react-use": "^17.2.4" @@ -49,15 +45,11 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", "@backstage/dev-utils": "workspace:^", - "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "@types/luxon": "^3.0.0", - "msw": "^1.0.0" + "@types/luxon": "^3.0.0" }, "files": [ "dist", diff --git a/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md b/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md index e9296041db..e5e4d93fa3 100644 --- a/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md +++ b/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md @@ -1,5 +1,114 @@ # @backstage/plugin-permission-backend-module-allow-all-policy +## 0.1.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/plugin-auth-node@0.4.3 + +## 0.1.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + - @backstage/plugin-permission-node@0.7.20-next.2 + +## 0.1.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/plugin-permission-node@0.7.20-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/plugin-permission-common@0.7.11 + +## 0.1.6-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/plugin-auth-node@0.4.3-next.0 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.20-next.0 + +## 0.1.5 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.19 + - @backstage/backend-plugin-api@0.6.8 + +## 0.1.5-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.3 + +## 0.1.5-next.2 + +### Patch Changes + +- cc4228e: Switched module ID to use kebab-case. +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.2 + +## 0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + +## 0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/plugin-permission-node@0.7.19-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/plugin-permission-common@0.7.10 + +## 0.1.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-auth-node@0.4.1 + - @backstage/plugin-permission-node@0.7.18 + ## 0.1.4-next.2 ### Patch Changes diff --git a/plugins/permission-backend-module-policy-allow-all/package.json b/plugins/permission-backend-module-policy-allow-all/package.json index ba4ea0911f..f03a5481d3 100644 --- a/plugins/permission-backend-module-policy-allow-all/package.json +++ b/plugins/permission-backend-module-policy-allow-all/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-permission-backend-module-allow-all-policy", "description": "Allow all policy backend module for the permission plugin.", - "version": "0.1.4-next.2", + "version": "0.1.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,7 +23,6 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/backend-common": "workspace:^", "@backstage/backend-plugin-api": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", "@backstage/plugin-permission-common": "workspace:^", diff --git a/plugins/permission-backend-module-policy-allow-all/src/module.ts b/plugins/permission-backend-module-policy-allow-all/src/module.ts index 47ab202a00..f7a38f293c 100644 --- a/plugins/permission-backend-module-policy-allow-all/src/module.ts +++ b/plugins/permission-backend-module-policy-allow-all/src/module.ts @@ -23,8 +23,8 @@ import { AllowAllPermissionPolicy } from './policy'; * @public */ export const permissionModuleAllowAllPolicy = createBackendModule({ - moduleId: 'allowAllPolicy', pluginId: 'permission', + moduleId: 'allow-all-policy', register(reg) { reg.registerInit({ deps: { policy: policyExtensionPoint }, diff --git a/plugins/permission-backend/CHANGELOG.md b/plugins/permission-backend/CHANGELOG.md index 79cabf4be4..43c5e85b4f 100644 --- a/plugins/permission-backend/CHANGELOG.md +++ b/plugins/permission-backend/CHANGELOG.md @@ -1,5 +1,134 @@ # @backstage/plugin-permission-backend +## 0.5.32 + +### Patch Changes + +- b1acd9b: Updated README +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.5.32-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + - @backstage/plugin-permission-node@0.7.20-next.2 + +## 0.5.32-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/plugin-permission-node@0.7.20-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-permission-common@0.7.11 + +## 0.5.32-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.3-next.0 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.20-next.0 + +## 0.5.31 + +### Patch Changes + +- 0cbb03b: Fixing regular expression ReDoS with zod packages. Upgrading to latest. ref: https://security.snyk.io/vuln/SNYK-JS-ZOD-5925617 +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.19 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.5.31-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.3 + +## 0.5.31-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.2 + +## 0.5.31-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + +## 0.5.31-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/plugin-permission-node@0.7.19-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-permission-common@0.7.10 + +## 0.5.30 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.1 + - @backstage/plugin-permission-node@0.7.18 + ## 0.5.30-next.2 ### Patch Changes diff --git a/plugins/permission-backend/README.md b/plugins/permission-backend/README.md index 59fe1730ba..b4f6124bf4 100644 --- a/plugins/permission-backend/README.md +++ b/plugins/permission-backend/README.md @@ -1,6 +1,3 @@ # @backstage/plugin-permission-backend -> NOTE: THIS PACKAGE IS EXPERIMENTAL, HERE BE DRAGONS - -Backend for Backstage authorization and permissions. For more information, see -the [authorization PRFC](https://github.com/backstage/backstage/pull/7761). +Backend for Backstage authorization and permissions. For more information, see the [permissions documentation on Backstage.io](https://backstage.io/docs/permissions/overview). diff --git a/plugins/permission-backend/alpha-api-report.md b/plugins/permission-backend/api-report-alpha.md similarity index 100% rename from plugins/permission-backend/alpha-api-report.md rename to plugins/permission-backend/api-report-alpha.md diff --git a/plugins/permission-backend/package.json b/plugins/permission-backend/package.json index 1f7e7bd28a..c8c908eccb 100644 --- a/plugins/permission-backend/package.json +++ b/plugins/permission-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-backend", - "version": "0.5.30-next.2", + "version": "0.5.32", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -56,7 +56,7 @@ "node-fetch": "^2.6.7", "winston": "^3.2.1", "yn": "^4.0.0", - "zod": "^3.21.4" + "zod": "^3.22.4" }, "devDependencies": { "@backstage/cli": "workspace:^", diff --git a/plugins/permission-common/CHANGELOG.md b/plugins/permission-common/CHANGELOG.md index c017cd00fc..74bd6db59b 100644 --- a/plugins/permission-common/CHANGELOG.md +++ b/plugins/permission-common/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-permission-common +## 0.7.12 + +### Patch Changes + +- b1acd9b: Updated README +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.7.11 + +### Patch Changes + +- 0cbb03b: Fixing regular expression ReDoS with zod packages. Upgrading to latest. ref: https://security.snyk.io/vuln/SNYK-JS-ZOD-5925617 +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.7.10 + +### Patch Changes + +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + ## 0.7.9 ### Patch Changes diff --git a/plugins/permission-common/README.md b/plugins/permission-common/README.md index 7ba998bed5..fdb72b4be5 100644 --- a/plugins/permission-common/README.md +++ b/plugins/permission-common/README.md @@ -1,7 +1,3 @@ # @backstage/plugin-permission-common -> NOTE: THIS PACKAGE IS EXPERIMENTAL, HERE BE DRAGONS - -Isomorphic types and client for Backstage permissions and authorization. For -more information, see the [authorization -PRFC](https://github.com/backstage/backstage/pull/7761). +Isomorphic types and client for Backstage permissions and authorization. For more information, see the [permissions documentation on Backstage.io](https://backstage.io/docs/permissions/overview). diff --git a/plugins/permission-common/package.json b/plugins/permission-common/package.json index fdf8bb6e73..b0ca7d74bf 100644 --- a/plugins/permission-common/package.json +++ b/plugins/permission-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-permission-common", "description": "Isomorphic types and client for Backstage permissions and authorization", - "version": "0.7.9", + "version": "0.7.12", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { @@ -47,7 +47,7 @@ "@backstage/types": "workspace:^", "cross-fetch": "^4.0.0", "uuid": "^8.0.0", - "zod": "^3.21.4" + "zod": "^3.22.4" }, "devDependencies": { "@backstage/cli": "workspace:^", diff --git a/plugins/permission-node/CHANGELOG.md b/plugins/permission-node/CHANGELOG.md index c8407a1b1a..5f66d4a337 100644 --- a/plugins/permission-node/CHANGELOG.md +++ b/plugins/permission-node/CHANGELOG.md @@ -1,5 +1,124 @@ # @backstage/plugin-permission-node +## 0.7.20 + +### Patch Changes + +- b1acd9b: Updated README +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.7.20-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + +## 0.7.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-permission-common@0.7.11 + +## 0.7.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.3-next.0 + - @backstage/plugin-permission-common@0.7.11 + +## 0.7.19 + +### Patch Changes + +- 0cbb03b: Fixing regular expression ReDoS with zod packages. Upgrading to latest. ref: https://security.snyk.io/vuln/SNYK-JS-ZOD-5925617 +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.7.19-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + - @backstage/plugin-permission-common@0.7.10 + +## 0.7.19-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/plugin-auth-node@0.4.2-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-permission-common@0.7.10 + +## 0.7.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-permission-common@0.7.10 + +## 0.7.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-permission-common@0.7.10 + +## 0.7.18 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.1 + ## 0.7.18-next.2 ### Patch Changes diff --git a/plugins/permission-node/README.md b/plugins/permission-node/README.md index 82dfe54f9c..39859d8f4c 100644 --- a/plugins/permission-node/README.md +++ b/plugins/permission-node/README.md @@ -1,7 +1,3 @@ # @backstage/plugin-permission-node -> NOTE: THIS PACKAGE IS EXPERIMENTAL, HERE BE DRAGONS - -Common permission and authorization utilities for backend plugins. For more -information, see the [authorization -PRFC](https://github.com/backstage/backstage/pull/7761). +Common permission and authorization utilities for backend plugins. For more information, see the [permissions documentation on Backstage.io](https://backstage.io/docs/permissions/overview). diff --git a/plugins/permission-node/alpha-api-report.md b/plugins/permission-node/api-report-alpha.md similarity index 100% rename from plugins/permission-node/alpha-api-report.md rename to plugins/permission-node/api-report-alpha.md diff --git a/plugins/permission-node/package.json b/plugins/permission-node/package.json index c2adf69d04..5ce7217d6c 100644 --- a/plugins/permission-node/package.json +++ b/plugins/permission-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-permission-node", "description": "Common permission and authorization utilities for backend plugins", - "version": "0.7.18-next.2", + "version": "0.7.20", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -55,7 +55,7 @@ "@types/express": "^4.17.6", "express": "^4.17.1", "express-promise-router": "^4.1.0", - "zod": "^3.21.4", + "zod": "^3.22.4", "zod-to-json-schema": "^3.20.4" }, "devDependencies": { diff --git a/plugins/permission-react/CHANGELOG.md b/plugins/permission-react/CHANGELOG.md index c7aa0a2e81..a432970e3f 100644 --- a/plugins/permission-react/CHANGELOG.md +++ b/plugins/permission-react/CHANGELOG.md @@ -1,5 +1,73 @@ # @backstage/plugin-permission-react +## 0.4.19 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- b1acd9b: Updated README +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/config@1.1.1 + +## 0.4.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/config@1.1.1 + - @backstage/plugin-permission-common@0.7.11 + +## 0.4.19-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-permission-common@0.7.11 + +## 0.4.18 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/config@1.1.1 + +## 0.4.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-permission-common@0.7.10 + +## 0.4.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/config@1.1.1 + - @backstage/plugin-permission-common@0.7.10 + +## 0.4.17 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/config@1.1.1 + ## 0.4.17-next.0 ### Patch Changes diff --git a/plugins/permission-react/README.md b/plugins/permission-react/README.md index 72383f024d..de22b0dba0 100644 --- a/plugins/permission-react/README.md +++ b/plugins/permission-react/README.md @@ -1,5 +1,3 @@ -# permission +# @backstage/plugin-permission-react -**NOTE: THIS PACKAGE IS EXPERIMENTAL!** - -Components and hooks to help implement permissions in Backstage frontend plugins. For more information, see the [authorization PRFC](https://github.com/backstage/backstage/pull/7761). +Components and hooks to help implement permissions in Backstage frontend plugins. For more information, see the [permissions documentation on Backstage.io](https://backstage.io/docs/permissions/overview). diff --git a/plugins/permission-react/package.json b/plugins/permission-react/package.json index 396116032e..7949433aa9 100644 --- a/plugins/permission-react/package.json +++ b/plugins/permission-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-react", - "version": "0.4.17-next.0", + "version": "0.4.19", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -36,8 +36,6 @@ "@backstage/core-plugin-api": "workspace:^", "@backstage/plugin-permission-common": "workspace:^", "@types/react": "^16.13.1 || ^17.0.0", - "cross-fetch": "^4.0.0", - "react-use": "^17.2.4", "swr": "^2.0.0" }, "peerDependencies": { diff --git a/plugins/playlist-backend/CHANGELOG.md b/plugins/playlist-backend/CHANGELOG.md index 20e68b9301..00e1c5be53 100644 --- a/plugins/playlist-backend/CHANGELOG.md +++ b/plugins/playlist-backend/CHANGELOG.md @@ -1,5 +1,163 @@ # @backstage/plugin-playlist-backend +## 0.3.13 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-playlist-common@0.1.14 + +## 0.3.13-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + - @backstage/plugin-permission-node@0.7.20-next.2 + +## 0.3.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/plugin-permission-node@0.7.20-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-playlist-common@0.1.13 + +## 0.3.13-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.3-next.0 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.20-next.0 + - @backstage/plugin-playlist-common@0.1.13 + +## 0.3.12 + +### Patch Changes + +- 0cbb03b: Fixing regular expression ReDoS with zod packages. Upgrading to latest. ref: https://security.snyk.io/vuln/SNYK-JS-ZOD-5925617 +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/catalog-client@1.5.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.19 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-playlist-common@0.1.13 + +## 0.3.12-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.3 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.3 + - @backstage/plugin-playlist-common@0.1.12 + +## 0.3.12-next.2 + +### Patch Changes + +- Updated dependencies + - @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/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.2 + - @backstage/plugin-playlist-common@0.1.12 + +## 0.3.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + - @backstage/plugin-playlist-common@0.1.12 + +## 0.3.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/plugin-auth-node@0.4.2-next.0 + - @backstage/plugin-permission-node@0.7.19-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-playlist-common@0.1.12 + +## 0.3.11 + +### Patch Changes + +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/catalog-client@1.4.6 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-node@0.4.1 + - @backstage/plugin-permission-node@0.7.18 + - @backstage/plugin-playlist-common@0.1.12 + ## 0.3.11-next.2 ### Patch Changes diff --git a/plugins/playlist-backend/package.json b/plugins/playlist-backend/package.json index bd32d40a8b..8b872b6e67 100644 --- a/plugins/playlist-backend/package.json +++ b/plugins/playlist-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-playlist-backend", - "version": "0.3.11-next.2", + "version": "0.3.13", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -46,13 +46,12 @@ "uuid": "^8.2.0", "winston": "^3.2.1", "yn": "^4.0.0", - "zod": "^3.21.4" + "zod": "^3.22.4" }, "devDependencies": { "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@types/supertest": "^2.0.8", - "msw": "^1.0.0", "supertest": "^6.1.3" }, "files": [ diff --git a/plugins/playlist-common/CHANGELOG.md b/plugins/playlist-common/CHANGELOG.md index 5916ed33e8..0b65ee551f 100644 --- a/plugins/playlist-common/CHANGELOG.md +++ b/plugins/playlist-common/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/plugin-playlist-common +## 0.1.14 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.12 + +## 0.1.13 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.11 + +## 0.1.12 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.10 + ## 0.1.11 ### Patch Changes diff --git a/plugins/playlist-common/package.json b/plugins/playlist-common/package.json index e08afb8392..9ab95c4c8a 100644 --- a/plugins/playlist-common/package.json +++ b/plugins/playlist-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-playlist-common", "description": "Common functionalities for the playlist plugin", - "version": "0.1.11", + "version": "0.1.14", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/playlist/CHANGELOG.md b/plugins/playlist/CHANGELOG.md index 2fe26e8cc7..f35b2a149a 100644 --- a/plugins/playlist/CHANGELOG.md +++ b/plugins/playlist/CHANGELOG.md @@ -1,5 +1,184 @@ # @backstage/plugin-playlist +## 0.2.3 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-search-react@1.7.5 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.20 + - @backstage/plugin-playlist-common@0.1.14 + +## 0.2.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + - @backstage/plugin-search-react@1.7.5-next.2 + +## 0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/plugin-permission-react@0.4.19-next.1 + - @backstage/plugin-search-react@1.7.5-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-playlist-common@0.1.13 + +## 0.2.3-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-permission-react@0.4.19-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/plugin-search-react@1.7.5-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-playlist-common@0.1.13 + +## 0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/plugin-search-react@1.7.4 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-react@0.4.18 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-playlist-common@0.1.13 + +## 0.2.2-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-react@1.9.2-next.3 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/plugin-playlist-common@0.1.12 + - @backstage/plugin-search-react@1.7.4-next.3 + +## 0.2.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/plugin-search-react@1.7.4-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/plugin-playlist-common@0.1.12 + +## 0.2.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/plugin-search-react@1.7.4-next.1 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-playlist-common@0.1.12 + +## 0.2.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/plugin-search-react@1.7.4-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/plugin-permission-react@0.4.18-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-playlist-common@0.1.12 + +## 0.2.0 + +### Minor Changes + +- f0e2ef3b81: Support being able to define custom composable Playlist index pages + + **BREAKING** The individual `PlaylistPage` route must now be manually hooked up by making the following change to your setup: + + ```diff + -import { PlaylistIndexPage } from '@backstage/plugin-playlist'; + +import { PlaylistIndexPage, PlaylistPage } from '@backstage/plugin-playlist'; + + // ... + + } /> + +} /> + ``` + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 69ee8d75f4: Remove `button` prop from used MaterialUI `MenuItem` component fixing incompatibility with MaterialUI v5. +- 62b5922916: Internal theme type updates +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-permission-react@0.4.17 + - @backstage/plugin-search-react@1.7.2 + - @backstage/theme@0.4.4 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-playlist-common@0.1.12 + ## 0.1.18-next.2 ### Patch Changes diff --git a/plugins/playlist/package.json b/plugins/playlist/package.json index 785c3f53e3..34d2911685 100644 --- a/plugins/playlist/package.json +++ b/plugins/playlist/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-playlist", - "version": "0.1.18-next.2", + "version": "0.2.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -39,7 +39,6 @@ "@backstage/plugin-permission-react": "workspace:^", "@backstage/plugin-playlist-common": "workspace:^", "@backstage/plugin-search-react": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", @@ -64,7 +63,6 @@ "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0", "swr": "^2.0.0" }, diff --git a/plugins/playlist/src/components/CreatePlaylistButton/CreatePlaylistButton.tsx b/plugins/playlist/src/components/CreatePlaylistButton/CreatePlaylistButton.tsx index ac32097680..26c7b3fd45 100644 --- a/plugins/playlist/src/components/CreatePlaylistButton/CreatePlaylistButton.tsx +++ b/plugins/playlist/src/components/CreatePlaylistButton/CreatePlaylistButton.tsx @@ -20,13 +20,12 @@ import { useRouteRef, alertApiRef, } from '@backstage/core-plugin-api'; -import { BackstageTheme } from '@backstage/theme'; import { usePermission } from '@backstage/plugin-permission-react'; import { permissions, PlaylistMetadata, } from '@backstage/plugin-playlist-common'; -import { Button, IconButton, useMediaQuery } from '@material-ui/core'; +import { Button, IconButton, Theme, useMediaQuery } from '@material-ui/core'; import AddCircleOutline from '@material-ui/icons/AddCircleOutline'; import React, { useCallback, useState } from 'react'; import { useNavigate } from 'react-router-dom'; @@ -49,7 +48,7 @@ export const CreatePlaylistButton = () => { const { allowed } = usePermission({ permission: permissions.playlistListCreate, }); - const isXSScreen = useMediaQuery(theme => + const isXSScreen = useMediaQuery(theme => theme.breakpoints.down('xs'), ); diff --git a/plugins/playlist/src/components/PersonalListPicker/PersonalListPicker.tsx b/plugins/playlist/src/components/PersonalListPicker/PersonalListPicker.tsx index 20bb5ba68a..0691d26732 100644 --- a/plugins/playlist/src/components/PersonalListPicker/PersonalListPicker.tsx +++ b/plugins/playlist/src/components/PersonalListPicker/PersonalListPicker.tsx @@ -29,7 +29,6 @@ import { ListItemText, makeStyles, MenuItem, - Theme, Typography, } from '@material-ui/core'; import PlaylistPlayIcon from '@material-ui/icons/PlaylistPlay'; @@ -75,7 +74,7 @@ export class PersonalListFilter implements PlaylistFilter { } } -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles(theme => ({ root: { backgroundColor: 'rgba(0, 0, 0, .11)', boxShadow: 'none', @@ -270,7 +269,6 @@ export const PersonalListPicker = () => { setSelectedPersonalFilter(item.id)} selected={item.id === selectedPersonalFilter} diff --git a/plugins/proxy-backend/CHANGELOG.md b/plugins/proxy-backend/CHANGELOG.md index 87458c7f74..e6649758f7 100644 --- a/plugins/proxy-backend/CHANGELOG.md +++ b/plugins/proxy-backend/CHANGELOG.md @@ -1,5 +1,95 @@ # @backstage/plugin-proxy-backend +## 0.4.7 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + +## 0.4.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + +## 0.4.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + +## 0.4.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/config@1.1.1 + +## 0.4.6 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/config@1.1.1 + +## 0.4.6-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/config@1.1.1 + +## 0.4.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/config@1.1.1 + +## 0.4.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/config@1.1.1 + +## 0.4.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/config@1.1.1 + +## 0.4.5 + +### Patch Changes + +- 8613ba3928: Switched to using `"exports"` field for `/alpha` subpath export. +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/config@1.1.1 + ## 0.4.5-next.2 ### Patch Changes diff --git a/plugins/proxy-backend/alpha-api-report.md b/plugins/proxy-backend/api-report-alpha.md similarity index 100% rename from plugins/proxy-backend/alpha-api-report.md rename to plugins/proxy-backend/api-report-alpha.md diff --git a/plugins/proxy-backend/package.json b/plugins/proxy-backend/package.json index 897d1b0b32..1e042a1bdc 100644 --- a/plugins/proxy-backend/package.json +++ b/plugins/proxy-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-proxy-backend", "description": "A Backstage backend plugin that helps you set up proxy endpoints in the backend", - "version": "0.4.5-next.2", + "version": "0.4.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/puppetdb/CHANGELOG.md b/plugins/puppetdb/CHANGELOG.md index 04aed439ec..9e8b991e02 100644 --- a/plugins/puppetdb/CHANGELOG.md +++ b/plugins/puppetdb/CHANGELOG.md @@ -1,5 +1,121 @@ # @backstage/plugin-puppetdb +## 0.1.12 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.1.12-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.1.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.1.12-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + +## 0.1.11 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.1.11-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## 0.1.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + +## 0.1.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + +## 0.1.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## 0.1.9 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + ## 0.1.9-next.2 ### Patch Changes diff --git a/plugins/puppetdb/package.json b/plugins/puppetdb/package.json index 76315fb10e..0d1cc3d44e 100644 --- a/plugins/puppetdb/package.json +++ b/plugins/puppetdb/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-puppetdb", "description": "Backstage plugin to visualize resource information and Puppet facts from PuppetDB.", - "version": "0.1.9-next.2", + "version": "0.1.12", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -40,10 +40,7 @@ "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", - "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "^4.0.0-alpha.57", "@types/react": "^16.13.1 || ^17.0.0", "react-use": "^17.2.4" }, @@ -59,7 +56,6 @@ "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", "msw": "^1.0.1" }, "files": [ diff --git a/plugins/puppetdb/src/components/ReportDetailsPage/ReportDetailsLogsTable.tsx b/plugins/puppetdb/src/components/ReportDetailsPage/ReportDetailsLogsTable.tsx index f512fcd935..d12b432314 100644 --- a/plugins/puppetdb/src/components/ReportDetailsPage/ReportDetailsLogsTable.tsx +++ b/plugins/puppetdb/src/components/ReportDetailsPage/ReportDetailsLogsTable.tsx @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import Typography from '@material-ui/core/Typography'; import React from 'react'; import { puppetDbApiRef, PuppetDbReportLog } from '../../api'; @@ -24,13 +25,12 @@ import { import useAsync from 'react-use/lib/useAsync'; import { useApi } from '@backstage/core-plugin-api'; import { makeStyles } from '@material-ui/core/styles'; -import { BackstageTheme } from '@backstage/theme'; type ReportLogsTableProps = { hash: string; }; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles(theme => ({ empty: { padding: theme.spacing(2), display: 'flex', diff --git a/plugins/puppetdb/src/components/ReportDetailsPage/ReportDetailsPage.tsx b/plugins/puppetdb/src/components/ReportDetailsPage/ReportDetailsPage.tsx index db6536fce4..c7da8df36b 100644 --- a/plugins/puppetdb/src/components/ReportDetailsPage/ReportDetailsPage.tsx +++ b/plugins/puppetdb/src/components/ReportDetailsPage/ReportDetailsPage.tsx @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { Link as RouterLink, useParams } from 'react-router-dom'; import { Breadcrumbs, Link } from '@backstage/core-components'; import { makeStyles } from '@material-ui/core/styles'; @@ -27,11 +28,10 @@ import { Typography, Tabs, } from '@material-ui/core'; -import { BackstageTheme } from '@backstage/theme'; import { ReportDetailsEventsTable } from './ReportDetailsEventsTable'; import { ReportDetailsLogsTable } from './ReportDetailsLogsTable'; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles(theme => ({ cards: { marginTop: theme.spacing(2), }, diff --git a/plugins/rollbar-backend/CHANGELOG.md b/plugins/rollbar-backend/CHANGELOG.md index 1f1dd768d0..4c14f2c9f9 100644 --- a/plugins/rollbar-backend/CHANGELOG.md +++ b/plugins/rollbar-backend/CHANGELOG.md @@ -1,5 +1,84 @@ # @backstage/plugin-rollbar-backend +## 0.1.54 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/config@1.1.1 + +## 0.1.54-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.2 + +## 0.1.54-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/config@1.1.1 + +## 0.1.54-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/config@1.1.1 + +## 0.1.53 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/config@1.1.1 + +## 0.1.53-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/config@1.1.1 + +## 0.1.53-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/config@1.1.1 + +## 0.1.53-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.1 + - @backstage/config@1.1.1 + +## 0.1.53-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/config@1.1.1 + +## 0.1.52 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.9 + - @backstage/config@1.1.1 + ## 0.1.52-next.2 ### Patch Changes diff --git a/plugins/rollbar-backend/package.json b/plugins/rollbar-backend/package.json index f15b954585..730bc3e6f3 100644 --- a/plugins/rollbar-backend/package.json +++ b/plugins/rollbar-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-rollbar-backend", "description": "A Backstage backend plugin that integrates towards Rollbar", - "version": "0.1.52-next.2", + "version": "0.1.54", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/rollbar/CHANGELOG.md b/plugins/rollbar/CHANGELOG.md index f68dcc38db..494dce0fe9 100644 --- a/plugins/rollbar/CHANGELOG.md +++ b/plugins/rollbar/CHANGELOG.md @@ -1,5 +1,113 @@ # @backstage/plugin-rollbar +## 0.4.29 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## 0.4.29-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 0.4.29-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-model@1.4.3 + +## 0.4.29-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + +## 0.4.28 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-model@1.4.3 + +## 0.4.28-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.3 + +## 0.4.28-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + +## 0.4.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0-next.0 + +## 0.4.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-model@1.4.3 + +## 0.4.26 + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`. +- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/core-plugin-api@1.8.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-model@1.4.3 + ## 0.4.26-next.2 ### Patch Changes diff --git a/plugins/rollbar/package.json b/plugins/rollbar/package.json index a501b963a4..a49254e366 100644 --- a/plugins/rollbar/package.json +++ b/plugins/rollbar/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-rollbar", "description": "A Backstage plugin that integrates towards Rollbar", - "version": "0.4.26-next.2", + "version": "0.4.29", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -38,9 +38,7 @@ "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", - "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", - "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", "@types/react": "^16.13.1 || ^17.0.0", "lodash": "^4.17.21", @@ -54,15 +52,11 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", "@backstage/dev-utils": "workspace:^", "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "cross-fetch": "^4.0.0", - "msw": "^1.0.0" + "@testing-library/react": "^14.0.0" }, "files": [ "dist", diff --git a/plugins/scaffolder-backend-module-azure/.eslintrc.js b/plugins/scaffolder-backend-module-azure/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/scaffolder-backend-module-azure/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/scaffolder-backend-module-azure/CHANGELOG.md b/plugins/scaffolder-backend-module-azure/CHANGELOG.md new file mode 100644 index 0000000000..3f56f61339 --- /dev/null +++ b/plugins/scaffolder-backend-module-azure/CHANGELOG.md @@ -0,0 +1,74 @@ +# @backstage/plugin-scaffolder-backend-module-azure + +## 0.1.1 + +### Patch Changes + +- d076ee4: Updated dependency `azure-devops-node-api` to `^12.0.0`. +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## 0.1.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-scaffolder-node@0.2.10-next.2 + +## 0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.10-next.1 + - @backstage/errors@1.2.3 + +## 0.1.1-next.0 + +### Patch Changes + +- d076ee4: Updated dependency `azure-devops-node-api` to `^12.0.0`. +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/plugin-scaffolder-node@0.2.10-next.0 + +## 0.1.0 + +### Minor Changes + +- 219d7f0: Create new scaffolder module for external integrations + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-scaffolder-node@0.2.9 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.1.0-next.0 + +### Minor Changes + +- 219d7f0: Create new scaffolder module for external integrations + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.9-next.3 + - @backstage/backend-common@0.20.0-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 diff --git a/plugins/scaffolder-backend-module-azure/README.md b/plugins/scaffolder-backend-module-azure/README.md new file mode 100644 index 0000000000..505ef36db1 --- /dev/null +++ b/plugins/scaffolder-backend-module-azure/README.md @@ -0,0 +1,5 @@ +# @backstage/plugin-scaffolder-backend-module-azure + +The azure module for [@backstage/plugin-scaffolder-backend](https://www.npmjs.com/package/@backstage/plugin-scaffolder-backend). + +_This plugin was created through the Backstage CLI_ diff --git a/plugins/scaffolder-backend-module-azure/api-report.md b/plugins/scaffolder-backend-module-azure/api-report.md new file mode 100644 index 0000000000..427ed2d1bf --- /dev/null +++ b/plugins/scaffolder-backend-module-azure/api-report.md @@ -0,0 +1,28 @@ +## API Report File for "@backstage/plugin-scaffolder-backend-module-azure" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { Config } from '@backstage/config'; +import { JsonObject } from '@backstage/types'; +import { ScmIntegrationRegistry } from '@backstage/integration'; +import { TemplateAction } from '@backstage/plugin-scaffolder-node'; + +// @public +export function createPublishAzureAction(options: { + integrations: ScmIntegrationRegistry; + config: Config; +}): TemplateAction< + { + repoUrl: string; + description?: string | undefined; + defaultBranch?: string | undefined; + sourcePath?: string | undefined; + token?: string | undefined; + gitCommitMessage?: string | undefined; + gitAuthorName?: string | undefined; + gitAuthorEmail?: string | undefined; + }, + JsonObject +>; +``` diff --git a/plugins/scaffolder-backend-module-azure/catalog-info.yaml b/plugins/scaffolder-backend-module-azure/catalog-info.yaml new file mode 100644 index 0000000000..16ae855eae --- /dev/null +++ b/plugins/scaffolder-backend-module-azure/catalog-info.yaml @@ -0,0 +1,10 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: backstage-plugin-scaffolder-backend-module-azure + title: '@backstage/plugin-scaffolder-backend-module-azure' + description: The azure module for @backstage/plugin-scaffolder-backend +spec: + lifecycle: experimental + type: backstage-backend-plugin-module + owner: maintainers diff --git a/plugins/scaffolder-backend-module-azure/package.json b/plugins/scaffolder-backend-module-azure/package.json new file mode 100644 index 0000000000..ce53811f15 --- /dev/null +++ b/plugins/scaffolder-backend-module-azure/package.json @@ -0,0 +1,40 @@ +{ + "name": "@backstage/plugin-scaffolder-backend-module-azure", + "description": "The azure module for @backstage/plugin-scaffolder-backend", + "version": "0.1.1", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "backend-plugin-module" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/backend-common": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/integration": "workspace:^", + "@backstage/plugin-scaffolder-node": "workspace:^", + "azure-devops-node-api": "^12.0.0", + "yaml": "^2.0.0" + }, + "devDependencies": { + "@backstage/cli": "workspace:^" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/azure.examples.test.ts b/plugins/scaffolder-backend-module-azure/src/actions/azure.examples.test.ts similarity index 95% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/azure.examples.test.ts rename to plugins/scaffolder-backend-module-azure/src/actions/azure.examples.test.ts index e4fd18ef59..27989650ce 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/azure.examples.test.ts +++ b/plugins/scaffolder-backend-module-azure/src/actions/azure.examples.test.ts @@ -21,7 +21,7 @@ import { ScmIntegrations } from '@backstage/integration'; import { getVoidLogger } from '@backstage/backend-common'; import { WebApi } from 'azure-devops-node-api'; import { PassThrough } from 'stream'; -import { initRepoAndPush } from '../helpers'; +import { initRepoAndPush } from '@backstage/plugin-scaffolder-node'; import { examples } from './azure.examples'; jest.mock('azure-devops-node-api', () => ({ @@ -29,8 +29,9 @@ jest.mock('azure-devops-node-api', () => ({ getPersonalAccessTokenHandler: jest.fn().mockReturnValue(() => {}), })); -jest.mock('../helpers', () => { +jest.mock('@backstage/plugin-scaffolder-node', () => { return { + ...jest.requireActual('@backstage/plugin-scaffolder-node'), initRepoAndPush: jest.fn().mockResolvedValue({ commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6', }), diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/azure.examples.ts b/plugins/scaffolder-backend-module-azure/src/actions/azure.examples.ts similarity index 100% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/azure.examples.ts rename to plugins/scaffolder-backend-module-azure/src/actions/azure.examples.ts diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/azure.test.ts b/plugins/scaffolder-backend-module-azure/src/actions/azure.test.ts similarity index 98% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/azure.test.ts rename to plugins/scaffolder-backend-module-azure/src/actions/azure.test.ts index 9b7673ea29..4401e01007 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/azure.test.ts +++ b/plugins/scaffolder-backend-module-azure/src/actions/azure.test.ts @@ -19,8 +19,9 @@ jest.mock('azure-devops-node-api', () => ({ getPersonalAccessTokenHandler: jest.fn().mockReturnValue(() => {}), })); -jest.mock('../helpers', () => { +jest.mock('@backstage/plugin-scaffolder-node', () => { return { + ...jest.requireActual('@backstage/plugin-scaffolder-node'), initRepoAndPush: jest.fn().mockResolvedValue({ commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6', }), @@ -36,7 +37,7 @@ import { ConfigReader } from '@backstage/config'; import { getVoidLogger } from '@backstage/backend-common'; import { WebApi } from 'azure-devops-node-api'; import { PassThrough } from 'stream'; -import { initRepoAndPush } from '../helpers'; +import { initRepoAndPush } from '@backstage/plugin-scaffolder-node'; describe('publish:azure', () => { const config = new ConfigReader({ diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/azure.ts b/plugins/scaffolder-backend-module-azure/src/actions/azure.ts similarity index 97% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/azure.ts rename to plugins/scaffolder-backend-module-azure/src/actions/azure.ts index a7df154687..e90cfeade4 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/azure.ts +++ b/plugins/scaffolder-backend-module-azure/src/actions/azure.ts @@ -19,15 +19,18 @@ import { DefaultAzureDevOpsCredentialsProvider, ScmIntegrationRegistry, } from '@backstage/integration'; -import { initRepoAndPush } from '../helpers'; +import { + initRepoAndPush, + getRepoSourceDirectory, + parseRepoUrl, + createTemplateAction, +} from '@backstage/plugin-scaffolder-node'; import { GitRepositoryCreateOptions } from 'azure-devops-node-api/interfaces/GitInterfaces'; import { getBearerHandler, getPersonalAccessTokenHandler, WebApi, } from 'azure-devops-node-api'; -import { getRepoSourceDirectory, parseRepoUrl } from './util'; -import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; import { Config } from '@backstage/config'; import { examples } from './azure.examples'; diff --git a/plugins/catalog-graphql/src/setupTests.ts b/plugins/scaffolder-backend-module-azure/src/actions/index.ts similarity index 89% rename from plugins/catalog-graphql/src/setupTests.ts rename to plugins/scaffolder-backend-module-azure/src/actions/index.ts index 8f32650781..76ea7c2f07 100644 --- a/plugins/catalog-graphql/src/setupTests.ts +++ b/plugins/scaffolder-backend-module-azure/src/actions/index.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Backstage Authors + * 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. @@ -13,4 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export {}; +export * from './azure'; diff --git a/plugins/catalog-graphql/src/index.ts b/plugins/scaffolder-backend-module-azure/src/index.ts similarity index 81% rename from plugins/catalog-graphql/src/index.ts rename to plugins/scaffolder-backend-module-azure/src/index.ts index 51ae12e684..e804f1a504 100644 --- a/plugins/catalog-graphql/src/index.ts +++ b/plugins/scaffolder-backend-module-azure/src/index.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Backstage Authors + * 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. @@ -15,9 +15,9 @@ */ /** - * An experimental Backstage catalog GraphQL module + * A module for the scaffolder backend that lets you interact with azure * * @packageDocumentation */ -export * from './graphql/module'; +export * from './actions'; diff --git a/plugins/scaffolder-backend-module-bitbucket/.eslintrc.js b/plugins/scaffolder-backend-module-bitbucket/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/scaffolder-backend-module-bitbucket/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md b/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md new file mode 100644 index 0000000000..c94898c953 --- /dev/null +++ b/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md @@ -0,0 +1,73 @@ +# @backstage/plugin-scaffolder-backend-module-bitbucket + +## 0.1.1 + +### Patch Changes + +- a694f71: The Scaffolder builtin actions now contains an action for running pipelines from Bitbucket Cloud Rest API +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## 0.1.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-scaffolder-node@0.2.10-next.2 + +## 0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.10-next.1 + - @backstage/errors@1.2.3 + +## 0.1.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/plugin-scaffolder-node@0.2.10-next.0 + +## 0.1.0 + +### Minor Changes + +- 219d7f0: Create new scaffolder module for external integrations + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-scaffolder-node@0.2.9 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.1.0-next.0 + +### Minor Changes + +- 219d7f0: Create new scaffolder module for external integrations + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.9-next.3 + - @backstage/backend-common@0.20.0-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 diff --git a/plugins/scaffolder-backend-module-bitbucket/README.md b/plugins/scaffolder-backend-module-bitbucket/README.md new file mode 100644 index 0000000000..90b8680e80 --- /dev/null +++ b/plugins/scaffolder-backend-module-bitbucket/README.md @@ -0,0 +1,5 @@ +# @backstage/plugin-scaffolder-backend-module-bitbucket + +The bitbucket module for [@backstage/plugin-scaffolder-backend](https://www.npmjs.com/package/@backstage/plugin-scaffolder-backend). + +_This plugin was created through the Backstage CLI_ diff --git a/plugins/scaffolder-backend-module-bitbucket/api-report.md b/plugins/scaffolder-backend-module-bitbucket/api-report.md new file mode 100644 index 0000000000..0f5f09b5b8 --- /dev/null +++ b/plugins/scaffolder-backend-module-bitbucket/api-report.md @@ -0,0 +1,95 @@ +## API Report File for "@backstage/plugin-scaffolder-backend-module-bitbucket" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { Config } from '@backstage/config'; +import { JsonObject } from '@backstage/types'; +import { ScmIntegrationRegistry } from '@backstage/integration'; +import { TemplateAction } from '@backstage/plugin-scaffolder-node'; + +// @public +export const createBitbucketPipelinesRunAction: (options: { + integrations: ScmIntegrationRegistry; +}) => TemplateAction< + { + workspace: string; + repo_slug: string; + body?: object | undefined; + token?: string | undefined; + }, + JsonObject +>; + +// @public @deprecated +export function createPublishBitbucketAction(options: { + integrations: ScmIntegrationRegistry; + config: Config; +}): TemplateAction< + { + repoUrl: string; + description?: string | undefined; + defaultBranch?: string | undefined; + repoVisibility?: 'private' | 'public' | undefined; + sourcePath?: string | undefined; + enableLFS?: boolean | undefined; + token?: string | undefined; + gitCommitMessage?: string | undefined; + gitAuthorName?: string | undefined; + gitAuthorEmail?: string | undefined; + }, + JsonObject +>; + +// @public +export function createPublishBitbucketCloudAction(options: { + integrations: ScmIntegrationRegistry; + config: Config; +}): TemplateAction< + { + repoUrl: string; + description?: string | undefined; + defaultBranch?: string | undefined; + repoVisibility?: 'private' | 'public' | undefined; + sourcePath?: string | undefined; + token?: string | undefined; + }, + JsonObject +>; + +// @public +export function createPublishBitbucketServerAction(options: { + integrations: ScmIntegrationRegistry; + config: Config; +}): TemplateAction< + { + repoUrl: string; + description?: string | undefined; + defaultBranch?: string | undefined; + repoVisibility?: 'private' | 'public' | undefined; + sourcePath?: string | undefined; + enableLFS?: boolean | undefined; + token?: string | undefined; + gitCommitMessage?: string | undefined; + gitAuthorName?: string | undefined; + gitAuthorEmail?: string | undefined; + }, + JsonObject +>; + +// @public +export function createPublishBitbucketServerPullRequestAction(options: { + integrations: ScmIntegrationRegistry; + config: Config; +}): TemplateAction< + { + repoUrl: string; + title: string; + description?: string | undefined; + targetBranch?: string | undefined; + sourceBranch: string; + token?: string | undefined; + }, + JsonObject +>; +``` diff --git a/plugins/scaffolder-backend-module-bitbucket/catalog-info.yaml b/plugins/scaffolder-backend-module-bitbucket/catalog-info.yaml new file mode 100644 index 0000000000..b0a94d1c13 --- /dev/null +++ b/plugins/scaffolder-backend-module-bitbucket/catalog-info.yaml @@ -0,0 +1,10 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: backstage-plugin-scaffolder-backend-module-bitbucket + title: '@backstage/plugin-scaffolder-backend-module-bitbucket' + description: The bitbucket module for @backstage/plugin-scaffolder-backend +spec: + lifecycle: experimental + type: backstage-backend-plugin-module + owner: maintainers diff --git a/plugins/scaffolder-backend-module-bitbucket/package.json b/plugins/scaffolder-backend-module-bitbucket/package.json new file mode 100644 index 0000000000..03ebab43fc --- /dev/null +++ b/plugins/scaffolder-backend-module-bitbucket/package.json @@ -0,0 +1,42 @@ +{ + "name": "@backstage/plugin-scaffolder-backend-module-bitbucket", + "description": "The bitbucket module for @backstage/plugin-scaffolder-backend", + "version": "0.1.1", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "backend-plugin-module" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/backend-common": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/integration": "workspace:^", + "@backstage/plugin-scaffolder-node": "workspace:^", + "node-fetch": "^2.6.7", + "yaml": "^2.0.0" + }, + "devDependencies": { + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", + "msw": "^1.0.0" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.examples.test.ts b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.examples.test.ts similarity index 98% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.examples.test.ts rename to plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.examples.test.ts index a1564d0498..73325ab5bf 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.examples.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.examples.test.ts @@ -14,8 +14,9 @@ * limitations under the License. */ -jest.mock('../helpers', () => { +jest.mock('@backstage/plugin-scaffolder-node', () => { return { + ...jest.requireActual('@backstage/plugin-scaffolder-node'), initRepoAndPush: jest.fn().mockResolvedValue({ commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6', }), @@ -33,7 +34,7 @@ import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; import { getVoidLogger } from '@backstage/backend-common'; import { PassThrough } from 'stream'; -import { initRepoAndPush } from '../helpers'; +import { initRepoAndPush } from '@backstage/plugin-scaffolder-node'; import yaml from 'yaml'; import { sep } from 'path'; import { examples } from './bitbucket.examples'; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.examples.ts b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.examples.ts similarity index 100% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.examples.ts rename to plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.examples.ts diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.test.ts b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.test.ts similarity index 98% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.test.ts rename to plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.test.ts index 5d46a28a60..d6e068c039 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.test.ts @@ -14,8 +14,9 @@ * limitations under the License. */ -jest.mock('../helpers', () => { +jest.mock('@backstage/plugin-scaffolder-node', () => { return { + ...jest.requireActual('@backstage/plugin-scaffolder-node'), initRepoAndPush: jest.fn().mockResolvedValue({ commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6', }), @@ -24,7 +25,6 @@ jest.mock('../helpers', () => { }), }; }); - import { createPublishBitbucketAction } from './bitbucket'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; @@ -33,7 +33,7 @@ import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; import { getVoidLogger } from '@backstage/backend-common'; import { PassThrough } from 'stream'; -import { initRepoAndPush } from '../helpers'; +import { initRepoAndPush } from '@backstage/plugin-scaffolder-node'; describe('publish:bitbucket', () => { const config = new ConfigReader({ diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.ts b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.ts similarity index 98% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.ts rename to plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.ts index a4d664e0e7..76fe1de5df 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.ts +++ b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.ts @@ -19,10 +19,13 @@ import { BitbucketIntegrationConfig, ScmIntegrationRegistry, } from '@backstage/integration'; -import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; +import { + createTemplateAction, + initRepoAndPush, + getRepoSourceDirectory, + parseRepoUrl, +} from '@backstage/plugin-scaffolder-node'; import fetch, { Response, RequestInit } from 'node-fetch'; -import { initRepoAndPush } from '../helpers'; -import { getRepoSourceDirectory, parseRepoUrl } from './util'; import { Config } from '@backstage/config'; import { examples } from './bitbucket.examples'; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucketCloud.test.ts b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucketCloud.test.ts similarity index 98% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucketCloud.test.ts rename to plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucketCloud.test.ts index 3159bfc562..7045d58e01 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucketCloud.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucketCloud.test.ts @@ -14,8 +14,9 @@ * limitations under the License. */ -jest.mock('../helpers', () => { +jest.mock('@backstage/plugin-scaffolder-node', () => { return { + ...jest.requireActual('@backstage/plugin-scaffolder-node'), initRepoAndPush: jest.fn().mockResolvedValue({ commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6', }), @@ -33,7 +34,7 @@ import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; import { getVoidLogger } from '@backstage/backend-common'; import { PassThrough } from 'stream'; -import { initRepoAndPush } from '../helpers'; +import { initRepoAndPush } from '@backstage/plugin-scaffolder-node'; describe('publish:bitbucketCloud', () => { const config = new ConfigReader({ diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucketCloud.ts b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucketCloud.ts similarity index 90% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucketCloud.ts rename to plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucketCloud.ts index 00529d5856..e9d815f5e8 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucketCloud.ts +++ b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucketCloud.ts @@ -16,11 +16,16 @@ import { InputError } from '@backstage/errors'; import { ScmIntegrationRegistry } from '@backstage/integration'; -import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; +import { + createTemplateAction, + initRepoAndPush, + getRepoSourceDirectory, + parseRepoUrl, +} from '@backstage/plugin-scaffolder-node'; import fetch, { Response, RequestInit } from 'node-fetch'; -import { initRepoAndPush } from '../helpers'; -import { getRepoSourceDirectory, parseRepoUrl } from './util'; + import { Config } from '@backstage/config'; +import { getAuthorizationHeader } from './helpers'; const createRepository = async (opts: { workspace: string; @@ -89,29 +94,6 @@ const createRepository = async (opts: { return { remoteUrl, repoContentsUrl }; }; -const getAuthorizationHeader = (config: { - username?: string; - appPassword?: string; - token?: string; -}) => { - if (config.username && config.appPassword) { - const buffer = Buffer.from( - `${config.username}:${config.appPassword}`, - 'utf8', - ); - - return `Basic ${buffer.toString('base64')}`; - } - - if (config.token) { - return `Bearer ${config.token}`; - } - - throw new Error( - `Authorization has not been provided for Bitbucket Cloud. Please add either username + appPassword to the Integrations config or a user login auth token`, - ); -}; - /** * Creates a new action that initializes a git repository of the content in the workspace * and publishes it to Bitbucket Cloud. diff --git a/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucketCloudPipelinesRun.examples.test.ts b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucketCloudPipelinesRun.examples.test.ts new file mode 100644 index 0000000000..90ae2c08b9 --- /dev/null +++ b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucketCloudPipelinesRun.examples.test.ts @@ -0,0 +1,274 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { getVoidLogger } from '@backstage/backend-common'; +import { rest } from 'msw'; +import { setupServer } from 'msw/node'; +import { PassThrough } from 'stream'; +import { createBitbucketPipelinesRunAction } from './bitbucketCloudPipelinesRun'; +import yaml from 'yaml'; +import { examples } from './bitbucketCloudPipelinesRun.examples'; +import { ConfigReader } from '@backstage/config'; +import { ScmIntegrations } from '@backstage/integration'; +import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; + +describe('bitbucket:pipelines:run', () => { + const config = new ConfigReader({ + integrations: { + bitbucketCloud: [ + { + username: 'u', + appPassword: 'p', + }, + ], + }, + }); + + const integrations = ScmIntegrations.fromConfig(config); + const action = createBitbucketPipelinesRunAction({ integrations }); + const mockContext = { + input: {}, + workspacePath: 'wsp', + logger: getVoidLogger(), + logStream: new PassThrough(), + output: jest.fn(), + createTemporaryDirectory: jest.fn(), + }; + const responseJson = { + repository: { + links: { + html: { href: 'https://bitbucket.org/test-workspace/test-repo-slug' }, + }, + }, + build_number: 1, + }; + const worker = setupServer(); + setupRequestMockHandlers(worker); + + beforeEach(() => { + jest.resetAllMocks(); + }); + + it('should trigger a pipeline for a branch', async () => { + expect.assertions(2); + worker.use( + rest.post( + 'https://api.bitbucket.org/2.0/repositories/test-workspace/test-repo-slug/pipelines', + (req, res, ctx) => { + expect(req.headers.get('Authorization')).toBe('Basic dTpw'); + expect(req.body).toEqual({ + target: { + ref_type: 'branch', + type: 'pipeline_ref_target', + ref_name: 'master', + }, + }); + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json(responseJson), + ); + }, + ), + ); + const ctx = Object.assign({}, mockContext, { + input: yaml.parse(examples[0].example).steps[0].input, + }); + await action.handler(ctx); + }); + + it('should trigger a pipeline for a commit on a branch', async () => { + expect.assertions(2); + worker.use( + rest.post( + 'https://api.bitbucket.org/2.0/repositories/test-workspace/test-repo-slug/pipelines', + (req, res, ctx) => { + expect(req.headers.get('Authorization')).toBe('Basic dTpw'); + expect(req.body).toEqual({ + target: { + commit: { + type: 'commit', + hash: 'ce5b7431602f7cbba007062eeb55225c6e18e956', + }, + ref_type: 'branch', + type: 'pipeline_ref_target', + ref_name: 'master', + }, + }); + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json(responseJson), + ); + }, + ), + ); + const ctx = Object.assign({}, mockContext, { + input: yaml.parse(examples[1].example).steps[0].input, + }); + await action.handler(ctx); + }); + + it('should trigger a specific pipeline definition for a commit', async () => { + expect.assertions(2); + worker.use( + rest.post( + 'https://api.bitbucket.org/2.0/repositories/test-workspace/test-repo-slug/pipelines', + (req, res, ctx) => { + expect(req.headers.get('Authorization')).toBe('Basic dTpw'); + expect(req.body).toEqual({ + target: { + commit: { + type: 'commit', + hash: 'a3c4e02c9a3755eccdc3764e6ea13facdf30f923', + }, + selector: { + type: 'custom', + pattern: 'Deploy to production', + }, + type: 'pipeline_commit_target', + }, + }); + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json(responseJson), + ); + }, + ), + ); + const ctx = Object.assign({}, mockContext, { + input: yaml.parse(examples[2].example).steps[0].input, + }); + await action.handler(ctx); + }); + + it('should trigger a specific pipeline definition for a commit on a branch or tag', async () => { + expect.assertions(2); + worker.use( + rest.post( + 'https://api.bitbucket.org/2.0/repositories/test-workspace/test-repo-slug/pipelines', + (req, res, ctx) => { + expect(req.headers.get('Authorization')).toBe('Basic dTpw'); + expect(req.body).toEqual({ + target: { + commit: { + type: 'commit', + hash: 'a3c4e02c9a3755eccdc3764e6ea13facdf30f923', + }, + selector: { + type: 'custom', + pattern: 'Deploy to production', + }, + type: 'pipeline_ref_target', + ref_name: 'master', + ref_type: 'branch', + }, + }); + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json(responseJson), + ); + }, + ), + ); + const ctx = Object.assign({}, mockContext, { + input: yaml.parse(examples[3].example).steps[0].input, + }); + await action.handler(ctx); + }); + + it('should trigger a custom pipeline with variables', async () => { + expect.assertions(2); + worker.use( + rest.post( + 'https://api.bitbucket.org/2.0/repositories/test-workspace/test-repo-slug/pipelines', + (req, res, ctx) => { + expect(req.headers.get('Authorization')).toBe('Basic dTpw'); + expect(req.body).toEqual({ + target: { + type: 'pipeline_ref_target', + ref_name: 'master', + ref_type: 'branch', + selector: { + type: 'custom', + pattern: 'Deploy to production', + }, + }, + variables: [ + { key: 'var1key', value: 'var1value', secured: true }, + { + key: 'var2key', + value: 'var2value', + }, + ], + }); + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json(responseJson), + ); + }, + ), + ); + const ctx = Object.assign({}, mockContext, { + input: yaml.parse(examples[4].example).steps[0].input, + }); + await action.handler(ctx); + }); + + it('should trigger a pull request pipeline', async () => { + expect.assertions(2); + worker.use( + rest.post( + 'https://api.bitbucket.org/2.0/repositories/test-workspace/test-repo-slug/pipelines', + (req, res, ctx) => { + expect(req.headers.get('Authorization')).toBe('Basic dTpw'); + expect(req.body).toEqual({ + target: { + type: 'pipeline_pullrequest_target', + source: 'pull-request-branch', + destination: 'master', + destination_commit: { + hash: '9f848b7', + }, + commit: { + hash: '1a372fc', + }, + pull_request: { + id: '3', + }, + selector: { + type: 'pull-requests', + pattern: '**', + }, + }, + }); + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json(responseJson), + ); + }, + ), + ); + const ctx = Object.assign({}, mockContext, { + input: yaml.parse(examples[5].example).steps[0].input, + }); + await action.handler(ctx); + }); +}); diff --git a/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucketCloudPipelinesRun.examples.ts b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucketCloudPipelinesRun.examples.ts new file mode 100644 index 0000000000..d6255526af --- /dev/null +++ b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucketCloudPipelinesRun.examples.ts @@ -0,0 +1,202 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { TemplateExample } from '@backstage/plugin-scaffolder-node'; +import yaml from 'yaml'; + +export const examples: TemplateExample[] = [ + { + description: 'Trigger a pipeline for a branch', + example: yaml.stringify({ + steps: [ + { + action: 'bitbucket:pipelines:run', + id: 'run-bitbucket-pipeline', + name: 'Run an example bitbucket pipeline', + input: { + workspace: 'test-workspace', + repo_slug: 'test-repo-slug', + body: { + target: { + ref_type: 'branch', + type: 'pipeline_ref_target', + ref_name: 'master', + }, + }, + }, + }, + ], + }), + }, + { + description: 'Trigger a pipeline for a commit on a branch', + example: yaml.stringify({ + steps: [ + { + action: 'bitbucket:pipelines:run', + id: 'run-bitbucket-pipeline', + name: 'Run an example bitbucket pipeline', + input: { + workspace: 'test-workspace', + repo_slug: 'test-repo-slug', + body: { + target: { + commit: { + type: 'commit', + hash: 'ce5b7431602f7cbba007062eeb55225c6e18e956', + }, + ref_type: 'branch', + type: 'pipeline_ref_target', + ref_name: 'master', + }, + }, + }, + }, + ], + }), + }, + { + description: 'Trigger a specific pipeline definition for a commit', + example: yaml.stringify({ + steps: [ + { + action: 'bitbucket:pipelines:run', + id: 'run-bitbucket-pipeline', + name: 'Run an example bitbucket pipeline', + input: { + workspace: 'test-workspace', + repo_slug: 'test-repo-slug', + body: { + target: { + commit: { + type: 'commit', + hash: 'a3c4e02c9a3755eccdc3764e6ea13facdf30f923', + }, + selector: { + type: 'custom', + pattern: 'Deploy to production', + }, + type: 'pipeline_commit_target', + }, + }, + }, + }, + ], + }), + }, + { + description: + 'Trigger a specific pipeline definition for a commit on a branch or tag', + example: yaml.stringify({ + steps: [ + { + action: 'bitbucket:pipelines:run', + id: 'run-bitbucket-pipeline', + name: 'Run an example bitbucket pipeline', + input: { + workspace: 'test-workspace', + repo_slug: 'test-repo-slug', + body: { + target: { + commit: { + type: 'commit', + hash: 'a3c4e02c9a3755eccdc3764e6ea13facdf30f923', + }, + selector: { + type: 'custom', + pattern: 'Deploy to production', + }, + type: 'pipeline_ref_target', + ref_name: 'master', + ref_type: 'branch', + }, + }, + }, + }, + ], + }), + }, + { + description: 'Trigger a custom pipeline with variables', + example: yaml.stringify({ + steps: [ + { + action: 'bitbucket:pipelines:run', + id: 'run-bitbucket-pipeline', + name: 'Run an example bitbucket pipeline', + input: { + workspace: 'test-workspace', + repo_slug: 'test-repo-slug', + body: { + target: { + type: 'pipeline_ref_target', + ref_name: 'master', + ref_type: 'branch', + selector: { + type: 'custom', + pattern: 'Deploy to production', + }, + }, + variables: [ + { key: 'var1key', value: 'var1value', secured: true }, + { + key: 'var2key', + value: 'var2value', + }, + ], + }, + }, + }, + ], + }), + }, + { + description: 'Trigger a pull request pipeline', + example: yaml.stringify({ + steps: [ + { + action: 'bitbucket:pipelines:run', + id: 'run-bitbucket-pipeline', + name: 'Run an example bitbucket pipeline', + input: { + workspace: 'test-workspace', + repo_slug: 'test-repo-slug', + body: { + target: { + type: 'pipeline_pullrequest_target', + source: 'pull-request-branch', + destination: 'master', + destination_commit: { + hash: '9f848b7', + }, + commit: { + hash: '1a372fc', + }, + pull_request: { + id: '3', + }, + selector: { + type: 'pull-requests', + pattern: '**', + }, + }, + }, + }, + }, + ], + }), + }, +]; diff --git a/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucketCloudPipelinesRun.test.ts b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucketCloudPipelinesRun.test.ts new file mode 100644 index 0000000000..dc76a79898 --- /dev/null +++ b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucketCloudPipelinesRun.test.ts @@ -0,0 +1,156 @@ +/* + * 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 { rest } from 'msw'; +import { setupServer } from 'msw/node'; +import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { PassThrough } from 'stream'; +import { createBitbucketPipelinesRunAction } from './bitbucketCloudPipelinesRun'; +import { ConfigReader } from '@backstage/config'; +import { ScmIntegrations } from '@backstage/integration'; + +describe('bitbucket:pipelines:run', () => { + const config = new ConfigReader({ + integrations: { + bitbucketCloud: [ + { + username: 'u', + appPassword: 'p', + }, + ], + }, + }); + + const integrations = ScmIntegrations.fromConfig(config); + const action = createBitbucketPipelinesRunAction({ integrations }); + const mockContext = { + input: {}, + workspacePath: 'wsp', + logger: getVoidLogger(), + logStream: new PassThrough(), + output: jest.fn(), + createTemporaryDirectory: jest.fn(), + }; + const workspace = 'test-workspace'; + const repo_slug = 'test-repo-slug'; + const responseJson = { + repository: { + links: { + html: { href: 'https://bitbucket.org/test-workspace/test-repo-slug' }, + }, + }, + build_number: 1, + }; + const worker = setupServer(); + setupRequestMockHandlers(worker); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should throw if there is no integration credentials or token provided', async () => { + const configNoCreds = new ConfigReader({ + integrations: { + bitbucketCloud: [], + }, + }); + + const integrationsNoCreds = ScmIntegrations.fromConfig(configNoCreds); + const actionNoCreds = createBitbucketPipelinesRunAction({ + integrations: integrationsNoCreds, + }); + const testContext = Object.assign({}, mockContext, { + input: { workspace, repo_slug }, + }); + await expect(actionNoCreds.handler(testContext)).rejects.toThrow( + /Authorization has not been provided for Bitbucket Cloud/, + ); + }); + + it('should call the bitbucket api for running a pipeline with integration credentials', async () => { + expect.assertions(1); + worker.use( + rest.post( + `https://api.bitbucket.org/2.0/repositories/${workspace}/${repo_slug}/pipelines`, + (req, res, ctx) => { + expect(req.headers.get('Authorization')).toBe('Basic dTpw'); + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json(responseJson), + ); + }, + ), + ); + + const testContext = Object.assign({}, mockContext, { + input: { workspace, repo_slug }, + }); + await action.handler(testContext); + }); + + it('should call the bitbucket api for running a pipeline with input token', async () => { + expect.assertions(1); + worker.use( + rest.post( + `https://api.bitbucket.org/2.0/repositories/${workspace}/${repo_slug}/pipelines`, + (req, res, ctx) => { + expect(req.headers.get('Authorization')).toBe('Bearer abc'); + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json(responseJson), + ); + }, + ), + ); + + const testContext = Object.assign({}, mockContext, { + input: { workspace, repo_slug, token: 'abc' }, + }); + await action.handler(testContext); + }); + + it('should call outputs with the correct data', async () => { + worker.use( + rest.post( + `https://api.bitbucket.org/2.0/repositories/${workspace}/${repo_slug}/pipelines`, + (_, res, ctx) => { + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json(responseJson), + ); + }, + ), + ); + + const testContext = Object.assign({}, mockContext, { + input: { workspace, repo_slug, token: 'abc' }, + }); + await action.handler(testContext); + expect(testContext.output).toHaveBeenCalledWith('buildNumber', 1); + expect(testContext.output).toHaveBeenCalledWith( + 'repoUrl', + 'https://bitbucket.org/test-workspace/test-repo-slug', + ); + expect(testContext.output).toHaveBeenCalledWith( + 'pipelinesUrl', + 'https://bitbucket.org/test-workspace/test-repo-slug/pipelines', + ); + }); +}); diff --git a/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucketCloudPipelinesRun.ts b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucketCloudPipelinesRun.ts new file mode 100644 index 0000000000..c44fdcc824 --- /dev/null +++ b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucketCloudPipelinesRun.ts @@ -0,0 +1,117 @@ +/* + * 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 { examples } from './bitbucketCloudPipelinesRun.examples'; +import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; +import fetch, { Response } from 'node-fetch'; +import * as inputProps from './inputProperties'; +import { ScmIntegrationRegistry } from '@backstage/integration'; +import { getAuthorizationHeader } from './helpers'; + +const id = 'bitbucket:pipelines:run'; +/** + * Creates a new action that triggers a run of a bitbucket pipeline + * + * @public + */ +export const createBitbucketPipelinesRunAction = (options: { + integrations: ScmIntegrationRegistry; +}) => { + const { integrations } = options; + return createTemplateAction<{ + workspace: string; + repo_slug: string; + body?: object; + token?: string; + }>({ + id, + description: 'Run a bitbucket cloud pipeline', + examples, + schema: { + input: { + type: 'object', + required: ['workspace', 'repo_slug'], + properties: { + workspace: inputProps.workspace, + repo_slug: inputProps.repo_slug, + body: inputProps.pipelinesRunBody, + token: inputProps.token, + }, + }, + output: { + type: 'object', + properties: { + buildNumber: { + title: 'Build number', + type: 'number', + }, + repoUrl: { + title: 'A URL to the pipeline repositry', + type: 'string', + }, + repoContentsUrl: { + title: 'A URL to the pipeline', + type: 'string', + }, + }, + }, + }, + supportsDryRun: false, + async handler(ctx) { + const { workspace, repo_slug, body, token } = ctx.input; + const host = 'bitbucket.org'; + const integrationConfig = integrations.bitbucketCloud.byHost(host); + + const authorization = getAuthorizationHeader( + token ? { token } : integrationConfig!.config, + ); + let response: Response; + try { + response = await fetch( + `https://api.bitbucket.org/2.0/repositories/${workspace}/${repo_slug}/pipelines`, + { + method: 'POST', + headers: { + Authorization: authorization, + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + body: JSON.stringify(body) ?? {}, + }, + ); + } catch (e) { + throw new Error(`Unable to run pipeline, ${e}`); + } + + if (response.status !== 201) { + throw new Error( + `Unable to run pipeline, ${response.status} ${ + response.statusText + }, ${await response.text()}`, + ); + } + + const responseObject = await response.json(); + + ctx.output('buildNumber', responseObject.build_number); + ctx.output('repoUrl', responseObject.repository.links.html.href); + ctx.output( + 'pipelinesUrl', + `${responseObject.repository.links.html.href}/pipelines`, + ); + }, + }); +}; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucketServer.test.ts b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucketServer.test.ts similarity index 99% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucketServer.test.ts rename to plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucketServer.test.ts index 67a29210fc..ab7b52996f 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucketServer.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucketServer.test.ts @@ -14,8 +14,9 @@ * limitations under the License. */ -jest.mock('../helpers', () => { +jest.mock('@backstage/plugin-scaffolder-node', () => { return { + ...jest.requireActual('@backstage/plugin-scaffolder-node'), initRepoAndPush: jest.fn().mockResolvedValue({ commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6', }), @@ -33,7 +34,7 @@ import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; import { getVoidLogger } from '@backstage/backend-common'; import { PassThrough } from 'stream'; -import { initRepoAndPush } from '../helpers'; +import { initRepoAndPush } from '@backstage/plugin-scaffolder-node'; describe('publish:bitbucketServer', () => { const config = new ConfigReader({ diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucketServer.ts b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucketServer.ts similarity index 97% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucketServer.ts rename to plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucketServer.ts index 66b7a46f77..31125deab2 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucketServer.ts +++ b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucketServer.ts @@ -19,10 +19,14 @@ import { getBitbucketServerRequestOptions, ScmIntegrationRegistry, } from '@backstage/integration'; -import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; +import { + createTemplateAction, + initRepoAndPush, + getRepoSourceDirectory, + parseRepoUrl, +} from '@backstage/plugin-scaffolder-node'; import fetch, { Response, RequestInit } from 'node-fetch'; -import { initRepoAndPush } from '../helpers'; -import { getRepoSourceDirectory, parseRepoUrl } from './util'; + import { Config } from '@backstage/config'; const createRepository = async (opts: { diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucketServerPullRequest.test.ts b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucketServerPullRequest.test.ts similarity index 98% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucketServerPullRequest.test.ts rename to plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucketServerPullRequest.test.ts index af3999097f..3af47853c3 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucketServerPullRequest.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucketServerPullRequest.test.ts @@ -14,8 +14,9 @@ * limitations under the License. */ -jest.mock('../helpers', () => { +jest.mock('@backstage/plugin-scaffolder-node', () => { return { + ...jest.requireActual('@backstage/plugin-scaffolder-node'), initRepoAndPush: jest.fn().mockResolvedValue({ commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6', }), diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucketServerPullRequest.ts b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucketServerPullRequest.ts similarity index 98% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucketServerPullRequest.ts rename to plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucketServerPullRequest.ts index 79711b9d69..dc75145ebc 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucketServerPullRequest.ts +++ b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucketServerPullRequest.ts @@ -19,9 +19,11 @@ import { getBitbucketServerRequestOptions, ScmIntegrationRegistry, } from '@backstage/integration'; -import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; +import { + createTemplateAction, + parseRepoUrl, +} from '@backstage/plugin-scaffolder-node'; import fetch, { RequestInit, Response } from 'node-fetch'; -import { parseRepoUrl } from './util'; import { Config } from '@backstage/config'; const createPullRequest = async (opts: { diff --git a/plugins/scaffolder-backend-module-bitbucket/src/actions/helpers.ts b/plugins/scaffolder-backend-module-bitbucket/src/actions/helpers.ts new file mode 100644 index 0000000000..efa6fd64f4 --- /dev/null +++ b/plugins/scaffolder-backend-module-bitbucket/src/actions/helpers.ts @@ -0,0 +1,38 @@ +/* + * 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 getAuthorizationHeader = (config: { + username?: string; + appPassword?: string; + token?: string; +}) => { + if (config.username && config.appPassword) { + const buffer = Buffer.from( + `${config.username}:${config.appPassword}`, + 'utf8', + ); + + return `Basic ${buffer.toString('base64')}`; + } + + if (config.token) { + return `Bearer ${config.token}`; + } + + throw new Error( + `Authorization has not been provided for Bitbucket Cloud. Please add either username + appPassword to the Integrations config or a user login auth token`, + ); +}; diff --git a/plugins/scaffolder-backend-module-bitbucket/src/actions/index.ts b/plugins/scaffolder-backend-module-bitbucket/src/actions/index.ts new file mode 100644 index 0000000000..9b009255fd --- /dev/null +++ b/plugins/scaffolder-backend-module-bitbucket/src/actions/index.ts @@ -0,0 +1,20 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export * from './bitbucket'; +export * from './bitbucketCloud'; +export * from './bitbucketServer'; +export * from './bitbucketServerPullRequest'; +export { createBitbucketPipelinesRunAction } from './bitbucketCloudPipelinesRun'; diff --git a/plugins/scaffolder-backend-module-bitbucket/src/actions/inputProperties.ts b/plugins/scaffolder-backend-module-bitbucket/src/actions/inputProperties.ts new file mode 100644 index 0000000000..d37426e982 --- /dev/null +++ b/plugins/scaffolder-backend-module-bitbucket/src/actions/inputProperties.ts @@ -0,0 +1,155 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const workspace = { + title: 'Workspace', + description: `The workspace name`, + type: 'string', +}; + +const repo_slug = { + title: 'Repository name', + description: 'The repository name', + type: 'string', +}; + +const ref_type = { + title: 'ref_type', + type: 'string', +}; + +const type = { + title: 'type', + type: 'string', +}; + +const ref_name = { + title: 'ref_name', + type: 'string', +}; +const source = { + title: 'source', + type: 'string', +}; +const destination = { + title: 'destination', + type: 'string', +}; +const hash = { + title: 'hash', + type: 'string', +}; + +const pattern = { + title: 'pattern', + type: 'string', +}; + +const id = { + title: 'id', + type: 'string', +}; + +const key = { + title: 'key', + type: 'string', +}; +const value = { + title: 'value', + type: 'string', +}; +const secured = { + title: 'secured', + type: 'boolean', +}; + +const token = { + title: 'Authentication Token', + type: 'string', + description: 'The token to use for authorization to BitBucket Cloud', +}; + +const destination_commit = { + title: 'destination_commit', + type: 'object', + properties: { + hash, + }, +}; + +const commit = { + title: 'commit', + type: 'object', + properties: { + type, + hash, + }, +}; + +const selector = { + title: 'selector', + type: 'object', + properties: { + type, + pattern, + }, +}; + +const pull_request = { + title: 'pull_request', + type: 'object', + properties: { + id, + }, +}; + +const pipelinesRunBody = { + title: 'Request Body', + description: + 'Request body properties: see Bitbucket Cloud Rest API documentation for more details', + type: 'object', + properties: { + target: { + title: 'target', + type: 'object', + properties: { + ref_type, + type, + ref_name, + source, + destination, + destination_commit, + commit, + selector, + pull_request, + }, + }, + variables: { + title: 'variables', + type: 'array', + items: { + type: 'object', + properties: { + key, + value, + secured, + }, + }, + }, + }, +}; + +export { workspace, repo_slug, pipelinesRunBody, token }; diff --git a/plugins/scaffolder-backend-module-bitbucket/src/index.ts b/plugins/scaffolder-backend-module-bitbucket/src/index.ts new file mode 100644 index 0000000000..38d973efb8 --- /dev/null +++ b/plugins/scaffolder-backend-module-bitbucket/src/index.ts @@ -0,0 +1,23 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * A module for the scaffolder backend that lets you interact with bitbucket + * + * @packageDocumentation + */ + +export * from './actions'; diff --git a/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md b/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md index 7d56652ebe..075d8db3b9 100644 --- a/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md @@ -1,5 +1,122 @@ # @backstage/plugin-scaffolder-backend-module-confluence-to-markdown +## 0.2.10 + +### Patch Changes + +- 7acbb5a: Removed `mock-fs` dev dependency. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## 0.2.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-scaffolder-node@0.2.10-next.2 + +## 0.2.10-next.1 + +### Patch Changes + +- 7acbb5a: Removed `mock-fs` dev dependency. +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.10-next.1 + - @backstage/errors@1.2.3 + +## 0.2.10-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/plugin-scaffolder-node@0.2.10-next.0 + +## 0.2.9 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-scaffolder-node@0.2.9 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.2.9-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.9-next.3 + - @backstage/backend-common@0.20.0-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/types@1.1.1 + +## 0.2.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.9-next.2 + +## 0.2.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.9-next.1 + +## 0.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/plugin-scaffolder-node@0.2.9-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.2.8 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.2 + - @backstage/backend-common@0.19.9 + - @backstage/plugin-scaffolder-node@0.2.8 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + ## 0.2.8-next.2 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-confluence-to-markdown/package.json b/plugins/scaffolder-backend-module-confluence-to-markdown/package.json index 38a1f333cb..2f0bd5188c 100644 --- a/plugins/scaffolder-backend-module-confluence-to-markdown/package.json +++ b/plugins/scaffolder-backend-module-confluence-to-markdown/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown", "description": "The confluence-to-markdown module for @backstage/plugin-scaffolder-backend", - "version": "0.2.8-next.2", + "version": "0.2.10", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,7 +35,6 @@ "@backstage/errors": "workspace:^", "@backstage/integration": "workspace:^", "@backstage/plugin-scaffolder-node": "workspace:^", - "@backstage/types": "workspace:^", "fs-extra": "10.1.0", "git-url-parse": "^13.1.0", "node-fetch": "^2.6.7", @@ -45,7 +44,6 @@ "devDependencies": { "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", - "mock-fs": "^5.2.0", "msw": "^1.0.0" }, "files": [ diff --git a/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/confluenceToMarkdown.examples.test.ts b/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/confluenceToMarkdown.examples.test.ts index e5aeadbf00..f3bf1fef35 100644 --- a/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/confluenceToMarkdown.examples.test.ts +++ b/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/confluenceToMarkdown.examples.test.ts @@ -19,28 +19,16 @@ import { getVoidLogger } from '@backstage/backend-common'; import { UrlReader } from '@backstage/backend-common'; import { ConfigReader } from '@backstage/config'; import { ScmIntegrations } from '@backstage/integration'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; -import mockFs from 'mock-fs'; -import os from 'os'; -import { readFile, writeFile, createWriteStream } from 'fs-extra'; +import { + createMockDirectory, + setupRequestMockHandlers, +} from '@backstage/backend-test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { examples } from './confluenceToMarkdown.examples'; import yaml from 'yaml'; import { ActionContext } from '@backstage/plugin-scaffolder-node'; -jest.mock('fs-extra', () => ({ - mkdirSync: jest.fn(), - readFile: jest.fn().mockResolvedValue('File contents'), - writeFile: jest.fn().mockImplementation(() => { - return Promise.resolve(); - }), - outputFile: jest.fn(), - openSync: jest.fn(), - createWriteStream: jest.fn().mockReturnValue(new PassThrough()), - ensureDir: jest.fn(), -})); - describe('confluence:transform:markdown examples', () => { const baseUrl = `https://confluence.example.com`; const worker = setupServer(); @@ -72,7 +60,8 @@ describe('confluence:transform:markdown examples', () => { const logger = getVoidLogger(); jest.spyOn(logger, 'info'); - const mockTmpDir = os.tmpdir(); + const mockDir = createMockDirectory(); + const workspacePath = mockDir.resolve('workspace'); beforeEach(() => { reader = { @@ -84,17 +73,18 @@ describe('confluence:transform:markdown examples', () => { }; mockContext = { input: yaml.parse(examples[0].example).steps[0].input, - workspacePath: '/tmp', + workspacePath, logger, logStream: new PassThrough(), output: jest.fn(), - createTemporaryDirectory: jest.fn().mockResolvedValue(mockTmpDir), + createTemporaryDirectory: jest.fn(), }; - mockFs({ [`${mockTmpDir}/src/docs`]: {} }); + + mockDir.setContent({ 'workspace/mkdocs.yml': 'File contents' }); }); + afterEach(() => { jest.clearAllMocks(); - mockFs.restore(); }); it('should call confluence to markdown action successfully with results array', async () => { @@ -155,8 +145,10 @@ describe('confluence:transform:markdown examples', () => { `Fetching the mkdocs.yml catalog from https://github.com/organization-name/repo-name/blob/main/mkdocs.yml`, ); expect(logger.info).toHaveBeenCalledTimes(5); - expect(createWriteStream).toHaveBeenCalledTimes(1); - expect(readFile).toHaveBeenCalledTimes(1); - expect(writeFile).toHaveBeenCalledTimes(1); + + expect(mockDir.content({ path: 'workspace/docs' })).toEqual({ + img: { 'testing.pdf': Buffer.from('hello') }, + 'Page-Title.md': 'hello world', + }); }); }); diff --git a/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/confluenceToMarkdown.test.ts b/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/confluenceToMarkdown.test.ts index 4e4f3091f1..5ce8bb2697 100644 --- a/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/confluenceToMarkdown.test.ts +++ b/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/confluenceToMarkdown.test.ts @@ -19,26 +19,14 @@ import { getVoidLogger } from '@backstage/backend-common'; import { UrlReader } from '@backstage/backend-common'; import { ConfigReader } from '@backstage/config'; import { ScmIntegrations } from '@backstage/integration'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; -import mockFs from 'mock-fs'; -import os from 'os'; +import { + createMockDirectory, + setupRequestMockHandlers, +} from '@backstage/backend-test-utils'; import type { ActionContext } from '@backstage/plugin-scaffolder-node'; -import { readFile, writeFile, createWriteStream } from 'fs-extra'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -jest.mock('fs-extra', () => ({ - mkdirSync: jest.fn(), - readFile: jest.fn().mockResolvedValue('File contents'), - writeFile: jest.fn().mockImplementation(() => { - return Promise.resolve(); - }), - outputFile: jest.fn(), - openSync: jest.fn(), - createWriteStream: jest.fn().mockReturnValue(new PassThrough()), - ensureDir: jest.fn(), -})); - describe('confluence:transform:markdown', () => { const baseUrl = `https://nodomain.confluence.com`; const worker = setupServer(); @@ -70,7 +58,8 @@ describe('confluence:transform:markdown', () => { const logger = getVoidLogger(); jest.spyOn(logger, 'info'); - const mockTmpDir = os.tmpdir(); + const mockDir = createMockDirectory(); + const workspacePath = mockDir.resolve('workspace'); beforeEach(() => { reader = { @@ -85,19 +74,21 @@ describe('confluence:transform:markdown', () => { confluenceUrls: [ 'https://nodomain.confluence.com/display/testing/mkdocs', ], - repoUrl: 'https://notreal.github.com/space/backstage/mkdocs.yml', + repoUrl: + 'https://notreal.github.com/space/backstage/blob/main/mkdocs.yml', }, - workspacePath: '/tmp', + workspacePath, logger, logStream: new PassThrough(), output: jest.fn(), - createTemporaryDirectory: jest.fn().mockResolvedValue(mockTmpDir), + createTemporaryDirectory: jest.fn(), }; - mockFs({ [`${mockTmpDir}/src/docs`]: {} }); + + mockDir.setContent({ 'workspace/mkdocs.yml': 'File contents' }); }); + afterEach(() => { jest.clearAllMocks(); - mockFs.restore(); }); it('should call confluence to markdown action successfully with results array', async () => { @@ -155,12 +146,14 @@ describe('confluence:transform:markdown', () => { await action.handler(mockContext); expect(logger.info).toHaveBeenCalledWith( - `Fetching the mkdocs.yml catalog from https://notreal.github.com/space/backstage/mkdocs.yml`, + `Fetching the mkdocs.yml catalog from https://notreal.github.com/space/backstage/blob/main/mkdocs.yml`, ); expect(logger.info).toHaveBeenCalledTimes(5); - expect(createWriteStream).toHaveBeenCalledTimes(1); - expect(readFile).toHaveBeenCalledTimes(1); - expect(writeFile).toHaveBeenCalledTimes(1); + + expect(mockDir.content({ path: 'workspace/docs' })).toEqual({ + img: { 'testing.pdf': Buffer.from('hello') }, + 'mkdocs.md': 'hello world', + }); }); it('should call confluence to markdown action successfully with empty results array', async () => { @@ -202,13 +195,13 @@ describe('confluence:transform:markdown', () => { await action.handler(mockContext); expect(logger.info).toHaveBeenCalledWith( - `Fetching the mkdocs.yml catalog from https://notreal.github.com/space/backstage/mkdocs.yml`, + `Fetching the mkdocs.yml catalog from https://notreal.github.com/space/backstage/blob/main/mkdocs.yml`, ); expect(logger.info).toHaveBeenCalledTimes(5); - expect(createWriteStream).not.toHaveBeenCalled(); - expect(readFile).toHaveBeenCalledTimes(1); - expect(writeFile).toHaveBeenCalledTimes(1); + expect(mockDir.content({ path: 'workspace/docs' })).toEqual({ + 'mkdocs.md': 'hello world', + }); }); it('should fail on the first fetch call with response.ok set to false', async () => { diff --git a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md index c04a58e745..541255a2d0 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md @@ -1,5 +1,123 @@ # @backstage/plugin-scaffolder-backend-module-cookiecutter +## 0.2.33 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + +## 0.2.33-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-scaffolder-node@0.2.10-next.2 + +## 0.2.33-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.10-next.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.2.33-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.10-next.0 + +## 0.2.32 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-scaffolder-node@0.2.9 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.2.32-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.9-next.3 + - @backstage/backend-common@0.20.0-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/types@1.1.1 + +## 0.2.32-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.9-next.2 + +## 0.2.32-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.9-next.1 + +## 0.2.32-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/plugin-scaffolder-node@0.2.9-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.2.31 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.2 + - @backstage/backend-common@0.19.9 + - @backstage/plugin-scaffolder-node@0.2.8 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + ## 0.2.31-next.2 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-cookiecutter/package.json b/plugins/scaffolder-backend-module-cookiecutter/package.json index edd0899437..98e96a491d 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/package.json +++ b/plugins/scaffolder-backend-module-cookiecutter/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-backend-module-cookiecutter", "description": "A module for the scaffolder backend that lets you template projects using cookiecutter", - "version": "0.2.31-next.2", + "version": "0.2.33", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -44,8 +44,7 @@ "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@types/command-exists": "^1.2.0", - "@types/fs-extra": "^9.0.1", - "msw": "^1.0.0" + "@types/fs-extra": "^9.0.1" }, "files": [ "dist" diff --git a/plugins/scaffolder-backend-module-gerrit/.eslintrc.js b/plugins/scaffolder-backend-module-gerrit/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/scaffolder-backend-module-gerrit/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md b/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md new file mode 100644 index 0000000000..361549275a --- /dev/null +++ b/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md @@ -0,0 +1,67 @@ +# @backstage/plugin-scaffolder-backend-module-gerrit + +## 0.1.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## 0.1.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.10-next.2 + +## 0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.10-next.1 + - @backstage/errors@1.2.3 + +## 0.1.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/plugin-scaffolder-node@0.2.10-next.0 + +## 0.1.0 + +### Minor Changes + +- 219d7f0: Create new scaffolder module for external integrations + +### Patch Changes + +- d86cd98: Add dry run support for the `publish:gerrit` action. +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.9 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.1.0-next.0 + +### Minor Changes + +- 219d7f0: Create new scaffolder module for external integrations + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.9-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 diff --git a/plugins/scaffolder-backend-module-gerrit/README.md b/plugins/scaffolder-backend-module-gerrit/README.md new file mode 100644 index 0000000000..f1492f5b35 --- /dev/null +++ b/plugins/scaffolder-backend-module-gerrit/README.md @@ -0,0 +1,5 @@ +# @backstage/plugin-scaffolder-backend-module-gerrit + +The gerrit module for [@backstage/plugin-scaffolder-backend](https://www.npmjs.com/package/@backstage/plugin-scaffolder-backend). + +_This plugin was created through the Backstage CLI_ diff --git a/plugins/scaffolder-backend-module-gerrit/api-report.md b/plugins/scaffolder-backend-module-gerrit/api-report.md new file mode 100644 index 0000000000..309de08574 --- /dev/null +++ b/plugins/scaffolder-backend-module-gerrit/api-report.md @@ -0,0 +1,43 @@ +## API Report File for "@backstage/plugin-scaffolder-backend-module-gerrit" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { Config } from '@backstage/config'; +import { JsonObject } from '@backstage/types'; +import { ScmIntegrationRegistry } from '@backstage/integration'; +import { TemplateAction } from '@backstage/plugin-scaffolder-node'; + +// @public +export function createPublishGerritAction(options: { + integrations: ScmIntegrationRegistry; + config: Config; +}): TemplateAction< + { + repoUrl: string; + description: string; + defaultBranch?: string | undefined; + gitCommitMessage?: string | undefined; + gitAuthorName?: string | undefined; + gitAuthorEmail?: string | undefined; + sourcePath?: string | undefined; + }, + JsonObject +>; + +// @public +export function createPublishGerritReviewAction(options: { + integrations: ScmIntegrationRegistry; + config: Config; +}): TemplateAction< + { + repoUrl: string; + branch?: string | undefined; + sourcePath?: string | undefined; + gitCommitMessage?: string | undefined; + gitAuthorName?: string | undefined; + gitAuthorEmail?: string | undefined; + }, + JsonObject +>; +``` diff --git a/plugins/scaffolder-backend-module-gerrit/catalog-info.yaml b/plugins/scaffolder-backend-module-gerrit/catalog-info.yaml new file mode 100644 index 0000000000..3eeb8a9018 --- /dev/null +++ b/plugins/scaffolder-backend-module-gerrit/catalog-info.yaml @@ -0,0 +1,10 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: backstage-plugin-scaffolder-backend-module-gerrit + title: '@backstage/plugin-scaffolder-backend-module-gerrit' + description: The gerrit module for @backstage/plugin-scaffolder-backend +spec: + lifecycle: experimental + type: backstage-backend-plugin-module + owner: maintainers diff --git a/plugins/scaffolder-backend-module-gerrit/package.json b/plugins/scaffolder-backend-module-gerrit/package.json new file mode 100644 index 0000000000..59159560b5 --- /dev/null +++ b/plugins/scaffolder-backend-module-gerrit/package.json @@ -0,0 +1,42 @@ +{ + "name": "@backstage/plugin-scaffolder-backend-module-gerrit", + "description": "The gerrit module for @backstage/plugin-scaffolder-backend", + "version": "0.1.1", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "backend-plugin-module" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/config": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/integration": "workspace:^", + "@backstage/plugin-scaffolder-node": "workspace:^", + "node-fetch": "^2.6.7", + "yaml": "^2.0.0" + }, + "devDependencies": { + "@backstage/backend-common": "workspace:^", + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", + "msw": "^1.0.0" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gerrit.examples.ts b/plugins/scaffolder-backend-module-gerrit/src/actions/gerrit.examples.ts similarity index 100% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gerrit.examples.ts rename to plugins/scaffolder-backend-module-gerrit/src/actions/gerrit.examples.ts diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gerrit.test.ts b/plugins/scaffolder-backend-module-gerrit/src/actions/gerrit.test.ts similarity index 92% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gerrit.test.ts rename to plugins/scaffolder-backend-module-gerrit/src/actions/gerrit.test.ts index 73dcc47225..d05c8727c4 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gerrit.test.ts +++ b/plugins/scaffolder-backend-module-gerrit/src/actions/gerrit.test.ts @@ -14,8 +14,9 @@ * limitations under the License. */ -jest.mock('../helpers', () => { +jest.mock('@backstage/plugin-scaffolder-node', () => { return { + ...jest.requireActual('@backstage/plugin-scaffolder-node'), initRepoAndPush: jest.fn().mockResolvedValue({ commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6', }), @@ -34,7 +35,7 @@ import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; import { getVoidLogger } from '@backstage/backend-common'; import { PassThrough } from 'stream'; -import { initRepoAndPush } from '../helpers'; +import { initRepoAndPush } from '@backstage/plugin-scaffolder-node'; describe('publish:gerrit', () => { const config = new ConfigReader({ @@ -240,7 +241,22 @@ describe('publish:gerrit', () => { 'https://gerrithost.org/repo/+/refs/heads/master', ); }); + it('should not create new projects on dryRun', async () => { + await action.handler({ + ...mockContext, + isDryRun: true, + input: { + ...mockContext.input, + repoUrl: 'gerrithost.org?workspace=workspace&repo=repo', + sourcePath: 'repository/', + }, + }); + expect(mockContext.output).toHaveBeenCalledWith( + 'commitHash', + 'abcd-dry-run-1234', + ); + }); afterEach(() => { jest.resetAllMocks(); }); diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gerrit.ts b/plugins/scaffolder-backend-module-gerrit/src/actions/gerrit.ts similarity index 87% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gerrit.ts rename to plugins/scaffolder-backend-module-gerrit/src/actions/gerrit.ts index 67ed868c4c..6f729227e6 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gerrit.ts +++ b/plugins/scaffolder-backend-module-gerrit/src/actions/gerrit.ts @@ -22,10 +22,13 @@ import { getGerritRequestOptions, ScmIntegrationRegistry, } from '@backstage/integration'; -import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; -import { getRepoSourceDirectory, parseRepoUrl } from './util'; +import { + createTemplateAction, + initRepoAndPush, + getRepoSourceDirectory, + parseRepoUrl, +} from '@backstage/plugin-scaffolder-node'; import fetch, { Response, RequestInit } from 'node-fetch'; -import { initRepoAndPush } from '../helpers'; import { examples } from './gerrit.examples'; const createGerritProject = async ( @@ -97,6 +100,7 @@ export function createPublishGerritAction(options: { sourcePath?: string; }>({ id: 'publish:gerrit', + supportsDryRun: true, description: 'Initializes a git repository of the content in the workspace, and publishes it to Gerrit.', examples, @@ -187,6 +191,31 @@ export function createPublishGerritAction(options: { ); } + const repoContentsUrl = `${integrationConfig.config.gitilesBaseUrl}/${repo}/+/refs/heads/${defaultBranch}`; + const remoteUrl = `${integrationConfig.config.cloneUrl}/a/${repo}`; + const gitName = gitAuthorName + ? gitAuthorName + : config.getOptionalString('scaffolder.defaultAuthor.name'); + const gitEmail = gitAuthorEmail + ? gitAuthorEmail + : config.getOptionalString('scaffolder.defaultAuthor.email'); + const commitMessage = generateCommitMessage(config, gitCommitMessage); + + if (ctx.isDryRun) { + ctx.logger.info( + `Dry run arguments: ${{ + gitName, + gitEmail, + commitMessage, + ...ctx.input, + }}`, + ); + ctx.output('remoteUrl', remoteUrl); + ctx.output('commitHash', 'abcd-dry-run-1234'); + ctx.output('repoContentsUrl', repoContentsUrl); + return; + } + await createGerritProject(integrationConfig.config, { description, owner: owner, @@ -198,15 +227,10 @@ export function createPublishGerritAction(options: { password: integrationConfig.config.password!, }; const gitAuthorInfo = { - name: gitAuthorName - ? gitAuthorName - : config.getOptionalString('scaffolder.defaultAuthor.name'), - email: gitAuthorEmail - ? gitAuthorEmail - : config.getOptionalString('scaffolder.defaultAuthor.email'), + name: gitName, + email: gitEmail, }; - const remoteUrl = `${integrationConfig.config.cloneUrl}/a/${repo}`; const commitResult = await initRepoAndPush({ dir: getRepoSourceDirectory(ctx.workspacePath, sourcePath), remoteUrl, @@ -217,7 +241,6 @@ export function createPublishGerritAction(options: { gitAuthorInfo, }); - const repoContentsUrl = `${integrationConfig.config.gitilesBaseUrl}/${repo}/+/refs/heads/${defaultBranch}`; ctx.output('remoteUrl', remoteUrl); ctx.output('commitHash', commitResult?.commitHash); ctx.output('repoContentsUrl', repoContentsUrl); diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gerritReview.test.ts b/plugins/scaffolder-backend-module-gerrit/src/actions/gerritReview.test.ts similarity index 93% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gerritReview.test.ts rename to plugins/scaffolder-backend-module-gerrit/src/actions/gerritReview.test.ts index 55d7bde5a7..eeae3871ee 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gerritReview.test.ts +++ b/plugins/scaffolder-backend-module-gerrit/src/actions/gerritReview.test.ts @@ -14,14 +14,19 @@ * limitations under the License. */ -jest.mock('../helpers'); +jest.mock('@backstage/plugin-scaffolder-node', () => { + return { + ...jest.requireActual('@backstage/plugin-scaffolder-node'), + commitAndPushRepo: jest.fn(), + }; +}); import { createPublishGerritReviewAction } from './gerritReview'; import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; import { getVoidLogger } from '@backstage/backend-common'; import { PassThrough } from 'stream'; -import { commitAndPushRepo } from '../helpers'; +import { commitAndPushRepo } from '@backstage/plugin-scaffolder-node'; describe('publish:gerrit:review', () => { const config = new ConfigReader({ diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gerritReview.ts b/plugins/scaffolder-backend-module-gerrit/src/actions/gerritReview.ts similarity index 96% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gerritReview.ts rename to plugins/scaffolder-backend-module-gerrit/src/actions/gerritReview.ts index 73e74f5cbc..bd8d0321ab 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gerritReview.ts +++ b/plugins/scaffolder-backend-module-gerrit/src/actions/gerritReview.ts @@ -18,9 +18,12 @@ import crypto from 'crypto'; import { InputError } from '@backstage/errors'; import { Config } from '@backstage/config'; import { ScmIntegrationRegistry } from '@backstage/integration'; -import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; -import { getRepoSourceDirectory, parseRepoUrl } from './util'; -import { commitAndPushRepo } from '../helpers'; +import { + createTemplateAction, + commitAndPushRepo, + getRepoSourceDirectory, + parseRepoUrl, +} from '@backstage/plugin-scaffolder-node'; const generateGerritChangeId = (): string => { const changeId = crypto.randomBytes(20).toString('hex'); diff --git a/plugins/scaffolder-backend-module-gerrit/src/actions/index.ts b/plugins/scaffolder-backend-module-gerrit/src/actions/index.ts new file mode 100644 index 0000000000..1918679320 --- /dev/null +++ b/plugins/scaffolder-backend-module-gerrit/src/actions/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export * from './gerrit'; +export * from './gerritReview'; diff --git a/plugins/scaffolder-backend-module-gerrit/src/index.ts b/plugins/scaffolder-backend-module-gerrit/src/index.ts new file mode 100644 index 0000000000..b00c307fa5 --- /dev/null +++ b/plugins/scaffolder-backend-module-gerrit/src/index.ts @@ -0,0 +1,23 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * A module for the scaffolder backend that lets you interact with gerrit + * + * @packageDocumentation + */ + +export * from './actions'; diff --git a/plugins/scaffolder-backend-module-github/.eslintrc.js b/plugins/scaffolder-backend-module-github/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/scaffolder-backend-module-github/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/scaffolder-backend-module-github/CHANGELOG.md b/plugins/scaffolder-backend-module-github/CHANGELOG.md new file mode 100644 index 0000000000..0f0ce0a045 --- /dev/null +++ b/plugins/scaffolder-backend-module-github/CHANGELOG.md @@ -0,0 +1,77 @@ +# @backstage/plugin-scaffolder-backend-module-github + +## 0.1.1 + +### Patch Changes + +- 5470300: Ensure `teamReviewers` list is unique before calling API +- bf92ae3: Updated dependency `octokit` to `^3.0.0`. +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## 0.1.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-scaffolder-node@0.2.10-next.2 + +## 0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.10-next.1 + - @backstage/errors@1.2.3 + +## 0.1.1-next.0 + +### Patch Changes + +- bf92ae3: Updated dependency `octokit` to `^3.0.0`. +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/plugin-scaffolder-node@0.2.10-next.0 + +## 0.1.0 + +### Minor Changes + +- 219d7f0: Create new scaffolder module for external integrations + +### Patch Changes + +- cb6a65e: The `scaffolder.defaultCommitMessage` config value is now being used if provided and uses "initial commit" when it is not provided. +- 28949ea: Add a new action for creating github-autolink references for a repository: `github:autolinks:create` +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-scaffolder-node@0.2.9 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.1.0-next.0 + +### Minor Changes + +- 219d7f0: Create new scaffolder module for external integrations + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.9-next.3 + - @backstage/backend-common@0.20.0-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 diff --git a/plugins/scaffolder-backend-module-github/README.md b/plugins/scaffolder-backend-module-github/README.md new file mode 100644 index 0000000000..ba4b3a8787 --- /dev/null +++ b/plugins/scaffolder-backend-module-github/README.md @@ -0,0 +1,5 @@ +# @backstage/plugin-scaffolder-backend-module-github + +The github module for [@backstage/plugin-scaffolder-backend](https://www.npmjs.com/package/@backstage/plugin-scaffolder-backend). + +_This plugin was created through the Backstage CLI_ diff --git a/plugins/scaffolder-backend-module-github/api-report.md b/plugins/scaffolder-backend-module-github/api-report.md new file mode 100644 index 0000000000..920be79d12 --- /dev/null +++ b/plugins/scaffolder-backend-module-github/api-report.md @@ -0,0 +1,380 @@ +## API Report File for "@backstage/plugin-scaffolder-backend-module-github" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { Config } from '@backstage/config'; +import { createPullRequest } from 'octokit-plugin-create-pull-request'; +import { GithubCredentialsProvider } from '@backstage/integration'; +import { JsonObject } from '@backstage/types'; +import { Octokit } from 'octokit'; +import { ScmIntegrationRegistry } from '@backstage/integration'; +import { ScmIntegrations } from '@backstage/integration'; +import { TemplateAction } from '@backstage/plugin-scaffolder-node'; + +// @public +export function createGithubActionsDispatchAction(options: { + integrations: ScmIntegrations; + githubCredentialsProvider?: GithubCredentialsProvider; +}): TemplateAction< + { + repoUrl: string; + workflowId: string; + branchOrTagName: string; + workflowInputs?: + | { + [key: string]: string; + } + | undefined; + token?: string | undefined; + }, + JsonObject +>; + +// @public +export function createGithubAutolinksAction(options: { + integrations: ScmIntegrations; + githubCredentialsProvider?: GithubCredentialsProvider; +}): TemplateAction< + { + repoUrl: string; + keyPrefix: string; + urlTemplate: string; + isAlphanumeric?: boolean | undefined; + token?: string | undefined; + }, + JsonObject +>; + +// @public +export function createGithubDeployKeyAction(options: { + integrations: ScmIntegrationRegistry; +}): TemplateAction< + { + repoUrl: string; + publicKey: string; + privateKey: string; + deployKeyName: string; + privateKeySecretName?: string | undefined; + token?: string | undefined; + }, + JsonObject +>; + +// @public +export function createGithubEnvironmentAction(options: { + integrations: ScmIntegrationRegistry; +}): TemplateAction< + { + repoUrl: string; + name: string; + deploymentBranchPolicy?: + | { + protected_branches: boolean; + custom_branch_policies: boolean; + } + | undefined; + customBranchPolicyNames?: string[] | undefined; + environmentVariables?: + | { + [key: string]: string; + } + | undefined; + secrets?: + | { + [key: string]: string; + } + | undefined; + token?: string | undefined; + }, + JsonObject +>; + +// @public +export function createGithubIssuesLabelAction(options: { + integrations: ScmIntegrationRegistry; + githubCredentialsProvider?: GithubCredentialsProvider; +}): TemplateAction< + { + repoUrl: string; + number: number; + labels: string[]; + token?: string | undefined; + }, + JsonObject +>; + +// @public +export interface CreateGithubPullRequestActionOptions { + clientFactory?: (input: { + integrations: ScmIntegrationRegistry; + githubCredentialsProvider?: GithubCredentialsProvider; + host: string; + owner: string; + repo: string; + token?: string; + }) => Promise< + Octokit & { + createPullRequest(options: createPullRequest.Options): Promise<{ + data: { + html_url: string; + number: number; + base: { + ref: string; + }; + }; + } | null>; + } + >; + githubCredentialsProvider?: GithubCredentialsProvider; + integrations: ScmIntegrationRegistry; +} + +// @public +export function createGithubRepoCreateAction(options: { + integrations: ScmIntegrationRegistry; + githubCredentialsProvider?: GithubCredentialsProvider; +}): TemplateAction< + { + repoUrl: string; + description?: string | undefined; + homepage?: string | undefined; + access?: string | undefined; + deleteBranchOnMerge?: boolean | undefined; + gitAuthorName?: string | undefined; + gitAuthorEmail?: string | undefined; + allowRebaseMerge?: boolean | undefined; + allowSquashMerge?: boolean | undefined; + squashMergeCommitTitle?: 'PR_TITLE' | 'COMMIT_OR_PR_TITLE' | undefined; + squashMergeCommitMessage?: + | 'PR_BODY' + | 'COMMIT_MESSAGES' + | 'BLANK' + | undefined; + allowMergeCommit?: boolean | undefined; + allowAutoMerge?: boolean | undefined; + requireCodeOwnerReviews?: boolean | undefined; + bypassPullRequestAllowances?: + | { + users?: string[] | undefined; + teams?: string[] | undefined; + apps?: string[] | undefined; + } + | undefined; + requiredApprovingReviewCount?: number | undefined; + restrictions?: + | { + users: string[]; + teams: string[]; + apps?: string[] | undefined; + } + | undefined; + requiredStatusCheckContexts?: string[] | undefined; + requireBranchesToBeUpToDate?: boolean | undefined; + requiredConversationResolution?: boolean | undefined; + repoVisibility?: 'internal' | 'private' | 'public' | undefined; + collaborators?: + | ( + | { + user: string; + access: string; + } + | { + team: string; + access: string; + } + | { + username: string; + access: 'pull' | 'push' | 'admin' | 'maintain' | 'triage'; + } + )[] + | undefined; + hasProjects?: boolean | undefined; + hasWiki?: boolean | undefined; + hasIssues?: boolean | undefined; + token?: string | undefined; + topics?: string[] | undefined; + repoVariables?: + | { + [key: string]: string; + } + | undefined; + secrets?: + | { + [key: string]: string; + } + | undefined; + requireCommitSigning?: boolean | undefined; + }, + JsonObject +>; + +// @public +export function createGithubRepoPushAction(options: { + integrations: ScmIntegrationRegistry; + config: Config; + githubCredentialsProvider?: GithubCredentialsProvider; +}): TemplateAction< + { + repoUrl: string; + description?: string | undefined; + defaultBranch?: string | undefined; + protectDefaultBranch?: boolean | undefined; + protectEnforceAdmins?: boolean | undefined; + gitCommitMessage?: string | undefined; + gitAuthorName?: string | undefined; + gitAuthorEmail?: string | undefined; + requireCodeOwnerReviews?: boolean | undefined; + dismissStaleReviews?: boolean | undefined; + bypassPullRequestAllowances?: + | { + users?: string[]; + teams?: string[]; + apps?: string[]; + } + | undefined; + requiredApprovingReviewCount?: number | undefined; + restrictions?: + | { + users: string[]; + teams: string[]; + apps?: string[]; + } + | undefined; + requiredStatusCheckContexts?: string[] | undefined; + requireBranchesToBeUpToDate?: boolean | undefined; + requiredConversationResolution?: boolean | undefined; + sourcePath?: string | undefined; + token?: string | undefined; + requiredCommitSigning?: boolean | undefined; + }, + JsonObject +>; + +// @public +export function createGithubWebhookAction(options: { + integrations: ScmIntegrationRegistry; + defaultWebhookSecret?: string; + githubCredentialsProvider?: GithubCredentialsProvider; +}): TemplateAction< + { + repoUrl: string; + webhookUrl: string; + webhookSecret?: string | undefined; + events?: string[] | undefined; + active?: boolean | undefined; + contentType?: 'form' | 'json' | undefined; + insecureSsl?: boolean | undefined; + token?: string | undefined; + }, + JsonObject +>; + +// @public +export function createPublishGithubAction(options: { + integrations: ScmIntegrationRegistry; + config: Config; + githubCredentialsProvider?: GithubCredentialsProvider; +}): TemplateAction< + { + repoUrl: string; + description?: string | undefined; + homepage?: string | undefined; + access?: string | undefined; + defaultBranch?: string | undefined; + protectDefaultBranch?: boolean | undefined; + protectEnforceAdmins?: boolean | undefined; + deleteBranchOnMerge?: boolean | undefined; + gitCommitMessage?: string | undefined; + gitAuthorName?: string | undefined; + gitAuthorEmail?: string | undefined; + allowRebaseMerge?: boolean | undefined; + allowSquashMerge?: boolean | undefined; + squashMergeCommitTitle?: 'PR_TITLE' | 'COMMIT_OR_PR_TITLE' | undefined; + squashMergeCommitMessage?: + | 'PR_BODY' + | 'COMMIT_MESSAGES' + | 'BLANK' + | undefined; + allowMergeCommit?: boolean | undefined; + allowAutoMerge?: boolean | undefined; + sourcePath?: string | undefined; + bypassPullRequestAllowances?: + | { + users?: string[]; + teams?: string[]; + apps?: string[]; + } + | undefined; + requiredApprovingReviewCount?: number | undefined; + restrictions?: + | { + users: string[]; + teams: string[]; + apps?: string[]; + } + | undefined; + requireCodeOwnerReviews?: boolean | undefined; + dismissStaleReviews?: boolean | undefined; + requiredStatusCheckContexts?: string[] | undefined; + requireBranchesToBeUpToDate?: boolean | undefined; + requiredConversationResolution?: boolean | undefined; + repoVisibility?: 'internal' | 'private' | 'public' | undefined; + collaborators?: + | ( + | { + user: string; + access: string; + } + | { + team: string; + access: string; + } + | { + username: string; + access: 'pull' | 'push' | 'admin' | 'maintain' | 'triage'; + } + )[] + | undefined; + hasProjects?: boolean | undefined; + hasWiki?: boolean | undefined; + hasIssues?: boolean | undefined; + token?: string | undefined; + topics?: string[] | undefined; + repoVariables?: + | { + [key: string]: string; + } + | undefined; + secrets?: + | { + [key: string]: string; + } + | undefined; + requiredCommitSigning?: boolean | undefined; + }, + JsonObject +>; + +// @public +export const createPublishGithubPullRequestAction: ( + options: CreateGithubPullRequestActionOptions, +) => TemplateAction< + { + title: string; + branchName: string; + targetBranchName?: string | undefined; + description: string; + repoUrl: string; + draft?: boolean | undefined; + targetPath?: string | undefined; + sourcePath?: string | undefined; + token?: string | undefined; + reviewers?: string[] | undefined; + teamReviewers?: string[] | undefined; + commitMessage?: string | undefined; + update?: boolean | undefined; + }, + JsonObject +>; +``` diff --git a/plugins/scaffolder-backend-module-github/catalog-info.yaml b/plugins/scaffolder-backend-module-github/catalog-info.yaml new file mode 100644 index 0000000000..5e70704940 --- /dev/null +++ b/plugins/scaffolder-backend-module-github/catalog-info.yaml @@ -0,0 +1,10 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: backstage-plugin-scaffolder-backend-module-github + title: '@backstage/plugin-scaffolder-backend-module-github' + description: The github module for @backstage/plugin-scaffolder-backend +spec: + lifecycle: experimental + type: backstage-backend-plugin-module + owner: maintainers diff --git a/plugins/scaffolder-backend-module-github/package.json b/plugins/scaffolder-backend-module-github/package.json new file mode 100644 index 0000000000..b035096dad --- /dev/null +++ b/plugins/scaffolder-backend-module-github/package.json @@ -0,0 +1,49 @@ +{ + "name": "@backstage/plugin-scaffolder-backend-module-github", + "description": "The github module for @backstage/plugin-scaffolder-backend", + "version": "0.1.1", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "backend-plugin-module" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/backend-common": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/integration": "workspace:^", + "@backstage/plugin-scaffolder-node": "workspace:^", + "@octokit/webhooks": "^10.0.0", + "libsodium-wrappers": "^0.7.11", + "octokit": "^3.0.0", + "octokit-plugin-create-pull-request": "^3.10.0", + "winston": "^3.2.1", + "yaml": "^2.0.0" + }, + "devDependencies": { + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", + "@types/libsodium-wrappers": "^0.7.10", + "fs-extra": "10.1.0", + "jest-when": "^3.1.0", + "jsonschema": "^1.2.6" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/helpers.ts b/plugins/scaffolder-backend-module-github/src/actions/gitHelpers.ts similarity index 58% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/helpers.ts rename to plugins/scaffolder-backend-module-github/src/actions/gitHelpers.ts index 5ac92128ca..84d8e507b3 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/helpers.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/gitHelpers.ts @@ -14,121 +14,10 @@ * limitations under the License. */ -import { Git } from '@backstage/backend-common'; -import { Config } from '@backstage/config'; import { assertError } from '@backstage/errors'; import { Octokit } from 'octokit'; import { Logger } from 'winston'; -export async function initRepoAndPush({ - dir, - remoteUrl, - auth, - logger, - defaultBranch = 'master', - commitMessage = 'Initial commit', - gitAuthorInfo, -}: { - dir: string; - remoteUrl: string; - // For use cases where token has to be used with Basic Auth - // it has to be provided as password together with a username - // which may be a fixed value defined by the provider. - auth: { username: string; password: string } | { token: string }; - logger: Logger; - defaultBranch?: string; - commitMessage?: string; - gitAuthorInfo?: { name?: string; email?: string }; -}): Promise<{ commitHash: string }> { - const git = Git.fromAuth({ - ...auth, - logger, - }); - - await git.init({ - dir, - defaultBranch, - }); - - await git.add({ dir, filepath: '.' }); - - // use provided info if possible, otherwise use fallbacks - const authorInfo = { - name: gitAuthorInfo?.name ?? 'Scaffolder', - email: gitAuthorInfo?.email ?? 'scaffolder@backstage.io', - }; - - const commitHash = await git.commit({ - dir, - message: commitMessage, - author: authorInfo, - committer: authorInfo, - }); - await git.addRemote({ - dir, - url: remoteUrl, - remote: 'origin', - }); - - await git.push({ - dir, - remote: 'origin', - }); - - return { commitHash }; -} - -export async function commitAndPushRepo({ - dir, - auth, - logger, - commitMessage, - gitAuthorInfo, - branch = 'master', - remoteRef, -}: { - dir: string; - // For use cases where token has to be used with Basic Auth - // it has to be provided as password together with a username - // which may be a fixed value defined by the provider. - auth: { username: string; password: string } | { token: string }; - logger: Logger; - commitMessage: string; - gitAuthorInfo?: { name?: string; email?: string }; - branch?: string; - remoteRef?: string; -}): Promise<{ commitHash: string }> { - const git = Git.fromAuth({ - ...auth, - logger, - }); - - await git.fetch({ dir }); - await git.checkout({ dir, ref: branch }); - await git.add({ dir, filepath: '.' }); - - // use provided info if possible, otherwise use fallbacks - const authorInfo = { - name: gitAuthorInfo?.name ?? 'Scaffolder', - email: gitAuthorInfo?.email ?? 'scaffolder@backstage.io', - }; - - const commitHash = await git.commit({ - dir, - message: commitMessage, - author: authorInfo, - committer: authorInfo, - }); - - await git.push({ - dir, - remote: 'origin', - remoteRef: remoteRef ?? `refs/heads/${branch}`, - }); - - return { commitHash }; -} - type BranchProtectionOptions = { client: Octokit; owner: string; @@ -239,15 +128,6 @@ export const enableBranchProtectionOnDefaultRepoBranch = async ({ } }; -export function getGitCommitMessage( - gitCommitMessage: string | undefined, - config: Config, -): string | undefined { - return gitCommitMessage - ? gitCommitMessage - : config.getOptionalString('scaffolder.defaultCommitMessage'); -} - export function entityRefToName(name: string): string { return name.replace(/^.*[:/]/g, ''); } diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/gitHubEnvironment.examples.ts b/plugins/scaffolder-backend-module-github/src/actions/gitHubEnvironment.examples.ts similarity index 100% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/gitHubEnvironment.examples.ts rename to plugins/scaffolder-backend-module-github/src/actions/gitHubEnvironment.examples.ts diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.examples.test.ts b/plugins/scaffolder-backend-module-github/src/actions/github.examples.test.ts similarity index 85% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.examples.test.ts rename to plugins/scaffolder-backend-module-github/src/actions/github.examples.test.ts index 4d87ec97c4..7ea5e025ce 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.examples.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/github.examples.test.ts @@ -13,9 +13,29 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -jest.mock('../helpers'); +jest.mock('./gitHelpers', () => { + return { + ...jest.requireActual('./gitHelpers'), + entityRefToName: jest.fn(), + }; +}); -import { TemplateAction } from '@backstage/plugin-scaffolder-node'; +jest.mock('@backstage/plugin-scaffolder-node', () => { + return { + ...jest.requireActual('@backstage/plugin-scaffolder-node'), + initRepoAndPush: jest.fn().mockResolvedValue({ + commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6', + }), + commitAndPushRepo: jest.fn().mockResolvedValue({ + commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6', + }), + }; +}); + +import { + TemplateAction, + initRepoAndPush, +} from '@backstage/plugin-scaffolder-node'; import { getVoidLogger } from '@backstage/backend-common'; import { ConfigReader } from '@backstage/config'; import { @@ -24,10 +44,10 @@ import { ScmIntegrations, } from '@backstage/integration'; import { PassThrough } from 'stream'; -import { entityRefToName, initRepoAndPush } from '../helpers'; import { createPublishGithubAction } from './github'; import { examples } from './github.examples'; import yaml from 'yaml'; +import { entityRefToName } from './gitHelpers'; const publicKey = '2Sg8iYjAxxmI2LvUXpJjkYrMxURPc8r+dB7TJyvvcCU='; @@ -76,7 +96,7 @@ describe('publish:github', () => { }); const { entityRefToName: realFamiliarizeEntityName } = - jest.requireActual('../helpers'); + jest.requireActual('./helpers'); const integrations = ScmIntegrations.fromConfig(config); let githubCredentialsProvider: GithubCredentialsProvider; let action: TemplateAction; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.examples.ts b/plugins/scaffolder-backend-module-github/src/actions/github.examples.ts similarity index 100% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.examples.ts rename to plugins/scaffolder-backend-module-github/src/actions/github.examples.ts diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.test.ts b/plugins/scaffolder-backend-module-github/src/actions/github.test.ts similarity index 98% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.test.ts rename to plugins/scaffolder-backend-module-github/src/actions/github.test.ts index e15d085cbf..a2a8e11e15 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/github.test.ts @@ -13,7 +13,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -jest.mock('../helpers'); +jest.mock('./gitHelpers', () => { + return { + ...jest.requireActual('./gitHelpers'), + enableBranchProtectionOnDefaultRepoBranch: jest.fn(), + entityRefToName: jest.fn(), + }; +}); + +jest.mock('@backstage/plugin-scaffolder-node', () => { + return { + ...jest.requireActual('@backstage/plugin-scaffolder-node'), + initRepoAndPush: jest.fn().mockResolvedValue({ + commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6', + }), + commitAndPushRepo: jest.fn().mockResolvedValue({ + commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6', + }), + }; +}); import { TemplateAction } from '@backstage/plugin-scaffolder-node'; import { getVoidLogger } from '@backstage/backend-common'; @@ -25,12 +43,12 @@ import { } from '@backstage/integration'; import { when } from 'jest-when'; import { PassThrough } from 'stream'; +import { createPublishGithubAction } from './github'; +import { initRepoAndPush } from '@backstage/plugin-scaffolder-node'; import { enableBranchProtectionOnDefaultRepoBranch, entityRefToName, - initRepoAndPush, -} from '../helpers'; -import { createPublishGithubAction } from './github'; +} from './gitHelpers'; const publicKey = '2Sg8iYjAxxmI2LvUXpJjkYrMxURPc8r+dB7TJyvvcCU='; @@ -79,7 +97,7 @@ describe('publish:github', () => { }); const { entityRefToName: realFamiliarizeEntityName } = - jest.requireActual('../helpers'); + jest.requireActual('./gitHelpers'); const integrations = ScmIntegrations.fromConfig(config); let githubCredentialsProvider: GithubCredentialsProvider; let action: TemplateAction; @@ -546,7 +564,7 @@ describe('publish:github', () => { defaultBranch: 'master', auth: { username: 'x-access-token', password: 'tokenlols' }, logger: mockContext.logger, - commitMessage: 'initial commit', + commitMessage: 'Test commit message', gitAuthorInfo: { email: undefined, name: undefined }, }); }); diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts b/plugins/scaffolder-backend-module-github/src/actions/github.ts similarity index 96% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts rename to plugins/scaffolder-backend-module-github/src/actions/github.ts index e5b6071863..91d7a34aea 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/github.ts @@ -21,15 +21,17 @@ import { ScmIntegrationRegistry, } from '@backstage/integration'; import { Octokit } from 'octokit'; -import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; +import { + createTemplateAction, + parseRepoUrl, +} from '@backstage/plugin-scaffolder-node'; import { createGithubRepoWithCollaboratorsAndTopics, getOctokitOptions, initRepoPushAndProtect, -} from '../github/helpers'; -import * as inputProps from '../github/inputProperties'; -import * as outputProps from '../github/outputProperties'; -import { parseRepoUrl } from './util'; +} from './helpers'; +import * as inputProps from './inputProperties'; +import * as outputProps from './outputProperties'; import { examples } from './github.examples'; /** @@ -185,7 +187,7 @@ export function createPublishGithubAction(options: { protectDefaultBranch = true, protectEnforceAdmins = true, deleteBranchOnMerge = false, - gitCommitMessage = 'initial commit', + gitCommitMessage, gitAuthorName, gitAuthorEmail, allowMergeCommit = true, diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubActionsDispatch.examples.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubActionsDispatch.examples.test.ts similarity index 100% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubActionsDispatch.examples.test.ts rename to plugins/scaffolder-backend-module-github/src/actions/githubActionsDispatch.examples.test.ts diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubActionsDispatch.examples.ts b/plugins/scaffolder-backend-module-github/src/actions/githubActionsDispatch.examples.ts similarity index 100% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubActionsDispatch.examples.ts rename to plugins/scaffolder-backend-module-github/src/actions/githubActionsDispatch.examples.ts diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubActionsDispatch.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubActionsDispatch.test.ts similarity index 100% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubActionsDispatch.test.ts rename to plugins/scaffolder-backend-module-github/src/actions/githubActionsDispatch.test.ts diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubActionsDispatch.ts b/plugins/scaffolder-backend-module-github/src/actions/githubActionsDispatch.ts similarity index 96% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubActionsDispatch.ts rename to plugins/scaffolder-backend-module-github/src/actions/githubActionsDispatch.ts index 6623ee1f27..0d24b74927 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubActionsDispatch.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubActionsDispatch.ts @@ -19,9 +19,11 @@ import { GithubCredentialsProvider, ScmIntegrations, } from '@backstage/integration'; -import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; +import { + createTemplateAction, + parseRepoUrl, +} from '@backstage/plugin-scaffolder-node'; import { Octokit } from 'octokit'; -import { parseRepoUrl } from '../publish/util'; import { getOctokitOptions } from './helpers'; import { examples } from './githubActionsDispatch.examples'; diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubAutolinks.examples.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubAutolinks.examples.test.ts new file mode 100644 index 0000000000..612f68dea2 --- /dev/null +++ b/plugins/scaffolder-backend-module-github/src/actions/githubAutolinks.examples.test.ts @@ -0,0 +1,90 @@ +/* + * 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 { getVoidLogger } from '@backstage/backend-common'; +import { ConfigReader } from '@backstage/config'; +import { + DefaultGithubCredentialsProvider, + GithubCredentialsProvider, + ScmIntegrations, +} from '@backstage/integration'; +import { TemplateAction } from '@backstage/plugin-scaffolder-node'; +import { PassThrough } from 'stream'; +import { createGithubAutolinksAction } from './githubAutolinks'; +import { examples } from './githubAutolinks.examples'; +import yaml from 'yaml'; + +const mockOctokit = { + rest: { + repos: { + createAutolink: jest.fn(), + }, + }, +}; +jest.mock('octokit', () => ({ + Octokit: class { + constructor() { + return mockOctokit; + } + }, +})); + +describe('github:autolinks:create', () => { + const config = new ConfigReader({ + integrations: { + github: [ + { host: 'github.com', token: 'tokenlols' }, + { host: 'ghe.github.com' }, + ], + }, + }); + + const integrations = ScmIntegrations.fromConfig(config); + let githubCredentialsProvider: GithubCredentialsProvider; + let action: TemplateAction; + + it('should call the githubApis for creating autolink reference', async () => { + const input = yaml.parse(examples[0].example).steps[0].input; + githubCredentialsProvider = + DefaultGithubCredentialsProvider.fromIntegrations(integrations); + action = createGithubAutolinksAction({ + integrations, + githubCredentialsProvider, + }); + + mockOctokit.rest.repos.createAutolink.mockResolvedValue({ + data: { + id: '1', + }, + }); + await action.handler({ + input, + workspacePath: 'lol', + logger: getVoidLogger(), + logStream: new PassThrough(), + output: jest.fn(), + createTemporaryDirectory: jest.fn(), + }); + + expect(mockOctokit.rest.repos.createAutolink).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repo', + key_prefix: 'TICKET-', + url_template: 'https://example.com/TICKET?query=', + is_alphanumeric: false, + }); + }); +}); diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubAutolinks.examples.ts b/plugins/scaffolder-backend-module-github/src/actions/githubAutolinks.examples.ts new file mode 100644 index 0000000000..5acaeeb6e2 --- /dev/null +++ b/plugins/scaffolder-backend-module-github/src/actions/githubAutolinks.examples.ts @@ -0,0 +1,38 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { TemplateExample } from '@backstage/plugin-scaffolder-node'; +import yaml from 'yaml'; + +export const examples: TemplateExample[] = [ + { + description: 'GitHub alphanumric autolink reference', + example: yaml.stringify({ + steps: [ + { + action: 'github:autolinks:create', + name: 'Create an autolink reference', + input: { + repoUrl: 'github.com?repo=repo&owner=owner', + keyPrefix: 'TICKET-', + urlTemplate: 'https://example.com/TICKET?query=', + isAlphanumeric: false, + }, + }, + ], + }), + }, +]; diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubAutolinks.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubAutolinks.test.ts new file mode 100644 index 0000000000..95c0226104 --- /dev/null +++ b/plugins/scaffolder-backend-module-github/src/actions/githubAutolinks.test.ts @@ -0,0 +1,125 @@ +/* + * 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 { getVoidLogger } from '@backstage/backend-common'; +import { ConfigReader } from '@backstage/config'; +import { + DefaultGithubCredentialsProvider, + GithubCredentialsProvider, + ScmIntegrations, +} from '@backstage/integration'; +import { TemplateAction } from '@backstage/plugin-scaffolder-node'; +import { PassThrough } from 'stream'; +import { createGithubAutolinksAction } from './githubAutolinks'; + +const mockOctokit = { + rest: { + repos: { + createAutolink: jest.fn(), + }, + }, +}; +jest.mock('octokit', () => ({ + Octokit: class { + constructor() { + return mockOctokit; + } + }, +})); + +describe('github:autolinks:create', () => { + const config = new ConfigReader({ + integrations: { + github: [ + { host: 'github.com', token: 'tokenlols' }, + { host: 'ghe.github.com' }, + ], + }, + }); + + const integrations = ScmIntegrations.fromConfig(config); + let githubCredentialsProvider: GithubCredentialsProvider; + let action: TemplateAction; + const mockContext = { + workspacePath: 'lol', + logger: getVoidLogger(), + logStream: new PassThrough(), + output: jest.fn(), + createTemporaryDirectory: jest.fn(), + }; + + it('should call the githubApis for creating alphanumeric autolink reference', async () => { + githubCredentialsProvider = + DefaultGithubCredentialsProvider.fromIntegrations(integrations); + action = createGithubAutolinksAction({ + integrations, + githubCredentialsProvider, + }); + + mockOctokit.rest.repos.createAutolink.mockResolvedValue({ + data: { + id: '1', + }, + }); + await action.handler({ + input: { + repoUrl: 'github.com?repo=repo&owner=owner', + keyPrefix: 'TICKET-', + urlTemplate: 'https://example.com/TICKET?query=', + }, + ...mockContext, + }); + + expect(mockOctokit.rest.repos.createAutolink).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repo', + key_prefix: 'TICKET-', + url_template: 'https://example.com/TICKET?query=', + }); + }); + + it('should call the githubApis for creating numeric autolink reference', async () => { + githubCredentialsProvider = + DefaultGithubCredentialsProvider.fromIntegrations(integrations); + action = createGithubAutolinksAction({ + integrations, + githubCredentialsProvider, + }); + + mockOctokit.rest.repos.createAutolink.mockResolvedValue({ + data: { + id: '1', + }, + }); + await action.handler({ + input: { + repoUrl: 'github.com?repo=repo&owner=owner', + keyPrefix: 'TICKET-', + urlTemplate: 'https://example.com/TICKET?query=', + isAlphanumeric: false, + }, + ...mockContext, + }); + + expect(mockOctokit.rest.repos.createAutolink).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repo', + key_prefix: 'TICKET-', + url_template: 'https://example.com/TICKET?query=', + is_alphanumeric: false, + }); + }); +}); diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubAutolinks.ts b/plugins/scaffolder-backend-module-github/src/actions/githubAutolinks.ts new file mode 100644 index 0000000000..4b0d0e1e1f --- /dev/null +++ b/plugins/scaffolder-backend-module-github/src/actions/githubAutolinks.ts @@ -0,0 +1,118 @@ +/* + * 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 { + GithubCredentialsProvider, + ScmIntegrations, +} from '@backstage/integration'; +import { + createTemplateAction, + parseRepoUrl, +} from '@backstage/plugin-scaffolder-node'; +import { Octokit } from 'octokit'; +import { examples } from './githubAutolinks.examples'; +import { getOctokitOptions } from './helpers'; + +/** + * Create an autolink reference for a repository + * @public + */ +export function createGithubAutolinksAction(options: { + integrations: ScmIntegrations; + githubCredentialsProvider?: GithubCredentialsProvider; +}) { + const { integrations, githubCredentialsProvider } = options; + + return createTemplateAction<{ + repoUrl: string; + keyPrefix: string; + urlTemplate: string; + isAlphanumeric?: boolean; + token?: string; + }>({ + id: 'github:autolinks:create', + description: 'Create an autolink reference for a repository', + examples, + schema: { + input: { + type: 'object', + required: ['repoUrl', 'keyPrefix', 'urlTemplate'], + properties: { + repoUrl: { + title: 'Repository Location', + description: `Accepts the format 'github.com?repo=reponame&owner=owner' where 'reponame' is the new repository name and 'owner' is an organization or username`, + type: 'string', + }, + keyPrefix: { + title: 'Key Prefix', + description: + 'This prefix appended by certain characters will generate a link any time it is found in an issue, pull request, or commit.', + type: 'string', + }, + urlTemplate: { + title: 'URL Template', + description: + 'The URL must contain for the reference number. matches different characters depending on the value of isAlphanumeric.', + type: 'string', + }, + isAlphanumeric: { + title: 'Alphanumeric', + description: + 'Whether this autolink reference matches alphanumeric characters. If true, the parameter of the url_template matches alphanumeric characters A-Z (case insensitive), 0-9, and -. If false, this autolink reference only matches numeric characters. Default: true', + type: 'boolean', + }, + token: { + title: 'Authentication Token', + type: 'string', + description: 'The token to use for authorization to GitHub', + }, + }, + }, + }, + async handler(ctx) { + const { repoUrl, keyPrefix, urlTemplate, isAlphanumeric, token } = + ctx.input; + + ctx.logger.info(`Creating autolink reference for repo ${repoUrl}`); + + const { owner, repo } = parseRepoUrl(repoUrl, integrations); + + if (!owner) { + throw new InputError('Invalid repository owner provided in repoUrl'); + } + + const client = new Octokit( + await getOctokitOptions({ + integrations, + repoUrl, + credentialsProvider: githubCredentialsProvider, + token, + }), + ); + + await client.rest.repos.createAutolink({ + owner, + repo, + key_prefix: keyPrefix, + url_template: urlTemplate, + is_alphanumeric: isAlphanumeric, + }); + + ctx.logger.info(`Autolink reference created successfully`); + }, + }); +} diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubDeployKey.examples.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubDeployKey.examples.test.ts similarity index 100% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubDeployKey.examples.test.ts rename to plugins/scaffolder-backend-module-github/src/actions/githubDeployKey.examples.test.ts diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubDeployKey.examples.ts b/plugins/scaffolder-backend-module-github/src/actions/githubDeployKey.examples.ts similarity index 100% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubDeployKey.examples.ts rename to plugins/scaffolder-backend-module-github/src/actions/githubDeployKey.examples.ts diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubDeployKey.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubDeployKey.test.ts similarity index 100% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubDeployKey.test.ts rename to plugins/scaffolder-backend-module-github/src/actions/githubDeployKey.test.ts diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubDeployKey.ts b/plugins/scaffolder-backend-module-github/src/actions/githubDeployKey.ts similarity index 97% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubDeployKey.ts rename to plugins/scaffolder-backend-module-github/src/actions/githubDeployKey.ts index 1db9746bb4..ba55b6a1fb 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubDeployKey.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubDeployKey.ts @@ -15,9 +15,11 @@ */ import { InputError } from '@backstage/errors'; -import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; +import { + createTemplateAction, + parseRepoUrl, +} from '@backstage/plugin-scaffolder-node'; import { ScmIntegrationRegistry } from '@backstage/integration'; -import { parseRepoUrl } from '../publish/util'; import { getOctokitOptions } from './helpers'; import { Octokit } from 'octokit'; import Sodium from 'libsodium-wrappers'; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubEnvironment.examples.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.examples.test.ts similarity index 95% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubEnvironment.examples.test.ts rename to plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.examples.test.ts index 5e3da2fcec..9d5dbfd35c 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubEnvironment.examples.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.examples.test.ts @@ -25,7 +25,7 @@ import { examples } from './gitHubEnvironment.examples'; const mockOctokit = { rest: { actions: { - getRepoPublicKey: jest.fn(), + getEnvironmentPublicKey: jest.fn(), createEnvironmentVariable: jest.fn(), createOrUpdateEnvironmentSecret: jest.fn(), }, @@ -68,7 +68,7 @@ describe('github:environment:create examples', () => { }; beforeEach(() => { - mockOctokit.rest.actions.getRepoPublicKey.mockResolvedValue({ + mockOctokit.rest.actions.getEnvironmentPublicKey.mockResolvedValue({ data: { key: publicKey, key_id: 'keyid', @@ -109,7 +109,9 @@ describe('github:environment:create examples', () => { expect( mockOctokit.rest.actions.createEnvironmentVariable, ).not.toHaveBeenCalled(); - expect(mockOctokit.rest.actions.getRepoPublicKey).not.toHaveBeenCalled(); + expect( + mockOctokit.rest.actions.getEnvironmentPublicKey, + ).not.toHaveBeenCalled(); expect( mockOctokit.rest.actions.createOrUpdateEnvironmentSecret, ).not.toHaveBeenCalled(); @@ -141,7 +143,9 @@ describe('github:environment:create examples', () => { expect( mockOctokit.rest.actions.createEnvironmentVariable, ).not.toHaveBeenCalled(); - expect(mockOctokit.rest.actions.getRepoPublicKey).not.toHaveBeenCalled(); + expect( + mockOctokit.rest.actions.getEnvironmentPublicKey, + ).not.toHaveBeenCalled(); expect( mockOctokit.rest.actions.createOrUpdateEnvironmentSecret, ).not.toHaveBeenCalled(); diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubEnvironment.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.test.ts similarity index 98% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubEnvironment.test.ts rename to plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.test.ts index d158bc122e..8ec3d84e36 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubEnvironment.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.test.ts @@ -24,7 +24,7 @@ import { ScmIntegrations } from '@backstage/integration'; const mockOctokit = { rest: { actions: { - getRepoPublicKey: jest.fn(), + getEnvironmentPublicKey: jest.fn(), createEnvironmentVariable: jest.fn(), createOrUpdateEnvironmentSecret: jest.fn(), }, @@ -71,7 +71,7 @@ describe('github:environment:create', () => { }; beforeEach(() => { - mockOctokit.rest.actions.getRepoPublicKey.mockResolvedValue({ + mockOctokit.rest.actions.getEnvironmentPublicKey.mockResolvedValue({ data: { key: publicKey, key_id: 'keyid', diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubEnvironment.ts b/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.ts similarity index 96% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubEnvironment.ts rename to plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.ts index 874798e4df..7f6f9f7fa3 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubEnvironment.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.ts @@ -15,9 +15,11 @@ */ import { InputError } from '@backstage/errors'; -import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; +import { + createTemplateAction, + parseRepoUrl, +} from '@backstage/plugin-scaffolder-node'; import { ScmIntegrationRegistry } from '@backstage/integration'; -import { parseRepoUrl } from '../publish/util'; import { getOctokitOptions } from './helpers'; import { Octokit } from 'octokit'; import Sodium from 'libsodium-wrappers'; @@ -167,10 +169,11 @@ export function createGithubEnvironmentAction(options: { } if (secrets) { - const publicKeyResponse = await client.rest.actions.getRepoPublicKey({ - owner: owner, - repo: repo, - }); + const publicKeyResponse = + await client.rest.actions.getEnvironmentPublicKey({ + repository_id: repository.data.id, + environment_name: name, + }); await Sodium.ready; const binaryKey = Sodium.from_base64( diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubIssuesLabel.examples.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubIssuesLabel.examples.test.ts similarity index 100% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubIssuesLabel.examples.test.ts rename to plugins/scaffolder-backend-module-github/src/actions/githubIssuesLabel.examples.test.ts diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubIssuesLabel.examples.ts b/plugins/scaffolder-backend-module-github/src/actions/githubIssuesLabel.examples.ts similarity index 100% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubIssuesLabel.examples.ts rename to plugins/scaffolder-backend-module-github/src/actions/githubIssuesLabel.examples.ts diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubIssuesLabel.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubIssuesLabel.test.ts similarity index 100% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubIssuesLabel.test.ts rename to plugins/scaffolder-backend-module-github/src/actions/githubIssuesLabel.test.ts diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubIssuesLabel.ts b/plugins/scaffolder-backend-module-github/src/actions/githubIssuesLabel.ts similarity index 96% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubIssuesLabel.ts rename to plugins/scaffolder-backend-module-github/src/actions/githubIssuesLabel.ts index 73a65ffb14..90f5a89dc7 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubIssuesLabel.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubIssuesLabel.ts @@ -18,11 +18,13 @@ import { GithubCredentialsProvider, ScmIntegrationRegistry, } from '@backstage/integration'; -import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; +import { + createTemplateAction, + parseRepoUrl, +} from '@backstage/plugin-scaffolder-node'; import { assertError, InputError } from '@backstage/errors'; import { Octokit } from 'octokit'; import { getOctokitOptions } from './helpers'; -import { parseRepoUrl } from '../publish/util'; import { examples } from './githubIssuesLabel.examples'; /** diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/githubPullRequest.examples.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubPullRequest.examples.test.ts similarity index 98% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/githubPullRequest.examples.test.ts rename to plugins/scaffolder-backend-module-github/src/actions/githubPullRequest.examples.test.ts index 3f13f2ab67..7e5d107026 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/githubPullRequest.examples.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubPullRequest.examples.test.ts @@ -23,10 +23,7 @@ import { ScmIntegrations, } from '@backstage/integration'; import { PassThrough } from 'stream'; -import { - OctokitWithPullRequestPluginClient, - createPublishGithubPullRequestAction, -} from './githubPullRequest'; +import { createPublishGithubPullRequestAction } from './githubPullRequest'; import yaml from 'yaml'; import { examples } from './githubPullRequest.examples'; import { createMockDirectory } from '@backstage/backend-test-utils'; @@ -103,9 +100,7 @@ describe('publish:github:pull-request examples', () => { }, }; - const clientFactory = jest.fn( - async () => fakeClient as unknown as OctokitWithPullRequestPluginClient, - ); + const clientFactory = jest.fn(async () => fakeClient as any); mockDir.setContent({ [workspacePath]: { 'file.txt': 'Hello there!' }, diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/githubPullRequest.examples.ts b/plugins/scaffolder-backend-module-github/src/actions/githubPullRequest.examples.ts similarity index 100% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/githubPullRequest.examples.ts rename to plugins/scaffolder-backend-module-github/src/actions/githubPullRequest.examples.ts diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/githubPullRequest.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubPullRequest.test.ts similarity index 98% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/githubPullRequest.test.ts rename to plugins/scaffolder-backend-module-github/src/actions/githubPullRequest.test.ts index a1f3712a9d..c5b1038a01 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/githubPullRequest.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubPullRequest.test.ts @@ -26,10 +26,7 @@ import { } from '@backstage/plugin-scaffolder-node'; import fs from 'fs-extra'; import { Writable } from 'stream'; -import { - createPublishGithubPullRequestAction, - OctokitWithPullRequestPluginClient, -} from './githubPullRequest'; +import { createPublishGithubPullRequestAction } from './githubPullRequest'; import { createMockDirectory } from '@backstage/backend-test-utils'; // Make sure root logger is initialized ahead of FS mock @@ -78,9 +75,7 @@ describe('createPublishGithubPullRequestAction', () => { }, }, }; - const clientFactory = jest.fn( - async () => fakeClient as unknown as OctokitWithPullRequestPluginClient, - ); + const clientFactory = jest.fn(async () => fakeClient as any); const githubCredentialsProvider: GithubCredentialsProvider = { getCredentials: jest.fn(), }; @@ -382,7 +377,7 @@ describe('createPublishGithubPullRequestAction', () => { branchName: 'new-app', description: 'This PR is really good', reviewers: ['foobar'], - teamReviewers: ['team-foo'], + teamReviewers: ['team-foo', 'team-foo', 'team-bar'], }; mockDir.setContent({ [workspacePath]: {} }); @@ -406,7 +401,7 @@ describe('createPublishGithubPullRequestAction', () => { repo: 'myrepo', pull_number: 123, reviewers: ['foobar'], - team_reviewers: ['team-foo'], + team_reviewers: ['team-foo', 'team-bar'], }); }); diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/githubPullRequest.ts b/plugins/scaffolder-backend-module-github/src/actions/githubPullRequest.ts similarity index 86% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/githubPullRequest.ts rename to plugins/scaffolder-backend-module-github/src/actions/githubPullRequest.ts index 3b6e7c3ced..2d8dc7ce8d 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/githubPullRequest.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubPullRequest.ts @@ -15,21 +15,21 @@ */ import path from 'path'; -import { parseRepoUrl } from './util'; import { GithubCredentialsProvider, ScmIntegrationRegistry, } from '@backstage/integration'; -import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; +import { + createTemplateAction, + parseRepoUrl, + SerializedFile, + serializeDirectoryContents, +} from '@backstage/plugin-scaffolder-node'; import { Octokit } from 'octokit'; import { InputError, CustomErrorBase } from '@backstage/errors'; import { resolveSafeChildPath } from '@backstage/backend-common'; import { createPullRequest } from 'octokit-plugin-create-pull-request'; -import { getOctokitOptions } from '../github/helpers'; -import { - SerializedFile, - serializeDirectoryContents, -} from '../../../../lib/files'; +import { getOctokitOptions } from './helpers'; import { Logger } from 'winston'; import { examples } from './githubPullRequest.examples'; @@ -37,57 +37,32 @@ export type Encoding = 'utf-8' | 'base64'; class GithubResponseError extends CustomErrorBase {} -/** @public */ -export type OctokitWithPullRequestPluginClient = Octokit & { - createPullRequest(options: createPullRequest.Options): Promise<{ - data: { - html_url: string; - number: number; - base: { - ref: string; - }; - }; - } | null>; -}; - -/** - * The options passed to the client factory function. - * @public - */ -export type CreateGithubPullRequestClientFactoryInput = { - integrations: ScmIntegrationRegistry; - githubCredentialsProvider?: GithubCredentialsProvider; - host: string; - owner: string; - repo: string; - token?: string; -}; - -export const defaultClientFactory = async ({ - integrations, - githubCredentialsProvider, - owner, - repo, - host = 'github.com', - token: providedToken, -}: CreateGithubPullRequestClientFactoryInput): Promise => { - const [encodedHost, encodedOwner, encodedRepo] = [host, owner, repo].map( - encodeURIComponent, - ); - - const octokitOptions = await getOctokitOptions({ +export const defaultClientFactory: CreateGithubPullRequestActionOptions['clientFactory'] = + async ({ integrations, - credentialsProvider: githubCredentialsProvider, - repoUrl: `${encodedHost}?owner=${encodedOwner}&repo=${encodedRepo}`, + githubCredentialsProvider, + owner, + repo, + host = 'github.com', token: providedToken, - }); + }) => { + const [encodedHost, encodedOwner, encodedRepo] = [host, owner, repo].map( + encodeURIComponent, + ); - const OctokitPR = Octokit.plugin(createPullRequest); - return new OctokitPR({ - ...octokitOptions, - ...{ throttle: { enabled: false } }, - }); -}; + const octokitOptions = await getOctokitOptions({ + integrations, + credentialsProvider: githubCredentialsProvider, + repoUrl: `${encodedHost}?owner=${encodedOwner}&repo=${encodedRepo}`, + token: providedToken, + }); + + const OctokitPR = Octokit.plugin(createPullRequest); + return new OctokitPR({ + ...octokitOptions, + ...{ throttle: { enabled: false } }, + }); + }; /** * The options passed to {@link createPublishGithubPullRequestAction} method @@ -105,9 +80,26 @@ export interface CreateGithubPullRequestActionOptions { /** * A method to return the Octokit client with the Pull Request Plugin. */ - clientFactory?: ( - input: CreateGithubPullRequestClientFactoryInput, - ) => Promise; + clientFactory?: (input: { + integrations: ScmIntegrationRegistry; + githubCredentialsProvider?: GithubCredentialsProvider; + host: string; + owner: string; + repo: string; + token?: string; + }) => Promise< + Octokit & { + createPullRequest(options: createPullRequest.Options): Promise<{ + data: { + html_url: string; + number: number; + base: { + ref: string; + }; + }; + } | null>; + } + >; } type GithubPullRequest = { @@ -380,7 +372,7 @@ export const createPublishGithubPullRequestAction = ( repo: pr.repo, pull_number: pr.number, reviewers, - team_reviewers: teamReviewers, + team_reviewers: teamReviewers ? [...new Set(teamReviewers)] : undefined, }); const addedUsers = result.data.requested_reviewers?.join(', ') ?? ''; const addedTeams = result.data.requested_teams?.join(', ') ?? ''; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.examples.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubRepoCreate.examples.test.ts similarity index 96% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.examples.test.ts rename to plugins/scaffolder-backend-module-github/src/actions/githubRepoCreate.examples.test.ts index 71bbc7c1c6..2377e9a7eb 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.examples.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubRepoCreate.examples.test.ts @@ -16,7 +16,12 @@ import { TemplateAction } from '@backstage/plugin-scaffolder-node'; -jest.mock('../helpers'); +jest.mock('./gitHelpers', () => { + return { + ...jest.requireActual('./gitHelpers'), + entityRefToName: jest.fn(), + }; +}); import { getVoidLogger } from '@backstage/backend-common'; import { ConfigReader } from '@backstage/config'; @@ -27,7 +32,7 @@ import { } from '@backstage/integration'; import { PassThrough } from 'stream'; import { createGithubRepoCreateAction } from './githubRepoCreate'; -import { entityRefToName } from '../helpers'; +import { entityRefToName } from './gitHelpers'; import yaml from 'yaml'; import { examples } from './githubRepoCreate.examples'; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.examples.ts b/plugins/scaffolder-backend-module-github/src/actions/githubRepoCreate.examples.ts similarity index 100% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.examples.ts rename to plugins/scaffolder-backend-module-github/src/actions/githubRepoCreate.examples.ts diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubRepoCreate.test.ts similarity index 99% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.test.ts rename to plugins/scaffolder-backend-module-github/src/actions/githubRepoCreate.test.ts index b5b31d0773..4cb007275e 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubRepoCreate.test.ts @@ -16,7 +16,12 @@ import { TemplateAction } from '@backstage/plugin-scaffolder-node'; -jest.mock('../helpers'); +jest.mock('./gitHelpers', () => { + return { + ...jest.requireActual('./gitHelpers'), + entityRefToName: jest.fn(), + }; +}); import { getVoidLogger } from '@backstage/backend-common'; import { ConfigReader } from '@backstage/config'; @@ -28,7 +33,7 @@ import { import { when } from 'jest-when'; import { PassThrough } from 'stream'; import { createGithubRepoCreateAction } from './githubRepoCreate'; -import { entityRefToName } from '../helpers'; +import { entityRefToName } from './gitHelpers'; const publicKey = '2Sg8iYjAxxmI2LvUXpJjkYrMxURPc8r+dB7TJyvvcCU='; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.ts b/plugins/scaffolder-backend-module-github/src/actions/githubRepoCreate.ts similarity index 98% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.ts rename to plugins/scaffolder-backend-module-github/src/actions/githubRepoCreate.ts index e0fde3b193..735919794f 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubRepoCreate.ts @@ -20,8 +20,10 @@ import { ScmIntegrationRegistry, } from '@backstage/integration'; import { Octokit } from 'octokit'; -import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; -import { parseRepoUrl } from '../publish/util'; +import { + createTemplateAction, + parseRepoUrl, +} from '@backstage/plugin-scaffolder-node'; import { createGithubRepoWithCollaboratorsAndTopics, getOctokitOptions, diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoPush.examples.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.examples.test.ts similarity index 85% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoPush.examples.test.ts rename to plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.examples.test.ts index 84d489272d..8f8c9bf8af 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoPush.examples.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.examples.test.ts @@ -13,7 +13,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { TemplateAction } from '@backstage/plugin-scaffolder-node'; +jest.mock('@backstage/plugin-scaffolder-node', () => { + return { + ...jest.requireActual('@backstage/plugin-scaffolder-node'), + initRepoAndPush: jest.fn().mockResolvedValue({ + commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6', + }), + commitAndPushRepo: jest.fn().mockResolvedValue({ + commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6', + }), + }; +}); + +import { + TemplateAction, + initRepoAndPush, +} from '@backstage/plugin-scaffolder-node'; import { getVoidLogger } from '@backstage/backend-common'; import { ConfigReader } from '@backstage/config'; import { @@ -22,7 +37,6 @@ import { ScmIntegrations, } from '@backstage/integration'; import { PassThrough } from 'stream'; -import { initRepoAndPush } from '../helpers'; import { createGithubRepoPushAction } from './githubRepoPush'; import { examples } from './githubRepoPush.examples'; import yaml from 'yaml'; @@ -48,7 +62,12 @@ jest.mock('@backstage/backend-common', () => ({ getVoidLogger: jest.requireActual('@backstage/backend-common').getVoidLogger, })); -jest.mock('../helpers'); +jest.mock('./helpers', () => { + return { + ...jest.requireActual('./helpers'), + entityRefToName: jest.fn(), + }; +}); const initRepoAndPushMocked = initRepoAndPush as jest.Mock< Promise<{ commitHash: string }> @@ -98,6 +117,7 @@ describe('github:repo:push examples', () => { githubCredentialsProvider = DefaultGithubCredentialsProvider.fromIntegrations(integrations); + action = createGithubRepoPushAction({ integrations, config, diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoPush.examples.ts b/plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.examples.ts similarity index 100% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoPush.examples.ts rename to plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.examples.ts diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoPush.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.test.ts similarity index 96% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoPush.test.ts rename to plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.test.ts index 8630dfab56..e16da0981d 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoPush.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.test.ts @@ -35,9 +35,30 @@ jest.mock('@backstage/backend-common', () => ({ getVoidLogger: jest.requireActual('@backstage/backend-common').getVoidLogger, })); -jest.mock('../helpers'); +jest.mock('./gitHelpers', () => { + return { + ...jest.requireActual('./gitHelpers'), + entityRefToName: jest.fn(), + enableBranchProtectionOnDefaultRepoBranch: jest.fn(), + }; +}); -import { TemplateAction } from '@backstage/plugin-scaffolder-node'; +jest.mock('@backstage/plugin-scaffolder-node', () => { + return { + ...jest.requireActual('@backstage/plugin-scaffolder-node'), + initRepoAndPush: jest.fn().mockResolvedValue({ + commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6', + }), + commitAndPushRepo: jest.fn().mockResolvedValue({ + commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6', + }), + }; +}); + +import { + TemplateAction, + initRepoAndPush, +} from '@backstage/plugin-scaffolder-node'; import { getVoidLogger } from '@backstage/backend-common'; import { ConfigReader } from '@backstage/config'; import { @@ -46,10 +67,7 @@ import { ScmIntegrations, } from '@backstage/integration'; import { PassThrough } from 'stream'; -import { - enableBranchProtectionOnDefaultRepoBranch, - initRepoAndPush, -} from '../helpers'; +import { enableBranchProtectionOnDefaultRepoBranch } from './gitHelpers'; import { createGithubRepoPushAction } from './githubRepoPush'; const initRepoAndPushMocked = initRepoAndPush as jest.Mock< diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoPush.ts b/plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.ts similarity index 98% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoPush.ts rename to plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.ts index e30eedad02..5b9db78f48 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoPush.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.ts @@ -21,8 +21,10 @@ import { ScmIntegrationRegistry, } from '@backstage/integration'; import { Octokit } from 'octokit'; -import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; -import { parseRepoUrl } from '../publish/util'; +import { + createTemplateAction, + parseRepoUrl, +} from '@backstage/plugin-scaffolder-node'; import { getOctokitOptions, initRepoPushAndProtect } from './helpers'; import * as inputProps from './inputProperties'; import * as outputProps from './outputProperties'; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubWebhook.examples.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubWebhook.examples.test.ts similarity index 100% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubWebhook.examples.test.ts rename to plugins/scaffolder-backend-module-github/src/actions/githubWebhook.examples.test.ts diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubWebhook.examples.ts b/plugins/scaffolder-backend-module-github/src/actions/githubWebhook.examples.ts similarity index 100% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubWebhook.examples.ts rename to plugins/scaffolder-backend-module-github/src/actions/githubWebhook.examples.ts diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubWebhook.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubWebhook.test.ts similarity index 100% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubWebhook.test.ts rename to plugins/scaffolder-backend-module-github/src/actions/githubWebhook.test.ts diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubWebhook.ts b/plugins/scaffolder-backend-module-github/src/actions/githubWebhook.ts similarity index 97% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubWebhook.ts rename to plugins/scaffolder-backend-module-github/src/actions/githubWebhook.ts index 5589c951a5..984029076e 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubWebhook.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubWebhook.ts @@ -18,12 +18,14 @@ import { GithubCredentialsProvider, ScmIntegrationRegistry, } from '@backstage/integration'; -import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; +import { + createTemplateAction, + parseRepoUrl, +} from '@backstage/plugin-scaffolder-node'; import { emitterEventNames } from '@octokit/webhooks'; import { assertError, InputError } from '@backstage/errors'; import { Octokit } from 'octokit'; import { getOctokitOptions } from './helpers'; -import { parseRepoUrl } from '../publish/util'; import { examples } from './githubWebhook.examples'; /** diff --git a/plugins/scaffolder-backend-module-github/src/actions/helper.test.ts b/plugins/scaffolder-backend-module-github/src/actions/helper.test.ts new file mode 100644 index 0000000000..3934e07db7 --- /dev/null +++ b/plugins/scaffolder-backend-module-github/src/actions/helper.test.ts @@ -0,0 +1,47 @@ +/* + * 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 { ConfigReader } from '@backstage/config'; +import { getGitCommitMessage } from './helpers'; + +describe('getGitCommitMessage', () => { + it('should return gitCommitMessage when provided', () => { + const mockConfig = new ConfigReader({}); + const gitCommitMessage = 'Custom commit message'; + + const result = getGitCommitMessage(gitCommitMessage, mockConfig); + + expect(result).toEqual('Custom commit message'); + }); + + it('should return default commit message from config when gitCommitMessage is undefined', () => { + const mockConfig = new ConfigReader({ + scaffolder: { + defaultCommitMessage: 'Default commit message', + }, + }); + const result = getGitCommitMessage(undefined, mockConfig); + + expect(result).toEqual('Default commit message'); + }); + + it('should return undefined when both gitCommitMessage and default commit message are undefined', () => { + const mockConfig = new ConfigReader({}); + const result = getGitCommitMessage(undefined, mockConfig); + + expect(result).toBeUndefined(); + }); +}); diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/helpers.ts b/plugins/scaffolder-backend-module-github/src/actions/helpers.ts similarity index 97% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/helpers.ts rename to plugins/scaffolder-backend-module-github/src/actions/helpers.ts index d91f3bf3a2..4d95a6494f 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/helpers.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/helpers.ts @@ -24,13 +24,18 @@ import { import { OctokitOptions } from '@octokit/core/dist-types/types'; import { Octokit } from 'octokit'; import { Logger } from 'winston'; + +import { + getRepoSourceDirectory, + initRepoAndPush, + parseRepoUrl, +} from '@backstage/plugin-scaffolder-node'; + +import Sodium from 'libsodium-wrappers'; import { enableBranchProtectionOnDefaultRepoBranch, - initRepoAndPush, -} from '../helpers'; -import { getRepoSourceDirectory, parseRepoUrl } from '../publish/util'; -import { entityRefToName } from '../../builtin/helpers'; -import Sodium from 'libsodium-wrappers'; + entityRefToName, +} from './gitHelpers'; const DEFAULT_TIMEOUT_MS = 60_000; @@ -349,9 +354,8 @@ export async function initRepoPushAndProtect( : config.getOptionalString('scaffolder.defaultAuthor.email'), }; - const commitMessage = gitCommitMessage - ? gitCommitMessage - : config.getOptionalString('scaffolder.defaultCommitMessage'); + const commitMessage = + getGitCommitMessage(gitCommitMessage, config) || 'initial commit'; const commitResult = await initRepoAndPush({ dir: getRepoSourceDirectory(workspacePath, sourcePath), @@ -422,3 +426,12 @@ async function validateAccessTeam(client: Octokit, access: string) { } } } + +export function getGitCommitMessage( + gitCommitMessage: string | undefined, + config: Config, +): string | undefined { + return gitCommitMessage + ? gitCommitMessage + : config.getOptionalString('scaffolder.defaultCommitMessage'); +} diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/index.ts b/plugins/scaffolder-backend-module-github/src/actions/index.ts similarity index 81% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/index.ts rename to plugins/scaffolder-backend-module-github/src/actions/index.ts index ecc8ce59f2..27eaca0e85 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/index.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/index.ts @@ -21,3 +21,10 @@ export { createGithubRepoPushAction } from './githubRepoPush'; export { createGithubWebhookAction } from './githubWebhook'; export { createGithubDeployKeyAction } from './githubDeployKey'; export { createGithubEnvironmentAction } from './githubEnvironment'; + +export { + createPublishGithubPullRequestAction, + type CreateGithubPullRequestActionOptions, +} from './githubPullRequest'; +export { createPublishGithubAction } from './github'; +export { createGithubAutolinksAction } from './githubAutolinks'; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/inputProperties.ts b/plugins/scaffolder-backend-module-github/src/actions/inputProperties.ts similarity index 100% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/inputProperties.ts rename to plugins/scaffolder-backend-module-github/src/actions/inputProperties.ts diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/outputProperties.ts b/plugins/scaffolder-backend-module-github/src/actions/outputProperties.ts similarity index 100% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/outputProperties.ts rename to plugins/scaffolder-backend-module-github/src/actions/outputProperties.ts diff --git a/plugins/scaffolder-backend-module-github/src/index.ts b/plugins/scaffolder-backend-module-github/src/index.ts new file mode 100644 index 0000000000..948a79d957 --- /dev/null +++ b/plugins/scaffolder-backend-module-github/src/index.ts @@ -0,0 +1,23 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * A module for the scaffolder backend that lets you interact with github + * + * @packageDocumentation + */ + +export * from './actions'; diff --git a/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md b/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md index d43b1124a9..9c7d462cda 100644 --- a/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,114 @@ # @backstage/plugin-scaffolder-backend-module-gitlab +## 0.2.12 + +### Patch Changes + +- 604c9dd: Add Scaffolder custom action that creates GitLab issues called `gitlab:issues:create` +- 7c522c5: Add `gitlab:repo:push` scaffolder action to push files to arbitrary branch without creating a Merge Request +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## 0.2.12-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-scaffolder-node@0.2.10-next.2 + +## 0.2.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.10-next.1 + - @backstage/errors@1.2.3 + +## 0.2.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/plugin-scaffolder-node@0.2.10-next.0 + +## 0.2.11 + +### Patch Changes + +- 219d7f0: Extract some more actions to this library +- 0cbb03b: Fixing regular expression ReDoS with zod packages. Upgrading to latest. ref: https://security.snyk.io/vuln/SNYK-JS-ZOD-5925617 +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-scaffolder-node@0.2.9 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.2.11-next.3 + +### Patch Changes + +- 219d7f0: Extract some more actions to this library +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.9-next.3 + - @backstage/backend-common@0.20.0-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + +## 0.2.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/plugin-scaffolder-node@0.2.9-next.2 + +## 0.2.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-scaffolder-node@0.2.9-next.1 + +## 0.2.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.0 + - @backstage/plugin-scaffolder-node@0.2.9-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.2.10 + +### Patch Changes + +- 26ca97ebaa: Add examples for `gitlab:projectAccessToken:create` scaffolder action & improve related tests +- Updated dependencies + - @backstage/integration@1.7.2 + - @backstage/plugin-scaffolder-node@0.2.8 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + ## 0.2.10-next.2 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gitlab/README.md b/plugins/scaffolder-backend-module-gitlab/README.md index 340b57bbf8..c946c8b476 100644 --- a/plugins/scaffolder-backend-module-gitlab/README.md +++ b/plugins/scaffolder-backend-module-gitlab/README.md @@ -24,6 +24,7 @@ import { createGitlabProjectDeployTokenAction, createGitlabProjectVariableAction, createGitlabGroupEnsureExistsAction, + createGitlabIssueAction, } from '@backstage/plugin-scaffolder-backend-module-gitlab'; // Create BuiltIn Actions @@ -41,6 +42,7 @@ const actions = [ createGitlabProjectDeployTokenAction({ integrations: integrations }), createGitlabProjectVariableAction({ integrations: integrations }), createGitlabGroupEnsureExistsAction({ integrations: integrations }), + createGitlabIssueAction({ integrations: integrations }), ]; // Create Scaffolder Router @@ -160,8 +162,26 @@ spec: repoContentsUrl: ${{ steps['publish'].output.repoContentsUrl }} catalogInfoPath: '/catalog-info.yaml' + - id: gitlabIssue + name: Issues + action: gitlab:issues:create + input: + repoUrl: ${{ parameters.repoUrl }} + token: ${{ secrets.USER_OAUTH_TOKEN }} + projectId: 1111111 + title: Test Issue + assignees: + - 2222222 + description: This is the description of the issue + confidential: true + createdAt: 2022-09-27 18:00:00.000 + dueDate: 2024-09-28 12:00:00.000 + epicId: 3333333 + labels: phase1:label1,phase2:label2 output: links: - title: Repository url: ${{ steps['publish'].output.remoteUrl }} + - title: Link to new issue + url: ${{ steps['gitlabIssue'].output.issueUrl }} ``` diff --git a/plugins/scaffolder-backend-module-gitlab/api-report.md b/plugins/scaffolder-backend-module-gitlab/api-report.md index eccada5d51..9b3eec5cdf 100644 --- a/plugins/scaffolder-backend-module-gitlab/api-report.md +++ b/plugins/scaffolder-backend-module-gitlab/api-report.md @@ -3,6 +3,7 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { Config } from '@backstage/config'; import { JsonObject } from '@backstage/types'; import { ScmIntegrationRegistry } from '@backstage/integration'; import { TemplateAction } from '@backstage/plugin-scaffolder-node'; @@ -21,6 +22,34 @@ export const createGitlabGroupEnsureExistsAction: (options: { } >; +// @public +export const createGitlabIssueAction: (options: { + integrations: ScmIntegrationRegistry; +}) => TemplateAction< + { + title: string; + repoUrl: string; + projectId: number; + token?: string | undefined; + assignees?: number[] | undefined; + confidential?: boolean | undefined; + description?: string | undefined; + createdAt?: string | undefined; + dueDate?: string | undefined; + discussionToResolve?: string | undefined; + epicId?: number | undefined; + labels?: string | undefined; + issueType?: IssueType | undefined; + mergeRequestToResolveDiscussionsOf?: number | undefined; + milestoneId?: number | undefined; + weight?: number | undefined; + }, + { + issueUrl: string; + issueId: number; + } +>; + // @public export const createGitlabProjectAccessTokenAction: (options: { integrations: ScmIntegrationRegistry; @@ -74,4 +103,101 @@ export const createGitlabProjectVariableAction: (options: { }, JsonObject >; + +// @public +export const createGitlabRepoPushAction: (options: { + integrations: ScmIntegrationRegistry; +}) => TemplateAction< + { + repoUrl: string; + branchName: string; + commitMessage: string; + sourcePath?: string | undefined; + targetPath?: string | undefined; + token?: string | undefined; + commitAction?: 'update' | 'delete' | 'create' | undefined; + }, + JsonObject +>; + +// @public +export function createPublishGitlabAction(options: { + integrations: ScmIntegrationRegistry; + config: Config; +}): TemplateAction< + { + repoUrl: string; + defaultBranch?: string | undefined; + repoVisibility?: 'internal' | 'private' | 'public' | undefined; + sourcePath?: string | undefined; + token?: string | undefined; + gitCommitMessage?: string | undefined; + gitAuthorName?: string | undefined; + gitAuthorEmail?: string | undefined; + setUserAsOwner?: boolean | undefined; + topics?: string[] | undefined; + settings?: + | { + path?: string | undefined; + auto_devops_enabled?: boolean | undefined; + ci_config_path?: string | undefined; + description?: string | undefined; + topics?: string[] | undefined; + visibility?: 'internal' | 'private' | 'public' | undefined; + } + | undefined; + branches?: + | { + name: string; + protect?: boolean | undefined; + create?: boolean | undefined; + ref?: string | undefined; + }[] + | undefined; + projectVariables?: + | { + key: string; + value: string; + description?: string | undefined; + variable_type?: string | undefined; + protected?: boolean | undefined; + masked?: boolean | undefined; + raw?: boolean | undefined; + environment_scope?: string | undefined; + }[] + | undefined; + }, + JsonObject +>; + +// @public +export const createPublishGitlabMergeRequestAction: (options: { + integrations: ScmIntegrationRegistry; +}) => TemplateAction< + { + repoUrl: string; + title: string; + description: string; + branchName: string; + targetBranchName?: string | undefined; + sourcePath?: string | undefined; + targetPath?: string | undefined; + token?: string | undefined; + commitAction?: 'update' | 'delete' | 'create' | undefined; + projectid?: string | undefined; + removeSourceBranch?: boolean | undefined; + assignee?: string | undefined; + }, + JsonObject +>; + +// @public +export enum IssueType { + // (undocumented) + INCIDENT = 'incident', + // (undocumented) + ISSUE = 'issue', + // (undocumented) + TEST = 'test_case', +} ``` diff --git a/plugins/scaffolder-backend-module-gitlab/package.json b/plugins/scaffolder-backend-module-gitlab/package.json index 6ba82fd81f..ca7e90f8c8 100644 --- a/plugins/scaffolder-backend-module-gitlab/package.json +++ b/plugins/scaffolder-backend-module-gitlab/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-gitlab", - "version": "0.2.10-next.2", + "version": "0.2.12", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,18 +31,22 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { + "@backstage/backend-common": "workspace:^", "@backstage/config": "workspace:^", "@backstage/errors": "workspace:^", "@backstage/integration": "workspace:^", "@backstage/plugin-scaffolder-node": "workspace:^", + "@gitbeaker/core": "^35.8.0", "@gitbeaker/node": "^35.8.0", + "@gitbeaker/rest": "^39.25.0", "yaml": "^2.0.0", - "zod": "^3.21.4" + "zod": "^3.22.4" }, "devDependencies": { - "@backstage/backend-common": "workspace:^", + "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^" + "@backstage/core-app-api": "workspace:^", + "jest-date-mock": "^1.0.8" }, "files": [ "dist" diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabIssueAction.examples.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabIssueAction.examples.ts new file mode 100644 index 0000000000..760caf0f9f --- /dev/null +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabIssueAction.examples.ts @@ -0,0 +1,85 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { TemplateExample } from '@backstage/plugin-scaffolder-node'; +import yaml from 'yaml'; +import { commonGitlabConfigExample } from '../commonGitlabConfig'; + +export const examples: TemplateExample[] = [ + { + description: 'Create a GitLab issue with minimal options', + example: yaml.stringify({ + steps: [ + { + id: 'gitlabIssue', + name: 'Issues', + action: 'gitlab:issues:create', + input: { + ...commonGitlabConfigExample, + projectId: 12, + title: 'Test Issue', + description: 'This is the description of the issue', + }, + }, + ], + }), + }, + { + description: 'Create a GitLab issue with assignees and date options', + example: yaml.stringify({ + steps: [ + { + id: 'gitlabIssue', + name: 'Issues', + action: 'gitlab:issues:create', + input: { + ...commonGitlabConfigExample, + projectId: 12, + title: 'Test Issue', + assignees: [18], + description: 'This is the description of the issue', + createdAt: '2022-09-27 18:00:00.000', + dueDate: '2022-09-28 12:00:00.000', + }, + }, + ], + }), + }, + { + description: 'Create a GitLab Issue with several options', + example: yaml.stringify({ + steps: [ + { + id: 'gitlabIssue', + name: 'Issues', + action: 'gitlab:issues:create', + input: { + ...commonGitlabConfigExample, + projectId: 12, + title: 'Test Issue', + assignees: [18, 15], + description: 'This is the description of the issue', + confidential: false, + createdAt: '2022-09-27 18:00:00.000', + dueDate: '2022-09-28 12:00:00.000', + discussionToResolve: 1, + epicId: 1, + labels: 'phase1:label1,phase2:label2', + }, + }, + ], + }), + }, +]; diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabIssueAction.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabIssueAction.test.ts new file mode 100644 index 0000000000..fe9e556656 --- /dev/null +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabIssueAction.test.ts @@ -0,0 +1,217 @@ +/* + * 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 { PassThrough } from 'stream'; +import { getVoidLogger } from '@backstage/backend-common'; +import { createGitlabIssueAction, IssueType } from './createGitlabIssueAction'; +import { ConfigReader } from '@backstage/core-app-api'; +import { ScmIntegrations } from '@backstage/integration'; +import { advanceTo, clear } from 'jest-date-mock'; + +const mockGitlabClient = { + Issues: { + create: jest.fn(), + }, +}; +jest.mock('@gitbeaker/rest', () => ({ + Gitlab: class { + constructor() { + return mockGitlabClient; + } + }, +})); + +describe('gitlab:issues:create', () => { + beforeEach(() => { + jest.clearAllMocks(); + advanceTo(new Date(1988, 5, 3, 12, 0, 0)); // Set the desired date and time + }); + + afterEach(() => { + clear(); // Reset the date mock after each test + }); + + const config = new ConfigReader({ + integrations: { + gitlab: [ + { + host: 'gitlab.com', + token: 'myIntegrationsToken', + apiBaseUrl: 'https://gitlab.com/api/v4', + }, + ], + }, + }); + const integrations = ScmIntegrations.fromConfig(config); + + const action = createGitlabIssueAction({ integrations }); + + it('should return a Gitlab issue when called with minimal input params', async () => { + const mockContext = { + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + title: 'Computer banks to rule the world', + }, + workspacePath: 'seen2much', + logger: getVoidLogger(), + logStream: new PassThrough(), + output: jest.fn(), + createTemporaryDirectory: jest.fn(), + }; + + mockGitlabClient.Issues.create.mockResolvedValue({ + id: 42, + web_url: 'https://gitlab.com/hangar18-/issues/42', + }); + + await action.handler({ + ...mockContext, + }); + + expect(mockGitlabClient.Issues.create).toHaveBeenCalledWith( + 123, + 'Computer banks to rule the world', + { + issueType: undefined, + description: '', + assigneeIds: [], + confidential: false, + epicId: undefined, + labels: '', + createdAt: new Date().toISOString(), + dueDate: undefined, + discussionToResolve: '', + mergeRequestToResolveDiscussionsOf: undefined, + milestoneId: undefined, + weight: undefined, + }, + ); + + expect(mockContext.output).toHaveBeenCalledWith('issueId', 42); + expect(mockContext.output).toHaveBeenCalledWith( + 'issueUrl', + 'https://gitlab.com/hangar18-/issues/42', + ); + }); + + it('should return a Gitlab issue when called with oAuth Token', async () => { + const mockContext = { + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + title: 'Computer banks to rule the world', + token: 'myAwesomeToken', + }, + workspacePath: 'seen2much', + logger: getVoidLogger(), + logStream: new PassThrough(), + output: jest.fn(), + createTemporaryDirectory: jest.fn(), + }; + + mockGitlabClient.Issues.create.mockResolvedValue({ + id: 42, + web_url: 'https://gitlab.com/hangar18-/issues/42', + }); + + await action.handler({ + ...mockContext, + }); + + expect(mockGitlabClient.Issues.create).toHaveBeenCalledWith( + 123, + 'Computer banks to rule the world', + { + issueType: undefined, + description: '', + assigneeIds: [], + confidential: false, + epicId: undefined, + labels: '', + createdAt: new Date().toISOString(), + dueDate: undefined, + discussionToResolve: '', + mergeRequestToResolveDiscussionsOf: undefined, + milestoneId: undefined, + weight: undefined, + }, + ); + + expect(mockContext.output).toHaveBeenCalledWith('issueId', 42); + expect(mockContext.output).toHaveBeenCalledWith( + 'issueUrl', + 'https://gitlab.com/hangar18-/issues/42', + ); + }); + + it('should return a Gitlab issue when called with several input params', async () => { + const mockContext = { + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: 123, + issueType: IssueType.INCIDENT, + title: 'Computer banks to rule the world', + description: + 'this issue should kickstart research on instruments to sight the stars', + dueDate: '1990-08-20T23:59:59Z', + token: 'myAwesomeToken', + assignees: [3, 14, 15], + labels: 'operation:mindcrime', + }, + workspacePath: 'seen2much', + logger: getVoidLogger(), + logStream: new PassThrough(), + output: jest.fn(), + createTemporaryDirectory: jest.fn(), + }; + + mockGitlabClient.Issues.create.mockResolvedValue({ + id: 42, + web_url: 'https://gitlab.com/hangar18-/issues/42', + }); + + await action.handler({ + ...mockContext, + }); + + expect(mockGitlabClient.Issues.create).toHaveBeenCalledWith( + 123, + 'Computer banks to rule the world', + { + issueType: 'incident', + description: + 'this issue should kickstart research on instruments to sight the stars', + assigneeIds: [3, 14, 15], + confidential: false, + epicId: undefined, + labels: 'operation:mindcrime', + createdAt: new Date().toISOString(), + dueDate: '1990-08-20T23:59:59.000Z', + discussionToResolve: '', + mergeRequestToResolveDiscussionsOf: undefined, + milestoneId: undefined, + weight: undefined, + }, + ); + + expect(mockContext.output).toHaveBeenCalledWith('issueId', 42); + expect(mockContext.output).toHaveBeenCalledWith( + 'issueUrl', + 'https://gitlab.com/hangar18-/issues/42', + ); + }); +}); diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabIssueAction.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabIssueAction.ts new file mode 100644 index 0000000000..bc9c796253 --- /dev/null +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabIssueAction.ts @@ -0,0 +1,209 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { InputError } from '@backstage/errors'; +import { ScmIntegrationRegistry } from '@backstage/integration'; +import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; +import commonGitlabConfig from '../commonGitlabConfig'; +import { examples } from './createGitlabIssueAction.examples'; +import { z } from 'zod'; +import { checkEpicScope, convertDate, getClient, parseRepoUrl } from '../util'; +import { Gitlab, CreateIssueOptions, IssueSchema } from '@gitbeaker/rest'; + +/** + * Gitlab issue types + * + * @public + */ +export enum IssueType { + ISSUE = 'issue', + INCIDENT = 'incident', + TEST = 'test_case', +} + +const issueInputProperties = z.object({ + projectId: z.number().describe('Project Id'), + title: z.string({ description: 'Title of the issue' }), + assignees: z + .array(z.number(), { + description: 'IDs of the users to assign the issue to.', + }) + .optional(), + confidential: z.boolean({ description: 'Issue Confidentiality' }).optional(), + description: z.string().describe('Issue description').max(1048576).optional(), + createdAt: z + .string() + .describe('Creation date/time') + .regex( + /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/, + 'Invalid date format. Use YYYY-MM-DDTHH:mm:ssZ or YYYY-MM-DDTHH:mm:ss.SSSZ', + ) + .optional(), + dueDate: z + .string() + .describe('Due date/time') + .regex( + /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/, + 'Invalid date format. Use YYYY-MM-DDTHH:mm:ssZ or YYYY-MM-DDTHH:mm:ss.SSSZ', + ) + .optional(), + discussionToResolve: z + .string({ + description: + 'Id of a discussion to resolve. Use in combination with "merge_request_to_resolve_discussions_of"', + }) + .optional(), + epicId: z + .number({ description: 'Id of the linked Epic' }) + .min(0, 'Valid values should be equal or greater than zero') + .optional(), + labels: z.string({ description: 'Labels to apply' }).optional(), + issueType: z + .nativeEnum(IssueType, { + description: 'Type of the issue', + }) + .optional(), + mergeRequestToResolveDiscussionsOf: z + .number({ + description: 'IID of a merge request in which to resolve all issues', + }) + .optional(), + milestoneId: z + .number({ description: 'Global ID of a milestone to assign the issue' }) + .optional(), + weight: z + .number({ description: 'The issue weight' }) + .min(0) + .refine(value => { + const isValid = value >= 0; + if (!isValid) { + return { + message: 'Valid values should be equal or greater than zero', + }; + } + return isValid; + }) + .optional(), +}); + +const issueOutputProperties = z.object({ + issueUrl: z.string({ description: 'Issue Url' }), + issueId: z.number({ description: 'Issue Id' }), +}); + +/** + * Creates a `gitlab:issues:create` Scaffolder action. + * + * @param options - Templating configuration. + * @public + */ +export const createGitlabIssueAction = (options: { + integrations: ScmIntegrationRegistry; +}) => { + const { integrations } = options; + return createTemplateAction({ + id: 'gitlab:issues:create', + description: 'Creates a Gitlab issue.', + examples, + schema: { + input: commonGitlabConfig.merge(issueInputProperties), + output: issueOutputProperties, + }, + async handler(ctx) { + try { + const { + repoUrl, + projectId, + title, + description = '', + confidential = false, + assignees = [], + createdAt = '', + dueDate, + discussionToResolve = '', + epicId, + labels = '', + issueType, + mergeRequestToResolveDiscussionsOf, + milestoneId, + weight, + token, + } = commonGitlabConfig.merge(issueInputProperties).parse(ctx.input); + + const { host } = parseRepoUrl(repoUrl, integrations); + const api = getClient({ host, integrations, token }); + + let isEpicScoped = false; + + if (epicId) { + isEpicScoped = await checkEpicScope( + api as any as InstanceType, + projectId, + epicId, + ); + + if (isEpicScoped) { + ctx.logger.info('Epic is within Project Scope'); + } else { + ctx.logger.warn( + 'Chosen epic is not within the Project Scope. The issue will be created without an associated epic.', + ); + } + } + const mappedCreatedAt = convertDate( + String(createdAt), + new Date().toISOString(), + ); + const mappedDueDate = dueDate + ? convertDate(String(dueDate), new Date().toISOString()) + : undefined; + + const issueOptions: CreateIssueOptions = { + description, + assigneeIds: assignees, + confidential, + epicId: isEpicScoped ? epicId : undefined, + labels, + createdAt: mappedCreatedAt, + dueDate: mappedDueDate, + discussionToResolve, + issueType, + mergeRequestToResolveDiscussionsOf, + milestoneId, + weight, + }; + + const response = (await api.Issues.create( + projectId, + title, + issueOptions, + )) as IssueSchema; + + ctx.output('issueId', response.id); + ctx.output('issueUrl', response.web_url); + } catch (error: any) { + if (error instanceof z.ZodError) { + // Handling Zod validation errors + throw new InputError(`Validation error: ${error.message}`, { + validationErrors: error.errors, + }); + } + // Handling other errors + throw new InputError(`Failed to create GitLab issue: ${error.message}`); + } + }, + }); +}; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.examples.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlab.examples.test.ts similarity index 94% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.examples.test.ts rename to plugins/scaffolder-backend-module-gitlab/src/actions/gitlab.examples.test.ts index 5d58431c61..e5aa610ebc 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.examples.test.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlab.examples.test.ts @@ -15,8 +15,9 @@ */ import yaml from 'yaml'; -jest.mock('../helpers', () => { +jest.mock('@backstage/plugin-scaffolder-node', () => { return { + ...jest.requireActual('@backstage/plugin-scaffolder-node'), initRepoAndPush: jest.fn().mockResolvedValue({ commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6', }), @@ -27,11 +28,11 @@ jest.mock('../helpers', () => { }); import { createPublishGitlabAction } from './gitlab'; +import { initRepoAndPush } from '@backstage/plugin-scaffolder-node'; import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; import { getVoidLogger } from '@backstage/backend-common'; import { PassThrough } from 'stream'; -import { initRepoAndPush } from '../helpers'; import { examples } from './gitlab.examples'; const mockGitlabClient = { diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.examples.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlab.examples.ts similarity index 100% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.examples.ts rename to plugins/scaffolder-backend-module-gitlab/src/actions/gitlab.examples.ts diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlab.test.ts similarity index 98% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.test.ts rename to plugins/scaffolder-backend-module-gitlab/src/actions/gitlab.test.ts index b2f3dc6480..5aca0a73e5 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.test.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlab.test.ts @@ -14,8 +14,9 @@ * limitations under the License. */ -jest.mock('../helpers', () => { +jest.mock('@backstage/plugin-scaffolder-node', () => { return { + ...jest.requireActual('@backstage/plugin-scaffolder-node'), initRepoAndPush: jest.fn().mockResolvedValue({ commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6', }), @@ -30,7 +31,7 @@ import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; import { getVoidLogger } from '@backstage/backend-common'; import { PassThrough } from 'stream'; -import { initRepoAndPush } from '../helpers'; +import { initRepoAndPush } from '@backstage/plugin-scaffolder-node'; const mockGitlabClient = { Namespaces: { diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlab.ts similarity index 99% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.ts rename to plugins/scaffolder-backend-module-gitlab/src/actions/gitlab.ts index 6d86841a20..22f875ca8d 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlab.ts @@ -18,8 +18,11 @@ import { InputError } from '@backstage/errors'; import { ScmIntegrationRegistry } from '@backstage/integration'; import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; import { Gitlab } from '@gitbeaker/node'; -import { initRepoAndPush } from '../helpers'; -import { getRepoSourceDirectory, parseRepoUrl } from './util'; +import { + initRepoAndPush, + getRepoSourceDirectory, + parseRepoUrl, +} from '@backstage/plugin-scaffolder-node'; import { Config } from '@backstage/config'; import { examples } from './gitlab.examples'; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.test.ts similarity index 100% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.test.ts rename to plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.test.ts diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.ts similarity index 89% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts rename to plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.ts index 8abb53288c..86f69ee357 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.ts @@ -14,15 +14,17 @@ * limitations under the License. */ -import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; -import { Gitlab } from '@gitbeaker/node'; +import { + createTemplateAction, + parseRepoUrl, + serializeDirectoryContents, +} from '@backstage/plugin-scaffolder-node'; import { Types } from '@gitbeaker/core'; import path from 'path'; import { ScmIntegrationRegistry } from '@backstage/integration'; import { InputError } from '@backstage/errors'; -import { parseRepoUrl } from './util'; import { resolveSafeChildPath } from '@backstage/backend-common'; -import { serializeDirectoryContents } from '../../../../lib/files'; +import { createGitlabApi } from './helpers'; /** * Create a new action that creates a gitlab merge request. @@ -156,33 +158,16 @@ export const createPublishGitlabMergeRequestAction = (options: { targetPath, sourcePath, title, - token: providedToken, + token, } = ctx.input; - const { host, owner, repo, project } = parseRepoUrl( - repoUrl, - integrations, - ); + const { owner, repo, project } = parseRepoUrl(repoUrl, integrations); const repoID = project ? project : `${owner}/${repo}`; - const integrationConfig = integrations.gitlab.byHost(host); - - if (!integrationConfig) { - throw new InputError( - `No matching integration configuration for host ${host}, please check your integrations config`, - ); - } - - if (!integrationConfig.config.token && !providedToken) { - throw new InputError(`No token available for host ${host}`); - } - - const token = providedToken ?? integrationConfig.config.token!; - const tokenType = providedToken ? 'oauthToken' : 'token'; - - const api = new Gitlab({ - host: integrationConfig.config.baseUrl, - [tokenType]: token, + const api = createGitlabApi({ + integrations, + token, + repoUrl, }); let assigneeId = undefined; diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabRepoPush.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabRepoPush.test.ts new file mode 100644 index 0000000000..840f506540 --- /dev/null +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabRepoPush.test.ts @@ -0,0 +1,436 @@ +/* + * 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 { createRootLogger, getRootLogger } from '@backstage/backend-common'; +import { ConfigReader } from '@backstage/config'; +import { ScmIntegrations } from '@backstage/integration'; +import { TemplateAction } from '@backstage/plugin-scaffolder-node'; +import { Writable } from 'stream'; +import { createMockDirectory } from '@backstage/backend-test-utils'; +import { createGitlabRepoPushAction } from './gitlabRepoPush'; + +// Make sure root logger is initialized ahead of FS mock +createRootLogger(); + +const mockGitlabClient = { + Projects: { + create: jest.fn(), + show: jest.fn(async (_: any) => { + return { + default_branch: 'main', + }; + }), + }, + Branches: { + create: jest.fn(), + show: jest.fn(), + }, + Commits: { + create: jest.fn(async (_: any) => ({ + id: 'bb6bce457ed069a38ef8d16ef38602972c7735c5', + })), + }, +}; + +jest.mock('@gitbeaker/node', () => ({ + Gitlab: class { + constructor() { + return mockGitlabClient; + } + }, +})); + +describe('createGitLabCommit', () => { + let instance: TemplateAction; + + const mockDir = createMockDirectory(); + const workspacePath = mockDir.resolve('workspace'); + + beforeEach(() => { + mockDir.clear(); + + const config = new ConfigReader({ + integrations: { + gitlab: [ + { + host: 'gitlab.com', + token: 'token', + apiBaseUrl: 'https://api.gitlab.com', + }, + { + host: 'hosted.gitlab.com', + apiBaseUrl: 'https://api.hosted.gitlab.com', + }, + ], + }, + }); + + const integrations = ScmIntegrations.fromConfig(config); + instance = createGitlabRepoPushAction({ integrations }); + }); + + describe('createGitLabCommitWithoutCommitAction', () => { + it('default commitAction is create', async () => { + const input = { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + commitMessage: 'Create my new commit', + branchName: 'some-branch', + }; + mockDir.setContent({ + [workspacePath]: { + 'foo.txt': 'Hello there!', + }, + }); + const ctx = { + createTemporaryDirectory: jest.fn(), + output: jest.fn(), + logger: getRootLogger(), + logStream: new Writable(), + input, + workspacePath, + }; + await instance.handler(ctx); + + expect(mockGitlabClient.Branches.create).toHaveBeenCalledTimes(0); + expect(mockGitlabClient.Commits.create).toHaveBeenCalledWith( + 'owner/repo', + 'some-branch', + 'Create my new commit', + [ + { + action: 'create', + filePath: 'foo.txt', + content: 'SGVsbG8gdGhlcmUh', + encoding: 'base64', + execute_filemode: false, + }, + ], + ); + expect(ctx.output).toHaveBeenCalledWith( + 'commitHash', + 'bb6bce457ed069a38ef8d16ef38602972c7735c5', + ); + }); + }); + + describe('createGitLabCommitWithCommitAction', () => { + it('commitAction is create when create is passed in options', async () => { + const input = { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + commitMessage: 'Create my new commit', + branchName: 'some-branch', + commitAction: 'create', + }; + mockDir.setContent({ + [workspacePath]: { + 'foo.txt': 'Hello there!', + }, + }); + + const ctx = { + createTemporaryDirectory: jest.fn(), + output: jest.fn(), + logger: getRootLogger(), + logStream: new Writable(), + input, + workspacePath, + }; + await instance.handler(ctx); + + expect(mockGitlabClient.Branches.create).toHaveBeenCalledTimes(0); + expect(mockGitlabClient.Commits.create).toHaveBeenCalledWith( + 'owner/repo', + 'some-branch', + 'Create my new commit', + [ + { + action: 'create', + filePath: 'foo.txt', + content: 'SGVsbG8gdGhlcmUh', + encoding: 'base64', + execute_filemode: false, + }, + ], + ); + expect(ctx.output).toHaveBeenCalledWith( + 'commitHash', + 'bb6bce457ed069a38ef8d16ef38602972c7735c5', + ); + }); + + it('commitAction is update when update is passed in options', async () => { + const input = { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + commitMessage: 'Create my new commit', + branchName: 'some-branch', + commitAction: 'update', + }; + mockDir.setContent({ + [workspacePath]: { + 'foo.txt': 'Hello there!', + }, + }); + + const ctx = { + createTemporaryDirectory: jest.fn(), + output: jest.fn(), + logger: getRootLogger(), + logStream: new Writable(), + input, + workspacePath, + }; + await instance.handler(ctx); + + expect(mockGitlabClient.Branches.create).toHaveBeenCalledTimes(0); + expect(mockGitlabClient.Commits.create).toHaveBeenCalledWith( + 'owner/repo', + 'some-branch', + 'Create my new commit', + [ + { + action: 'update', + filePath: 'foo.txt', + content: 'SGVsbG8gdGhlcmUh', + encoding: 'base64', + execute_filemode: false, + }, + ], + ); + expect(ctx.output).toHaveBeenCalledWith( + 'commitHash', + 'bb6bce457ed069a38ef8d16ef38602972c7735c5', + ); + }); + + it('commitAction is delete when delete is passed in options', async () => { + const input = { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + commitMessage: 'Create my new commit', + branchName: 'some-branch', + commitAction: 'delete', + }; + mockDir.setContent({ + [workspacePath]: { + 'foo.txt': 'Hello there!', + }, + }); + + const ctx = { + createTemporaryDirectory: jest.fn(), + output: jest.fn(), + logger: getRootLogger(), + logStream: new Writable(), + input, + workspacePath, + }; + await instance.handler(ctx); + + expect(mockGitlabClient.Branches.create).toHaveBeenCalledTimes(0); + expect(mockGitlabClient.Commits.create).toHaveBeenCalledWith( + 'owner/repo', + 'some-branch', + 'Create my new commit', + [ + { + action: 'delete', + filePath: 'foo.txt', + content: 'SGVsbG8gdGhlcmUh', + encoding: 'base64', + execute_filemode: false, + }, + ], + ); + expect(ctx.output).toHaveBeenCalledWith( + 'commitHash', + 'bb6bce457ed069a38ef8d16ef38602972c7735c5', + ); + }); + }); + + describe('with sourcePath', () => { + it('creates a commit with only relevant files', async () => { + const input = { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + commitMessage: 'Create my new commit', + branchName: 'some-branch', + sourcePath: 'source', + commitAction: 'create', + }; + + mockDir.setContent({ + [workspacePath]: { + source: { 'foo.txt': 'Hello there!' }, + irrelevant: { 'bar.txt': 'Nothing to see here' }, + }, + }); + + const ctx = { + createTemporaryDirectory: jest.fn(), + output: jest.fn(), + logger: getRootLogger(), + logStream: new Writable(), + input, + workspacePath, + }; + + await instance.handler(ctx); + + expect(mockGitlabClient.Branches.create).toHaveBeenCalledTimes(0); + expect(mockGitlabClient.Commits.create).toHaveBeenCalledWith( + 'owner/repo', + 'some-branch', + 'Create my new commit', + [ + { + action: 'create', + filePath: 'foo.txt', + content: 'SGVsbG8gdGhlcmUh', + encoding: 'base64', + execute_filemode: false, + }, + ], + ); + expect(ctx.output).toHaveBeenCalledWith( + 'commitHash', + 'bb6bce457ed069a38ef8d16ef38602972c7735c5', + ); + }); + + it('creates a commit with only relevant files placed under different targetPath', async () => { + const input = { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + commitMessage: 'Create my new commit', + branchName: 'some-branch', + sourcePath: 'source', + targetPath: 'target', + commitAction: 'create', + }; + + mockDir.setContent({ + [workspacePath]: { + source: { 'foo.txt': 'Hello there!' }, + irrelevant: { 'bar.txt': 'Nothing to see here' }, + }, + }); + + const ctx = { + createTemporaryDirectory: jest.fn(), + output: jest.fn(), + logger: getRootLogger(), + logStream: new Writable(), + input, + workspacePath, + }; + + await instance.handler(ctx); + + expect(mockGitlabClient.Branches.create).toHaveBeenCalledTimes(0); + expect(mockGitlabClient.Commits.create).toHaveBeenCalledWith( + 'owner/repo', + 'some-branch', + 'Create my new commit', + [ + { + action: 'create', + filePath: 'target/foo.txt', + content: 'SGVsbG8gdGhlcmUh', + encoding: 'base64', + execute_filemode: false, + }, + ], + ); + expect(ctx.output).toHaveBeenCalledWith( + 'commitHash', + 'bb6bce457ed069a38ef8d16ef38602972c7735c5', + ); + }); + + it('should not allow to use files outside of the workspace', async () => { + const input = { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + commitMessage: 'Create my new commit', + branchName: 'some-branch', + sourcePath: '../../test', + commitAction: 'create', + }; + + const ctx = { + createTemporaryDirectory: jest.fn(), + output: jest.fn(), + logger: getRootLogger(), + logStream: new Writable(), + input, + workspacePath, + }; + + await expect(instance.handler(ctx)).rejects.toThrow( + 'Relative path is not allowed to refer to a directory outside its parent', + ); + }); + }); + + describe('createCommitToBranchThatDoesNotExist', () => { + it('should create a new branch', async () => { + mockGitlabClient.Branches.show.mockRejectedValue({ + response: { + statusCode: 404, + }, + }); + const input = { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + commitMessage: 'Create my new commit', + branchName: 'some-branch', + }; + mockDir.setContent({ + [workspacePath]: { + 'foo.txt': 'Hello there!', + }, + }); + const ctx = { + createTemporaryDirectory: jest.fn(), + output: jest.fn(), + logger: getRootLogger(), + logStream: new Writable(), + input, + workspacePath, + }; + await instance.handler(ctx); + + expect(mockGitlabClient.Branches.create).toHaveBeenCalledWith( + 'owner/repo', + 'some-branch', + 'main', + ); + expect(mockGitlabClient.Commits.create).toHaveBeenCalledWith( + 'owner/repo', + 'some-branch', + 'Create my new commit', + [ + { + action: 'create', + filePath: 'foo.txt', + content: 'SGVsbG8gdGhlcmUh', + encoding: 'base64', + execute_filemode: false, + }, + ], + ); + expect(ctx.output).toHaveBeenCalledWith( + 'commitHash', + 'bb6bce457ed069a38ef8d16ef38602972c7735c5', + ); + }); + }); +}); diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabRepoPush.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabRepoPush.ts new file mode 100644 index 0000000000..330d0f6f08 --- /dev/null +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabRepoPush.ts @@ -0,0 +1,194 @@ +/* + * 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 { + createTemplateAction, + parseRepoUrl, + serializeDirectoryContents, +} from '@backstage/plugin-scaffolder-node'; +import { Types } from '@gitbeaker/core'; +import path from 'path'; +import { ScmIntegrationRegistry } from '@backstage/integration'; +import { InputError } from '@backstage/errors'; +import { resolveSafeChildPath } from '@backstage/backend-common'; +import { createGitlabApi } from './helpers'; + +/** + * Create a new action that commits into a gitlab repository. + * + * @public + */ +export const createGitlabRepoPushAction = (options: { + integrations: ScmIntegrationRegistry; +}) => { + const { integrations } = options; + + return createTemplateAction<{ + repoUrl: string; + branchName: string; + commitMessage: string; + sourcePath?: string; + targetPath?: string; + token?: string; + commitAction?: 'create' | 'delete' | 'update'; + }>({ + id: 'gitlab:repo:push', + schema: { + input: { + required: ['repoUrl', 'branchName', 'commitMessage'], + type: 'object', + properties: { + repoUrl: { + type: 'string', + title: 'Repository Location', + description: `Accepts the format 'gitlab.com?repo=project_name&owner=group_name' where 'project_name' is the repository name and 'group_name' is a group or username`, + }, + branchName: { + type: 'string', + title: 'Source Branch Name', + description: 'The branch name for the commit', + }, + commitMessage: { + type: 'string', + title: 'Commit Message', + description: `The commit message`, + }, + sourcePath: { + type: 'string', + title: 'Working Subdirectory', + description: + 'Subdirectory of working directory to copy changes from', + }, + targetPath: { + type: 'string', + title: 'Repository Subdirectory', + description: 'Subdirectory of repository to apply changes to', + }, + token: { + title: 'Authentication Token', + type: 'string', + description: 'The token to use for authorization to GitLab', + }, + commitAction: { + title: 'Commit action', + type: 'string', + enum: ['create', 'update', 'delete'], + description: + 'The action to be used for git commit. Defaults to create.', + }, + }, + }, + output: { + type: 'object', + properties: { + projectid: { + title: 'Gitlab Project id/Name(slug)', + type: 'string', + }, + projectPath: { + title: 'Gitlab Project path', + type: 'string', + }, + commitHash: { + title: 'The git commit hash of the commit', + type: 'string', + }, + }, + }, + }, + async handler(ctx) { + const { + branchName, + repoUrl, + targetPath, + sourcePath, + token, + commitAction, + } = ctx.input; + + const { owner, repo, project } = parseRepoUrl(repoUrl, integrations); + const repoID = project ? project : `${owner}/${repo}`; + + const api = createGitlabApi({ + integrations, + token, + repoUrl, + }); + + let fileRoot: string; + if (sourcePath) { + fileRoot = resolveSafeChildPath(ctx.workspacePath, sourcePath); + } else { + fileRoot = ctx.workspacePath; + } + + const fileContents = await serializeDirectoryContents(fileRoot, { + gitignore: true, + }); + + const actions: Types.CommitAction[] = fileContents.map(file => ({ + action: commitAction ?? 'create', + filePath: targetPath + ? path.posix.join(targetPath, file.path) + : file.path, + encoding: 'base64', + content: file.content.toString('base64'), + execute_filemode: file.executable, + })); + + let branchExists = false; + try { + await api.Branches.show(repoID, branchName); + branchExists = true; + } catch (e: any) { + if (e.response?.statusCode !== 404) { + throw new InputError( + `Failed to check status of branch '${branchName}'. Please make sure that branch already exists or Backstage has permissions to create one. ${e}`, + ); + } + } + + if (!branchExists) { + // create a branch using the default branch as ref + try { + const projects = await api.Projects.show(repoID); + const { default_branch: defaultBranch } = projects; + await api.Branches.create(repoID, branchName, String(defaultBranch)); + } catch (e) { + throw new InputError( + `The branch '${branchName}' was not found and creation failed with error. Please make sure that branch already exists or Backstage has permissions to create one. ${e}`, + ); + } + } + + try { + const commit = await api.Commits.create( + repoID, + branchName, + ctx.input.commitMessage, + actions, + ); + ctx.output('projectid', repoID); + ctx.output('projectPath', repoID); + ctx.output('commitHash', commit.id); + } catch (e) { + throw new InputError( + `Committing the changes to ${branchName} failed. Please check that none of the files created by the template already exists. ${e}`, + ); + } + }, + }); +}; diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/helpers.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/helpers.ts new file mode 100644 index 0000000000..1d12a6d394 --- /dev/null +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/helpers.ts @@ -0,0 +1,50 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { parseRepoUrl } from '@backstage/plugin-scaffolder-node'; +import { InputError } from '@backstage/errors'; +import { Gitlab } from '@gitbeaker/node'; +import { ScmIntegrationRegistry } from '@backstage/integration'; +import { Resources } from '@gitbeaker/core'; + +export function createGitlabApi(options: { + integrations: ScmIntegrationRegistry; + token?: string; + repoUrl: string; +}): Resources.Gitlab { + const { integrations, token: providedToken, repoUrl } = options; + + const { host } = parseRepoUrl(repoUrl, integrations); + + const integrationConfig = integrations.gitlab.byHost(host); + + if (!integrationConfig) { + throw new InputError( + `No matching integration configuration for host ${host}, please check your integrations config`, + ); + } + + if (!integrationConfig.config.token && !providedToken) { + throw new InputError(`No token available for host ${host}`); + } + + const token = providedToken ?? integrationConfig.config.token!; + const tokenType = providedToken ? 'oauthToken' : 'token'; + + return new Gitlab({ + host: integrationConfig.config.baseUrl, + [tokenType]: token, + }); +} diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/index.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/index.ts new file mode 100644 index 0000000000..4a5ca06c98 --- /dev/null +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/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 * from './createGitlabGroupEnsureExistsAction'; +export * from './createGitlabProjectDeployTokenAction'; +export * from './createGitlabProjectAccessTokenAction'; +export * from './createGitlabProjectVariableAction'; +export * from './createGitlabIssueAction'; +export * from './gitlab'; +export * from './gitlabMergeRequest'; +export * from './gitlabRepoPush'; diff --git a/plugins/scaffolder-backend-module-gitlab/src/commonGitlabConfig.ts b/plugins/scaffolder-backend-module-gitlab/src/commonGitlabConfig.ts index 02724a3674..3c83eacf19 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/commonGitlabConfig.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/commonGitlabConfig.ts @@ -24,3 +24,8 @@ const commonGitlabConfig = z.object({ }); export default commonGitlabConfig; + +export const commonGitlabConfigExample = { + repoUrl: 'gitlab.com?owner=namespace-or-owner&repo=project-name', + token: '${{ secrets.USER_OAUTH_TOKEN }}', +}; diff --git a/plugins/scaffolder-backend-module-gitlab/src/index.ts b/plugins/scaffolder-backend-module-gitlab/src/index.ts index 4fd4dee35b..11d4247569 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/index.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/index.ts @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Backstage Authors + * 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. @@ -19,7 +19,5 @@ * * @packageDocumentation */ -export * from './actions/createGitlabGroupEnsureExistsAction'; -export * from './actions/createGitlabProjectDeployTokenAction'; -export * from './actions/createGitlabProjectAccessTokenAction'; -export * from './actions/createGitlabProjectVariableAction'; + +export * from './actions'; diff --git a/plugins/scaffolder-backend-module-gitlab/src/util.test.ts b/plugins/scaffolder-backend-module-gitlab/src/util.test.ts new file mode 100644 index 0000000000..61c61e87c3 --- /dev/null +++ b/plugins/scaffolder-backend-module-gitlab/src/util.test.ts @@ -0,0 +1,388 @@ +/* + * 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 * as util from './util'; +import { Gitlab, GroupSchema } from '@gitbeaker/rest'; +import { InputError } from '@backstage/errors'; + +// Mock the Gitlab client and its methods +const mockGitlabClient = { + Groups: { + show: jest.fn(), + }, + Projects: { + show: jest.fn(), + }, + Epics: { + all: jest.fn(), + }, +}; + +jest.mock('@gitbeaker/rest', () => ({ + Gitlab: class { + constructor() { + return mockGitlabClient; + } + }, +})); + +const mockConfig = { + gitlab: [ + { + host: 'gitlab.com', + token: 'withToken', + apiBaseUrl: 'gitlab.com/api/v4', + }, + { + host: 'gitlab.com', + apiBaseUrl: 'gitlab.com/api/v4', + }, + ], +}; +describe('getTopLevelParentGroup', () => { + afterEach(() => jest.resetAllMocks()); + + // Mocked nested groups + const mockGroups: GroupSchema[] = [ + { + id: 789, + parent_id: 0, + path: '', + description: '', + visibility: '', + share_with_group_lock: false, + require_two_factor_authentication: false, + two_factor_grace_period: 0, + project_creation_level: '', + subgroup_creation_level: '', + lfs_enabled: false, + default_branch_protection: 0, + request_access_enabled: false, + created_at: '', + avatar_url: '', + full_name: '', + full_path: '', + web_url: '', + name: '', + }, + { + id: 456, + parent_id: 789, + path: '', + description: '', + visibility: '', + share_with_group_lock: false, + require_two_factor_authentication: false, + two_factor_grace_period: 0, + project_creation_level: '', + subgroup_creation_level: '', + lfs_enabled: false, + default_branch_protection: 0, + request_access_enabled: false, + created_at: '', + avatar_url: '', + full_name: '', + full_path: '', + web_url: '', + name: '', + }, + { + id: 123, + parent_id: 456, + path: '', + description: '', + visibility: '', + share_with_group_lock: false, + require_two_factor_authentication: false, + two_factor_grace_period: 0, + project_creation_level: '', + subgroup_creation_level: '', + lfs_enabled: false, + default_branch_protection: 0, + request_access_enabled: false, + created_at: '', + avatar_url: '', + full_name: '', + full_path: '', + web_url: '', + name: '', + }, + ]; + + // Top level group + const mockTopParentGroup: GroupSchema = { + id: 789, + parent_id: 0, + path: '', + description: '', + visibility: '', + share_with_group_lock: false, + require_two_factor_authentication: false, + two_factor_grace_period: 0, + project_creation_level: '', + subgroup_creation_level: '', + lfs_enabled: false, + default_branch_protection: 0, + request_access_enabled: false, + created_at: '', + avatar_url: '', + full_name: '', + full_path: '', + web_url: '', + name: '', + }; + + it('should return the top-level parent group if the input group has a parent in the hierarchy', async () => { + // Instance with token + const apiClient = new Gitlab({ + host: mockConfig.gitlab[0].host, + token: mockConfig.gitlab[0].token!, + }); + + const showSpy = jest.spyOn(mockGitlabClient.Groups, 'show'); + + // Mock implementation of Groups.show + showSpy.mockImplementation( + async (groupId: string | number): Promise => { + const id = + typeof groupId === 'number' ? groupId : parseInt(groupId, 10); + const mockGroup = mockGroups.find(group => group.id === id) || null; + return mockGroup as GroupSchema; + }, + ); + + const action = util.getTopLevelParentGroup(apiClient, 123); + + const result = await action; + expect(result).toEqual(mockTopParentGroup); + }); + + it('should return the input group if it has no parents in the hierarchy', async () => { + // Instance with token + const apiClient = new Gitlab({ + host: mockConfig.gitlab[0].host, + token: mockConfig.gitlab[0].token!, + }); + + const showSpy = jest.spyOn(mockGitlabClient.Groups, 'show'); + + // Mock implementation of Groups.show + showSpy.mockImplementation( + async (groupId: string | number): Promise => { + const id = + typeof groupId === 'number' ? groupId : parseInt(groupId, 10); + const mockGroup = mockGroups.find(group => group.id === id) || null; + return mockGroup as GroupSchema; + }, + ); + + const action = util.getTopLevelParentGroup(apiClient, 789); + + const result = await action; + expect(result).toEqual(mockTopParentGroup); + }); +}); + +describe('checkEpicScope', () => { + afterEach(() => jest.resetAllMocks()); + + it('should return true if the project is inside the epic scope', async () => { + const apiClient = new Gitlab({ + host: mockConfig.gitlab[0].host, + token: mockConfig.gitlab[0].token!, + }); + + const projectId = 123; + const epicId = 456; + + // Mock project, top-level parent group, and epic + const mockProject = { + id: 123, + name: 'You learn', + namespace: { id: 789 }, + path_with_namespace: 'at-once/you-learn', + }; + const mockTopParentGroup = { + id: 789, + name: 'LivingTwice', + full_path: 'at-once/you-learn', + }; + const mockEpic = { id: epicId, group_id: 789 }; + + mockGitlabClient.Projects.show.mockResolvedValue(mockProject); + mockGitlabClient.Groups.show.mockResolvedValue(mockTopParentGroup); + mockGitlabClient.Epics.all.mockResolvedValue([mockEpic]); + + const result = await util.checkEpicScope(apiClient, projectId, epicId); + + expect(result).toBe(true); + expect(mockGitlabClient.Projects.show).toHaveBeenCalledWith(projectId); + expect(mockGitlabClient.Groups.show).toHaveBeenCalledWith( + mockProject.namespace.id, + ); + expect(mockGitlabClient.Epics.all).toHaveBeenCalledWith( + mockTopParentGroup.id, + ); + }); + + it('should return false if the project is not inside the epic scope', async () => { + const apiClient = new Gitlab({ + host: mockConfig.gitlab[0].host, + token: mockConfig.gitlab[0].token!, + }); + + const projectId = 123; + const epicId = 45; + + // Mock project, top-level parent group, and epic + const mockProject = { + id: 123, + name: 'You learn', + namespace: { id: 32 }, + path_with_namespace: 'at-once/you-learn', + }; + const mockTopParentGroup = { + id: 32, + name: 'TheWalls', + full_path: 'you-built/within', + }; + + const mockEpic = { id: epicId, group_id: 32 }; + + mockGitlabClient.Projects.show.mockResolvedValue(mockProject); + mockGitlabClient.Groups.show.mockResolvedValue(mockTopParentGroup); + mockGitlabClient.Epics.all.mockResolvedValue([mockEpic]); + + const result = await util.checkEpicScope(apiClient, projectId, epicId); + + expect(result).toBe(false); + expect(mockGitlabClient.Projects.show).toHaveBeenCalledWith(projectId); + expect(mockGitlabClient.Groups.show).toHaveBeenCalledWith( + mockProject.namespace.id, + ); + expect(mockGitlabClient.Epics.all).toHaveBeenCalledWith( + mockTopParentGroup.id, + ); + }); + + it('should throw an InputError if the project is not found', async () => { + const apiClient = new Gitlab({ + host: mockConfig.gitlab[0].host, + token: mockConfig.gitlab[0].token!, + }); + + const projectId = 123; + const epicId = 456; + + mockGitlabClient.Projects.show.mockResolvedValue(null); + + await expect( + util.checkEpicScope(apiClient, projectId, epicId), + ).rejects.toThrow(InputError); + expect(mockGitlabClient.Projects.show).toHaveBeenCalledWith(projectId); + }); + + it('should throw an InputError if the top-level parent group is not found', async () => { + const apiClient = new Gitlab({ + host: mockConfig.gitlab[0].host, + token: mockConfig.gitlab[0].token!, + }); + + const projectId = 123; + const epicId = 456; + + mockGitlabClient.Projects.show.mockResolvedValue({ + id: 123, + name: 'You learn', + namespace: { id: 789 }, + path_with_namespace: 'at-once/you-learn', + }); + mockGitlabClient.Groups.show.mockResolvedValue(null); + + await expect( + util.checkEpicScope(apiClient, projectId, epicId), + ).rejects.toThrow(InputError); + expect(mockGitlabClient.Projects.show).toHaveBeenCalledWith(projectId); + expect(mockGitlabClient.Groups.show).toHaveBeenCalledWith(789); + }); + + it('should throw an InputError if the epic is not found', async () => { + const apiClient = new Gitlab({ + host: mockConfig.gitlab[0].host, + token: mockConfig.gitlab[0].token!, + }); + + const projectId = 123; + const epicId = 456; + + mockGitlabClient.Projects.show.mockResolvedValue({ + id: 123, + name: 'You learn', + namespace: { id: 789 }, + path_with_namespace: 'at-once/you-learn', + }); + mockGitlabClient.Groups.show.mockResolvedValue({ + id: 789, + name: 'LivingTwice', + full_path: 'at-once/you-learn', + }); + mockGitlabClient.Epics.all.mockResolvedValue([]); + + await expect( + util.checkEpicScope(apiClient, projectId, epicId), + ).rejects.toThrow(InputError); + expect(mockGitlabClient.Projects.show).toHaveBeenCalledWith(projectId); + expect(mockGitlabClient.Groups.show).toHaveBeenCalledWith(789); + expect(mockGitlabClient.Epics.all).toHaveBeenCalledWith(789); + }); +}); + +describe('convertDate', () => { + it('should convert a valid input date with miliseconds to an ISO string', () => { + const inputDate = '1970-01-01T12:00:00.000Z'; + const defaultDate = '1978-10-09T12:00:00Z'; + + const result = util.convertDate(inputDate, defaultDate); + + expect(result).toEqual('1970-01-01T12:00:00.000Z'); + }); + + it('should convert a valid input date to an ISO string', () => { + const inputDate = '1970-01-01T12:00:00Z'; + const defaultDate = '1978-10-09T12:00:00Z'; + + const result = util.convertDate(inputDate, defaultDate); + + expect(result).toEqual('1970-01-01T12:00:00.000Z'); + }); + + it('should use default date if input date is undefined', () => { + const inputDate = undefined; + const defaultDate = '1970-01-01T12:00:00Z'; + + const result = util.convertDate(inputDate, defaultDate); + + expect(result).toEqual('1970-01-01T12:00:00.000Z'); + }); + + it('should throw an InputError if input date is invalid', () => { + const inputDate = 'invalidDate'; + const defaultDate = '2023-02-01T12:00:00Z'; + + // Expecting an InputError to be thrown + expect(() => util.convertDate(inputDate, defaultDate)).toThrow(InputError); + }); +}); diff --git a/plugins/scaffolder-backend-module-gitlab/src/util.ts b/plugins/scaffolder-backend-module-gitlab/src/util.ts index 13c95e48e8..a4d819d490 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/util.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/util.ts @@ -21,6 +21,8 @@ import { } from '@backstage/integration'; import { z } from 'zod'; import commonGitlabConfig from './commonGitlabConfig'; +import { Gitlab, GroupSchema } from '@gitbeaker/rest'; +import * as util from './util'; export const parseRepoHost = (repoUrl: string): string => { let parsed; @@ -56,3 +58,138 @@ export const getToken = ( return { token: token, integrationConfig: integrationConfig }; }; + +export type RepoSpec = { + repo: string; + host: string; + owner?: string; +}; + +export const parseRepoUrl = ( + repoUrl: string, + integrations: ScmIntegrationRegistry, +): RepoSpec => { + let parsed; + try { + parsed = new URL(`https://${repoUrl}`); + } catch (error) { + throw new InputError( + `Invalid repo URL passed to publisher, got ${repoUrl}, ${error}`, + ); + } + const host = parsed.host; + const owner = parsed.searchParams.get('owner') ?? undefined; + const repo: string = parsed.searchParams.get('repo')!; + + const type = integrations.byHost(host)?.type; + + if (!type) { + throw new InputError( + `No matching integration configuration for host ${host}, please check your integrations config`, + ); + } + + return { host, owner, repo }; +}; + +export function getClient(props: { + host: string; + token?: string; + integrations: ScmIntegrationRegistry; +}): InstanceType { + const { host, token, integrations } = props; + const integrationConfig = integrations.gitlab.byHost(host); + + if (!integrationConfig) { + throw new InputError( + `No matching integration configuration for host ${host}, please check your integrations config`, + ); + } + + const { config } = integrationConfig; + + if (!config.token && !token) { + throw new InputError(`No token available for host ${host}`); + } + + const requestToken = token || config.token!; + const tokenType = token ? 'oauthToken' : 'token'; + + const gitlabOptions: any = { + host: config.baseUrl, + }; + + gitlabOptions[tokenType] = requestToken; + return new Gitlab(gitlabOptions); +} + +export function convertDate( + inputDate: string | undefined, + defaultDate: string, +) { + try { + return inputDate + ? new Date(inputDate).toISOString() + : new Date(defaultDate).toISOString(); + } catch (error) { + throw new InputError(`Error converting input date - ${error}`); + } +} + +export async function getTopLevelParentGroup( + client: InstanceType, + groupId: number, +): Promise { + try { + const topParentGroup = await client.Groups.show(groupId); + if (topParentGroup.parent_id) { + return util.getTopLevelParentGroup( + client, + topParentGroup.parent_id as number, + ); + } + return topParentGroup as GroupSchema; + } catch (error: any) { + throw new InputError( + `Error finding top-level parent group ID: ${error.message}`, + ); + } +} + +export async function checkEpicScope( + client: InstanceType, + projectId: number, + epicId: number, +) { + try { + // If project exists, get the top level group id + const project = await client.Projects.show(projectId); + if (!project) { + throw new InputError( + `Project with id ${projectId} not found. Check your GitLab instance.`, + ); + } + const topParentGroup = await getTopLevelParentGroup( + client, + project.namespace.id, + ); + if (!topParentGroup) { + throw new InputError(`Couldn't find a suitable top-level parent group.`); + } + // Get the epic + const epic = (await client.Epics.all(topParentGroup.id)).find( + (x: any) => x.id === epicId, + ); + if (!epic) { + throw new InputError( + `Epic with id ${epicId} not found in the top-level parent group ${topParentGroup.name}.`, + ); + } + + const epicGroup = await client.Groups.show(epic.group_id as number); + const projectNamespace: string = project.path_with_namespace as string; + return projectNamespace.startsWith(epicGroup.full_path as string); + } catch (error: any) { + throw new InputError(`Could not find epic scope: ${error.message}`); + } +} diff --git a/plugins/scaffolder-backend-module-rails/CHANGELOG.md b/plugins/scaffolder-backend-module-rails/CHANGELOG.md index 42da0f806a..a923feec27 100644 --- a/plugins/scaffolder-backend-module-rails/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-rails/CHANGELOG.md @@ -1,5 +1,121 @@ # @backstage/plugin-scaffolder-backend-module-rails +## 0.4.26 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + +## 0.4.26-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-scaffolder-node@0.2.10-next.2 + +## 0.4.26-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.10-next.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.4.26-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.10-next.0 + +## 0.4.25 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-scaffolder-node@0.2.9 + - @backstage/integration@1.8.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.4.25-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.9-next.3 + - @backstage/backend-common@0.20.0-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/types@1.1.1 + +## 0.4.25-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.9-next.2 + +## 0.4.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.9-next.1 + +## 0.4.25-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/plugin-scaffolder-node@0.2.9-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## 0.4.24 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.2 + - @backstage/backend-common@0.19.9 + - @backstage/plugin-scaffolder-node@0.2.8 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + ## 0.4.24-next.2 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-rails/package.json b/plugins/scaffolder-backend-module-rails/package.json index 5b253fdb9d..65969643c1 100644 --- a/plugins/scaffolder-backend-module-rails/package.json +++ b/plugins/scaffolder-backend-module-rails/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-backend-module-rails", "description": "A module for the scaffolder backend that lets you template projects using Rails", - "version": "0.4.24-next.2", + "version": "0.4.26", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-backend-module-sentry/CHANGELOG.md b/plugins/scaffolder-backend-module-sentry/CHANGELOG.md index b0386e706e..5ba8dd0f05 100644 --- a/plugins/scaffolder-backend-module-sentry/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-sentry/CHANGELOG.md @@ -1,5 +1,95 @@ # @backstage/plugin-scaffolder-backend-module-sentry +## 0.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.1.17-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.10-next.2 + +## 0.1.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.10-next.1 + - @backstage/errors@1.2.3 + +## 0.1.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-scaffolder-node@0.2.10-next.0 + +## 0.1.16 + +### Patch Changes + +- 7f8a801: Added examples for `sentry:project:create` scaffolder action and unit tests. +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.9 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.1.16-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.9-next.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.1.16-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-scaffolder-node@0.2.9-next.2 + +## 0.1.16-next.1 + +### Patch Changes + +- 7f8a801e6d: Added examples for `sentry:project:create` scaffolder action and unit tests. +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-scaffolder-node@0.2.9-next.1 + +## 0.1.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.9-next.0 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## 0.1.15 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.8 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + ## 0.1.15-next.2 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-sentry/package.json b/plugins/scaffolder-backend-module-sentry/package.json index 1413dfb004..7828713d08 100644 --- a/plugins/scaffolder-backend-module-sentry/package.json +++ b/plugins/scaffolder-backend-module-sentry/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-sentry", - "version": "0.1.15-next.2", + "version": "0.1.17", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,10 +30,14 @@ "dependencies": { "@backstage/config": "workspace:^", "@backstage/errors": "workspace:^", - "@backstage/plugin-scaffolder-node": "workspace:^" + "@backstage/plugin-scaffolder-node": "workspace:^", + "yaml": "^2.3.3" }, "devDependencies": { - "@backstage/cli": "workspace:^" + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", + "@backstage/types": "workspace:^", + "msw": "^2.0.0" }, "files": [ "dist" diff --git a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.examples.ts b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.examples.ts new file mode 100644 index 0000000000..9d4551c1b5 --- /dev/null +++ b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.examples.ts @@ -0,0 +1,53 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { TemplateExample } from '@backstage/plugin-scaffolder-node'; +import yaml from 'yaml'; + +export const examples: TemplateExample[] = [ + { + description: 'Creates a Sentry project with the specified parameters.', + example: yaml.stringify({ + steps: [ + { + id: 'create-sentry-project', + action: 'sentry:project:create', + name: 'Create a Sentry project with provided project slug.', + input: { + organizationSlug: 'my-org', + teamSlug: 'team-a', + name: 'Scaffolded project A', + slug: 'scaff-proj-a', + authToken: + 'a14711beb516e1e910d2ede554dc1bf725654ef3c75e5a9106de9aec13d5df96', + }, + }, + { + id: 'create-sentry-project', + action: 'sentry:project:create', + name: 'Create a Sentry project without providing a project slug.', + input: { + organizationSlug: 'my-org', + teamSlug: 'team-b', + name: 'Scaffolded project B', + authToken: + 'b15711beb516e1e910d2ede554dc1bf725654ef3c75e5a9106de9aec13d4gf93', + }, + }, + ], + }), + }, +]; diff --git a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts new file mode 100644 index 0000000000..972b0f1e8e --- /dev/null +++ b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.test.ts @@ -0,0 +1,217 @@ +/* + * 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 { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { ConfigReader } from '@backstage/config'; +import { InputError } from '@backstage/errors'; +import { ActionContext } from '@backstage/plugin-scaffolder-node'; +import { JsonObject } from '@backstage/types'; +import { randomBytes } from 'crypto'; +import { setupServer } from 'msw/node'; +import { HttpResponse, http } from 'msw'; +import { createSentryCreateProjectAction } from './createProject'; + +describe('sentry:project:create action', () => { + const worker = setupServer(); + setupRequestMockHandlers(worker); + + const createScaffolderConfig = (configData: JsonObject = {}) => ({ + config: new ConfigReader({ + scaffolder: { + ...configData, + }, + }), + }); + + const getActionContext = (): ActionContext<{ + organizationSlug: string; + teamSlug: string; + name: string; + slug?: string; + authToken?: string; + }> => ({ + workspacePath: './dev/proj', + createTemporaryDirectory: jest.fn(), + logger: jest.createMockFromModule('winston'), + logStream: jest.createMockFromModule('stream'), + input: { + organizationSlug: 'org', + teamSlug: 'team', + name: 'test project', + authToken: randomBytes(5).toString('hex'), + }, + output: jest.fn(), + }); + + it('should request sentry project create with specified parameters.', async () => { + expect.assertions(3); + + const action = createSentryCreateProjectAction(createScaffolderConfig()); + const actionContext = getActionContext(); + + worker.use( + http.post( + `https://sentry.io/api/0/teams/${actionContext.input.organizationSlug}/${actionContext.input.teamSlug}/projects/`, + async ({ request }) => { + expect(request.headers.get('Authorization')).toBe( + `Bearer ${actionContext.input.authToken}`, + ); + expect(request.headers.get('Content-Type')).toBe(`application/json`); + await expect(request.json()).resolves.toEqual({ + name: actionContext.input.name, + }); + return HttpResponse.json( + { detail: 'project creation mocked result' }, + { status: 201 }, + ); + }, + ), + ); + + await action.handler(actionContext); + }); + + it('should request sentry project create with added optional specified project slug', async () => { + expect.assertions(3); + + const action = createSentryCreateProjectAction(createScaffolderConfig()); + const actionContext = getActionContext(); + actionContext.input = { ...actionContext.input, slug: 'project-slug' }; + + worker.use( + http.post( + `https://sentry.io/api/0/teams/${actionContext.input.organizationSlug}/${actionContext.input.teamSlug}/projects/`, + async ({ request }) => { + expect(request.headers.get('Authorization')).toBe( + `Bearer ${actionContext.input.authToken}`, + ); + expect(request.headers.get('Content-Type')).toBe(`application/json`); + await expect(request.json()).resolves.toEqual({ + name: actionContext.input.name, + slug: actionContext.input.slug, + }); + return HttpResponse.json( + { detail: 'project creation mocked result' }, + { status: 201 }, + ); + }, + ), + ); + + await action.handler(actionContext); + }); + + it('should take Sentry auth token from scaffolder config when input authToken is missing.', async () => { + expect.assertions(3); + + const sentryScaffolderConfigToken = randomBytes(5).toString('hex'); + const action = createSentryCreateProjectAction( + createScaffolderConfig({ + sentry: { + token: sentryScaffolderConfigToken, + }, + }), + ); + const actionContext = getActionContext(); + actionContext.input.authToken = undefined; + + worker.use( + http.post( + `https://sentry.io/api/0/teams/${actionContext.input.organizationSlug}/${actionContext.input.teamSlug}/projects/`, + async ({ request }) => { + expect(request.headers.get('Authorization')).toBe( + `Bearer ${sentryScaffolderConfigToken}`, + ); + expect(request.headers.get('Content-Type')).toBe(`application/json`); + await expect(request.json()).resolves.toEqual({ + name: actionContext.input.name, + }); + return HttpResponse.json( + { detail: 'project creation mocked result' }, + { status: 201 }, + ); + }, + ), + ); + + await action.handler(actionContext); + }); + + it('should throw InputError when auth token is missing from input parameters and scaffolder config.', async () => { + const action = createSentryCreateProjectAction(createScaffolderConfig()); + const actionContext = getActionContext(); + actionContext.input.authToken = undefined; + + worker.use( + http.post( + `https://sentry.io/api/0/teams/${actionContext.input.organizationSlug}/${actionContext.input.teamSlug}/projects/`, + async ({ request }) => { + expect(request.headers.get('Authorization')).toBe( + `Bearer ${actionContext.input.authToken}`, + ); + expect(request.headers.get('Content-Type')).toBe(`application/json`); + await expect(request.json()).resolves.toEqual({ + name: actionContext.input.name, + }); + return HttpResponse.json( + { detail: 'project creation mocked result' }, + { status: 201 }, + ); + }, + ), + ); + + await expect(() => action.handler(actionContext)).rejects.toThrow( + new InputError('No valid sentry token given'), + ); + }); + + it('should throw InputError when sentry API returns unexpected content-type.', async () => { + const action = createSentryCreateProjectAction(createScaffolderConfig()); + const actionContext = getActionContext(); + + worker.use( + http.post( + `https://sentry.io/api/0/teams/${actionContext.input.organizationSlug}/${actionContext.input.teamSlug}/projects/`, + async () => { + return HttpResponse.text('Bad response', { status: 201 }); + }, + ), + ); + + await expect(() => action.handler(actionContext)).rejects.toThrow( + new InputError(`Unexpected Sentry Response Type: Bad response`), + ); + }); + + it('should throw InputError when sentry API returns unexpected status code.', async () => { + const action = createSentryCreateProjectAction(createScaffolderConfig()); + const actionContext = getActionContext(); + + worker.use( + http.post( + `https://sentry.io/api/0/teams/${actionContext.input.organizationSlug}/${actionContext.input.teamSlug}/projects/`, + async () => { + return HttpResponse.json({ detail: 'OUCH' }, { status: 400 }); + }, + ), + ); + + await expect(() => action.handler(actionContext)).rejects.toThrow( + new InputError(`Sentry Response was: OUCH`), + ); + }); +}); diff --git a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts index 85a74eda07..259b670f9e 100644 --- a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts +++ b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts @@ -19,7 +19,7 @@ import { InputError } from '@backstage/errors'; import { Config } from '@backstage/config'; /** - * Creates the `sentry:craete-project` Scaffolder action. + * Creates the `sentry:project:create` Scaffolder action. * * @remarks * diff --git a/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md b/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md index 46c2784d47..1b4858dec9 100644 --- a/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md @@ -1,5 +1,92 @@ # @backstage/plugin-scaffolder-backend-module-yeoman +## 0.2.30 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/types@1.1.1 + +## 0.2.30-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.10-next.2 + +## 0.2.30-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.10-next.1 + - @backstage/types@1.1.1 + +## 0.2.30-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.10-next.0 + +## 0.2.29 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.9 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## 0.2.29-next.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.9-next.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## 0.2.29-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.9-next.2 + +## 0.2.29-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-node@0.2.9-next.1 + +## 0.2.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.9-next.0 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## 0.2.28 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.8 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + ## 0.2.28-next.2 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-yeoman/package.json b/plugins/scaffolder-backend-module-yeoman/package.json index 811e09f6ad..94883084e4 100644 --- a/plugins/scaffolder-backend-module-yeoman/package.json +++ b/plugins/scaffolder-backend-module-yeoman/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-yeoman", - "version": "0.2.28-next.2", + "version": "0.2.30", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -28,7 +28,6 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/config": "workspace:^", "@backstage/plugin-scaffolder-node": "workspace:^", "@backstage/types": "workspace:^", "winston": "^3.2.1", diff --git a/plugins/scaffolder-backend/CHANGELOG.md b/plugins/scaffolder-backend/CHANGELOG.md index 8725488364..2fb35e3d24 100644 --- a/plugins/scaffolder-backend/CHANGELOG.md +++ b/plugins/scaffolder-backend/CHANGELOG.md @@ -1,5 +1,291 @@ # @backstage/plugin-scaffolder-backend +## 1.20.0 + +### Minor Changes + +- a694f71: The Scaffolder builtin actions now contains an action for running pipelines from Bitbucket Cloud Rest API +- 7c522c5: Add `gitlab:repo:push` scaffolder action to push files to arbitrary branch without creating a Merge Request + +### Patch Changes + +- e9ab1c4: Fixed an issue where not passing a `value` to any of the action's permission conditions caused an error. +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-backend-module-github@0.1.1 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.2.12 + - @backstage/plugin-scaffolder-common@1.4.5 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.1.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-scaffolder-backend-module-azure@0.1.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.6 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.1.1 + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + +## 1.19.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + - @backstage/plugin-auth-node@0.4.3-next.2 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.6-next.2 + - @backstage/plugin-catalog-node@1.6.1-next.2 + - @backstage/plugin-permission-node@0.7.20-next.2 + - @backstage/plugin-scaffolder-node@0.2.10-next.2 + - @backstage/backend-tasks@0.5.14-next.2 + - @backstage/plugin-scaffolder-backend-module-azure@0.1.1-next.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.1.1-next.2 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.1.1-next.2 + - @backstage/plugin-scaffolder-backend-module-github@0.1.1-next.2 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.2.12-next.2 + +## 1.19.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.2.12-next.1 + - @backstage/config@1.1.1 + - @backstage/backend-tasks@0.5.14-next.1 + - @backstage/plugin-auth-node@0.4.3-next.1 + - @backstage/plugin-permission-node@0.7.20-next.1 + - @backstage/plugin-scaffolder-backend-module-azure@0.1.1-next.1 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.1.1-next.1 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.1.1-next.1 + - @backstage/plugin-scaffolder-backend-module-github@0.1.1-next.1 + - @backstage/plugin-scaffolder-node@0.2.10-next.1 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.6-next.1 + - @backstage/plugin-catalog-node@1.6.1-next.1 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-scaffolder-common@1.4.4 + +## 1.19.3-next.0 + +### Patch Changes + +- e9ab1c4: Fixed an issue where not passing a `value` to any of the action's permission conditions caused an error. +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/plugin-scaffolder-backend-module-github@0.1.1-next.0 + - @backstage/plugin-scaffolder-backend-module-azure@0.1.1-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.6-next.0 + - @backstage/plugin-catalog-node@1.6.1-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/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.3-next.0 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.20-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.1.1-next.0 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.1.1-next.0 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.2.12-next.0 + - @backstage/plugin-scaffolder-common@1.4.4 + - @backstage/plugin-scaffolder-node@0.2.10-next.0 + +## 1.19.2 + +### Patch Changes + +- 219d7f0: Refactor some methods to `-node` instead and use the new external modules +- aff34fc: Fix issue with Circular JSON dependencies in templating +- 48667b4: Fix creating env secret in github:environment:create action +- 0cbb03b: Fixing regular expression ReDoS with zod packages. Upgrading to latest. ref: https://security.snyk.io/vuln/SNYK-JS-ZOD-5925617 +- 28949ea: Add a new action for creating github-autolink references for a repository: `github:autolinks:create` +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/plugin-scaffolder-backend-module-github@0.1.0 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.2.11 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.1.0 + - @backstage/plugin-catalog-node@1.6.0 + - @backstage/catalog-client@1.5.0 + - @backstage/plugin-scaffolder-node@0.2.9 + - @backstage/backend-tasks@0.5.13 + - @backstage/integration@1.8.0 + - @backstage/plugin-auth-node@0.4.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.1.0 + - @backstage/plugin-scaffolder-backend-module-azure@0.1.0 + - @backstage/plugin-permission-common@0.7.11 + - @backstage/plugin-permission-node@0.7.19 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.5 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-common@1.4.4 + +## 1.19.2-next.3 + +### Patch Changes + +- 219d7f0: Refactor some methods to `-node` instead and use the new external modules +- Updated dependencies + - @backstage/plugin-scaffolder-backend-module-gitlab@0.2.11-next.3 + - @backstage/plugin-scaffolder-node@0.2.9-next.3 + - @backstage/backend-common@0.20.0-next.3 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.1.0-next.0 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.1.0-next.0 + - @backstage/plugin-scaffolder-backend-module-github@0.1.0-next.0 + - @backstage/plugin-scaffolder-backend-module-azure@0.1.0-next.0 + - @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/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.3 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.5-next.3 + - @backstage/plugin-catalog-node@1.6.0-next.3 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.3 + - @backstage/plugin-scaffolder-common@1.4.3 + +## 1.19.2-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/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/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/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.2 + - @backstage/plugin-scaffolder-common@1.4.3 + - @backstage/plugin-scaffolder-node@0.2.9-next.2 + +## 1.19.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.15.1-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/backend-tasks@0.5.13-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.2-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.5-next.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-node@1.5.1-next.1 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-permission-node@0.7.19-next.1 + - @backstage/plugin-scaffolder-common@1.4.3 + - @backstage/plugin-scaffolder-node@0.2.9-next.1 + +## 1.19.2-next.0 + +### Patch Changes + +- aff34fcf23: Fix issue with Circular JSON dependencies in templating +- 48667b4d3a: Fix creating env secret in github:environment:create action +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/backend-tasks@0.5.13-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/plugin-auth-node@0.4.2-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-permission-node@0.7.19-next.0 + - @backstage/plugin-scaffolder-node@0.2.9-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-scaffolder-common@1.4.3 + +## 1.19.0 + +### Minor Changes + +- f3ab9cfcb7: Made shut down stale tasks configurable. + + There are two properties exposed: + + - `scaffolder.processingInterval` - sets the processing interval for staled tasks. + - `scaffolder.taskTimeoutJanitorFrequency` - sets the task's heartbeat timeout, when to consider a task to be staled. + +- 7d5a921114: Allow using `globby`'s negative matching with `copyWithoutTemplating`/`copyWithoutRender`. This allows including an entire subdirectory while excluding a single file so that it will still be templated instead of needing to list every other file and ensure the list is updated when new files are added. +- 5e4127c18e: Allow setting `update: true` in `publish:github:pull-request` scaffolder action + +### Patch Changes + +- 0920fd02ac: Add examples for `github:environment:create` scaffolder action & improve related tests +- ae30a9ae8c: Added description for publish:gerrit scaffolder actions +- 013611b42e: `knex` has been bumped to major version 3 and `better-sqlite3` to major version 9, which deprecate node 16 support. +- 23f72b2cba: Refactoring the runner to generate minimally informative task log per iteration and properly validate iterated actions. +- 8613ba3928: Switched to using `"exports"` field for `/alpha` subpath export. +- 99d4936f6c: Add examples for `github:webhook` scaffolder action & improve related tests +- 2be3922eb8: Add examples for `github:deployKey:create` scaffolder action & improve related tests +- 76d07da66a: Make it possible to define control buttons text (Back, Create, Review) per template +- f8727ad228: Add examples for `publish:github:pull-request` scaffolder action & improve related tests +- Updated dependencies + - @backstage/plugin-catalog-backend@1.15.0 + - @backstage/plugin-catalog-node@1.5.0 + - @backstage/plugin-scaffolder-common@1.4.3 + - @backstage/integration@1.7.2 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/backend-tasks@0.5.12 + - @backstage/catalog-client@1.4.6 + - @backstage/plugin-permission-common@0.7.10 + - @backstage/plugin-scaffolder-node@0.2.8 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.4 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-node@0.4.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-node@0.7.18 + ## 1.19.0-next.2 ### Patch Changes diff --git a/plugins/scaffolder-backend/alpha-api-report.md b/plugins/scaffolder-backend/api-report-alpha.md similarity index 100% rename from plugins/scaffolder-backend/alpha-api-report.md rename to plugins/scaffolder-backend/api-report-alpha.md diff --git a/plugins/scaffolder-backend/api-report.md b/plugins/scaffolder-backend/api-report.md index b92b883767..c928e5341e 100644 --- a/plugins/scaffolder-backend/api-report.md +++ b/plugins/scaffolder-backend/api-report.md @@ -4,21 +4,23 @@ ```ts import { ActionContext as ActionContext_2 } from '@backstage/plugin-scaffolder-node'; +import * as azure from '@backstage/plugin-scaffolder-backend-module-azure'; +import * as bitbucket from '@backstage/plugin-scaffolder-backend-module-bitbucket'; import { CatalogApi } from '@backstage/catalog-client'; import { Config } from '@backstage/config'; -import { createPullRequest } from 'octokit-plugin-create-pull-request'; import { Duration } from 'luxon'; import { executeShellCommand as executeShellCommand_2 } from '@backstage/plugin-scaffolder-node'; import { ExecuteShellCommandOptions } from '@backstage/plugin-scaffolder-node'; import express from 'express'; import { fetchContents as fetchContents_2 } from '@backstage/plugin-scaffolder-node'; -import { GithubCredentialsProvider } from '@backstage/integration'; +import * as gerrit from '@backstage/plugin-scaffolder-backend-module-gerrit'; +import * as github from '@backstage/plugin-scaffolder-backend-module-github'; +import * as gitlab from '@backstage/plugin-scaffolder-backend-module-gitlab'; import { HumanDuration } from '@backstage/types'; import { IdentityApi } from '@backstage/plugin-auth-node'; import { JsonObject } from '@backstage/types'; import { Knex } from 'knex'; import { Logger } from 'winston'; -import { Octokit } from 'octokit'; import { PermissionEvaluator } from '@backstage/plugin-permission-common'; import { PermissionRule } from '@backstage/plugin-permission-node'; import { PermissionRuleParams } from '@backstage/plugin-permission-common'; @@ -197,454 +199,58 @@ export const createFilesystemRenameAction: () => TemplateAction_2< JsonObject >; -// @public -export function createGithubActionsDispatchAction(options: { - integrations: ScmIntegrations; - githubCredentialsProvider?: GithubCredentialsProvider; -}): TemplateAction_2< - { - repoUrl: string; - workflowId: string; - branchOrTagName: string; - workflowInputs?: - | { - [key: string]: string; - } - | undefined; - token?: string | undefined; - }, - JsonObject ->; +// @public @deprecated (undocumented) +export const createGithubActionsDispatchAction: typeof github.createGithubActionsDispatchAction; -// @public -export function createGithubDeployKeyAction(options: { - integrations: ScmIntegrationRegistry; -}): TemplateAction_2< - { - repoUrl: string; - publicKey: string; - privateKey: string; - deployKeyName: string; - privateKeySecretName?: string | undefined; - token?: string | undefined; - }, - JsonObject ->; +// @public @deprecated (undocumented) +export const createGithubDeployKeyAction: typeof github.createGithubDeployKeyAction; -// @public -export function createGithubEnvironmentAction(options: { - integrations: ScmIntegrationRegistry; -}): TemplateAction_2< - { - repoUrl: string; - name: string; - deploymentBranchPolicy?: - | { - protected_branches: boolean; - custom_branch_policies: boolean; - } - | undefined; - customBranchPolicyNames?: string[] | undefined; - environmentVariables?: - | { - [key: string]: string; - } - | undefined; - secrets?: - | { - [key: string]: string; - } - | undefined; - token?: string | undefined; - }, - JsonObject ->; +// @public @deprecated (undocumented) +export const createGithubEnvironmentAction: typeof github.createGithubEnvironmentAction; -// @public -export function createGithubIssuesLabelAction(options: { - integrations: ScmIntegrationRegistry; - githubCredentialsProvider?: GithubCredentialsProvider; -}): TemplateAction_2< - { - repoUrl: string; - number: number; - labels: string[]; - token?: string | undefined; - }, - JsonObject ->; +// @public @deprecated (undocumented) +export const createGithubIssuesLabelAction: typeof github.createGithubIssuesLabelAction; -// @public -export interface CreateGithubPullRequestActionOptions { - clientFactory?: ( - input: CreateGithubPullRequestClientFactoryInput, - ) => Promise; - githubCredentialsProvider?: GithubCredentialsProvider; - integrations: ScmIntegrationRegistry; -} +// @public @deprecated (undocumented) +export type CreateGithubPullRequestActionOptions = + github.CreateGithubPullRequestActionOptions; -// @public -export type CreateGithubPullRequestClientFactoryInput = { - integrations: ScmIntegrationRegistry; - githubCredentialsProvider?: GithubCredentialsProvider; - host: string; - owner: string; - repo: string; - token?: string; -}; +// @public @deprecated (undocumented) +export const createGithubRepoCreateAction: typeof github.createGithubRepoCreateAction; -// @public -export function createGithubRepoCreateAction(options: { - integrations: ScmIntegrationRegistry; - githubCredentialsProvider?: GithubCredentialsProvider; -}): TemplateAction_2< - { - repoUrl: string; - description?: string | undefined; - homepage?: string | undefined; - access?: string | undefined; - deleteBranchOnMerge?: boolean | undefined; - gitAuthorName?: string | undefined; - gitAuthorEmail?: string | undefined; - allowRebaseMerge?: boolean | undefined; - allowSquashMerge?: boolean | undefined; - squashMergeCommitTitle?: 'PR_TITLE' | 'COMMIT_OR_PR_TITLE' | undefined; - squashMergeCommitMessage?: - | 'PR_BODY' - | 'COMMIT_MESSAGES' - | 'BLANK' - | undefined; - allowMergeCommit?: boolean | undefined; - allowAutoMerge?: boolean | undefined; - requireCodeOwnerReviews?: boolean | undefined; - bypassPullRequestAllowances?: - | { - users?: string[] | undefined; - teams?: string[] | undefined; - apps?: string[] | undefined; - } - | undefined; - requiredApprovingReviewCount?: number | undefined; - restrictions?: - | { - users: string[]; - teams: string[]; - apps?: string[] | undefined; - } - | undefined; - requiredStatusCheckContexts?: string[] | undefined; - requireBranchesToBeUpToDate?: boolean | undefined; - requiredConversationResolution?: boolean | undefined; - repoVisibility?: 'internal' | 'private' | 'public' | undefined; - collaborators?: - | ( - | { - user: string; - access: string; - } - | { - team: string; - access: string; - } - | { - username: string; - access: 'pull' | 'push' | 'admin' | 'maintain' | 'triage'; - } - )[] - | undefined; - hasProjects?: boolean | undefined; - hasWiki?: boolean | undefined; - hasIssues?: boolean | undefined; - token?: string | undefined; - topics?: string[] | undefined; - repoVariables?: - | { - [key: string]: string; - } - | undefined; - secrets?: - | { - [key: string]: string; - } - | undefined; - requireCommitSigning?: boolean | undefined; - }, - JsonObject ->; +// @public @deprecated (undocumented) +export const createGithubRepoPushAction: typeof github.createGithubRepoPushAction; -// @public -export function createGithubRepoPushAction(options: { - integrations: ScmIntegrationRegistry; - config: Config; - githubCredentialsProvider?: GithubCredentialsProvider; -}): TemplateAction_2< - { - repoUrl: string; - description?: string | undefined; - defaultBranch?: string | undefined; - protectDefaultBranch?: boolean | undefined; - protectEnforceAdmins?: boolean | undefined; - gitCommitMessage?: string | undefined; - gitAuthorName?: string | undefined; - gitAuthorEmail?: string | undefined; - requireCodeOwnerReviews?: boolean | undefined; - dismissStaleReviews?: boolean | undefined; - bypassPullRequestAllowances?: - | { - users?: string[]; - teams?: string[]; - apps?: string[]; - } - | undefined; - requiredApprovingReviewCount?: number | undefined; - restrictions?: - | { - users: string[]; - teams: string[]; - apps?: string[]; - } - | undefined; - requiredStatusCheckContexts?: string[] | undefined; - requireBranchesToBeUpToDate?: boolean | undefined; - requiredConversationResolution?: boolean | undefined; - sourcePath?: string | undefined; - token?: string | undefined; - requiredCommitSigning?: boolean | undefined; - }, - JsonObject ->; +// @public @deprecated (undocumented) +export const createGithubWebhookAction: typeof github.createGithubWebhookAction; -// @public -export function createGithubWebhookAction(options: { - integrations: ScmIntegrationRegistry; - defaultWebhookSecret?: string; - githubCredentialsProvider?: GithubCredentialsProvider; -}): TemplateAction_2< - { - repoUrl: string; - webhookUrl: string; - webhookSecret?: string | undefined; - events?: string[] | undefined; - active?: boolean | undefined; - contentType?: 'form' | 'json' | undefined; - insecureSsl?: boolean | undefined; - token?: string | undefined; - }, - JsonObject ->; +// @public @deprecated (undocumented) +export const createPublishAzureAction: typeof azure.createPublishAzureAction; -// @public -export function createPublishAzureAction(options: { - integrations: ScmIntegrationRegistry; - config: Config; -}): TemplateAction_2< - { - repoUrl: string; - description?: string | undefined; - defaultBranch?: string | undefined; - sourcePath?: string | undefined; - token?: string | undefined; - gitCommitMessage?: string | undefined; - gitAuthorName?: string | undefined; - gitAuthorEmail?: string | undefined; - }, - JsonObject ->; +// @public @deprecated (undocumented) +export const createPublishBitbucketAction: typeof bitbucket.createPublishBitbucketAction; -// @public @deprecated -export function createPublishBitbucketAction(options: { - integrations: ScmIntegrationRegistry; - config: Config; -}): TemplateAction_2< - { - repoUrl: string; - description?: string | undefined; - defaultBranch?: string | undefined; - repoVisibility?: 'private' | 'public' | undefined; - sourcePath?: string | undefined; - enableLFS?: boolean | undefined; - token?: string | undefined; - gitCommitMessage?: string | undefined; - gitAuthorName?: string | undefined; - gitAuthorEmail?: string | undefined; - }, - JsonObject ->; +// @public @deprecated (undocumented) +export const createPublishBitbucketCloudAction: typeof bitbucket.createPublishBitbucketCloudAction; -// @public -export function createPublishBitbucketCloudAction(options: { - integrations: ScmIntegrationRegistry; - config: Config; -}): TemplateAction_2< - { - repoUrl: string; - description?: string | undefined; - defaultBranch?: string | undefined; - repoVisibility?: 'private' | 'public' | undefined; - sourcePath?: string | undefined; - token?: string | undefined; - }, - JsonObject ->; +// @public @deprecated (undocumented) +export const createPublishBitbucketServerAction: typeof bitbucket.createPublishBitbucketServerAction; -// @public -export function createPublishBitbucketServerAction(options: { - integrations: ScmIntegrationRegistry; - config: Config; -}): TemplateAction_2< - { - repoUrl: string; - description?: string | undefined; - defaultBranch?: string | undefined; - repoVisibility?: 'private' | 'public' | undefined; - sourcePath?: string | undefined; - enableLFS?: boolean | undefined; - token?: string | undefined; - gitCommitMessage?: string | undefined; - gitAuthorName?: string | undefined; - gitAuthorEmail?: string | undefined; - }, - JsonObject ->; +// @public @deprecated (undocumented) +export const createPublishBitbucketServerPullRequestAction: typeof bitbucket.createPublishBitbucketServerPullRequestAction; -// @public -export function createPublishBitbucketServerPullRequestAction(options: { - integrations: ScmIntegrationRegistry; - config: Config; -}): TemplateAction_2< - { - repoUrl: string; - title: string; - description?: string | undefined; - targetBranch?: string | undefined; - sourceBranch: string; - token?: string | undefined; - }, - JsonObject ->; +// @public @deprecated (undocumented) +export const createPublishGerritAction: typeof gerrit.createPublishGerritAction; -// @public -export function createPublishGerritAction(options: { - integrations: ScmIntegrationRegistry; - config: Config; -}): TemplateAction_2< - { - repoUrl: string; - description: string; - defaultBranch?: string | undefined; - gitCommitMessage?: string | undefined; - gitAuthorName?: string | undefined; - gitAuthorEmail?: string | undefined; - sourcePath?: string | undefined; - }, - JsonObject ->; +// @public @deprecated (undocumented) +export const createPublishGerritReviewAction: typeof gerrit.createPublishGerritReviewAction; -// @public -export function createPublishGerritReviewAction(options: { - integrations: ScmIntegrationRegistry; - config: Config; -}): TemplateAction_2< - { - repoUrl: string; - branch?: string | undefined; - sourcePath?: string | undefined; - gitCommitMessage?: string | undefined; - gitAuthorName?: string | undefined; - gitAuthorEmail?: string | undefined; - }, - JsonObject ->; +// @public @deprecated (undocumented) +export const createPublishGithubAction: typeof github.createPublishGithubAction; -// @public -export function createPublishGithubAction(options: { - integrations: ScmIntegrationRegistry; - config: Config; - githubCredentialsProvider?: GithubCredentialsProvider; -}): TemplateAction_2< - { - repoUrl: string; - description?: string | undefined; - homepage?: string | undefined; - access?: string | undefined; - defaultBranch?: string | undefined; - protectDefaultBranch?: boolean | undefined; - protectEnforceAdmins?: boolean | undefined; - deleteBranchOnMerge?: boolean | undefined; - gitCommitMessage?: string | undefined; - gitAuthorName?: string | undefined; - gitAuthorEmail?: string | undefined; - allowRebaseMerge?: boolean | undefined; - allowSquashMerge?: boolean | undefined; - squashMergeCommitTitle?: 'PR_TITLE' | 'COMMIT_OR_PR_TITLE' | undefined; - squashMergeCommitMessage?: - | 'PR_BODY' - | 'COMMIT_MESSAGES' - | 'BLANK' - | undefined; - allowMergeCommit?: boolean | undefined; - allowAutoMerge?: boolean | undefined; - sourcePath?: string | undefined; - bypassPullRequestAllowances?: - | { - users?: string[]; - teams?: string[]; - apps?: string[]; - } - | undefined; - requiredApprovingReviewCount?: number | undefined; - restrictions?: - | { - users: string[]; - teams: string[]; - apps?: string[]; - } - | undefined; - requireCodeOwnerReviews?: boolean | undefined; - dismissStaleReviews?: boolean | undefined; - requiredStatusCheckContexts?: string[] | undefined; - requireBranchesToBeUpToDate?: boolean | undefined; - requiredConversationResolution?: boolean | undefined; - repoVisibility?: 'internal' | 'private' | 'public' | undefined; - collaborators?: - | ( - | { - user: string; - access: string; - } - | { - team: string; - access: string; - } - | { - username: string; - access: 'pull' | 'push' | 'admin' | 'maintain' | 'triage'; - } - )[] - | undefined; - hasProjects?: boolean | undefined; - hasWiki?: boolean | undefined; - hasIssues?: boolean | undefined; - token?: string | undefined; - topics?: string[] | undefined; - repoVariables?: - | { - [key: string]: string; - } - | undefined; - secrets?: - | { - [key: string]: string; - } - | undefined; - requiredCommitSigning?: boolean | undefined; - }, - JsonObject ->; - -// @public +// @public @deprecated (undocumented) export const createPublishGithubPullRequestAction: ( - options: CreateGithubPullRequestActionOptions, + options: github.CreateGithubPullRequestActionOptions, ) => TemplateAction_2< { title: string; @@ -664,57 +270,10 @@ export const createPublishGithubPullRequestAction: ( JsonObject >; -// @public -export function createPublishGitlabAction(options: { - integrations: ScmIntegrationRegistry; - config: Config; -}): TemplateAction_2< - { - repoUrl: string; - defaultBranch?: string | undefined; - repoVisibility?: 'internal' | 'private' | 'public' | undefined; - sourcePath?: string | undefined; - token?: string | undefined; - gitCommitMessage?: string | undefined; - gitAuthorName?: string | undefined; - gitAuthorEmail?: string | undefined; - setUserAsOwner?: boolean | undefined; - topics?: string[] | undefined; - settings?: - | { - path?: string | undefined; - auto_devops_enabled?: boolean | undefined; - ci_config_path?: string | undefined; - description?: string | undefined; - topics?: string[] | undefined; - visibility?: 'internal' | 'private' | 'public' | undefined; - } - | undefined; - branches?: - | { - name: string; - protect?: boolean | undefined; - create?: boolean | undefined; - ref?: string | undefined; - }[] - | undefined; - projectVariables?: - | { - key: string; - value: string; - description?: string | undefined; - variable_type?: string | undefined; - protected?: boolean | undefined; - masked?: boolean | undefined; - raw?: boolean | undefined; - environment_scope?: string | undefined; - }[] - | undefined; - }, - JsonObject ->; +// @public @deprecated (undocumented) +export const createPublishGitlabAction: typeof gitlab.createPublishGitlabAction; -// @public +// @public @deprecated (undocumented) export const createPublishGitlabMergeRequestAction: (options: { integrations: ScmIntegrationRegistry; }) => TemplateAction_2< @@ -858,19 +417,6 @@ export const executeShellCommand: typeof executeShellCommand_2; // @public @deprecated export const fetchContents: typeof fetchContents_2; -// @public (undocumented) -export type OctokitWithPullRequestPluginClient = Octokit & { - createPullRequest(options: createPullRequest.Options): Promise<{ - data: { - html_url: string; - number: number; - base: { - ref: string; - }; - }; - } | null>; -}; - // @public export interface RouterOptions { // (undocumented) diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index df1298f93e..24325449b3 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-backend", "description": "The Backstage backend plugin that helps you create new things", - "version": "1.19.0-next.2", + "version": "1.20.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -55,42 +55,31 @@ "@backstage/errors": "workspace:^", "@backstage/integration": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", - "@backstage/plugin-catalog-backend": "workspace:^", "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "workspace:^", - "@backstage/plugin-catalog-common": "workspace:^", "@backstage/plugin-catalog-node": "workspace:^", "@backstage/plugin-permission-common": "workspace:^", "@backstage/plugin-permission-node": "workspace:^", + "@backstage/plugin-scaffolder-backend-module-azure": "workspace:^", + "@backstage/plugin-scaffolder-backend-module-bitbucket": "workspace:^", + "@backstage/plugin-scaffolder-backend-module-gerrit": "workspace:^", + "@backstage/plugin-scaffolder-backend-module-github": "workspace:^", + "@backstage/plugin-scaffolder-backend-module-gitlab": "workspace:^", "@backstage/plugin-scaffolder-common": "workspace:^", "@backstage/plugin-scaffolder-node": "workspace:^", "@backstage/types": "workspace:^", - "@gitbeaker/core": "^35.6.0", - "@gitbeaker/node": "^35.1.0", - "@octokit/webhooks": "^10.0.0", "@types/express": "^4.17.6", "@types/luxon": "^3.0.0", - "azure-devops-node-api": "^11.0.1", - "command-exists": "^1.2.9", - "compression": "^1.7.4", - "cors": "^2.8.5", "express": "^4.17.1", "express-promise-router": "^4.1.0", "fs-extra": "10.1.0", - "git-url-parse": "^13.0.0", "globby": "^11.0.0", "isbinaryfile": "^5.0.0", "isolated-vm": "^4.5.0", - "isomorphic-git": "^1.23.0", "jsonschema": "^1.2.6", "knex": "^3.0.0", - "libsodium-wrappers": "^0.7.11", "lodash": "^4.17.21", "luxon": "^3.0.0", - "morgan": "^1.10.0", - "node-fetch": "^2.6.7", "nunjucks": "^3.2.3", - "octokit": "^2.0.0", - "octokit-plugin-create-pull-request": "^3.10.0", "p-limit": "^3.1.0", "p-queue": "^6.6.2", "prom-client": "^14.0.1", @@ -98,25 +87,19 @@ "winston": "^3.2.1", "yaml": "^2.0.0", "zen-observable": "^0.10.0", - "zod": "^3.21.4" + "zod": "^3.22.4" }, "devDependencies": { "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", - "@types/command-exists": "^1.2.0", "@types/fs-extra": "^9.0.1", - "@types/git-url-parse": "^9.0.0", - "@types/libsodium-wrappers": "^0.7.10", "@types/nunjucks": "^3.1.4", "@types/supertest": "^2.0.8", "@types/zen-observable": "^0.8.0", "esbuild": "^0.19.0", - "jest-when": "^3.1.0", - "msw": "^1.0.0", "strip-ansi": "^7.1.0", "supertest": "^6.1.3", - "wait-for-expect": "^3.0.2", - "yaml": "^2.0.0" + "wait-for-expect": "^3.0.2" }, "files": [ "dist", diff --git a/plugins/scaffolder-backend/src/lib/templating/filters.ts b/plugins/scaffolder-backend/src/lib/templating/filters.ts index 7808d6d136..21b43a6164 100644 --- a/plugins/scaffolder-backend/src/lib/templating/filters.ts +++ b/plugins/scaffolder-backend/src/lib/templating/filters.ts @@ -17,7 +17,7 @@ import { parseEntityRef } from '@backstage/catalog-model'; import { ScmIntegrations } from '@backstage/integration'; import type { JsonObject, JsonValue } from '@backstage/types'; import { TemplateFilter } from '..'; -import { parseRepoUrl } from '../../scaffolder/actions/builtin/publish/util'; +import { parseRepoUrl } from '@backstage/plugin-scaffolder-node'; import get from 'lodash/get'; export const createDefaultFilters = ({ diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts index 4dcd2c2a0d..02b96e9fa7 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts @@ -42,26 +42,37 @@ import { } from './filesystem'; import { createGithubActionsDispatchAction, + createGithubAutolinksAction, createGithubDeployKeyAction, createGithubEnvironmentAction, createGithubIssuesLabelAction, createGithubRepoCreateAction, createGithubRepoPushAction, createGithubWebhookAction, -} from './github'; + createPublishGithubAction, + createPublishGithubPullRequestAction, +} from '@backstage/plugin-scaffolder-backend-module-github'; + +import { createPublishAzureAction } from '@backstage/plugin-scaffolder-backend-module-azure'; + import { - createPublishAzureAction, createPublishBitbucketAction, createPublishBitbucketCloudAction, createPublishBitbucketServerAction, createPublishBitbucketServerPullRequestAction, + createBitbucketPipelinesRunAction, +} from '@backstage/plugin-scaffolder-backend-module-bitbucket'; + +import { createPublishGerritAction, createPublishGerritReviewAction, - createPublishGithubAction, - createPublishGithubPullRequestAction, +} from '@backstage/plugin-scaffolder-backend-module-gerrit'; + +import { createPublishGitlabAction, + createGitlabRepoPushAction, createPublishGitlabMergeRequestAction, -} from './publish'; +} from '@backstage/plugin-scaffolder-backend-module-gitlab'; /** * The options passed to {@link createBuiltinActions} @@ -96,8 +107,11 @@ export interface CreateBuiltInActionsOptions { * A function to generate create a list of default actions that the scaffolder provides. * Is called internally in the default setup, but can be used when adding your own actions or overriding the default ones * + * TODO(blam): version 2 of the scaffolder shouldn't ship with the additional modules. We should ship the basics, and let people install + * modules for the providers they want to use. * @public * @returns A list of actions that can be used in the scaffolder + * */ export const createBuiltinActions = ( options: CreateBuiltInActionsOptions, @@ -153,6 +167,9 @@ export const createBuiltinActions = ( createPublishGitlabMergeRequestAction({ integrations, }), + createGitlabRepoPushAction({ + integrations, + }), createPublishBitbucketAction({ integrations, config, @@ -207,6 +224,13 @@ export const createBuiltinActions = ( createGithubDeployKeyAction({ integrations, }), + createGithubAutolinksAction({ + integrations, + githubCredentialsProvider, + }), + createBitbucketPipelinesRunAction({ + integrations, + }), ]; return actions as TemplateAction[]; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/index.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/index.ts index 7ab98482ff..6fdbb24484 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/index.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/index.ts @@ -19,5 +19,3 @@ export * from './createBuiltinActions'; export * from './debug'; export * from './fetch'; export * from './filesystem'; -export * from './publish'; -export * from './github'; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/index.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/index.ts deleted file mode 100644 index bed3a2316c..0000000000 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/index.ts +++ /dev/null @@ -1,32 +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. - */ - -export { createPublishAzureAction } from './azure'; -export { createPublishBitbucketAction } from './bitbucket'; -export { createPublishBitbucketCloudAction } from './bitbucketCloud'; -export { createPublishBitbucketServerAction } from './bitbucketServer'; -export { createPublishBitbucketServerPullRequestAction } from './bitbucketServerPullRequest'; -export { createPublishGerritAction } from './gerrit'; -export { createPublishGerritReviewAction } from './gerritReview'; -export { createPublishGithubAction } from './github'; -export { createPublishGithubPullRequestAction } from './githubPullRequest'; -export type { - CreateGithubPullRequestClientFactoryInput, - CreateGithubPullRequestActionOptions, - OctokitWithPullRequestPluginClient, -} from './githubPullRequest'; -export { createPublishGitlabAction } from './gitlab'; -export { createPublishGitlabMergeRequestAction } from './gitlabMergeRequest'; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/util.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/util.test.ts deleted file mode 100644 index 5446109056..0000000000 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/util.test.ts +++ /dev/null @@ -1,181 +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 path from 'path'; -import { getRepoSourceDirectory, isExecutable, parseRepoUrl } from './util'; -import { ScmIntegrations } from '@backstage/integration'; -import { ConfigReader } from '@backstage/config'; - -describe('getRepoSourceDirectory', () => { - it('should return workspace root if no sub folder is given', () => { - expect( - getRepoSourceDirectory(path.join('/', 'var', 'workspace'), undefined), - ).toEqual(path.join('/', 'var', 'workspace')); - }); - - it('should return path in workspace if sub folder is given', () => { - expect( - getRepoSourceDirectory( - path.join('/', 'var', 'workspace'), - path.join('path', 'of', 'subfolder'), - ), - ).toEqual(path.join('/', 'var', 'workspace', 'path', 'of', 'subfolder')); - }); - - it('should not allow traversal outside the workspace root', () => { - // We have to construct the path manually here, as path.join would mitigate the path traversal - expect( - getRepoSourceDirectory( - path.join('/', 'var', 'workspace'), - `..${path.sep}secret`, - ), - ).toEqual(path.join('/', 'var', 'workspace', 'secret')); - expect( - getRepoSourceDirectory( - path.join('/', 'var', 'workspace'), - `.${path.sep}path${path.sep}..${path.sep}..${path.sep}secret`, - ), - ).toEqual(path.join('/', 'var', 'workspace', 'secret')); - expect( - getRepoSourceDirectory( - path.join('/', 'var', 'workspace'), - path.join('/', 'absolute', 'secret'), - ), - ).toEqual(path.join('/', 'var', 'workspace', 'absolute', 'secret')); - }); -}); - -describe('isExecutable', () => { - it('should return true for file mode 777', () => { - expect(isExecutable(0o100777)).toBe(true); - }); - it('should return true for file mode 775', () => { - expect(isExecutable(0o100775)).toBe(true); - }); - it('should return true for file mode 755', () => { - expect(isExecutable(0o100755)).toBe(true); - }); - it('should return true for file mode 700', () => { - expect(isExecutable(0o100700)).toBe(true); - }); - it('should return true for file mode 770', () => { - expect(isExecutable(0o100770)).toBe(true); - }); - it('should return true for file mode 670', () => { - expect(isExecutable(0o100670)).toBe(true); - }); - it('should return false for file mode 644', () => { - expect(isExecutable(0o100644)).toBe(false); - }); - it('should return false for file mode 600', () => { - expect(isExecutable(0o100600)).toBe(false); - }); - it('should return false for file mode 640', () => { - expect(isExecutable(0o100640)).toBe(false); - }); -}); - -describe('parseRepoUrl', () => { - const config = new ConfigReader({ - integrations: { - gitlab: [ - { - host: 'www.gitlab.com', - token: 'token', - apiBaseUrl: 'https://api.gitlab.com', - }, - ], - bitbucket: [ - { - host: 'www.bitbucket.net', - apiBaseUrl: 'https://api.hosted.bitbucket.net', - }, - { - host: 'www.bitbucket.org', - username: 'username', - appPassword: 'password', - apiBaseUrl: 'https://api.hosted.bitbucket.org', - }, - ], - }, - }); - const integrations = ScmIntegrations.fromConfig(config); - it('should throw an exception if no parameters are passed (gitlab)', () => { - expect(() => parseRepoUrl('www.gitlab.com', integrations)).toThrow( - 'Invalid repo URL passed to publisher: https://www.gitlab.com/, missing owner', - ); - }); - it('should return the project ID in the `project` parameter (gitlab)', () => { - expect( - parseRepoUrl('www.gitlab.com?project=234', integrations), - ).toStrictEqual({ - host: 'www.gitlab.com', - organization: undefined, - owner: undefined, - project: '234', - repo: null, - workspace: undefined, - }); - }); - it('should throw an exception if the repo parameter is missing, but owner parameter is set', () => { - expect(() => - parseRepoUrl('www.gitlab.com?owner=owner', integrations), - ).toThrow( - 'Invalid repo URL passed to publisher: https://www.gitlab.com/?owner=owner, missing repo', - ); - }); - it('should throw an exception if the owner parameter is missing, but repo parameter is set (gitlab)', () => { - expect(() => - parseRepoUrl('www.gitlab.com?repo=repo', integrations), - ).toThrow( - 'Invalid repo URL passed to publisher: https://www.gitlab.com/?repo=repo, missing owner', - ); - }); - it('should return the workspace, project and repo (bitbucket.org)', () => { - expect( - parseRepoUrl( - 'www.bitbucket.org?project=project&workspace=workspace&repo=repo', - integrations, - ), - ).toStrictEqual({ - host: 'www.bitbucket.org', - organization: undefined, - owner: undefined, - project: 'project', - repo: 'repo', - workspace: 'workspace', - }); - }); - it('should return the project and repo (another bitbucket instance)', () => { - expect( - parseRepoUrl('www.bitbucket.net?project=project&repo=repo', integrations), - ).toStrictEqual({ - host: 'www.bitbucket.net', - organization: undefined, - owner: undefined, - project: 'project', - repo: 'repo', - workspace: undefined, - }); - }); - it('should throw an exception if the workspace parameter is missing for bitbucket.org instance (bitbucket.org)', () => { - expect(() => - parseRepoUrl('www.bitbucket.org?project=project&repo=repo', integrations), - ).toThrow( - 'Invalid repo URL passed to publisher: https://www.bitbucket.org/?project=project&repo=repo, missing workspace', - ); - }); -}); diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/deprecated.ts b/plugins/scaffolder-backend/src/scaffolder/actions/deprecated.ts new file mode 100644 index 0000000000..d5a13fbf6d --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/actions/deprecated.ts @@ -0,0 +1,126 @@ +/* + * 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 * as github from '@backstage/plugin-scaffolder-backend-module-github'; +import * as gitlab from '@backstage/plugin-scaffolder-backend-module-gitlab'; +import * as azure from '@backstage/plugin-scaffolder-backend-module-azure'; +import * as bitbucket from '@backstage/plugin-scaffolder-backend-module-bitbucket'; +import * as gerrit from '@backstage/plugin-scaffolder-backend-module-gerrit'; + +/** + * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-github instead + */ +export const createGithubActionsDispatchAction = + github.createGithubActionsDispatchAction; + +/** + * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-github instead + */ +export const createGithubDeployKeyAction = github.createGithubDeployKeyAction; + +/** + * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-github instead + */ +export const createGithubEnvironmentAction = + github.createGithubEnvironmentAction; + +/** + * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-github instead + */ +export const createGithubIssuesLabelAction = + github.createGithubIssuesLabelAction; + +/** + * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-github instead + */ +export type CreateGithubPullRequestActionOptions = + github.CreateGithubPullRequestActionOptions; + +/** + * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-github instead + */ +export const createGithubRepoCreateAction = github.createGithubRepoCreateAction; + +/** + * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-github instead + */ +export const createGithubRepoPushAction = github.createGithubRepoPushAction; + +/** + * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-github instead + */ +export const createGithubWebhookAction = github.createGithubWebhookAction; + +/** + * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-github instead + */ +export const createPublishGithubAction = github.createPublishGithubAction; + +/** + * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-github instead + */ +export const createPublishGithubPullRequestAction = + github.createPublishGithubPullRequestAction; + +/** + * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-bitbucket instead + */ +export const createPublishBitbucketAction = + bitbucket.createPublishBitbucketAction; + +/** + * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-bitbucket instead + */ +export const createPublishBitbucketCloudAction = + bitbucket.createPublishBitbucketCloudAction; + +/** + * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-bitbucket instead + */ +export const createPublishBitbucketServerAction = + bitbucket.createPublishBitbucketServerAction; + +/** + * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-bitbucket instead + */ +export const createPublishBitbucketServerPullRequestAction = + bitbucket.createPublishBitbucketServerPullRequestAction; + +/** + * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-azure instead + */ +export const createPublishAzureAction = azure.createPublishAzureAction; + +/** + * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-gerrit instead + */ +export const createPublishGerritAction = gerrit.createPublishGerritAction; + +/** + * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-gerrit instead + */ +export const createPublishGerritReviewAction = + gerrit.createPublishGerritReviewAction; + +/** + * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-gitlab instead + */ +export const createPublishGitlabAction = gitlab.createPublishGitlabAction; + +/** + * @public @deprecated use import from \@backstage/plugin-scaffolder-backend-module-gitlab instead + */ +export const createPublishGitlabMergeRequestAction = + gitlab.createPublishGitlabMergeRequestAction; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/index.ts b/plugins/scaffolder-backend/src/scaffolder/actions/index.ts index 9ea0607f06..8fdad68499 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/index.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/index.ts @@ -15,4 +15,6 @@ */ export * from './builtin'; +export * from './deprecated'; + export { TemplateActionRegistry } from './TemplateActionRegistry'; diff --git a/plugins/scaffolder-backend/src/scaffolder/dryrun/createDryRunner.ts b/plugins/scaffolder-backend/src/scaffolder/dryrun/createDryRunner.ts index 655c485a6d..e202111d79 100644 --- a/plugins/scaffolder-backend/src/scaffolder/dryrun/createDryRunner.ts +++ b/plugins/scaffolder-backend/src/scaffolder/dryrun/createDryRunner.ts @@ -21,20 +21,19 @@ import { v4 as uuid } from 'uuid'; import { pathToFileURL } from 'url'; import { Logger } from 'winston'; import { + createTemplateAction, + TaskSecrets, + TemplateFilter, + TemplateGlobal, deserializeDirectoryContents, SerializedFile, serializeDirectoryContents, -} from '../../lib/files'; -import { TemplateFilter, TemplateGlobal } from '../../lib'; +} from '@backstage/plugin-scaffolder-node'; import { TemplateActionRegistry } from '../actions'; import { NunjucksWorkflowRunner } from '../tasks/NunjucksWorkflowRunner'; import { DecoratedActionsRegistry } from './DecoratedActionsRegistry'; import fs from 'fs-extra'; import { resolveSafeChildPath } from '@backstage/backend-common'; -import { - createTemplateAction, - TaskSecrets, -} from '@backstage/plugin-scaffolder-node'; import { PermissionEvaluator } from '@backstage/plugin-permission-common'; interface DryRunInput { diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts index 58ea689260..139d91b7a2 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts @@ -290,14 +290,15 @@ export class NunjucksWorkflowRunner implements WorkflowRunner { input: step.input ? this.render( step.input, - { ...context, ...i, ...task }, + { ...context, secrets: task.secrets ?? {}, ...i }, renderTemplate, ) : {}, })); for (const iteration of iterations) { - const actionId = - action.id + (iteration.each ? `[${iteration.each.key}]` : ''); + const actionId = `${action.id}${ + iteration.each ? `[${iteration.each.key}]` : '' + }`; if (action.schema?.input) { const validateResult = validateJsonSchema( diff --git a/plugins/scaffolder-backend/src/service/rules.test.ts b/plugins/scaffolder-backend/src/service/rules.test.ts index e6032dde15..8e24cacb32 100644 --- a/plugins/scaffolder-backend/src/service/rules.test.ts +++ b/plugins/scaffolder-backend/src/service/rules.test.ts @@ -23,6 +23,9 @@ import { hasStringProperty, hasTag, } from './rules'; +import { createConditionAuthorizer } from '@backstage/plugin-permission-node'; +import { RESOURCE_TYPE_SCAFFOLDER_ACTION } from '@backstage/plugin-scaffolder-common/alpha'; +import { AuthorizeResult } from '@backstage/plugin-permission-common'; describe('hasTag', () => { describe('apply', () => { @@ -206,6 +209,84 @@ describe('hasProperty', () => { ).toEqual(true); }, ); + + it('should throw if params are invalid', () => { + const isActionAuthorized = createConditionAuthorizer([hasProperty]); + + expect(() => + isActionAuthorized( + { + resourceType: RESOURCE_TYPE_SCAFFOLDER_ACTION, + pluginId: 'scaffolder', + result: AuthorizeResult.CONDITIONAL, + conditions: { + resourceType: RESOURCE_TYPE_SCAFFOLDER_ACTION, + rule: 'HAS_PROPERTY', + params: { + key: 1, + }, + }, + }, + { action: 'an-action', input: {} }, + ), + ).toThrow(); + expect(() => + isActionAuthorized( + { + resourceType: RESOURCE_TYPE_SCAFFOLDER_ACTION, + pluginId: 'scaffolder', + result: AuthorizeResult.CONDITIONAL, + conditions: { + resourceType: RESOURCE_TYPE_SCAFFOLDER_ACTION, + rule: 'HAS_PROPERTY', + params: {}, + }, + }, + { action: 'an-action', input: {} }, + ), + ).toThrow(); + }); + + it('should not throw if params are valid', () => { + const isActionAuthorized = createConditionAuthorizer([hasProperty]); + + expect(() => + isActionAuthorized( + { + resourceType: RESOURCE_TYPE_SCAFFOLDER_ACTION, + pluginId: 'scaffolder', + result: AuthorizeResult.CONDITIONAL, + conditions: { + resourceType: RESOURCE_TYPE_SCAFFOLDER_ACTION, + rule: 'HAS_PROPERTY', + params: { + key: 'key', + }, + }, + }, + { action: 'an-action', input: {} }, + ), + ).not.toThrow(); + + expect(() => + isActionAuthorized( + { + resourceType: RESOURCE_TYPE_SCAFFOLDER_ACTION, + pluginId: 'scaffolder', + result: AuthorizeResult.CONDITIONAL, + conditions: { + resourceType: RESOURCE_TYPE_SCAFFOLDER_ACTION, + rule: 'HAS_PROPERTY', + params: { + key: 'key', + value: 'value', + }, + }, + }, + { action: 'an-action', input: {} }, + ), + ).not.toThrow(); + }); }); }); diff --git a/plugins/scaffolder-backend/src/service/rules.ts b/plugins/scaffolder-backend/src/service/rules.ts index 19b34b9f7c..b197810757 100644 --- a/plugins/scaffolder-backend/src/service/rules.ts +++ b/plugins/scaffolder-backend/src/service/rules.ts @@ -106,7 +106,9 @@ function buildHasProperty>({ key: z .string() .describe(`Property within the action parameters to match on`), - value: valueSchema.describe(`Value of the given property to match on`), + value: valueSchema + .optional() + .describe(`Value of the given property to match on`), }) as unknown as z.ZodType<{ key: string; value?: z.infer }>, apply: (resource, { key, value }) => { const foundValue = get(resource.input, key); diff --git a/plugins/scaffolder-backend/src/setupTests.ts b/plugins/scaffolder-backend/src/setupTests.ts new file mode 100644 index 0000000000..a494d80f22 --- /dev/null +++ b/plugins/scaffolder-backend/src/setupTests.ts @@ -0,0 +1,19 @@ +/* + * 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 { Settings } from 'luxon'; + +Settings.defaultLocale = 'en'; diff --git a/plugins/scaffolder-common/CHANGELOG.md b/plugins/scaffolder-common/CHANGELOG.md index f040d3c03e..dfc6b310ed 100644 --- a/plugins/scaffolder-common/CHANGELOG.md +++ b/plugins/scaffolder-common/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-scaffolder-common +## 1.4.5 + +### Patch Changes + +- 178b8d8: Updated Template.v1beta3.schema.json, added a missing "presentation" field +- Updated dependencies + - @backstage/plugin-permission-common@0.7.12 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + +## 1.4.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.11 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + +## 1.4.3 + +### Patch Changes + +- 2e0cef42ab: Add missing required property `type` in `Template.v1beta3.schema.json` schema +- 76d07da66a: Make it possible to define control buttons text (Back, Create, Review) per template +- Updated dependencies + - @backstage/plugin-permission-common@0.7.10 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + ## 1.4.3-next.1 ### Patch Changes diff --git a/plugins/scaffolder-common/alpha-api-report.md b/plugins/scaffolder-common/api-report-alpha.md similarity index 100% rename from plugins/scaffolder-common/alpha-api-report.md rename to plugins/scaffolder-common/api-report-alpha.md diff --git a/plugins/scaffolder-common/package.json b/plugins/scaffolder-common/package.json index 7d69e8a91e..699867fbb1 100644 --- a/plugins/scaffolder-common/package.json +++ b/plugins/scaffolder-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-common", "description": "Common functionalities for the scaffolder, to be shared between scaffolder and scaffolder-backend plugin", - "version": "1.4.3-next.1", + "version": "1.4.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-common/src/Template.v1beta3.schema.json b/plugins/scaffolder-common/src/Template.v1beta3.schema.json index d4be9b7538..d7698511d8 100644 --- a/plugins/scaffolder-common/src/Template.v1beta3.schema.json +++ b/plugins/scaffolder-common/src/Template.v1beta3.schema.json @@ -139,6 +139,24 @@ } ] }, + "presentation": { + "type": "object", + "description": "A way to redefine the labels for actionable buttons.", + "properties": { + "backButtonText": { + "type": "string", + "description": "A button which return the user to one step back." + }, + "createButtonText": { + "type": "string", + "description": "A button which start the execution of the template." + }, + "reviewButtonText": { + "type": "string", + "description": "A button which open the review step to verify the input prior to start the execution." + } + } + }, "steps": { "type": "array", "description": "A list of steps to execute.", diff --git a/plugins/scaffolder-node/CHANGELOG.md b/plugins/scaffolder-node/CHANGELOG.md index 9ea5d7c3a5..49ea604b11 100644 --- a/plugins/scaffolder-node/CHANGELOG.md +++ b/plugins/scaffolder-node/CHANGELOG.md @@ -1,5 +1,134 @@ # @backstage/plugin-scaffolder-node +## 0.2.10 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-common@1.4.5 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + +## 0.2.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9-next.2 + - @backstage/backend-common@0.20.1-next.2 + +## 0.2.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/backend-plugin-api@0.6.9-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-common@1.4.4 + +## 0.2.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1-next.0 + - @backstage/backend-plugin-api@0.6.9-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-common@1.4.4 + +## 0.2.9 + +### Patch Changes + +- 219d7f0: Refactor some methods to `-node` instead and use the new external modules +- 0cbb03b: Fixing regular expression ReDoS with zod packages. Upgrading to latest. ref: https://security.snyk.io/vuln/SNYK-JS-ZOD-5925617 +- Updated dependencies + - @backstage/backend-common@0.20.0 + - @backstage/integration@1.8.0 + - @backstage/backend-plugin-api@0.6.8 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-common@1.4.4 + +## 0.2.9-next.3 + +### Patch Changes + +- 219d7f0: Refactor some methods to `-node` instead and use the new external modules +- Updated dependencies + - @backstage/backend-common@0.20.0-next.3 + - @backstage/backend-plugin-api@0.6.8-next.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-common@1.4.3 + +## 0.2.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.2 + - @backstage/backend-plugin-api@0.6.8-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-common@1.4.3 + +## 0.2.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.8.0-next.1 + - @backstage/backend-common@0.20.0-next.1 + - @backstage/backend-plugin-api@0.6.8-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-common@1.4.3 + +## 0.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.0-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/backend-plugin-api@0.6.8-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-common@1.4.3 + +## 0.2.8 + +### Patch Changes + +- 8613ba3928: Switched to using `"exports"` field for `/alpha` subpath export. +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.4.3 + - @backstage/integration@1.7.2 + - @backstage/backend-common@0.19.9 + - @backstage/backend-plugin-api@0.6.7 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + ## 0.2.8-next.2 ### Patch Changes diff --git a/plugins/scaffolder-node/alpha-api-report.md b/plugins/scaffolder-node/api-report-alpha.md similarity index 100% rename from plugins/scaffolder-node/alpha-api-report.md rename to plugins/scaffolder-node/api-report-alpha.md diff --git a/plugins/scaffolder-node/api-report.md b/plugins/scaffolder-node/api-report.md index 08caf36812..6bb1534679 100644 --- a/plugins/scaffolder-node/api-report.md +++ b/plugins/scaffolder-node/api-report.md @@ -10,6 +10,7 @@ import { JsonValue } from '@backstage/types'; import { Logger } from 'winston'; import { Observable } from '@backstage/types'; import { Schema } from 'jsonschema'; +import { ScmIntegrationRegistry } from '@backstage/integration'; import { ScmIntegrations } from '@backstage/integration'; import { SpawnOptionsWithoutStdio } from 'child_process'; import { TaskSpec } from '@backstage/plugin-scaffolder-common'; @@ -44,6 +45,29 @@ export type ActionContext< each?: JsonObject; }; +// @public (undocumented) +export function commitAndPushRepo(input: { + dir: string; + auth: + | { + username: string; + password: string; + } + | { + token: string; + }; + logger: Logger; + commitMessage: string; + gitAuthorInfo?: { + name?: string; + email?: string; + }; + branch?: string; + remoteRef?: string; +}): Promise<{ + commitHash: string; +}>; + // @public export const createTemplateAction: < TInputParams extends JsonObject = JsonObject, @@ -73,6 +97,12 @@ export const createTemplateAction: < >, ) => TemplateAction; +// @public +export function deserializeDirectoryContents( + targetPath: string, + files: SerializedFile[], +): Promise; + // @public export function executeShellCommand( options: ExecuteShellCommandOptions, @@ -104,6 +134,69 @@ export function fetchFile(options: { outputPath: string; }): Promise; +// @public (undocumented) +export const getRepoSourceDirectory: ( + workspacePath: string, + sourcePath: string | undefined, +) => string; + +// @public (undocumented) +export function initRepoAndPush(input: { + dir: string; + remoteUrl: string; + auth: + | { + username: string; + password: string; + } + | { + token: string; + }; + logger: Logger; + defaultBranch?: string; + commitMessage?: string; + gitAuthorInfo?: { + name?: string; + email?: string; + }; +}): Promise<{ + commitHash: string; +}>; + +// @public (undocumented) +export const parseRepoUrl: ( + repoUrl: string, + integrations: ScmIntegrationRegistry, +) => { + repo: string; + host: string; + owner?: string | undefined; + organization?: string | undefined; + workspace?: string | undefined; + project?: string | undefined; +}; + +// @public (undocumented) +export interface SerializedFile { + // (undocumented) + content: Buffer; + // (undocumented) + executable?: boolean; + // (undocumented) + path: string; + // (undocumented) + symlink?: boolean; +} + +// @public (undocumented) +export function serializeDirectoryContents( + sourcePath: string, + options?: { + gitignore?: boolean; + globPatterns?: string[]; + }, +): Promise; + // @public export type SerializedTask = { id: string; diff --git a/plugins/scaffolder-node/package.json b/plugins/scaffolder-node/package.json index 2e9a4956fa..b4c843ce65 100644 --- a/plugins/scaffolder-node/package.json +++ b/plugins/scaffolder-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-node", "description": "The plugin-scaffolder-node module for @backstage/plugin-scaffolder-backend", - "version": "0.2.8-next.2", + "version": "0.2.10", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -50,12 +50,15 @@ "@backstage/plugin-scaffolder-common": "workspace:^", "@backstage/types": "workspace:^", "fs-extra": "10.1.0", + "globby": "^11.0.0", "jsonschema": "^1.2.6", + "p-limit": "^3.1.0", "winston": "^3.2.1", - "zod": "^3.21.4", + "zod": "^3.22.4", "zod-to-json-schema": "^3.20.4" }, "devDependencies": { + "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@backstage/config": "workspace:^" }, diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/helpers.test.ts b/plugins/scaffolder-node/src/actions/gitHelpers.test.ts similarity index 94% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/helpers.test.ts rename to plugins/scaffolder-node/src/actions/gitHelpers.test.ts index 7362e99892..7bc3f64f46 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/helpers.test.ts +++ b/plugins/scaffolder-node/src/actions/gitHelpers.test.ts @@ -15,7 +15,7 @@ */ import { Git, getVoidLogger } from '@backstage/backend-common'; -import { commitAndPushRepo, entityRefToName, initRepoAndPush } from './helpers'; +import { commitAndPushRepo, initRepoAndPush } from './gitHelpers'; jest.mock('@backstage/backend-common', () => ({ Git: { @@ -303,17 +303,3 @@ describe('commitAndPushRepo', () => { }); }); }); - -describe('entityRefToName', () => { - it.each([ - 'user:default/catpants', - 'group:default/catpants', - 'user:catpants', - 'default/catpants', - 'user:custom/catpants', - 'group:custom/catpants', - 'catpants', - ])('should parse: "%s"', (entityName: string) => { - expect(entityRefToName(entityName)).toEqual('catpants'); - }); -}); diff --git a/plugins/scaffolder-node/src/actions/gitHelpers.ts b/plugins/scaffolder-node/src/actions/gitHelpers.ts new file mode 100644 index 0000000000..6d449a0a29 --- /dev/null +++ b/plugins/scaffolder-node/src/actions/gitHelpers.ts @@ -0,0 +1,136 @@ +/* + * 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 { Git } from '@backstage/backend-common'; +import { Logger } from 'winston'; + +/** + * @public + */ +export async function initRepoAndPush(input: { + dir: string; + remoteUrl: string; + // For use cases where token has to be used with Basic Auth + // it has to be provided as password together with a username + // which may be a fixed value defined by the provider. + auth: { username: string; password: string } | { token: string }; + logger: Logger; + defaultBranch?: string; + commitMessage?: string; + gitAuthorInfo?: { name?: string; email?: string }; +}): Promise<{ commitHash: string }> { + const { + dir, + remoteUrl, + auth, + logger, + defaultBranch = 'master', + commitMessage = 'Initial commit', + gitAuthorInfo, + } = input; + const git = Git.fromAuth({ + ...auth, + logger, + }); + + await git.init({ + dir, + defaultBranch, + }); + + await git.add({ dir, filepath: '.' }); + + // use provided info if possible, otherwise use fallbacks + const authorInfo = { + name: gitAuthorInfo?.name ?? 'Scaffolder', + email: gitAuthorInfo?.email ?? 'scaffolder@backstage.io', + }; + + const commitHash = await git.commit({ + dir, + message: commitMessage, + author: authorInfo, + committer: authorInfo, + }); + await git.addRemote({ + dir, + url: remoteUrl, + remote: 'origin', + }); + + await git.push({ + dir, + remote: 'origin', + }); + + return { commitHash }; +} + +/** + * @public + */ +export async function commitAndPushRepo(input: { + dir: string; + // For use cases where token has to be used with Basic Auth + // it has to be provided as password together with a username + // which may be a fixed value defined by the provider. + auth: { username: string; password: string } | { token: string }; + logger: Logger; + commitMessage: string; + gitAuthorInfo?: { name?: string; email?: string }; + branch?: string; + remoteRef?: string; +}): Promise<{ commitHash: string }> { + const { + dir, + auth, + logger, + commitMessage, + gitAuthorInfo, + branch = 'master', + remoteRef, + } = input; + + const git = Git.fromAuth({ + ...auth, + logger, + }); + + await git.fetch({ dir }); + await git.checkout({ dir, ref: branch }); + await git.add({ dir, filepath: '.' }); + + // use provided info if possible, otherwise use fallbacks + const authorInfo = { + name: gitAuthorInfo?.name ?? 'Scaffolder', + email: gitAuthorInfo?.email ?? 'scaffolder@backstage.io', + }; + + const commitHash = await git.commit({ + dir, + message: commitMessage, + author: authorInfo, + committer: authorInfo, + }); + + await git.push({ + dir, + remote: 'origin', + remoteRef: remoteRef ?? `refs/heads/${branch}`, + }); + + return { commitHash }; +} diff --git a/plugins/scaffolder-node/src/actions/index.ts b/plugins/scaffolder-node/src/actions/index.ts index 47af320ccb..74a0bb61f9 100644 --- a/plugins/scaffolder-node/src/actions/index.ts +++ b/plugins/scaffolder-node/src/actions/index.ts @@ -25,3 +25,5 @@ export { } from './executeShellCommand'; export { fetchContents, fetchFile } from './fetch'; export { type ActionContext, type TemplateAction } from './types'; +export { initRepoAndPush, commitAndPushRepo } from './gitHelpers'; +export { parseRepoUrl, getRepoSourceDirectory } from './util'; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/util.ts b/plugins/scaffolder-node/src/actions/util.ts similarity index 86% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/util.ts rename to plugins/scaffolder-node/src/actions/util.ts index 61bd704a0b..327cfa9c2f 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/util.ts +++ b/plugins/scaffolder-node/src/actions/util.ts @@ -19,6 +19,9 @@ import { isChildPath } from '@backstage/backend-common'; import { join as joinPath, normalize as normalizePath } from 'path'; import { ScmIntegrationRegistry } from '@backstage/integration'; +/** + * @public + */ export const getRepoSourceDirectory = ( workspacePath: string, sourcePath: string | undefined, @@ -36,19 +39,21 @@ export const getRepoSourceDirectory = ( } return workspacePath; }; -export type RepoSpec = { + +/** + * @public + */ +export const parseRepoUrl = ( + repoUrl: string, + integrations: ScmIntegrationRegistry, +): { repo: string; host: string; owner?: string; organization?: string; workspace?: string; project?: string; -}; - -export const parseRepoUrl = ( - repoUrl: string, - integrations: ScmIntegrationRegistry, -): RepoSpec => { +} => { let parsed; try { parsed = new URL(`https://${repoUrl}`); @@ -99,23 +104,7 @@ export const parseRepoUrl = ( return { host, owner, repo, organization, workspace, project }; }; -export const isExecutable = (fileMode: number) => { - const executeBitMask = 0o000111; - const res = fileMode & executeBitMask; - return res > 0; -}; -/** - * This function checks if the required parameters (given as the `params` argument) are present in the URL - * - * @param repoUrl - the URL for the repository - * @param params - a variadic list of URL query parameter names - * - * @throws - * An InputError exception is thrown if any of the required parameters is not in the URL. - * - * @public - */ function checkRequiredParams(repoUrl: URL, ...params: string[]) { for (let i = 0; i < params.length; i++) { if (!repoUrl.searchParams.get(params[i])) { diff --git a/plugins/scaffolder-backend/src/lib/files/deserializeDirectoryContents.test.ts b/plugins/scaffolder-node/src/files/deserializeDirectoryContents.test.ts similarity index 100% rename from plugins/scaffolder-backend/src/lib/files/deserializeDirectoryContents.test.ts rename to plugins/scaffolder-node/src/files/deserializeDirectoryContents.test.ts diff --git a/plugins/scaffolder-backend/src/lib/files/deserializeDirectoryContents.ts b/plugins/scaffolder-node/src/files/deserializeDirectoryContents.ts similarity index 99% rename from plugins/scaffolder-backend/src/lib/files/deserializeDirectoryContents.ts rename to plugins/scaffolder-node/src/files/deserializeDirectoryContents.ts index cb567eed9d..bdcecd99f1 100644 --- a/plugins/scaffolder-backend/src/lib/files/deserializeDirectoryContents.ts +++ b/plugins/scaffolder-node/src/files/deserializeDirectoryContents.ts @@ -25,7 +25,7 @@ import { SerializedFile } from './types'; * This method uses `resolveSafeChildPath` to make sure that files are * not written outside of the target directory. * - * @internal + * @public */ export async function deserializeDirectoryContents( targetPath: string, diff --git a/plugins/scaffolder-backend/src/lib/files/index.ts b/plugins/scaffolder-node/src/files/index.ts similarity index 100% rename from plugins/scaffolder-backend/src/lib/files/index.ts rename to plugins/scaffolder-node/src/files/index.ts diff --git a/plugins/scaffolder-backend/src/lib/files/serializeDirectoryContents.test.ts b/plugins/scaffolder-node/src/files/serializeDirectoryContents.test.ts similarity index 100% rename from plugins/scaffolder-backend/src/lib/files/serializeDirectoryContents.test.ts rename to plugins/scaffolder-node/src/files/serializeDirectoryContents.test.ts diff --git a/plugins/scaffolder-backend/src/lib/files/serializeDirectoryContents.ts b/plugins/scaffolder-node/src/files/serializeDirectoryContents.ts similarity index 99% rename from plugins/scaffolder-backend/src/lib/files/serializeDirectoryContents.ts rename to plugins/scaffolder-node/src/files/serializeDirectoryContents.ts index 1197db000a..7e52f6323b 100644 --- a/plugins/scaffolder-backend/src/lib/files/serializeDirectoryContents.ts +++ b/plugins/scaffolder-node/src/files/serializeDirectoryContents.ts @@ -41,6 +41,9 @@ async function asyncFilter( return array.filter((_value, index) => filterMap[index]); } +/** + * @public + */ export async function serializeDirectoryContents( sourcePath: string, options?: { diff --git a/plugins/scaffolder-backend/src/lib/files/types.ts b/plugins/scaffolder-node/src/files/types.ts similarity index 97% rename from plugins/scaffolder-backend/src/lib/files/types.ts rename to plugins/scaffolder-node/src/files/types.ts index d3a1eaa008..cd471a7881 100644 --- a/plugins/scaffolder-backend/src/lib/files/types.ts +++ b/plugins/scaffolder-node/src/files/types.ts @@ -14,6 +14,9 @@ * limitations under the License. */ +/** + * @public + */ export interface SerializedFile { path: string; content: Buffer; diff --git a/plugins/scaffolder-node/src/index.ts b/plugins/scaffolder-node/src/index.ts index 98691c2afa..0ec492dd32 100644 --- a/plugins/scaffolder-node/src/index.ts +++ b/plugins/scaffolder-node/src/index.ts @@ -22,4 +22,5 @@ export * from './actions'; export * from './tasks'; +export * from './files'; export type { TemplateFilter, TemplateGlobal } from './types'; diff --git a/plugins/scaffolder-react/CHANGELOG.md b/plugins/scaffolder-react/CHANGELOG.md index 39193de200..89468800e8 100644 --- a/plugins/scaffolder-react/CHANGELOG.md +++ b/plugins/scaffolder-react/CHANGELOG.md @@ -1,5 +1,239 @@ # @backstage/plugin-scaffolder-react +## 1.7.1 + +### Patch Changes + +- c28f281: Scaffolder form now shows a list of errors at the top of the form. +- 0b9ce2b: Fix for a step with no properties +- 98ac5ab: Updated dependency `@rjsf/utils` to `5.15.1`. + Updated dependency `@rjsf/core` to `5.15.1`. + Updated dependency `@rjsf/material-ui` to `5.15.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.1`. +- 4016f21: Remove some unused dependencies +- d16f85f: Show first scaffolder output text by default +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/plugin-scaffolder-common@1.4.5 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## 1.7.1-next.2 + +### Patch Changes + +- 98ac5ab: Updated dependency `@rjsf/utils` to `5.15.1`. + Updated dependency `@rjsf/core` to `5.15.1`. + Updated dependency `@rjsf/material-ui` to `5.15.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.1`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.3-next.2 + +## 1.7.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-scaffolder-common@1.4.4 + +## 1.7.1-next.0 + +### Patch Changes + +- c28f281: Scaffolder form now shows a list of errors at the top of the form. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-scaffolder-common@1.4.4 + +## 1.7.0 + +### Minor Changes + +- 33edf50: Added support for dealing with user provided secrets using a new field extension `ui:field: Secret` + +### Patch Changes + +- 670c7cc: Fix bug where `properties` is set to empty object when it should be empty for schema dependencies +- fa66d1b: Fixed bug in `ReviewState` where `enum` value was displayed in step review instead of the corresponding label when using `enumNames` +- e516bf4: Step titles in the Stepper are now clickable and redirect the user to the corresponding step, as an alternative to using the back buttons. +- aaa6fb3: Minor updates for TypeScript 5.2.2+ compatibility +- 2aee53b: Add horizontal slider if stepper overflows +- 2b72591: Updated dependency `@rjsf/utils` to `5.14.3`. + Updated dependency `@rjsf/core` to `5.14.3`. + Updated dependency `@rjsf/material-ui` to `5.14.3`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.3`. +- 6cd12f2: Updated dependency `@rjsf/utils` to `5.14.1`. + Updated dependency `@rjsf/core` to `5.14.1`. + Updated dependency `@rjsf/material-ui` to `5.14.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.1`. +- a518c5a: Updated dependency `@react-hookz/web` to `^23.0.0`. +- 64301d3: Updated dependency `@rjsf/utils` to `5.15.0`. + Updated dependency `@rjsf/core` to `5.15.0`. + Updated dependency `@rjsf/material-ui` to `5.15.0`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.0`. +- 63c494e: Updated dependency `@rjsf/utils` to `5.14.2`. + Updated dependency `@rjsf/core` to `5.14.2`. + Updated dependency `@rjsf/material-ui` to `5.14.2`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.2`. +- c8908d4: Use new option from RJSF 5.15 +- 0cbb03b: Fixing regular expression ReDoS with zod packages. Upgrading to latest. ref: https://security.snyk.io/vuln/SNYK-JS-ZOD-5925617 +- 5bb5240: Fixed issue for showing undefined for hidden form items +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/catalog-client@1.5.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-scaffolder-common@1.4.4 + +## 1.6.2-next.3 + +### Patch Changes + +- 64301d3: Updated dependency `@rjsf/utils` to `5.15.0`. + Updated dependency `@rjsf/core` to `5.15.0`. + Updated dependency `@rjsf/material-ui` to `5.15.0`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.0`. +- c8908d4: Use new option from RJSF 5.15 +- Updated dependencies + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-catalog-react@1.9.2-next.3 + - @backstage/plugin-scaffolder-common@1.4.3 + +## 1.6.2-next.2 + +### Patch Changes + +- 5bb5240: Fixed issue for showing undefined for hidden form items +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-scaffolder-common@1.4.3 + +## 1.6.2-next.1 + +### Patch Changes + +- fa66d1b5b3: Fixed bug in `ReviewState` where `enum` value was displayed in step review instead of the corresponding label when using `enumNames` +- 2aee53bbeb: Add horizontal slider if stepper overflows +- 2b725913c1: Updated dependency `@rjsf/utils` to `5.14.3`. + Updated dependency `@rjsf/core` to `5.14.3`. + Updated dependency `@rjsf/material-ui` to `5.14.3`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.3`. +- a518c5a25b: Updated dependency `@react-hookz/web` to `^23.0.0`. +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-scaffolder-common@1.4.3 + +## 1.6.2-next.0 + +### Patch Changes + +- e516bf4da8: Step titles in the Stepper are now clickable and redirect the user to the corresponding step, as an alternative to using the back buttons. +- aaa6fb3bc9: Minor updates for TypeScript 5.2.2+ compatibility +- 6cd12f277b: Updated dependency `@rjsf/utils` to `5.14.1`. + Updated dependency `@rjsf/core` to `5.14.1`. + Updated dependency `@rjsf/material-ui` to `5.14.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.1`. +- 63c494ef22: Updated dependency `@rjsf/utils` to `5.14.2`. + Updated dependency `@rjsf/core` to `5.14.2`. + Updated dependency `@rjsf/material-ui` to `5.14.2`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.2`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-scaffolder-common@1.4.3 + +## 1.6.0 + +### Minor Changes + +- 3fdffbb699: Release design improvements for the `Scaffolder` plugin and support v5 of `@rjsf/*` libraries. + + This change should be non-breaking. If you're seeing typescript issues after migrating please [open an issue](https://github.com/backstage/backstage/issues/new/choose) + + The `next` versions like `createNextFieldExtension` and `NextScaffolderPage` have been promoted to the public interface under `createScaffolderFieldExtension` and `ScaffolderPage`, so any older imports which are no longer found will need updating from `@backstage/plugin-scaffolder/alpha` or `@backstage/plugin-scaffolder-react/alpha` will need to be imported from `@backstage/plugin-scaffolder` and `@backstage/plugin-scaffolder-react` respectively. + + The legacy versions are now available in `/alpha` under `createLegacyFieldExtension` and `LegacyScaffolderPage` if you're running into issues, but be aware that these will be removed in a next mainline release. + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 171a99816b: Fixed `backstage:featureFlag` in `scaffolder/next` by sorting out `manifest.steps`. +- c838da0edd: Updated dependency `@rjsf/utils` to `5.13.6`. + Updated dependency `@rjsf/core` to `5.13.6`. + Updated dependency `@rjsf/material-ui` to `5.13.6`. + Updated dependency `@rjsf/validator-ajv8` to `5.13.6`. +- 69c14904b6: Use `EntityRefLinks` with `hideIcons` property to avoid double icons +- 62b5922916: Internal theme type updates +- dda56ae265: Preserve step's time execution for a non-running task. +- 76d07da66a: Make it possible to define control buttons text (Back, Create, Review) per template +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/plugin-scaffolder-common@1.4.3 + - @backstage/core-plugin-api@1.8.0 + - @backstage/version-bridge@1.0.7 + - @backstage/theme@0.4.4 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + ## 1.6.0-next.2 ### Patch Changes diff --git a/plugins/scaffolder-react/alpha-api-report.md b/plugins/scaffolder-react/api-report-alpha.md similarity index 98% rename from plugins/scaffolder-react/alpha-api-report.md rename to plugins/scaffolder-react/api-report-alpha.md index 3d9361bf18..615b54df84 100644 --- a/plugins/scaffolder-react/alpha-api-report.md +++ b/plugins/scaffolder-react/api-report-alpha.md @@ -290,6 +290,11 @@ export interface TemplateGroupsProps { templateFilter?: (entity: TemplateEntityV1beta3) => boolean; } +// @alpha +export const useFilteredSchemaProperties: ( + manifest: TemplateParameterSchema | undefined, +) => TemplateParameterSchema | undefined; + // @alpha export const useFormDataFromQuery: ( initialState?: Record, diff --git a/plugins/scaffolder-react/package.json b/plugins/scaffolder-react/package.json index 24a5441488..f8390667be 100644 --- a/plugins/scaffolder-react/package.json +++ b/plugins/scaffolder-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-react", "description": "A frontend library that helps other Backstage plugins interact with the Scaffolder", - "version": "1.6.0-next.2", + "version": "1.7.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -50,7 +50,6 @@ "@backstage/catalog-model": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", - "@backstage/errors": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", "@backstage/plugin-scaffolder-common": "workspace:^", "@backstage/theme": "workspace:^", @@ -59,11 +58,11 @@ "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", - "@react-hookz/web": "^20.0.0", - "@rjsf/core": "5.13.6", - "@rjsf/material-ui": "5.13.6", - "@rjsf/utils": "5.13.6", - "@rjsf/validator-ajv8": "5.13.6", + "@react-hookz/web": "^23.0.0", + "@rjsf/core": "5.15.1", + "@rjsf/material-ui": "5.15.1", + "@rjsf/utils": "5.15.1", + "@rjsf/validator-ajv8": "5.15.1", "@types/json-schema": "^7.0.9", "@types/react": "^16.13.1 || ^17.0.0", "classnames": "^2.2.6", @@ -77,7 +76,7 @@ "react-use": "^17.2.4", "use-immer": "^0.9.0", "zen-observable": "^0.10.0", - "zod": "^3.21.4", + "zod": "^3.22.4", "zod-to-json-schema": "^3.20.4" }, "peerDependencies": { diff --git a/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.test.tsx b/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.test.tsx index 0f56a32d1d..e9277b2230 100644 --- a/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.test.tsx +++ b/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.test.tsx @@ -94,10 +94,10 @@ describe('ReviewState', () => { }, ]; - const { queryByRole } = render( + const { queryByRole, getAllByRole } = render( , ); - + expect(getAllByRole('row').length).toEqual(1); expect(queryByRole('row', { name: 'Name ******' })).not.toBeInTheDocument(); }); @@ -136,4 +136,70 @@ describe('ReviewState', () => { expect(getByRole('row', { name: 'Name lols' })).toBeInTheDocument(); }); + + it('should display enum label from enumNames', async () => { + const formState = { + name: 'type2', + }; + + const schemas: ParsedTemplateSchema[] = [ + { + mergedSchema: { + type: 'object', + properties: { + name: { + type: 'string', + default: 'type1', + enum: ['type1', 'type2', 'type3'], + enumNames: ['Label-type1', 'Label-type2', 'Label-type3'], + }, + }, + }, + schema: {}, + title: 'test', + uiSchema: {}, + description: 'asd', + }, + ]; + + const { queryByRole } = render( + , + ); + + expect( + queryByRole('row', { name: 'Name Label-type2' }), + ).toBeInTheDocument(); + }); + + it('should display enum value if no corresponding enumNames', async () => { + const formState = { + name: 'type4', + }; + + const schemas: ParsedTemplateSchema[] = [ + { + mergedSchema: { + type: 'object', + properties: { + name: { + type: 'string', + default: 'type1', + enum: ['type1', 'type2', 'type3', 'type4'], + enumNames: ['Label-type1', 'Label-type2', 'Label-type3'], + }, + }, + }, + schema: {}, + title: 'test', + uiSchema: {}, + description: 'asd', + }, + ]; + + const { queryByRole } = render( + , + ); + + expect(queryByRole('row', { name: 'Name type4' })).toBeInTheDocument(); + }); }); diff --git a/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.tsx b/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.tsx index 52ad80c4c2..b601f77bf6 100644 --- a/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.tsx +++ b/plugins/scaffolder-react/src/next/components/ReviewState/ReviewState.tsx @@ -34,33 +34,44 @@ export type ReviewStateProps = { */ export const ReviewState = (props: ReviewStateProps) => { const reviewData = Object.fromEntries( - Object.entries(props.formState).map(([key, value]) => { - for (const step of props.schemas) { - const parsedSchema = new JSONSchema(step.mergedSchema); - const definitionInSchema = parsedSchema.getSchema( - `#/${key}`, - props.formState, - ); - if (definitionInSchema) { - const backstageReviewOptions = - definitionInSchema['ui:backstage']?.review; + Object.entries(props.formState) + .map(([key, value]) => { + for (const step of props.schemas) { + const parsedSchema = new JSONSchema(step.mergedSchema); + const definitionInSchema = parsedSchema.getSchema( + `#/${key}`, + props.formState, + ); + if (definitionInSchema) { + const backstageReviewOptions = + definitionInSchema['ui:backstage']?.review; - if (backstageReviewOptions) { - if (backstageReviewOptions.mask) { - return [key, backstageReviewOptions.mask]; + if (backstageReviewOptions) { + if (backstageReviewOptions.mask) { + return [key, backstageReviewOptions.mask]; + } + if (backstageReviewOptions.show === false) { + return []; + } } - if (backstageReviewOptions.show === false) { - return []; - } - } - if (definitionInSchema['ui:widget'] === 'password') { - return [key, '******']; + if (definitionInSchema['ui:widget'] === 'password') { + return [key, '******']; + } + + if (definitionInSchema.enum && definitionInSchema.enumNames) { + return [ + key, + definitionInSchema.enumNames[ + definitionInSchema.enum.indexOf(value) + ] || value, + ]; + } } } - } - return [key, value]; - }), + return [key, value]; + }) + .filter(prop => prop.length > 0), ); return ; }; diff --git a/plugins/scaffolder-react/src/next/components/Stepper/ErrorListTemplate/errorListTemplate.test.tsx b/plugins/scaffolder-react/src/next/components/Stepper/ErrorListTemplate/errorListTemplate.test.tsx new file mode 100644 index 0000000000..c5ddf6854f --- /dev/null +++ b/plugins/scaffolder-react/src/next/components/Stepper/ErrorListTemplate/errorListTemplate.test.tsx @@ -0,0 +1,43 @@ +/* + * 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 React from 'react'; +import { ErrorListTemplate } from './errorListTemplate'; +import { renderInTestApp } from '@backstage/test-utils'; +import { ErrorListProps } from '@rjsf/utils'; + +describe('Error List Template', () => { + const errorList = { + errors: [ + { + stack: 'Test error 1', + }, + { + stack: 'Test error 2', + }, + ], + errorSchema: {}, + } as Partial as ErrorListProps; + + it('should render the error messages', async () => { + const { getByText } = await renderInTestApp( + , + ); + + for (const error of errorList.errors) { + expect(getByText(error.stack)).toBeInTheDocument(); + } + }); +}); diff --git a/plugins/scaffolder-react/src/next/components/Stepper/ErrorListTemplate/errorListTemplate.tsx b/plugins/scaffolder-react/src/next/components/Stepper/ErrorListTemplate/errorListTemplate.tsx new file mode 100644 index 0000000000..9b6920108b --- /dev/null +++ b/plugins/scaffolder-react/src/next/components/Stepper/ErrorListTemplate/errorListTemplate.tsx @@ -0,0 +1,66 @@ +/* + * 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 React from 'react'; +import { ErrorListProps } from '@rjsf/utils'; +import { + List, + ListItem, + ListItemIcon, + ListItemText, + Paper, + Theme, + createStyles, + makeStyles, +} from '@material-ui/core'; +import ErrorIcon from '@material-ui/icons/Error'; + +const useStyles = makeStyles((_theme: Theme) => + createStyles({ + list: { + width: '100%', + }, + text: { + textWrap: 'wrap', + }, + }), +); + +/** + * Shows a list of errors found in the form + * + * @public + */ +export const ErrorListTemplate = ({ errors }: ErrorListProps) => { + const classes = useStyles(); + + return ( + + + {errors.map((error, index) => ( + + + + + + + ))} + + + ); +}; diff --git a/plugins/scaffolder-react/src/next/components/Stepper/ErrorListTemplate/index.ts b/plugins/scaffolder-react/src/next/components/Stepper/ErrorListTemplate/index.ts new file mode 100644 index 0000000000..8a982bc68b --- /dev/null +++ b/plugins/scaffolder-react/src/next/components/Stepper/ErrorListTemplate/index.ts @@ -0,0 +1,16 @@ +/* + * 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. + */ +export { ErrorListTemplate } from './errorListTemplate'; diff --git a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.test.tsx b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.test.tsx index 34243e232d..d7e271f8b3 100644 --- a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.test.tsx +++ b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.test.tsx @@ -21,6 +21,7 @@ import { act, fireEvent } from '@testing-library/react'; import type { RJSFValidationError } from '@rjsf/utils'; import { JsonValue } from '@backstage/types'; import { FieldExtensionComponentProps } from '../../../extensions'; +import { SecretsContextProvider } from '../../../secrets'; import { LayoutTemplate } from '../../../layouts'; describe('Stepper', () => { @@ -34,7 +35,9 @@ describe('Stepper', () => { }; const { getByText } = await renderInTestApp( - , + + + , ); for (const step of manifest.steps) { @@ -52,7 +55,9 @@ describe('Stepper', () => { }; const { getByRole } = await renderInTestApp( - , + + + , ); expect(getByRole('button', { name: 'Next' })).toBeInTheDocument(); @@ -92,7 +97,9 @@ describe('Stepper', () => { }; const { getByRole } = await renderInTestApp( - , + + + , ); await fireEvent.change(getByRole('textbox', { name: 'name' }), { @@ -112,6 +119,56 @@ describe('Stepper', () => { ); }); + it('should remember the state of the form when cycling through the pages by directly clicking on the step labels', async () => { + const manifest: TemplateParameterSchema = { + steps: [ + { + title: 'Step 1', + schema: { + properties: { + name: { + type: 'string', + }, + }, + }, + }, + { + title: 'Step 2', + schema: { + properties: { + description: { + type: 'string', + }, + }, + }, + }, + ], + title: 'React JSON Schema Form Test', + }; + + const { getByRole, getByLabelText } = await renderInTestApp( + + + , + ); + + await fireEvent.change(getByRole('textbox', { name: 'name' }), { + target: { value: 'im a test value' }, + }); + + await act(async () => { + await fireEvent.click(getByRole('button', { name: 'Next' })); + }); + + await act(async () => { + await fireEvent.click(getByLabelText('Step 1')); + }); + + expect(getByRole('textbox', { name: 'name' })).toHaveValue( + 'im a test value', + ); + }); + it('should merge nested formData correctly in multiple steps', async () => { const Repo = ({ onChange, @@ -171,14 +228,16 @@ describe('Stepper', () => { }); const { getByRole } = await renderInTestApp( - , + + + , ); await fireEvent.change(getByRole('textbox', { name: 'repo' }), { @@ -227,11 +286,13 @@ describe('Stepper', () => { }; const { getByText } = await renderInTestApp( - , + + + , ); expect(getByText('im a custom field extension')).toBeInTheDocument(); @@ -260,17 +321,19 @@ describe('Stepper', () => { }; const { getByRole } = await renderInTestApp( - new Promise(r => setTimeout(r, 1000)), - }, - ]} - onCreate={jest.fn()} - />, + + new Promise(r => setTimeout(r, 1000)), + }, + ]} + onCreate={jest.fn()} + /> + , ); act(() => { @@ -308,12 +371,14 @@ describe('Stepper', () => { }; const { getByText, getByRole } = await renderInTestApp( - , + + + , ); await fireEvent.change(getByRole('textbox', { name: 'postcode' }), { @@ -353,7 +418,9 @@ describe('Stepper', () => { }); const { getByRole } = await renderInTestApp( - , + + + , ); expect(getByRole('textbox', { name: 'firstName' })).toHaveValue('John'); @@ -381,7 +448,9 @@ describe('Stepper', () => { }); const { getByRole } = await renderInTestApp( - , + + + , ); await act(async () => { @@ -416,15 +485,17 @@ describe('Stepper', () => { }; const { getByRole } = await renderInTestApp( - Make, - reviewButtonText: Inspect, - }} - />, + + Make, + reviewButtonText: Inspect, + }} + /> + , ); await act(async () => { @@ -468,12 +539,14 @@ describe('Stepper', () => { }; const { getByText, getByRole } = await renderInTestApp( - , + + + , ); expect(getByText('A Scaffolder Layout')).toBeInTheDocument(); diff --git a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx index 9a333944b9..9b475870d2 100644 --- a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx +++ b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx @@ -51,6 +51,7 @@ import { FormProps, } from '@backstage/plugin-scaffolder-react'; import { ReviewStepProps } from '@backstage/plugin-scaffolder-react'; +import { ErrorListTemplate } from './ErrorListTemplate'; const useStyles = makeStyles(theme => ({ backButton: { @@ -190,12 +191,28 @@ export const Stepper = (stepperProps: StepperProps) => { return ( <> {isValidating && } - - {steps.map((step, index) => ( - - {step.title} - - ))} + + {steps.map((step, index) => { + const isAllowedLabelClick = activeStep > index; + return ( + + { + if (isAllowedLabelClick) setActiveStep(index); + }} + > + {step.title} + + + ); + })} Review @@ -212,8 +229,12 @@ export const Stepper = (stepperProps: StepperProps) => { uiSchema={currentStep.uiSchema} onSubmit={handleNext} fields={fields} - showErrorList={false} + showErrorList="top" + templates={{ ErrorListTemplate }} onChange={handleChange} + experimental_defaultFormStateBehavior={{ + allOf: 'populateDefaults', + }} {...(props.formProps ?? {})} >
    diff --git a/plugins/scaffolder-react/src/next/components/TaskSteps/TaskSteps.tsx b/plugins/scaffolder-react/src/next/components/TaskSteps/TaskSteps.tsx index 96f0d9d865..d74d298778 100644 --- a/plugins/scaffolder-react/src/next/components/TaskSteps/TaskSteps.tsx +++ b/plugins/scaffolder-react/src/next/components/TaskSteps/TaskSteps.tsx @@ -58,6 +58,7 @@ export const TaskSteps = (props: TaskStepsProps) => { activeStep={props.activeStep} alternativeLabel variant="elevation" + style={{ overflowX: 'auto' }} > {props.steps.map(step => { const isCompleted = step.status === 'completed'; diff --git a/plugins/scaffolder-react/src/next/components/TemplateCard/CardHeader.tsx b/plugins/scaffolder-react/src/next/components/TemplateCard/CardHeader.tsx index 608af1a0bf..1180c8f106 100644 --- a/plugins/scaffolder-react/src/next/components/TemplateCard/CardHeader.tsx +++ b/plugins/scaffolder-react/src/next/components/TemplateCard/CardHeader.tsx @@ -15,14 +15,13 @@ */ import React from 'react'; -import { makeStyles, useTheme } from '@material-ui/core'; +import { Theme, makeStyles, useTheme } from '@material-ui/core'; import { ItemCardHeader } from '@backstage/core-components'; -import { BackstageTheme } from '@backstage/theme'; import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; import { FavoriteEntity } from '@backstage/plugin-catalog-react'; const useStyles = makeStyles< - BackstageTheme, + Theme, { cardFontColor: string; cardBackgroundImage: string; @@ -55,7 +54,7 @@ export const CardHeader = (props: CardHeaderProps) => { spec: { type }, }, } = props; - const { getPageTheme } = useTheme(); + const { getPageTheme } = useTheme(); const themeForType = getPageTheme({ themeId: type }); const styles = useStyles({ diff --git a/plugins/scaffolder-react/src/next/components/TemplateCard/CardLink.tsx b/plugins/scaffolder-react/src/next/components/TemplateCard/CardLink.tsx index 9bdb3cf7fb..839d6c7ac1 100644 --- a/plugins/scaffolder-react/src/next/components/TemplateCard/CardLink.tsx +++ b/plugins/scaffolder-react/src/next/components/TemplateCard/CardLink.tsx @@ -13,8 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { IconComponent } from '@backstage/core-plugin-api'; -import { BackstageTheme } from '@backstage/theme'; import { Link } from '@backstage/core-components'; import { makeStyles } from '@material-ui/core'; import React from 'react'; @@ -25,7 +25,7 @@ interface CardLinkProps { url: string; } -const useStyles = makeStyles(() => ({ +const useStyles = makeStyles(() => ({ linkText: { display: 'inline-flex', alignItems: 'center', diff --git a/plugins/scaffolder-react/src/next/components/TemplateCard/TemplateCard.tsx b/plugins/scaffolder-react/src/next/components/TemplateCard/TemplateCard.tsx index 82dc46266d..7850137945 100644 --- a/plugins/scaffolder-react/src/next/components/TemplateCard/TemplateCard.tsx +++ b/plugins/scaffolder-react/src/next/components/TemplateCard/TemplateCard.tsx @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { RELATION_OWNED_BY } from '@backstage/catalog-model'; import { MarkdownContent, UserIcon } from '@backstage/core-components'; import { IconComponent, useApp } from '@backstage/core-plugin-api'; @@ -21,7 +22,6 @@ import { getEntityRelations, } from '@backstage/plugin-catalog-react'; import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; -import { BackstageTheme } from '@backstage/theme'; import { Box, Card, @@ -32,13 +32,14 @@ import { Button, Grid, makeStyles, + Theme, } from '@material-ui/core'; import LanguageIcon from '@material-ui/icons/Language'; import React from 'react'; import { CardHeader } from './CardHeader'; import { CardLink } from './CardLink'; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles(theme => ({ box: { overflow: 'hidden', textOverflow: 'ellipsis', diff --git a/plugins/scaffolder-react/src/next/components/TemplateCategoryPicker/TemplateCategoryPicker.tsx b/plugins/scaffolder-react/src/next/components/TemplateCategoryPicker/TemplateCategoryPicker.tsx index b850c3bcfe..eba6aebf93 100644 --- a/plugins/scaffolder-react/src/next/components/TemplateCategoryPicker/TemplateCategoryPicker.tsx +++ b/plugins/scaffolder-react/src/next/components/TemplateCategoryPicker/TemplateCategoryPicker.tsx @@ -65,7 +65,7 @@ export const TemplateCategoryPicker = () => { > Categories - multiple id="categories-picker" options={availableTypes} diff --git a/plugins/scaffolder-react/src/next/components/TemplateOutputs/DefaultTemplateOutputs.test.tsx b/plugins/scaffolder-react/src/next/components/TemplateOutputs/DefaultTemplateOutputs.test.tsx index 8366dcadf8..4c631b86b0 100644 --- a/plugins/scaffolder-react/src/next/components/TemplateOutputs/DefaultTemplateOutputs.test.tsx +++ b/plugins/scaffolder-react/src/next/components/TemplateOutputs/DefaultTemplateOutputs.test.tsx @@ -25,7 +25,10 @@ describe('', () => { it('should render template output', async () => { const output = { links: [{ title: 'Link 1', url: 'https://backstage.io/' }], - text: [{ title: 'Text 1', content: 'Hello, **world**!' }], + text: [ + { title: 'Text 1', content: 'Hello, **world**!' }, + { title: 'Text 2', content: 'Hello, **mars**!' }, + ], }; const { getByRole } = await renderInTestApp( @@ -37,6 +40,11 @@ describe('', () => { }, ); + // first text output default visible + expect(getByRole('heading', { level: 2 }).innerHTML).toBe( + output.text[0].title, + ); + // test link outputs for (const link of output.links ?? []) { expect( diff --git a/plugins/scaffolder-react/src/next/components/TemplateOutputs/DefaultTemplateOutputs.tsx b/plugins/scaffolder-react/src/next/components/TemplateOutputs/DefaultTemplateOutputs.tsx index a495e4ca9e..c105c5a571 100644 --- a/plugins/scaffolder-react/src/next/components/TemplateOutputs/DefaultTemplateOutputs.tsx +++ b/plugins/scaffolder-react/src/next/components/TemplateOutputs/DefaultTemplateOutputs.tsx @@ -28,17 +28,18 @@ import { TextOutputs } from './TextOutputs'; export const DefaultTemplateOutputs = (props: { output?: ScaffolderTaskOutput; }) => { - const [textOutputIndex, setTextOutputIndex] = useState(); + const { output } = props; + const [textOutputIndex, setTextOutputIndex] = useState( + output?.text?.length ? 0 : undefined, + ); const textOutput = useMemo( () => - textOutputIndex !== undefined - ? props.output?.text?.[textOutputIndex] - : null, - [props.output, textOutputIndex], + textOutputIndex !== undefined ? output?.text?.[textOutputIndex] : null, + [output, textOutputIndex], ); - if (!props.output) { + if (!output) { return null; } @@ -48,11 +49,11 @@ export const DefaultTemplateOutputs = (props: { - + diff --git a/plugins/scaffolder-react/src/next/components/TemplateOutputs/TextOutputs.tsx b/plugins/scaffolder-react/src/next/components/TemplateOutputs/TextOutputs.tsx index 7e64603e92..8f61aa6a30 100644 --- a/plugins/scaffolder-react/src/next/components/TemplateOutputs/TextOutputs.tsx +++ b/plugins/scaffolder-react/src/next/components/TemplateOutputs/TextOutputs.tsx @@ -47,7 +47,11 @@ export const TextOutputs = (props: { startIcon={} component="div" color="primary" - onClick={() => setIndex?.(index !== i ? i : undefined)} + onClick={() => { + if (index !== i) { + setIndex?.(i); + } + }} variant={index === i ? 'outlined' : undefined} > {title} diff --git a/plugins/scaffolder-react/src/next/components/Workflow/Workflow.tsx b/plugins/scaffolder-react/src/next/components/Workflow/Workflow.tsx index e7c56378a7..c6030930c5 100644 --- a/plugins/scaffolder-react/src/next/components/Workflow/Workflow.tsx +++ b/plugins/scaffolder-react/src/next/components/Workflow/Workflow.tsx @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import React, { useEffect } from 'react'; import { Content, @@ -22,14 +23,14 @@ import { } from '@backstage/core-components'; import { stringifyEntityRef } from '@backstage/catalog-model'; import { makeStyles } from '@material-ui/core'; -import { BackstageTheme } from '@backstage/theme'; import { errorApiRef, useApi } from '@backstage/core-plugin-api'; import { useTemplateParameterSchema } from '../../hooks/useTemplateParameterSchema'; import { Stepper, type StepperProps } from '../Stepper/Stepper'; import { SecretsContextProvider } from '../../../secrets/SecretsContext'; +import { useFilteredSchemaProperties } from '../../hooks/useFilteredSchemaProperties'; import { ReviewStepProps } from '@backstage/plugin-scaffolder-react'; -const useStyles = makeStyles(() => ({ +const useStyles = makeStyles({ markdown: { /** to make the styles for React Markdown not leak into the description */ '& :first-child': { @@ -39,7 +40,7 @@ const useStyles = makeStyles(() => ({ marginBottom: 0, }, }, -})); +}); /** * @alpha @@ -81,6 +82,8 @@ export const Workflow = (workflowProps: WorkflowProps): JSX.Element | null => { const { loading, manifest, error } = useTemplateParameterSchema(templateRef); + const sortedManifest = useFilteredSchemaProperties(manifest); + useEffect(() => { if (error) { errorApi.post(new Error(`Failed to load template, ${error}`)); @@ -94,19 +97,25 @@ export const Workflow = (workflowProps: WorkflowProps): JSX.Element | null => { return ( {loading && } - {manifest && ( + {sortedManifest && ( } noPadding titleTypographyProps={{ component: 'h2' }} > - + )} diff --git a/plugins/scaffolder-react/src/next/hooks/index.ts b/plugins/scaffolder-react/src/next/hooks/index.ts index ca8ce10eff..63f8cda4e9 100644 --- a/plugins/scaffolder-react/src/next/hooks/index.ts +++ b/plugins/scaffolder-react/src/next/hooks/index.ts @@ -19,3 +19,4 @@ export { type ParsedTemplateSchema, } from './useTemplateSchema'; export { useTemplateParameterSchema } from './useTemplateParameterSchema'; +export { useFilteredSchemaProperties } from './useFilteredSchemaProperties'; diff --git a/plugins/scaffolder-react/src/next/hooks/useFilteredSchemaProperties.test.tsx b/plugins/scaffolder-react/src/next/hooks/useFilteredSchemaProperties.test.tsx new file mode 100644 index 0000000000..3e568fa7bd --- /dev/null +++ b/plugins/scaffolder-react/src/next/hooks/useFilteredSchemaProperties.test.tsx @@ -0,0 +1,232 @@ +/* + * 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 { renderHook } from '@testing-library/react'; +import { useFilteredSchemaProperties } from './useFilteredSchemaProperties'; +import { TemplateParameterSchema } from '../../types'; +import { TestApiProvider } from '@backstage/test-utils'; +import React from 'react'; +import { featureFlagsApiRef } from '@backstage/core-plugin-api'; + +const mockFeatureFlagApi = { + isActive: jest.fn(), +}; + +describe('useFilteredSchemaProperties', () => { + it('should return the same manifest if no feature flag is set', () => { + mockFeatureFlagApi.isActive.mockReturnValue(true); + + const manifest: TemplateParameterSchema = { + title: 'Test Action template', + description: 'scaffolder v1beta3 template demo', + steps: [ + { + title: 'Fill in some steps', + schema: { + type: 'object', + 'backstage:featureFlag': 'experimental-feature', + properties: { + name: { + description: 'Unique name of the component', + title: 'Name', + type: 'string', + 'ui:autofocus': true, + }, + }, + }, + }, + { + title: 'Choose a location', + schema: { + type: 'object', + properties: { + repoUrl: { + type: 'string', + title: 'Repository Location', + 'ui:field': 'RepoUrlPicker', + }, + }, + }, + }, + ], + }; + + const filteredManifest = renderHook( + () => useFilteredSchemaProperties(manifest), + { + wrapper: ({ children }) => ( + + {children} + + ), + }, + ); + + expect(filteredManifest.result.current).toEqual(manifest); + }); + + it('should hide individual fields from steps of template', () => { + mockFeatureFlagApi.isActive.mockReturnValue(false); + + const manifest: TemplateParameterSchema = { + title: 'Test Action template', + description: 'scaffolder v1beta3 template demo', + steps: [ + { + title: 'Fill in some steps', + schema: { + type: 'object', + properties: { + name: { + description: 'Unique name of the component', + title: 'Name', + type: 'string', + 'ui:autofocus': true, + }, + }, + }, + }, + { + title: 'Choose a location', + schema: { + type: 'object', + properties: { + repoUrl: { + type: 'string', + title: 'Repository Location', + 'ui:field': 'RepoUrlPicker', + 'backstage:featureFlag': 'experimental-feature', + }, + }, + }, + }, + ], + }; + + const filteredManifest = renderHook( + () => useFilteredSchemaProperties(manifest), + { + wrapper: ({ children }) => ( + + {children} + + ), + }, + ); + + const expectedManifest: TemplateParameterSchema = { + title: 'Test Action template', + description: 'scaffolder v1beta3 template demo', + steps: [ + { + title: 'Fill in some steps', + schema: { + type: 'object', + properties: { + name: { + description: 'Unique name of the component', + title: 'Name', + type: 'string', + 'ui:autofocus': true, + }, + }, + }, + }, + { + title: 'Choose a location', + schema: { + type: 'object', + properties: {}, + }, + }, + ], + }; + + expect(filteredManifest.result.current).toEqual(expectedManifest); + }); + + it('should hide "Fill in some steps" from steps of template', () => { + mockFeatureFlagApi.isActive.mockReturnValue(false); + + const manifest: TemplateParameterSchema = { + title: 'Test Action template', + description: 'scaffolder v1beta3 template demo', + steps: [ + { + title: 'Fill in some steps', + schema: { + type: 'object', + 'backstage:featureFlag': 'experimental-feature', + properties: { + name: { + description: 'Unique name of the component', + title: 'Name', + type: 'string', + 'ui:autofocus': true, + }, + }, + }, + }, + { + title: 'Choose a location', + schema: { + type: 'object', + properties: { + repoUrl: { + type: 'string', + title: 'Repository Location', + 'ui:field': 'RepoUrlPicker', + }, + }, + }, + }, + ], + }; + + const filteredManifest = renderHook( + () => useFilteredSchemaProperties(manifest), + { + wrapper: ({ children }) => ( + + {children} + + ), + }, + ); + + const expectedManifest: TemplateParameterSchema = { + title: 'Test Action template', + description: 'scaffolder v1beta3 template demo', + steps: [ + { + title: 'Choose a location', + schema: { + type: 'object', + properties: { + repoUrl: { + type: 'string', + title: 'Repository Location', + 'ui:field': 'RepoUrlPicker', + }, + }, + }, + }, + ], + }; + + expect(filteredManifest.result.current).toEqual(expectedManifest); + }); +}); diff --git a/plugins/scaffolder-react/src/next/hooks/useFilteredSchemaProperties.ts b/plugins/scaffolder-react/src/next/hooks/useFilteredSchemaProperties.ts new file mode 100644 index 0000000000..be6f581f87 --- /dev/null +++ b/plugins/scaffolder-react/src/next/hooks/useFilteredSchemaProperties.ts @@ -0,0 +1,76 @@ +/* + * 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 cloneDeep from 'lodash/cloneDeep'; +import { useApi, featureFlagsApiRef } from '@backstage/core-plugin-api'; +import { TemplateParameterSchema } from '@backstage/plugin-scaffolder-react'; + +/** + * Returns manifest of software templates with steps without a featureFlag tag. + * @alpha + */ + +export const useFilteredSchemaProperties = ( + manifest: TemplateParameterSchema | undefined, +): TemplateParameterSchema | undefined => { + const featureFlagKey = 'backstage:featureFlag'; + const featureFlagApi = useApi(featureFlagsApiRef); + + if (!manifest) { + return undefined; + } + + const filteredSteps = manifest?.steps + .filter(step => { + const featureFlag = step.schema[featureFlagKey]; + return ( + typeof featureFlag !== 'string' || featureFlagApi.isActive(featureFlag) + ); + }) + .map(step => { + const filteredStep = cloneDeep(step); + const removedPropertyKeys: Array = []; + if (filteredStep.schema.properties) { + filteredStep.schema.properties = Object.fromEntries( + Object.entries(filteredStep.schema.properties).filter( + ([key, value]) => { + if (value[featureFlagKey]) { + if (featureFlagApi.isActive(value[featureFlagKey])) { + return true; + } + + removedPropertyKeys.push(key); + return false; + } + return true; + }, + ), + ); + + // remove the feature flag property key from required if they are not active + filteredStep.schema.required = Array.isArray( + filteredStep.schema.required, + ) + ? filteredStep.schema.required?.filter( + r => !removedPropertyKeys.includes(r as string), + ) + : filteredStep.schema.required; + } + + return filteredStep; + }); + + return { ...manifest, steps: filteredSteps }; +}; diff --git a/plugins/scaffolder-react/src/next/hooks/useTemplateSchema.test.tsx b/plugins/scaffolder-react/src/next/hooks/useTemplateSchema.test.tsx index d2771b2eb9..d1d86ab977 100644 --- a/plugins/scaffolder-react/src/next/hooks/useTemplateSchema.test.tsx +++ b/plugins/scaffolder-react/src/next/hooks/useTemplateSchema.test.tsx @@ -266,5 +266,116 @@ describe('useTemplateSchema', () => { properties: {}, }); }); + + it('should deal with dependencies and oneOf options', () => { + const firstStepDependencies = { + preconditions: { + oneOf: [ + { + title: 'About', + description: 'you have chosen option A', + properties: { + preconditions: { + enum: ['optionA'], + }, + }, + }, + { + title: 'About', + description: 'you have chosen option B', + properties: { + preconditions: { + enum: ['optionB'], + }, + }, + }, + ], + }, + }; + + const secondStepDependencies = { + preconditions: { + oneOf: [ + { + required: ['inputA'], + properties: { + preconditions: { + enum: ['optionA'], + }, + inputA: { + title: 'Input A', + type: 'string', + }, + }, + }, + { + required: ['inputB'], + properties: { + preconditions: { + enum: ['optionB'], + }, + inputA: { + title: 'Input B', + type: 'string', + }, + }, + }, + ], + }, + }; + + const manifest: TemplateParameterSchema = { + title: 'Test Template', + description: 'Test Template Description', + steps: [ + { + title: 'First step', + schema: { + type: 'object', + properties: { + preconditions: { + title: 'Preconditions', + type: 'string', + description: 'Choose an option', + enum: ['optionA', 'optionB'], + enumNames: ['Option A', 'Option B'], + }, + }, + dependencies: firstStepDependencies, + }, + }, + { + title: 'Second step', + schema: { + dependencies: secondStepDependencies, + }, + }, + ], + }; + + const { result } = renderHook(() => useTemplateSchema(manifest), { + wrapper: ({ children }: React.PropsWithChildren<{}>) => ( + false }]]} + > + {children} + + ), + }); + + const [first, second] = result.current.steps; + + expect(first.schema).toEqual({ + dependencies: firstStepDependencies, + properties: expect.anything(), + title: undefined, + type: 'object', + }); + + expect(second.schema).toEqual({ + dependencies: secondStepDependencies, + title: undefined, + }); + }); }); }); diff --git a/plugins/scaffolder-react/src/next/hooks/useTemplateSchema.ts b/plugins/scaffolder-react/src/next/hooks/useTemplateSchema.ts index 838f8b1c30..af004910be 100644 --- a/plugins/scaffolder-react/src/next/hooks/useTemplateSchema.ts +++ b/plugins/scaffolder-react/src/next/hooks/useTemplateSchema.ts @@ -59,14 +59,19 @@ export const useTemplateSchema = ( return stepFeatureFlag ? featureFlags.isActive(stepFeatureFlag) : true; }) // Then filter out the properties that are not enabled with feature flag - .map(step => ({ - ...step, - schema: { - ...step.schema, - // Title is rendered at the top of the page, so let's ignore this from jsonschemaform - title: undefined, - properties: Object.fromEntries( - Object.entries((step.schema?.properties ?? []) as JsonObject).filter( + .map(step => { + const strippedSchema = { + ...step, + schema: { + ...step.schema, + // Title is rendered at the top of the page, so let's ignore this from jsonschemaform + title: undefined, + }, + } as ParsedTemplateSchema; + + if (step.schema?.properties || !step.schema?.dependencies) { + strippedSchema.schema.properties = Object.fromEntries( + Object.entries((step.schema?.properties ?? {}) as JsonObject).filter( ([key]) => { const stepFeatureFlag = step.uiSchema[key]?.['ui:backstage']?.featureFlag; @@ -75,9 +80,11 @@ export const useTemplateSchema = ( : true; }, ), - ), - }, - })); + ); + } + + return strippedSchema; + }); return { presentation: manifest.presentation, diff --git a/plugins/scaffolder/CHANGELOG.md b/plugins/scaffolder/CHANGELOG.md index 1bafc76774..8482d41538 100644 --- a/plugins/scaffolder/CHANGELOG.md +++ b/plugins/scaffolder/CHANGELOG.md @@ -1,5 +1,278 @@ # @backstage/plugin-scaffolder +## 1.17.1 + +### Patch Changes + +- 98ac5ab: Updated dependency `@rjsf/utils` to `5.15.1`. + Updated dependency `@rjsf/core` to `5.15.1`. + Updated dependency `@rjsf/material-ui` to `5.15.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.1`. +- 4016f21: Remove some unused dependencies +- df4bc9d: Minor internal refactor +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.7.1 + - @backstage/core-components@0.13.10 + - @backstage/plugin-scaffolder-common@1.4.5 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.20 + +## 1.17.1-next.2 + +### Patch Changes + +- 98ac5ab: Updated dependency `@rjsf/utils` to `5.15.1`. + Updated dependency `@rjsf/core` to `5.15.1`. + Updated dependency `@rjsf/material-ui` to `5.15.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.1`. +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.7.1-next.2 + - @backstage/plugin-catalog-react@1.9.3-next.2 + - @backstage/integration-react@1.1.23-next.0 + +## 1.17.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2-next.0 + - @backstage/core-components@0.13.10-next.1 + - @backstage/integration-react@1.1.23-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.1 + - @backstage/plugin-permission-react@0.4.19-next.1 + - @backstage/plugin-scaffolder-react@1.7.1-next.1 + - @backstage/integration@1.8.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-scaffolder-common@1.4.4 + +## 1.17.1-next.0 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.7.1-next.0 + - @backstage/core-components@0.13.10-next.0 + - @backstage/catalog-client@1.5.2-next.0 + - @backstage/plugin-permission-react@0.4.19-next.0 + - @backstage/plugin-catalog-react@1.9.3-next.0 + - @backstage/integration-react@1.1.22 + - @backstage/catalog-model@1.4.3 + - @backstage/core-plugin-api@1.8.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-scaffolder-common@1.4.4 + +## 1.17.0 + +### Minor Changes + +- df88d09: Add a new git repository url picker for `gitea`. This `GiteaRepoPicker` can be used in a template to scaffold a project to be cloned using gitea. +- 33edf50: Added support for dealing with user provided secrets using a new field extension `ui:field: Secret` + +### Patch Changes + +- 6806d10: Added `headerOptions` to `TemplateListPage` to optionally override default values. + Changed `themeId` of TemplateListPage from `website` to `home`. +- aaa6fb3: Minor updates for TypeScript 5.2.2+ compatibility +- 2b72591: Updated dependency `@rjsf/utils` to `5.14.3`. + Updated dependency `@rjsf/core` to `5.14.3`. + Updated dependency `@rjsf/material-ui` to `5.14.3`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.3`. +- 6cd12f2: Updated dependency `@rjsf/utils` to `5.14.1`. + Updated dependency `@rjsf/core` to `5.14.1`. + Updated dependency `@rjsf/material-ui` to `5.14.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.1`. +- a518c5a: Updated dependency `@react-hookz/web` to `^23.0.0`. +- 64301d3: Updated dependency `@rjsf/utils` to `5.15.0`. + Updated dependency `@rjsf/core` to `5.15.0`. + Updated dependency `@rjsf/material-ui` to `5.15.0`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.0`. +- 63c494e: Updated dependency `@rjsf/utils` to `5.14.2`. + Updated dependency `@rjsf/core` to `5.14.2`. + Updated dependency `@rjsf/material-ui` to `5.14.2`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.2`. +- b5fa691: Fixing `headerOptions` not being passed through the `TemplatePage` component +- c8908d4: Use new option from RJSF 5.15 +- 0cbb03b: Fixing regular expression ReDoS with zod packages. Upgrading to latest. ref: https://security.snyk.io/vuln/SNYK-JS-ZOD-5925617 +- Updated dependencies + - @backstage/core-plugin-api@1.8.1 + - @backstage/plugin-catalog-react@1.9.2 + - @backstage/core-components@0.13.9 + - @backstage/theme@0.5.0 + - @backstage/plugin-scaffolder-react@1.7.0 + - @backstage/catalog-client@1.5.0 + - @backstage/integration@1.8.0 + - @backstage/integration-react@1.1.22 + - @backstage/plugin-permission-react@0.4.18 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.19 + - @backstage/plugin-scaffolder-common@1.4.4 + +## 1.16.2-next.3 + +### Patch Changes + +- 64301d3: Updated dependency `@rjsf/utils` to `5.15.0`. + Updated dependency `@rjsf/core` to `5.15.0`. + Updated dependency `@rjsf/material-ui` to `5.15.0`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.0`. +- c8908d4: Use new option from RJSF 5.15 +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.6.2-next.3 + - @backstage/core-components@0.13.9-next.3 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/theme@0.5.0-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-catalog-react@1.9.2-next.3 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/plugin-scaffolder-common@1.4.3 + +## 1.16.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.5.0-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.2 + - @backstage/catalog-client@1.5.0-next.1 + - @backstage/plugin-scaffolder-react@1.6.2-next.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-components@0.13.9-next.2 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/plugin-scaffolder-common@1.4.3 + +## 1.16.2-next.1 + +### Patch Changes + +- 2b725913c1: Updated dependency `@rjsf/utils` to `5.14.3`. + Updated dependency `@rjsf/core` to `5.14.3`. + Updated dependency `@rjsf/material-ui` to `5.14.3`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.3`. +- a518c5a25b: Updated dependency `@react-hookz/web` to `^23.0.0`. +- b5fa6918dc: Fixing `headerOptions` not being passed through the `TemplatePage` component +- Updated dependencies + - @backstage/core-components@0.13.9-next.1 + - @backstage/core-plugin-api@1.8.1-next.1 + - @backstage/plugin-catalog-react@1.9.2-next.1 + - @backstage/catalog-client@1.5.0-next.0 + - @backstage/plugin-scaffolder-react@1.6.2-next.1 + - @backstage/integration@1.8.0-next.1 + - @backstage/integration-react@1.1.22-next.1 + - @backstage/plugin-permission-react@0.4.18-next.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-scaffolder-common@1.4.3 + +## 1.16.2-next.0 + +### Patch Changes + +- 6806d10be3: Added `headerOptions` to `TemplateListPage` to optionally override default values. + Changed `themeId` of TemplateListPage from `website` to `home`. +- aaa6fb3bc9: Minor updates for TypeScript 5.2.2+ compatibility +- 6cd12f277b: Updated dependency `@rjsf/utils` to `5.14.1`. + Updated dependency `@rjsf/core` to `5.14.1`. + Updated dependency `@rjsf/material-ui` to `5.14.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.1`. +- 63c494ef22: Updated dependency `@rjsf/utils` to `5.14.2`. + Updated dependency `@rjsf/core` to `5.14.2`. + Updated dependency `@rjsf/material-ui` to `5.14.2`. + Updated dependency `@rjsf/validator-ajv8` to `5.14.2`. +- Updated dependencies + - @backstage/core-plugin-api@1.8.1-next.0 + - @backstage/plugin-catalog-react@1.9.2-next.0 + - @backstage/core-components@0.13.9-next.0 + - @backstage/plugin-scaffolder-react@1.6.2-next.0 + - @backstage/integration@1.8.0-next.0 + - @backstage/theme@0.5.0-next.0 + - @backstage/integration-react@1.1.22-next.0 + - @backstage/plugin-permission-react@0.4.18-next.0 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + - @backstage/plugin-scaffolder-common@1.4.3 + +## 1.16.0 + +### Minor Changes + +- f28c11743a: Add a possibility to use a formatter on a warning panel. Applied it for a scaffolder template +- 3fdffbb699: Release design improvements for the `Scaffolder` plugin and support v5 of `@rjsf/*` libraries. + + This change should be non-breaking. If you're seeing typescript issues after migrating please [open an issue](https://github.com/backstage/backstage/issues/new/choose) + + The `next` versions like `createNextFieldExtension` and `NextScaffolderPage` have been promoted to the public interface under `createScaffolderFieldExtension` and `ScaffolderPage`, so any older imports which are no longer found will need updating from `@backstage/plugin-scaffolder/alpha` or `@backstage/plugin-scaffolder-react/alpha` will need to be imported from `@backstage/plugin-scaffolder` and `@backstage/plugin-scaffolder-react` respectively. + + The legacy versions are now available in `/alpha` under `createLegacyFieldExtension` and `LegacyScaffolderPage` if you're running into issues, but be aware that these will be removed in a next mainline release. + +### Patch Changes + +- 6c2b872153: Add official support for React 18. +- 69ee8d75f4: Remove `button` prop from used MaterialUI `MenuItem` component fixing incompatibility with MaterialUI v5. +- c838da0edd: Updated dependency `@rjsf/utils` to `5.13.6`. + Updated dependency `@rjsf/core` to `5.13.6`. + Updated dependency `@rjsf/material-ui` to `5.13.6`. + Updated dependency `@rjsf/validator-ajv8` to `5.13.6`. +- 26e4d916d5: Title and description in RepoUrlPicker are now correctly displayed. +- 69c14904b6: Use `EntityRefLinks` with `hideIcons` property to avoid double icons +- 62b5922916: Internal theme type updates +- Updated dependencies + - @backstage/plugin-catalog-react@1.9.0 + - @backstage/core-components@0.13.8 + - @backstage/plugin-scaffolder-common@1.4.3 + - @backstage/integration@1.7.2 + - @backstage/integration-react@1.1.21 + - @backstage/core-plugin-api@1.8.0 + - @backstage/plugin-permission-react@0.4.17 + - @backstage/plugin-scaffolder-react@1.6.0 + - @backstage/theme@0.4.4 + - @backstage/catalog-client@1.4.6 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.18 + ## 1.16.0-next.2 ### Minor Changes diff --git a/plugins/scaffolder/alpha-api-report.md b/plugins/scaffolder/api-report-alpha.md similarity index 92% rename from plugins/scaffolder/alpha-api-report.md rename to plugins/scaffolder/api-report-alpha.md index 55d14bff75..6a1e0648a4 100644 --- a/plugins/scaffolder/alpha-api-report.md +++ b/plugins/scaffolder/api-report-alpha.md @@ -70,6 +70,11 @@ export type TemplateListPageProps = { actions?: boolean; tasks?: boolean; }; + headerOptions?: { + pageTitleOverride?: string; + title?: string; + subtitle?: string; + }; }; // @alpha (undocumented) @@ -80,6 +85,11 @@ export type TemplateWizardPageProps = { }; layouts?: LayoutOptions[]; formProps?: FormProps_3; + headerOptions?: { + pageTitleOverride?: string; + title?: string; + subtitle?: string; + }; }; // (No @packageDocumentation comment for this package) diff --git a/plugins/scaffolder/api-report.md b/plugins/scaffolder/api-report.md index 6f8479990b..4df1eff430 100644 --- a/plugins/scaffolder/api-report.md +++ b/plugins/scaffolder/api-report.md @@ -379,6 +379,7 @@ export const RepoUrlPickerFieldExtension: FieldExtensionComponent_2< secretsKey: string; additionalScopes?: | { + gitea?: string[] | undefined; gerrit?: string[] | undefined; github?: string[] | undefined; gitlab?: string[] | undefined; @@ -405,6 +406,7 @@ export const RepoUrlPickerFieldSchema: FieldSchema< secretsKey: string; additionalScopes?: | { + gitea?: string[] | undefined; gerrit?: string[] | undefined; github?: string[] | undefined; gitlab?: string[] | undefined; diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index d54ff8c3bf..690af2f971 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder", "description": "The Backstage plugin that helps you create new things", - "version": "1.16.0-next.2", + "version": "1.17.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -48,7 +48,6 @@ "dependencies": { "@backstage/catalog-client": "workspace:^", "@backstage/catalog-model": "workspace:^", - "@backstage/config": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", @@ -59,7 +58,6 @@ "@backstage/plugin-permission-react": "workspace:^", "@backstage/plugin-scaffolder-common": "workspace:^", "@backstage/plugin-scaffolder-react": "workspace:^", - "@backstage/theme": "workspace:^", "@backstage/types": "workspace:^", "@codemirror/language": "^6.0.0", "@codemirror/legacy-modes": "^6.1.0", @@ -67,11 +65,11 @@ "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", - "@react-hookz/web": "^20.0.0", - "@rjsf/core": "5.13.6", - "@rjsf/material-ui": "5.13.6", - "@rjsf/utils": "5.13.6", - "@rjsf/validator-ajv8": "5.13.6", + "@react-hookz/web": "^23.0.0", + "@rjsf/core": "5.15.1", + "@rjsf/material-ui": "5.15.1", + "@rjsf/utils": "5.15.1", + "@rjsf/validator-ajv8": "5.15.1", "@types/react": "^16.13.1 || ^17.0.0", "@uiw/react-codemirror": "^4.9.3", "classnames": "^2.2.6", @@ -88,7 +86,7 @@ "react-use": "^17.2.4", "yaml": "^2.0.0", "zen-observable": "^0.10.0", - "zod": "^3.21.4", + "zod": "^3.22.4", "zod-to-json-schema": "^3.20.4" }, "peerDependencies": { diff --git a/plugins/scaffolder/src/api.ts b/plugins/scaffolder/src/api.ts index c67a5c944e..a66ac522c2 100644 --- a/plugins/scaffolder/src/api.ts +++ b/plugins/scaffolder/src/api.ts @@ -107,6 +107,7 @@ export class ScaffolderClient implements ScaffolderApi { ...this.scmIntegrationsApi.bitbucketCloud.list(), ...this.scmIntegrationsApi.bitbucketServer.list(), ...this.scmIntegrationsApi.gerrit.list(), + ...this.scmIntegrationsApi.gitea.list(), ...this.scmIntegrationsApi.github.list(), ...this.scmIntegrationsApi.gitlab.list(), ] diff --git a/plugins/scaffolder/src/components/ListTasksPage/OwnerListPicker.tsx b/plugins/scaffolder/src/components/ListTasksPage/OwnerListPicker.tsx index ee383569ee..fdb13b68a0 100644 --- a/plugins/scaffolder/src/components/ListTasksPage/OwnerListPicker.tsx +++ b/plugins/scaffolder/src/components/ListTasksPage/OwnerListPicker.tsx @@ -21,7 +21,6 @@ import { ListItemText, makeStyles, MenuItem, - Theme, Typography, } from '@material-ui/core'; import SettingsIcon from '@material-ui/icons/Settings'; @@ -29,7 +28,7 @@ import React, { Fragment } from 'react'; import AllIcon from '@material-ui/icons/FontDownload'; -const useStyles = makeStyles( +const useStyles = makeStyles( theme => ({ root: { backgroundColor: 'rgba(0, 0, 0, .11)', @@ -111,7 +110,6 @@ export const OwnerListPicker = (props: { {group.items.map(item => ( onSelectOwner(item.id as 'owned' | 'all')} diff --git a/plugins/scaffolder/src/components/OngoingTask/ContextMenu.tsx b/plugins/scaffolder/src/components/OngoingTask/ContextMenu.tsx index 166c26e854..1612b943c2 100644 --- a/plugins/scaffolder/src/components/OngoingTask/ContextMenu.tsx +++ b/plugins/scaffolder/src/components/OngoingTask/ContextMenu.tsx @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { BackstageTheme } from '@backstage/theme'; + import { IconButton, ListItemIcon, @@ -22,6 +22,7 @@ import { MenuItem, MenuList, Popover, + Theme, useTheme, } from '@material-ui/core'; import { useAsync } from '@react-hookz/web'; @@ -44,7 +45,7 @@ type ContextMenuProps = { taskId?: string; }; -const useStyles = makeStyles(() => ({ +const useStyles = makeStyles(() => ({ button: { color: ({ fontColor }) => fontColor, }, @@ -60,7 +61,7 @@ export const ContextMenu = (props: ContextMenuProps) => { onToggleButtonBar, taskId, } = props; - const { getPageTheme } = useTheme(); + const { getPageTheme } = useTheme(); const pageTheme = getPageTheme({ themeId: 'website' }); const classes = useStyles({ fontColor: pageTheme.fontColor }); const scaffolderApi = useApi(scaffolderApiRef); diff --git a/plugins/scaffolder/src/components/Router/Router.tsx b/plugins/scaffolder/src/components/Router/Router.tsx index dede51d676..c3d971bd11 100644 --- a/plugins/scaffolder/src/components/Router/Router.tsx +++ b/plugins/scaffolder/src/components/Router/Router.tsx @@ -133,6 +133,7 @@ export const Router = (props: PropsWithChildren) => { contextMenu={props.contextMenu} groups={props.groups} templateFilter={props.templateFilter} + headerOptions={props.headerOptions} /> } /> @@ -141,6 +142,7 @@ export const Router = (props: PropsWithChildren) => { element={ { > Categories - id="categories-picker" multiple options={availableTypes} diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/GiteaRepoPicker.test.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/GiteaRepoPicker.test.tsx new file mode 100644 index 0000000000..e66ca49af1 --- /dev/null +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/GiteaRepoPicker.test.tsx @@ -0,0 +1,40 @@ +/* + * 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 React from 'react'; +import { GiteaRepoPicker } from './GiteaRepoPicker'; +import { render, fireEvent } from '@testing-library/react'; + +describe('GiteaRepoPicker', () => { + describe('owner input field', () => { + it('calls onChange when the owner input changes', () => { + const onChange = jest.fn(); + const { getAllByRole } = render( + , + ); + + const ownerInput = getAllByRole('textbox')[0]; + + fireEvent.change(ownerInput, { target: { value: 'test-owner' } }); + + expect(onChange).toHaveBeenCalledWith({ owner: 'test-owner' }); + }); + }); +}); diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/GiteaRepoPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/GiteaRepoPicker.tsx new file mode 100644 index 0000000000..566a2732e3 --- /dev/null +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/GiteaRepoPicker.tsx @@ -0,0 +1,75 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; +import FormControl from '@material-ui/core/FormControl'; +import FormHelperText from '@material-ui/core/FormHelperText'; +import Input from '@material-ui/core/Input'; +import InputLabel from '@material-ui/core/InputLabel'; +import { Select, SelectItem } from '@backstage/core-components'; +import { RepoUrlPickerState } from './types'; + +export const GiteaRepoPicker = (props: { + allowedOwners?: string[]; + allowedRepos?: string[]; + state: RepoUrlPickerState; + onChange: (state: RepoUrlPickerState) => void; + rawErrors: string[]; +}) => { + const { allowedOwners = [], state, onChange, rawErrors } = props; + const ownerItems: SelectItem[] = allowedOwners + ? allowedOwners.map(i => ({ label: i, value: i })) + : [{ label: 'Loading...', value: 'loading' }]; + + const { owner } = state; + + return ( + <> + 0 && !owner} + > + {allowedOwners?.length ? ( + onChange({ owner: e.target.value })} + value={owner} + /> + + )} + + Gitea namespace where this repository will belong to. It can be the + name of organization, group, subgroup, user, or the project. + + + + ); +}; diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx index 7fc71d8338..ba333088ab 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx @@ -20,6 +20,7 @@ import { } from '@backstage/integration-react'; import React, { useEffect, useState, useMemo, useCallback } from 'react'; import { GithubRepoPicker } from './GithubRepoPicker'; +import { GiteaRepoPicker } from './GiteaRepoPicker'; import { GitlabRepoPicker } from './GitlabRepoPicker'; import { AzureRepoPicker } from './AzureRepoPicker'; import { BitbucketRepoPicker } from './BitbucketRepoPicker'; @@ -183,6 +184,15 @@ export const RepoUrlPicker = (props: RepoUrlPickerProps) => { state={state} /> )} + {hostType === 'gitea' && ( + + )} {hostType === 'gitlab' && ( { + onChange(Array(e.target?.value.length).fill('*').join('')); + setSecrets({ [name]: e.target?.value }); + }} + value={secrets[name] ?? ''} + type="password" + autoComplete="off" + /> + + ); +}; diff --git a/plugins/scaffolder/src/components/fields/SecretInput/index.tsx b/plugins/scaffolder/src/components/fields/SecretInput/index.tsx new file mode 100644 index 0000000000..859a04a4d3 --- /dev/null +++ b/plugins/scaffolder/src/components/fields/SecretInput/index.tsx @@ -0,0 +1,16 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export * from './SecretInput'; diff --git a/plugins/scaffolder/src/components/fields/index.ts b/plugins/scaffolder/src/components/fields/index.ts index 7ee4448f6b..7f119f27be 100644 --- a/plugins/scaffolder/src/components/fields/index.ts +++ b/plugins/scaffolder/src/components/fields/index.ts @@ -19,4 +19,5 @@ export * from './RepoUrlPicker'; export * from './OwnedEntityPicker'; export * from './EntityTagsPicker'; export * from './MyGroupsPicker'; + export { type FieldSchema, makeFieldSchemaFromZod } from './utils'; diff --git a/plugins/scaffolder/src/extensions/default.ts b/plugins/scaffolder/src/extensions/default.ts index 013f242a12..2e4b7032de 100644 --- a/plugins/scaffolder/src/extensions/default.ts +++ b/plugins/scaffolder/src/extensions/default.ts @@ -44,6 +44,8 @@ import { MyGroupsPickerSchema, } from '../components/fields/MyGroupsPicker/MyGroupsPicker'; +import { SecretInput } from '../components/fields/SecretInput'; + export const DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS = [ { component: EntityPicker, @@ -82,4 +84,8 @@ export const DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS = [ name: 'MyGroupsPicker', schema: MyGroupsPickerSchema, }, + { + component: SecretInput, + name: 'Secret', + }, ]; diff --git a/plugins/scaffolder/src/legacy/MultistepJsonForm/MultistepJsonForm.tsx b/plugins/scaffolder/src/legacy/MultistepJsonForm/MultistepJsonForm.tsx index 312522bc88..68b25d97d2 100644 --- a/plugins/scaffolder/src/legacy/MultistepJsonForm/MultistepJsonForm.tsx +++ b/plugins/scaffolder/src/legacy/MultistepJsonForm/MultistepJsonForm.tsx @@ -192,6 +192,9 @@ export const MultistepJsonForm = (props: MultistepJsonFormProps) => { onSubmit={(e: IChangeEvent) => { if (e.errors.length === 0) handleNext(); }} + experimental_defaultFormStateBehavior={{ + allOf: 'populateDefaults', + }} {...formProps} {...transformSchemaToProps(schema, layouts)} > diff --git a/plugins/scaffolder/src/legacy/ScaffolderPage/ScaffolderPageContextMenu.tsx b/plugins/scaffolder/src/legacy/ScaffolderPage/ScaffolderPageContextMenu.tsx index 5558b314da..f6151c227b 100644 --- a/plugins/scaffolder/src/legacy/ScaffolderPage/ScaffolderPageContextMenu.tsx +++ b/plugins/scaffolder/src/legacy/ScaffolderPage/ScaffolderPageContextMenu.tsx @@ -15,7 +15,6 @@ */ import { useRouteRef } from '@backstage/core-plugin-api'; -import { BackstageTheme } from '@backstage/theme'; import IconButton from '@material-ui/core/IconButton'; import ListItemIcon from '@material-ui/core/ListItemIcon'; import ListItemText from '@material-ui/core/ListItemText'; @@ -35,7 +34,7 @@ import { scaffolderListTaskRouteRef, } from '../../routes'; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles(theme => ({ button: { color: theme.page.fontColor, }, diff --git a/plugins/scaffolder/src/legacy/TemplateCard/TemplateCard.tsx b/plugins/scaffolder/src/legacy/TemplateCard/TemplateCard.tsx index b4e68318d0..80f719bd36 100644 --- a/plugins/scaffolder/src/legacy/TemplateCard/TemplateCard.tsx +++ b/plugins/scaffolder/src/legacy/TemplateCard/TemplateCard.tsx @@ -45,7 +45,6 @@ import { getEntitySourceLocation, } from '@backstage/plugin-catalog-react'; import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; -import { BackstageTheme } from '@backstage/theme'; import { Box, Card, @@ -55,6 +54,7 @@ import { Chip, IconButton, makeStyles, + Theme, Tooltip, Typography, useTheme, @@ -65,7 +65,7 @@ import React from 'react'; import { selectedTemplateRouteRef, viewTechDocRouteRef } from '../../routes'; const useStyles = makeStyles< - BackstageTheme, + Theme, { fontColor: string; backgroundImage: string } >(theme => ({ cardHeader: { @@ -179,7 +179,7 @@ const DeprecationWarning = () => { export const TemplateCard = ({ template, deprecated }: TemplateCardProps) => { const app = useApp(); - const backstageTheme = useTheme(); + const backstageTheme = useTheme(); const templateRoute = useRouteRef(selectedTemplateRouteRef); const templateProps = getTemplateCardProps(template); const ownedByRelations = getEntityRelations( diff --git a/plugins/scaffolder/src/legacy/TemplateEditorPage/CustomFieldExplorer.tsx b/plugins/scaffolder/src/legacy/TemplateEditorPage/CustomFieldExplorer.tsx index 9107ac67eb..def3bf1796 100644 --- a/plugins/scaffolder/src/legacy/TemplateEditorPage/CustomFieldExplorer.tsx +++ b/plugins/scaffolder/src/legacy/TemplateEditorPage/CustomFieldExplorer.tsx @@ -161,6 +161,9 @@ export const CustomFieldExplorer = ({ onSubmit={e => handleFieldConfigChange(e.formData)} validator={validator} schema={selectedField.schema?.uiOptions || {}} + experimental_defaultFormStateBehavior={{ + allOf: 'populateDefaults', + }} >