diff --git a/.changeset/afraid-garlics-glow.md b/.changeset/afraid-garlics-glow.md deleted file mode 100644 index dfe2596869..0000000000 --- a/.changeset/afraid-garlics-glow.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -The `create-plugin` and `create` commands have both been deprecated in favor of a new `new` command. The `new` command is functionally identical to `create`, but the new naming makes it possible to use as yarn script, since `yarn create` is reserved. diff --git a/.changeset/afraid-horses-lick.md b/.changeset/afraid-horses-lick.md deleted file mode 100644 index f2dfcf4ed6..0000000000 --- a/.changeset/afraid-horses-lick.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -'@backstage/app-defaults': patch -'@backstage/core-app-api': patch -'@backstage/core-components': patch -'@backstage/core-plugin-api': patch -'@backstage/dev-utils': patch -'@backstage/test-utils': patch -'@backstage/plugin-adr': patch -'@backstage/plugin-airbrake': patch -'@backstage/plugin-allure': patch -'@backstage/plugin-api-docs': patch -'@backstage/plugin-azure-devops': patch -'@backstage/plugin-badges': patch -'@backstage/plugin-bazaar': patch -'@backstage/plugin-catalog-graph': patch -'@backstage/plugin-catalog-import': patch -'@backstage/plugin-catalog-react': patch -'@backstage/plugin-catalog': patch -'@backstage/plugin-circleci': patch -'@backstage/plugin-cloudbuild': patch -'@backstage/plugin-code-climate': patch -'@backstage/plugin-code-coverage': patch -'@backstage/plugin-codescene': patch -'@backstage/plugin-cost-insights': patch -'@backstage/plugin-explore': patch -'@backstage/plugin-gcp-projects': patch -'@backstage/plugin-git-release-manager': patch -'@backstage/plugin-github-actions': patch -'@backstage/plugin-gitops-profiles': patch -'@backstage/plugin-graphiql': patch -'@backstage/plugin-home': patch -'@backstage/plugin-jenkins': patch -'@backstage/plugin-kafka': patch -'@backstage/plugin-kubernetes': patch -'@backstage/plugin-lighthouse': patch -'@backstage/plugin-org': patch -'@backstage/plugin-pagerduty': patch -'@backstage/plugin-permission-react': patch -'@backstage/plugin-rollbar': patch -'@backstage/plugin-scaffolder': patch -'@backstage/plugin-search-react': patch -'@backstage/plugin-search': patch -'@backstage/plugin-sentry': patch -'@backstage/plugin-shortcuts': patch -'@backstage/plugin-splunk-on-call': patch -'@backstage/plugin-tech-insights': patch -'@backstage/plugin-techdocs-addons-test-utils': patch -'@backstage/plugin-techdocs-react': patch -'@backstage/plugin-techdocs': patch -'@backstage/plugin-todo': patch -'@backstage/plugin-user-settings': patch ---- - -Updated React Router dependencies to be peer dependencies. diff --git a/.changeset/afraid-radios-boil.md b/.changeset/afraid-radios-boil.md deleted file mode 100644 index a9533d55c0..0000000000 --- a/.changeset/afraid-radios-boil.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-msgraph': patch ---- - -Fixed a bug in the `MicrosoftGraphEntityProvider` that ignored the `userExpand` and `groupExpand` configuration parameters diff --git a/.changeset/beige-coins-type.md b/.changeset/beige-coins-type.md deleted file mode 100644 index 340170a83e..0000000000 --- a/.changeset/beige-coins-type.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/backend-app-api': patch -'@backstage/backend-plugin-api': patch ---- - -Made `ApiRef.defaultFactory` internal. diff --git a/.changeset/beige-monkeys-add.md b/.changeset/beige-monkeys-add.md deleted file mode 100644 index ee54e4d090..0000000000 --- a/.changeset/beige-monkeys-add.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-common': patch ---- - -Workaround support for `swc` instead of `sucrase` diff --git a/.changeset/beige-pumas-tap.md b/.changeset/beige-pumas-tap.md deleted file mode 100644 index 8ed8aab1f4..0000000000 --- a/.changeset/beige-pumas-tap.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': minor ---- - -Add the option for a homepage when using the `github:publish` action diff --git a/.changeset/big-dolls-reflect.md b/.changeset/big-dolls-reflect.md deleted file mode 100644 index e57fb74e09..0000000000 --- a/.changeset/big-dolls-reflect.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-auth-node': patch -'@backstage/plugin-permission-node': patch ---- - -Minor update to tests diff --git a/.changeset/big-spies-check.md b/.changeset/big-spies-check.md deleted file mode 100644 index c704c7d00e..0000000000 --- a/.changeset/big-spies-check.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs-node': patch ---- - -Fix Techdocs S3 and GCS publisher to include bucketRootPath in requests diff --git a/.changeset/big-teachers-tell.md b/.changeset/big-teachers-tell.md deleted file mode 100644 index 180a974e5e..0000000000 --- a/.changeset/big-teachers-tell.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/test-utils': minor ---- - -Elements rendered in a test app are no longer wrapped in a `Routes` and `Route` element, as this is not compatible with React Router v6 stable. diff --git a/.changeset/blue-snakes-compete.md b/.changeset/blue-snakes-compete.md deleted file mode 100644 index 73054554b1..0000000000 --- a/.changeset/blue-snakes-compete.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-adr-backend': patch ---- - -Continue processing subsequent entities when an error occurs in collator diff --git a/.changeset/brave-steaks-lay.md b/.changeset/brave-steaks-lay.md deleted file mode 100644 index a36fa5c80b..0000000000 --- a/.changeset/brave-steaks-lay.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-kubernetes-backend': patch ---- - -chore: Exporting KubernetesClientProvider and everything in kubernetes-auth-translator as requested in issue #10457 diff --git a/.changeset/chatty-cars-kick.md b/.changeset/chatty-cars-kick.md deleted file mode 100644 index fcda65d0f7..0000000000 --- a/.changeset/chatty-cars-kick.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-node': patch ---- - -Adds experimental `catalogServiceRef` for obtaining a `CatalogClient` in the new backend system. diff --git a/.changeset/clever-beans-turn.md b/.changeset/clever-beans-turn.md deleted file mode 100644 index 69846a2516..0000000000 --- a/.changeset/clever-beans-turn.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/plugin-kafka': patch -'@backstage/plugin-kafka-backend': patch -'@backstage/plugin-lighthouse': patch -'@backstage/plugin-proxy-backend': patch ---- - -Minor API signatures cleanup diff --git a/.changeset/clever-turtles-work.md b/.changeset/clever-turtles-work.md deleted file mode 100644 index 9ddad4d1d2..0000000000 --- a/.changeset/clever-turtles-work.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Deprecated the `plugin:diff` command. If you wish to keep running similar checks in your project we recommend using bespoke scripts. A useful utility for such scripts is `@manypkg/get-packages`, which helps you enumerate all packages in a monorepo. diff --git a/.changeset/cold-frogs-kiss.md b/.changeset/cold-frogs-kiss.md deleted file mode 100644 index 7af9468ca1..0000000000 --- a/.changeset/cold-frogs-kiss.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': minor ---- - -Fixed a bug in plugin-scaffolder-backend where it ignores the skip migration database options. - -To use this new implementation you need to create the instance of `DatabaseTaskStore` using the `PluginDatabaseManager` instead of `Knex`; - -``` -import { DatabaseManager, getRootLogger, loadBackendConfig } from '@backstage/backend-common'; -import { DatabaseTaskStore } from '@backstage/plugin-scaffolder-backend'; - -const config = await loadBackendConfig({ argv: process.argv, logger: getRootLogger() }); -const databaseManager = DatabaseManager.fromConfig(config, { migrations: { skip: true } }); -const databaseTaskStore = await DatabaseTaskStore.create(databaseManager); -``` diff --git a/.changeset/cool-cameras-count.md b/.changeset/cool-cameras-count.md deleted file mode 100644 index 02c8ffc2bd..0000000000 --- a/.changeset/cool-cameras-count.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-app-api': patch ---- - -When using React Router v6 stable, it is now possible for components within the `Route` element tree to have `path` props, although they will be ignored. diff --git a/.changeset/cuddly-clocks-dance.md b/.changeset/cuddly-clocks-dance.md deleted file mode 100644 index 9d33535a62..0000000000 --- a/.changeset/cuddly-clocks-dance.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-msgraph': patch ---- - -Added $select attribute to user query diff --git a/.changeset/cuddly-needles-marry.md b/.changeset/cuddly-needles-marry.md deleted file mode 100644 index 84963a7fe5..0000000000 --- a/.changeset/cuddly-needles-marry.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -'@backstage/backend-common': patch -'@backstage/integration': patch -'@backstage/plugin-adr': patch -'@backstage/plugin-catalog-backend': patch -'@backstage/plugin-catalog-import': patch -'@backstage/plugin-scaffolder': patch -'@backstage/plugin-scaffolder-backend': patch -'@backstage/plugin-techdocs': patch -'@backstage/plugin-techdocs-module-addons-contrib': patch -'@backstage/plugin-techdocs-node': patch ---- - -Bump `git-url-parse` version to `^13.0.0` diff --git a/.changeset/curly-hounds-wait.md b/.changeset/curly-hounds-wait.md deleted file mode 100644 index 58ebfe89a3..0000000000 --- a/.changeset/curly-hounds-wait.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-stack-overflow-backend': patch ---- - -Now requests all questions available using pagination. Default max page is set to 100, with a configurable `maxPage` option on the collator. diff --git a/.changeset/dry-games-end.md b/.changeset/dry-games-end.md deleted file mode 100644 index dc2f86ee10..0000000000 --- a/.changeset/dry-games-end.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder': patch ---- - -Fix bug with empty strings in `EntityPicker` diff --git a/.changeset/dry-tips-build.md b/.changeset/dry-tips-build.md deleted file mode 100644 index b800161fc8..0000000000 --- a/.changeset/dry-tips-build.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-node': patch ---- - -`IdentityClient` is now deprecated. Please migrate to `IdentityApi` and `DefaultIdentityClient` instead. The authenticate function on `DefaultIdentityClient` is also deprecated. Please use `getIdentity` instead. diff --git a/.changeset/dull-spoons-doubt.md b/.changeset/dull-spoons-doubt.md deleted file mode 100644 index 533a1ea38f..0000000000 --- a/.changeset/dull-spoons-doubt.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Removed usage of the deprecated `diff` command in the root `package.json`. - -To make this change in an existing app, make the following change in the root `package.json`: - -```diff -- "diff": "lerna run diff --", -``` diff --git a/.changeset/eight-shrimps-call.md b/.changeset/eight-shrimps-call.md deleted file mode 100644 index 2e19681f7a..0000000000 --- a/.changeset/eight-shrimps-call.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-react': patch ---- - -humanizeEntityRef function can now be forced to include default namespace diff --git a/.changeset/eight-spies-protect.md b/.changeset/eight-spies-protect.md deleted file mode 100644 index 0011dece72..0000000000 --- a/.changeset/eight-spies-protect.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -'@backstage/plugin-azure-devops': patch -'@backstage/plugin-azure-devops-backend': patch -'@backstage/plugin-azure-devops-common': patch -'@backstage/plugin-cloudbuild': patch -'@backstage/plugin-explore': patch -'@backstage/plugin-fossa': patch -'@backstage/plugin-git-release-manager': patch -'@backstage/plugin-github-actions': patch -'@backstage/plugin-jenkins': patch -'@backstage/plugin-newrelic-dashboard': patch -'@backstage/plugin-pagerduty': patch -'@backstage/plugin-scaffolder': patch -'@backstage/plugin-search-backend-node': patch -'@backstage/plugin-sentry': patch -'@backstage/plugin-sonarqube': patch -'@backstage/plugin-tech-insights': patch -'@backstage/plugin-tech-insights-node': patch -'@backstage/plugin-techdocs': patch -'@backstage/plugin-techdocs-module-addons-contrib': patch -'@backstage/plugin-user-settings': patch -'@backstage/plugin-vault-backend': patch ---- - -Minor API signatures cleanup diff --git a/.changeset/eleven-bees-marry.md b/.changeset/eleven-bees-marry.md deleted file mode 100644 index fb0a6fb32e..0000000000 --- a/.changeset/eleven-bees-marry.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/backend-common': patch ---- - -Added a keep-alive refresh loop to the `DatabaseManager`, keeping the connection -pool up. diff --git a/.changeset/empty-colts-whisper.md b/.changeset/empty-colts-whisper.md deleted file mode 100644 index 1eabe8c58c..0000000000 --- a/.changeset/empty-colts-whisper.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/config-loader': patch ---- - -No longer log when reloading remote config. diff --git a/.changeset/famous-cups-roll.md b/.changeset/famous-cups-roll.md deleted file mode 100644 index fdd5559c72..0000000000 --- a/.changeset/famous-cups-roll.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-plugin-api': patch ---- - -Updated `createBackendPlugin` and `createBackendModule` to properly forward lack of options. diff --git a/.changeset/famous-hounds-sit.md b/.changeset/famous-hounds-sit.md deleted file mode 100644 index d6cc852ff0..0000000000 --- a/.changeset/famous-hounds-sit.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/backend-common': patch ---- - -The options part of `DatabaseManager.fromConfig` now accepts an optional logger -field. diff --git a/.changeset/famous-pianos-kick.md b/.changeset/famous-pianos-kick.md deleted file mode 100644 index 51688077f9..0000000000 --- a/.changeset/famous-pianos-kick.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -The `versions:bump` command will now update dependency ranges in `package.json`, even if the new version is within the current range. diff --git a/.changeset/famous-wombats-happen.md b/.changeset/famous-wombats-happen.md deleted file mode 100644 index 9d8a2f0b0e..0000000000 --- a/.changeset/famous-wombats-happen.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/plugin-cloudbuild': patch -'@backstage/plugin-scaffolder': patch -'@backstage/plugin-tech-insights': patch -'@backstage/plugin-techdocs': patch ---- - -Internal refactor to use more type safe code when dealing with route parameters. diff --git a/.changeset/fast-paws-press.md b/.changeset/fast-paws-press.md deleted file mode 100644 index 8ddb0bc49e..0000000000 --- a/.changeset/fast-paws-press.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Added support for custom certificate for webpack dev server. diff --git a/.changeset/five-carrots-pay.md b/.changeset/five-carrots-pay.md deleted file mode 100644 index 60fa91c163..0000000000 --- a/.changeset/five-carrots-pay.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/backend-tasks': patch -'@backstage/plugin-catalog-backend': patch ---- - -Added support to mysql on some raw queries diff --git a/.changeset/flat-crabs-love.md b/.changeset/flat-crabs-love.md deleted file mode 100644 index 96f566d712..0000000000 --- a/.changeset/flat-crabs-love.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-node': minor ---- - -Added refresh function to the `EntityProviderConnection` to be able to schedule refreshes from entity providers. diff --git a/.changeset/flat-humans-dance.md b/.changeset/flat-humans-dance.md deleted file mode 100644 index ea7571f5bc..0000000000 --- a/.changeset/flat-humans-dance.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-plugin-api': patch ---- - -Service are now scoped to either `'plugin'` or `'root'` scope. Service factories have been updated to provide dependency instances directly rather than factory functions. diff --git a/.changeset/flat-plums-shout.md b/.changeset/flat-plums-shout.md deleted file mode 100644 index 250d6a1b35..0000000000 --- a/.changeset/flat-plums-shout.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': minor ---- - -Allow unknown typed location from being registered via the location service by configuration settings diff --git a/.changeset/flat-walls-kiss.md b/.changeset/flat-walls-kiss.md deleted file mode 100644 index ea2d2556ed..0000000000 --- a/.changeset/flat-walls-kiss.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -The Backstage packages and plugins have all been updated to support React Router v6 stable. The `create-app` template has not been migrated yet, but if you want to migrate your own app or plugins, check out the [migration guide](https://backstage.io/docs/tutorials/react-router-stable-migration). diff --git a/.changeset/fresh-rabbits-juggle.md b/.changeset/fresh-rabbits-juggle.md deleted file mode 100644 index 804ae70853..0000000000 --- a/.changeset/fresh-rabbits-juggle.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@backstage/plugin-dynatrace': minor ---- - -New features: - -- Some visual improvements to the table that displays Problems -- Added support for viewing recent Synthetics results using -- Added some additional linking to the configured Dynatrace instance diff --git a/.changeset/funny-hounds-obey.md b/.changeset/funny-hounds-obey.md deleted file mode 100644 index 065af245c7..0000000000 --- a/.changeset/funny-hounds-obey.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder': patch ---- - -Fixing bug when the workspace would not be automatically saved when using `allowedOwners` diff --git a/.changeset/funny-years-speak.md b/.changeset/funny-years-speak.md deleted file mode 100644 index b82c10a59f..0000000000 --- a/.changeset/funny-years-speak.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-backend': minor ---- - -Removed the previously deprecated class `AtlassianAuthProvider`. Please use `providers.atlassian.create(...)` instead. diff --git a/.changeset/gold-fishes-yawn.md b/.changeset/gold-fishes-yawn.md deleted file mode 100644 index 4b9ef0f605..0000000000 --- a/.changeset/gold-fishes-yawn.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Avoid validating the backend configuration schema when loading static configuration for building the frontend. diff --git a/.changeset/gold-hounds-vanish.md b/.changeset/gold-hounds-vanish.md deleted file mode 100644 index d221f0f5e9..0000000000 --- a/.changeset/gold-hounds-vanish.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': minor ---- - -The search index now does retain fields that have a very long value, but in the form of just a null. This makes it possible to at least filter for their existence. diff --git a/.changeset/gold-laws-attend.md b/.changeset/gold-laws-attend.md deleted file mode 100644 index 08f1250a7d..0000000000 --- a/.changeset/gold-laws-attend.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-techdocs-backend': minor -'@backstage/plugin-techdocs-node': minor ---- - -Add `projectId` config option to GCP Cloud Storage techdocs publisher. This will allow users to override the project ID, instead of implicitly using the same one as found in a credentials bundle. diff --git a/.changeset/good-avocados-grow.md b/.changeset/good-avocados-grow.md deleted file mode 100644 index dcc685c36d..0000000000 --- a/.changeset/good-avocados-grow.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-app-api': minor ---- - -Updated the routing system to be compatible with React Router v6 stable. diff --git a/.changeset/good-papayas-dress.md b/.changeset/good-papayas-dress.md deleted file mode 100644 index 26062c8da8..0000000000 --- a/.changeset/good-papayas-dress.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': minor ---- - -Added `projectId` for gitlab projects to be displayed in the `gitlab:publish` output diff --git a/.changeset/gorgeous-boats-prove.md b/.changeset/gorgeous-boats-prove.md deleted file mode 100644 index 46e72db735..0000000000 --- a/.changeset/gorgeous-boats-prove.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-bazaar': patch ---- - -Fixed broken routing by removing the wrapping `Router` from the `RoutedTabs` children. diff --git a/.changeset/gorgeous-pillows-retire.md b/.changeset/gorgeous-pillows-retire.md deleted file mode 100644 index d6d4009ac2..0000000000 --- a/.changeset/gorgeous-pillows-retire.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-react': patch ---- - -Support showing counts in option labels of the `EntityTagPicker`. You can enable this by adding the `showCounts` property diff --git a/.changeset/gorgeous-swans-kiss.md b/.changeset/gorgeous-swans-kiss.md deleted file mode 100644 index c33eb49d73..0000000000 --- a/.changeset/gorgeous-swans-kiss.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-github': patch ---- - -New experimental alpha exports for use with the upcoming backend system. diff --git a/.changeset/great-cats-sit.md b/.changeset/great-cats-sit.md deleted file mode 100644 index abdf9cfb39..0000000000 --- a/.changeset/great-cats-sit.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': patch ---- - -Fixes a bug to be able to utilize refresh keys after the entity is loaded from cache diff --git a/.changeset/great-rules-march.md b/.changeset/great-rules-march.md deleted file mode 100644 index eb8d901910..0000000000 --- a/.changeset/great-rules-march.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/backend-common': patch -'@backstage/cli': patch ---- - -Remove use of deprecated trimLeft/trimRight diff --git a/.changeset/grumpy-kiwis-juggle.md b/.changeset/grumpy-kiwis-juggle.md deleted file mode 100644 index e303f8f674..0000000000 --- a/.changeset/grumpy-kiwis-juggle.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Added a new `migrate react-router-deps` command to aid in the migration to React Router v6 stable. diff --git a/.changeset/happy-kiwis-look.md b/.changeset/happy-kiwis-look.md deleted file mode 100644 index ff0da8943b..0000000000 --- a/.changeset/happy-kiwis-look.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Fix typo in the documentation diff --git a/.changeset/heavy-ligers-laugh.md b/.changeset/heavy-ligers-laugh.md deleted file mode 100644 index 71f8b99b12..0000000000 --- a/.changeset/heavy-ligers-laugh.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-search-backend-node': patch ---- - -Fixed bug in LunrSearchEngine where stopwords in title is causing in-doc search not working diff --git a/.changeset/hot-brooms-drive.md b/.changeset/hot-brooms-drive.md deleted file mode 100644 index 3b020acdc8..0000000000 --- a/.changeset/hot-brooms-drive.md +++ /dev/null @@ -1,89 +0,0 @@ ---- -'@backstage/app-defaults': patch -'@backstage/catalog-client': patch -'@backstage/catalog-model': patch -'@backstage/cli-common': patch -'@backstage/config': patch -'@backstage/config-loader': patch -'@backstage/core-app-api': patch -'@backstage/core-components': patch -'@backstage/core-plugin-api': patch -'@backstage/create-app': patch -'@backstage/dev-utils': patch -'@backstage/errors': patch -'@backstage/integration': patch -'@backstage/integration-react': patch -'@backstage/release-manifests': patch -'@techdocs/cli': patch -'@backstage/test-utils': patch -'@backstage/plugin-adr': patch -'@backstage/plugin-airbrake': patch -'@backstage/plugin-allure': patch -'@backstage/plugin-analytics-module-ga': patch -'@backstage/plugin-apache-airflow': patch -'@backstage/plugin-api-docs': patch -'@backstage/plugin-apollo-explorer': patch -'@backstage/plugin-azure-devops': patch -'@backstage/plugin-badges': patch -'@backstage/plugin-bitrise': patch -'@backstage/plugin-catalog': patch -'@backstage/plugin-catalog-graph': patch -'@backstage/plugin-catalog-import': patch -'@backstage/plugin-catalog-react': patch -'@backstage/plugin-circleci': patch -'@backstage/plugin-cloudbuild': patch -'@backstage/plugin-code-climate': patch -'@backstage/plugin-code-coverage': patch -'@backstage/plugin-codescene': patch -'@backstage/plugin-config-schema': patch -'@backstage/plugin-cost-insights': patch -'@backstage/plugin-dynatrace': patch -'@backstage/plugin-explore': patch -'@backstage/plugin-explore-react': patch -'@backstage/plugin-firehydrant': patch -'@backstage/plugin-fossa': patch -'@backstage/plugin-gcalendar': patch -'@backstage/plugin-gcp-projects': patch -'@backstage/plugin-git-release-manager': patch -'@backstage/plugin-github-actions': patch -'@backstage/plugin-github-deployments': patch -'@backstage/plugin-github-issues': patch -'@backstage/plugin-github-pull-requests-board': patch -'@backstage/plugin-gitops-profiles': patch -'@backstage/plugin-gocd': patch -'@backstage/plugin-graphiql': patch -'@backstage/plugin-home': patch -'@backstage/plugin-ilert': patch -'@backstage/plugin-jenkins': patch -'@backstage/plugin-kafka': patch -'@backstage/plugin-kubernetes': patch -'@backstage/plugin-lighthouse': patch -'@backstage/plugin-newrelic': patch -'@backstage/plugin-org': patch -'@backstage/plugin-pagerduty': patch -'@backstage/plugin-periskop': patch -'@backstage/plugin-permission-common': patch -'@backstage/plugin-permission-react': patch -'@backstage/plugin-rollbar': patch -'@backstage/plugin-scaffolder': patch -'@backstage/plugin-scaffolder-backend-module-cookiecutter': patch -'@backstage/plugin-scaffolder-backend-module-rails': patch -'@backstage/plugin-scaffolder-backend-module-yeoman': patch -'@backstage/plugin-search': patch -'@backstage/plugin-sentry': patch -'@backstage/plugin-shortcuts': patch -'@backstage/plugin-sonarqube': patch -'@backstage/plugin-splunk-on-call': patch -'@backstage/plugin-stack-overflow': patch -'@backstage/plugin-tech-insights': patch -'@backstage/plugin-tech-radar': patch -'@backstage/plugin-techdocs': patch -'@backstage/plugin-techdocs-addons-test-utils': patch -'@backstage/plugin-techdocs-module-addons-contrib': patch -'@backstage/plugin-todo': patch -'@backstage/plugin-user-settings': patch -'@backstage/plugin-vault': patch -'@backstage/plugin-xcmetrics': patch ---- - -Removed dependency on `@types/jest`. diff --git a/.changeset/hot-files-begin.md b/.changeset/hot-files-begin.md deleted file mode 100644 index e9b9076986..0000000000 --- a/.changeset/hot-files-begin.md +++ /dev/null @@ -1,71 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -The `packages/backend/Dockerfile` received a couple of updates, it now looks as follows: - -```Dockerfile -FROM node:16-bullseye-slim - -# Install sqlite3 dependencies. You can skip this if you don't use sqlite3 in the image, -# in which case you should also move better-sqlite3 to "devDependencies" in package.json. -RUN apt-get update && \ - apt-get install -y --no-install-recommends libsqlite3-dev python3 build-essential && \ - rm -rf /var/lib/apt/lists/* && \ - yarn config set python /usr/bin/python3 - -# From here on we use the least-privileged `node` user to run the backend. -USER node -WORKDIR /app - -# This switches many Node.js dependencies to production mode. -ENV NODE_ENV production - -# Copy repo skeleton first, to avoid unnecessary docker cache invalidation. -# The skeleton contains the package.json of each package in the monorepo, -# and along with yarn.lock and the root package.json, that's enough to run yarn install. -COPY --chown=node:node yarn.lock package.json packages/backend/dist/skeleton.tar.gz ./ -RUN tar xzf skeleton.tar.gz && rm skeleton.tar.gz - -RUN yarn install --frozen-lockfile --production --network-timeout 300000 && rm -rf "$(yarn cache dir)" - -# Then copy the rest of the backend bundle, along with any other files we might want. -COPY --chown=node:node packages/backend/dist/bundle.tar.gz app-config*.yaml ./ -RUN tar xzf bundle.tar.gz && rm bundle.tar.gz - -CMD ["node", "packages/backend", "--config", "app-config.yaml", "--config", "app-config.production.yaml"] -``` - -The two notable changes are that a `USER node` instruction has been added and the ordering of instructions has been changed accordingly. This means that the app will now be running using the least-privileged `node` user. In order for this to work we now need to make sure that all app files are owned by the `node` user, which we do by adding the `--chown=node:node` option to the `COPY` instructions. - -The second change is the addition of `ENV NODE_ENV production`, which ensured that all Node.js modules run in production mode. If you apply this change to an existing app, note that one of the more significant changes is that this switches the log formatting to use the default production format, JSON. Rather than your log lines looking like this: - -```log -2022-08-10T11:36:05.478Z catalog info Performing database migration type=plugin -``` - -They will now look like this: - -```log -{"level":"info","message":"Performing database migration","plugin":"catalog","service":"backstage","type":"plugin"} -``` - -If you wish to keep the existing format, you can override this change by applying the following change to `packages/backend/src/index.ts`: - -```diff - getRootLogger, -+ setRootLogger, -+ createRootLogger, -+ coloredFormat, - useHotMemoize, - ... - ServerTokenManager, - } from '@backstage/backend-common'; - - ... - - async function main() { -+ setRootLogger(createRootLogger({ format: coloredFormat })); -+ - const config = await loadBackendConfig({ -``` diff --git a/.changeset/hot-suits-glow.md b/.changeset/hot-suits-glow.md deleted file mode 100644 index e394d3b8c0..0000000000 --- a/.changeset/hot-suits-glow.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-cost-insights': patch ---- - -The `CostInsightsHeader`component now uses group names if available diff --git a/.changeset/hungry-dogs-agree.md b/.changeset/hungry-dogs-agree.md deleted file mode 100644 index b111b6e463..0000000000 --- a/.changeset/hungry-dogs-agree.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/core-app-api': patch -'@backstage/core-plugin-api': patch ---- - -Added `getSystemIcons()` function to the `AppContext` available through `useApp` that will pull a list of all the icons that have been registered in the App. diff --git a/.changeset/itchy-brooms-end.md b/.changeset/itchy-brooms-end.md deleted file mode 100644 index 632eb33d97..0000000000 --- a/.changeset/itchy-brooms-end.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Fix issue when using `.jsx` files inside tests diff --git a/.changeset/itchy-kiwis-warn.md b/.changeset/itchy-kiwis-warn.md deleted file mode 100644 index 28c4c875ff..0000000000 --- a/.changeset/itchy-kiwis-warn.md +++ /dev/null @@ -1,53 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Adds `IdentityApi` configuration to `create-app` scaffolding templates. - -To migrate to the new `IdentityApi`, edit the `packages/backend/src/index.ts` adding the following import: - -```typescript -import { DefaultIdentityClient } from '@backstage/plugin-auth-node'; -``` - -Use the factory function to create an `IdentityApi` in the `makeCreateEnv` function and return it from the -function as follows: - -```typescript -function makeCreateEnv(config: Config) { -... - const identity = DefaultIdentityClient.create({ - discovery, - }); -... - - return { - ..., - identity - } -} -``` - -Backend plugins can be upgraded to work with this new `IdentityApi`. - -Add `identity` to the `RouterOptions` type. - -```typescript -export interface RouterOptions { - ... - identity: IdentityApi; -} -``` - -Then you can use the `IdentityApi` from the plugin. - -```typescript -export async function createRouter( - options: RouterOptions, -): Promise { - const { identity } = options; - - router.get('/user', async (req, res) => { - const user = await identity.getIdentity({ request: req }); - ... -``` diff --git a/.changeset/kind-penguins-report.md b/.changeset/kind-penguins-report.md new file mode 100644 index 0000000000..4023ea5976 --- /dev/null +++ b/.changeset/kind-penguins-report.md @@ -0,0 +1,10 @@ +--- +'@backstage/plugin-auth-backend': minor +--- + +CookieConfigurer can optionally return the `SameSite` cookie attribute. +CookieConfigurer now requires an additional argument `appOrigin` - the origin URL of the app - which is used to calculate the `SameSite` attribute. +defaultCookieConfigurer returns the `SameSite` attribute which defaults to `Lax`. In cases where an auth-backend is running on a different domain than the App, `SameSite=None` is used - but only for secure contexts. This is so that cookies can be included in third-party requests. + +OAuthAdapterOptions has been modified to require additional arguments, `baseUrl`, and `cookieConfigurer`. +OAuthAdapter now resolves cookie configuration using its supplied CookieConfigurer for each request to make sure that the proper attributes always are set. diff --git a/.changeset/large-books-deny.md b/.changeset/large-books-deny.md deleted file mode 100644 index c88d391639..0000000000 --- a/.changeset/large-books-deny.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/catalog-client': minor ---- - -Adding `validateEntity` method that calls `/validate-entity` endpoint. diff --git a/.changeset/large-eagles-shop.md b/.changeset/large-eagles-shop.md deleted file mode 100644 index bd5bd2e28d..0000000000 --- a/.changeset/large-eagles-shop.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -'@backstage/plugin-airbrake-backend': patch -'@backstage/plugin-catalog-backend-module-bitbucket-server': patch -'@backstage/plugin-dynatrace': patch -'@backstage/plugin-periskop-backend': patch -'@backstage/plugin-stack-overflow-backend': patch -'@backstage/plugin-vault-backend': patch ---- - -Switched to using node-fetch instead of cross-fetch as is standard for our backend packages diff --git a/.changeset/large-trainers-float.md b/.changeset/large-trainers-float.md deleted file mode 100644 index b5d1d9be1d..0000000000 --- a/.changeset/large-trainers-float.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-react': patch ---- - -Properly handle free-text entity filtering in the case of empty tag arrays diff --git a/.changeset/late-turtles-listen.md b/.changeset/late-turtles-listen.md deleted file mode 100644 index 117737a064..0000000000 --- a/.changeset/late-turtles-listen.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -'@backstage/backend-common': patch ---- - -Implemented KubernetesContainerRunner: a ContainerRunner implementation that leverages Jobs on a kubernetes cluster - -```ts -const kubeConfig = new KubeConfig(); -kubeConfig.loadFromDefault(); - -const options: KubernetesContainerRunnerOptions = { - kubeConfig, - // namespace where Jobs will be created - namespace: 'default', - // Jobs name will be prefixed with this name - name: 'my-runner', - // An existing Kubernetes volume that will be used - // as base for mounts - mountBase: { - volumeName: 'workdir', - // Every mount must start with the base path - // see example below - basePath: '/workdir', - }, - // Define a Pod template for the Jobs. It has to include - // a volume definition named as the mountBase volumeName - podTemplate: { - spec: { - containers: [], - volumes: [ - { - name: 'workdir', - persistentVolumeClaim: { - claimName: 'workdir-claim', - }, - }, - ], - }, - }, -}; -const containerRunner = new KubernetesContainerRunner(options); - -const runOptions: RunContainerOptions = { - imageName: 'golang:1.17', - args: ['echo', 'hello world'], - mountDirs: { - '/workdir/app': '/app', - }, -}; -containerRunner.runContainer(runOptions); -``` diff --git a/.changeset/lazy-beds-pull.md b/.changeset/lazy-beds-pull.md new file mode 100644 index 0000000000..0d8be46576 --- /dev/null +++ b/.changeset/lazy-beds-pull.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Updated fallback versions of dependencies in all templates. diff --git a/.changeset/lazy-snakes-film.md b/.changeset/lazy-snakes-film.md deleted file mode 100644 index ffb9c539c8..0000000000 --- a/.changeset/lazy-snakes-film.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -Adds code to generate ids for headers parsed through the MarkdownContent component. diff --git a/.changeset/light-beans-share.md b/.changeset/light-beans-share.md deleted file mode 100644 index 51c59ff7d0..0000000000 --- a/.changeset/light-beans-share.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -'@backstage/plugin-search-backend-module-pg': minor ---- - -Fixed a bug in search-backend-module-pg where it ignores the skip migration database options when using the database. - -To use this new implementation you need to create the instance of `DatabaseDocumentStore` using the `PluginDatabaseManager` instead of `Knex`; - -``` -import { DatabaseManager, getRootLogger, loadBackendConfig } from '@backstage/backend-common'; -import { DatabaseDocumentStore } from '@backstage/plugin-search-backend-module-pg'; - -const config = await loadBackendConfig({ argv: process.argv, logger: getRootLogger() }); -const databaseManager = DatabaseManager.fromConfig(config, { migrations: { skip: true } }); -const databaseDocumentStore = await DatabaseDocumentStore.create(databaseManager); -``` diff --git a/.changeset/light-donuts-obey.md b/.changeset/light-donuts-obey.md deleted file mode 100644 index abe6a1697c..0000000000 --- a/.changeset/light-donuts-obey.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Added support for handling broken symlinks within the scaffolder backend. This is intended for templates that may hold a symlink that is invalid at build time but valid within the destination repo. diff --git a/.changeset/little-roses-rule.md b/.changeset/little-roses-rule.md new file mode 100644 index 0000000000..4acec131e6 --- /dev/null +++ b/.changeset/little-roses-rule.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Added a new `repo test` command. diff --git a/.changeset/loud-comics-search.md b/.changeset/loud-comics-search.md deleted file mode 100644 index 27f5b3c5d9..0000000000 --- a/.changeset/loud-comics-search.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -'@backstage/plugin-tech-insights': minor ---- - -Added the possibility to display check results of different types on a single scorecard. - -- **BREAKING** Removed the `getScorecardsDefinition` method from the `TechInsightsApi` interface. Added the `getCheckResultRenderers` method that returns rendering components for given types. -- **BREAKING** The `CheckResultRenderer` type now exposes the `component` factory method that creates a React component used to display a result of a provided check result. -- The `TechInsightsClient` constructor accepts now the optional `renderers` parameter that can be used to inject a custom renderer. -- **BREAKING** The `title` parameter in the `EntityTechInsightsScorecardContent` and `EntityTechInsightsScorecardCard` components is now mandatory. -- The `jsonRulesEngineCheckResultRenderer` used to render `json-rules-engine` check results is exported. -- The `BooleanCheck` component that can be used to render other check results types is also exported. - -If you were overriding the `getScorecardsDefinition` method to adjust the rendering of check results, you should now provide a custom renderer using `renderers` parameter in the `TechInsightsClient` class. - -See the [README](https://github.com/backstage/backstage/tree/master/plugins/tech-insights/README.md) for more details. diff --git a/.changeset/lovely-ants-invite.md b/.changeset/lovely-ants-invite.md deleted file mode 100644 index 688850f776..0000000000 --- a/.changeset/lovely-ants-invite.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Applied the fix from version 1.5.1 of this package, which is part of the v1.5.1 release of Backstage. diff --git a/.changeset/lucky-ads-worry.md b/.changeset/lucky-ads-worry.md deleted file mode 100644 index a7f749da17..0000000000 --- a/.changeset/lucky-ads-worry.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder': patch ---- - -Support displaying and ordering by counts in `EntityTagPicker` field. Add the `showCounts` option to enable this. Also support configuring `helperText`. diff --git a/.changeset/lucky-points-wash.md b/.changeset/lucky-points-wash.md deleted file mode 100644 index 961c354574..0000000000 --- a/.changeset/lucky-points-wash.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-org': patch ---- - -Added an edit button to the `UserProfileCard` that is enabled when the `backstage.io/edit-url` is present, this matches how the `GroupProfileCard` works diff --git a/.changeset/many-rules-raise.md b/.changeset/many-rules-raise.md deleted file mode 100644 index 40a26a85fe..0000000000 --- a/.changeset/many-rules-raise.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-ldap': patch ---- - -Added ae-dir LDAP vendor to correctly extract DN. diff --git a/.changeset/mean-tomatoes-visit.md b/.changeset/mean-tomatoes-visit.md deleted file mode 100644 index 111063d805..0000000000 --- a/.changeset/mean-tomatoes-visit.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs': patch ---- - -Updated the `TechDocsReaderPage` to be compatible with React Router v6 stable. diff --git a/.changeset/metal-candles-tease.md b/.changeset/metal-candles-tease.md deleted file mode 100644 index a48df562e4..0000000000 --- a/.changeset/metal-candles-tease.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/dev-utils': patch ---- - -Fixed routing when using React Router v6 stable. diff --git a/.changeset/metal-crabs-wash.md b/.changeset/metal-crabs-wash.md deleted file mode 100644 index 6ecb50ef67..0000000000 --- a/.changeset/metal-crabs-wash.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-backend': minor ---- - -Renamed the `RedirectInfo` type to `OAuthStartResponse` diff --git a/.changeset/metal-weeks-kiss.md b/.changeset/metal-weeks-kiss.md deleted file mode 100644 index 90e453dd5c..0000000000 --- a/.changeset/metal-weeks-kiss.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/backend-app-api': patch -'@backstage/backend-defaults': patch -'@backstage/backend-test-utils': patch ---- - -Updated to support new `ServiceFactory` formats. diff --git a/.changeset/moody-berries-sneeze.md b/.changeset/moody-berries-sneeze.md deleted file mode 100644 index 87a5230f2c..0000000000 --- a/.changeset/moody-berries-sneeze.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs': patch ---- - -Fixed a bug where addons wouldn't render on sub pages when using React Route v6 stable. diff --git a/.changeset/neat-kangaroos-turn.md b/.changeset/neat-kangaroos-turn.md deleted file mode 100644 index 6f1572d096..0000000000 --- a/.changeset/neat-kangaroos-turn.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Tweaked workspace packaging to not rewrite existing `package.json` files. diff --git a/.changeset/nervous-rivers-sneeze.md b/.changeset/nervous-rivers-sneeze.md deleted file mode 100644 index 534dbb4a1a..0000000000 --- a/.changeset/nervous-rivers-sneeze.md +++ /dev/null @@ -1,63 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Switch out `sucrase` for `swc` for transpilation. - -`sucrase` is a little more relaxed when it comes to supporting the ways of mocking in `jest`. You might have to make some changes to your tests to meet the `jest` standard and spec if your tests seems to start failing. - -Mocks that look like this are invalid, and they will throw a reference error in line with the `jest` documentation [here on example 3](https://jestjs.io/docs/es6-class-mocks#calling-jestmock-with-the-module-factory-parameter) - -```ts -const mockCommandExists = jest.fn(); -jest.mock('command-exists', () => mockCommandExists); -``` - -You might need to update these mocks to look a little like the following to defer the call to the `jest.fn()` spy until the mock is called. - -```ts -const mockCommandExists = jest.fn(); -jest.mock( - 'command-exists', - () => - (...args: any[]) => - commandExists(...args), -); -``` - -Also, imports are immutable. So it means that you might get some errors when trying to use `jest.spyOn` with starred imports. You might see an error like this: - -```log -TypeError: Cannot redefine property: executeFrameHandlerStrategy - at Function.defineProperty () - - 20 | import { AuthResolverContext } from '../types'; - 21 | - > 22 | const mockFrameHandler = jest.spyOn( - | ^ - 23 | helpers, - 24 | 'executeFrameHandlerStrategy', - 25 | ) as unknown as jest.MockedFunction< -``` - -This happens when you try to do `import * as something from './something'` and then `jest.spyOn(something, 'test)`. You will need to add a `jest.mock` call to mock out the required starred import to return `jest.fn()` functions from the start. Something like this fixes the above test: - -```ts -jest.mock('../../helpers', () => ({ - executeFrameHandlerStrategy: jest.fn(), -})); -``` - -You can also remove any occurrence of `hot(App)` and any import of `react-hot-loader` if you're using the that package locally, as all this has now been replaced with [React Refresh](https://www.npmjs.com/package/react-refresh) which you will get out of the box with the new CLI. - -**Note** If you're experiencing difficulties with running tests after the migration, please reach out to us on Discord to see if we can help, or raise an issue. But in the meantime you can switch back to the existing behaviour by using the following config in your root `package.json`. - -```json -"jest": { - "transform": { - "\\.(js|jsx|ts|tsx|mjs|cjs)$": "@backstage/cli/config/jestSucraseTransform.js", - "\\.(bmp|gif|jpg|jpeg|png|frag|xml|svg|eot|woff|woff2|ttf)$": "@backstage/cli/config/jestFileTransform.js", - "\\.(yaml)$": "jest-transform-yaml" - } -} -``` diff --git a/.changeset/new-taxis-vanish.md b/.changeset/new-taxis-vanish.md deleted file mode 100644 index 4d0c6d64b9..0000000000 --- a/.changeset/new-taxis-vanish.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder': patch ---- - -Addition of a dismissible Error Banner in Scaffolder page diff --git a/.changeset/old-lemons-switch.md b/.changeset/old-lemons-switch.md deleted file mode 100644 index 62f8d099b3..0000000000 --- a/.changeset/old-lemons-switch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -The `RoutedTabs` component has been updated to be compatible with React Router v6 stable. diff --git a/.changeset/old-readers-provide.md b/.changeset/old-readers-provide.md deleted file mode 100644 index db8677b0ca..0000000000 --- a/.changeset/old-readers-provide.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-github-pull-requests-board': patch ---- - -Clarified GitHub app permissions required by plugin diff --git a/.changeset/old-rockets-doubt.md b/.changeset/old-rockets-doubt.md deleted file mode 100644 index 459cd2790c..0000000000 --- a/.changeset/old-rockets-doubt.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -'@backstage/backend-common': patch ---- - -Added port ranges in allowed hosts: - -```yaml -reading: - allow: - - host: *.examples.org:900-1000 -``` diff --git a/.changeset/old-tables-joke.md b/.changeset/old-tables-joke.md deleted file mode 100644 index d458244b3a..0000000000 --- a/.changeset/old-tables-joke.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-plugin-api': patch ---- - -Simplified the `ServiceFactory` type and removed `AnyServiceFactory`. diff --git a/.changeset/perfect-moose-drum.md b/.changeset/perfect-moose-drum.md new file mode 100644 index 0000000000..833e5eeb35 --- /dev/null +++ b/.changeset/perfect-moose-drum.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Updated lockfile parsing to have better support for Yarn 3. diff --git a/.changeset/pink-feet-repeat.md b/.changeset/pink-feet-repeat.md deleted file mode 100644 index c4ac7560a6..0000000000 --- a/.changeset/pink-feet-repeat.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/backend-common': patch -'@backstage/plugin-apache-airflow': patch ---- - -Got rid of usages of the uppercase String type diff --git a/.changeset/pink-moons-smell.md b/.changeset/pink-moons-smell.md deleted file mode 100644 index 77475295be..0000000000 --- a/.changeset/pink-moons-smell.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': minor ---- - -Added `repositoryId` output when create a repository in Azure diff --git a/.changeset/popular-shirts-happen.md b/.changeset/popular-shirts-happen.md deleted file mode 100644 index 137354fe2b..0000000000 --- a/.changeset/popular-shirts-happen.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-permission-react': patch ---- - -**DEPRECATION**: The `PermissionedRoute` component has been deprecated in favor of the new `RequirePermission` component. This is because the usage pattern of `PermissionedRoute` is not compatible with React Router v6 stable. - -Embed the type from `react-router` instead of exporting it directly. diff --git a/.changeset/pre.json b/.changeset/pre.json index 028a1a665f..46123733ca 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -2,334 +2,178 @@ "mode": "pre", "tag": "next", "initialVersions": { - "example-app": "0.2.74", - "@backstage/app-defaults": "1.0.5", - "example-backend": "0.2.74", - "@backstage/backend-app-api": "0.2.0", - "@backstage/backend-common": "0.15.0", - "@backstage/backend-defaults": "0.1.0", - "example-backend-next": "0.0.2", - "@backstage/backend-plugin-api": "0.1.1", - "@backstage/backend-tasks": "0.3.4", - "@backstage/backend-test-utils": "0.1.27", - "@backstage/catalog-client": "1.0.4", - "@backstage/catalog-model": "1.1.0", - "@backstage/cli": "0.18.1", - "@backstage/cli-common": "0.1.9", - "@backstage/codemods": "0.1.38", - "@backstage/config": "1.0.1", - "@backstage/config-loader": "1.1.3", - "@backstage/core-app-api": "1.0.5", - "@backstage/core-components": "0.11.0", - "@backstage/core-plugin-api": "1.0.5", - "@backstage/create-app": "0.4.30", - "@backstage/dev-utils": "1.0.5", + "example-app": "0.2.75", + "@backstage/app-defaults": "1.0.6", + "example-backend": "0.2.75", + "@backstage/backend-app-api": "0.2.1", + "@backstage/backend-common": "0.15.1", + "@backstage/backend-defaults": "0.1.1", + "example-backend-next": "0.0.3", + "@backstage/backend-plugin-api": "0.1.2", + "@backstage/backend-tasks": "0.3.5", + "@backstage/backend-test-utils": "0.1.28", + "@backstage/catalog-client": "1.1.0", + "@backstage/catalog-model": "1.1.1", + "@backstage/cli": "0.19.0", + "@backstage/cli-common": "0.1.10", + "@backstage/codemods": "0.1.39", + "@backstage/config": "1.0.2", + "@backstage/config-loader": "1.1.4", + "@backstage/core-app-api": "1.1.0", + "@backstage/core-components": "0.11.1", + "@backstage/core-plugin-api": "1.0.6", + "@backstage/create-app": "0.4.31", + "@backstage/dev-utils": "1.0.6", "e2e-test": "0.2.0", - "@backstage/errors": "1.1.0", - "@backstage/integration": "1.3.0", - "@backstage/integration-react": "1.1.3", - "@backstage/release-manifests": "0.0.5", - "@techdocs/cli": "1.2.0", - "techdocs-cli-embedded-app": "0.2.73", - "@backstage/test-utils": "1.1.3", + "@backstage/errors": "1.1.1", + "@backstage/integration": "1.3.1", + "@backstage/integration-react": "1.1.4", + "@backstage/release-manifests": "0.0.6", + "@techdocs/cli": "1.2.1", + "techdocs-cli-embedded-app": "0.2.74", + "@backstage/test-utils": "1.2.0", "@backstage/theme": "0.2.16", "@backstage/types": "1.0.0", "@backstage/version-bridge": "1.0.1", - "@backstage/plugin-adr": "0.2.0", - "@backstage/plugin-adr-backend": "0.2.0", - "@backstage/plugin-adr-common": "0.2.0", - "@backstage/plugin-airbrake": "0.3.8", - "@backstage/plugin-airbrake-backend": "0.2.8", - "@backstage/plugin-allure": "0.1.24", - "@backstage/plugin-analytics-module-ga": "0.1.19", - "@backstage/plugin-apache-airflow": "0.2.1", - "@backstage/plugin-api-docs": "0.8.8", + "@backstage/plugin-adr": "0.2.1", + "@backstage/plugin-adr-backend": "0.2.1", + "@backstage/plugin-adr-common": "0.2.1", + "@backstage/plugin-airbrake": "0.3.9", + "@backstage/plugin-airbrake-backend": "0.2.9", + "@backstage/plugin-allure": "0.1.25", + "@backstage/plugin-analytics-module-ga": "0.1.20", + "@backstage/plugin-apache-airflow": "0.2.2", + "@backstage/plugin-api-docs": "0.8.9", "@backstage/plugin-api-docs-module-protoc-gen-doc": "0.1.0", - "@backstage/plugin-apollo-explorer": "0.1.1", - "@backstage/plugin-app-backend": "0.3.35", - "@backstage/plugin-auth-backend": "0.15.1", - "@backstage/plugin-auth-node": "0.2.4", - "@backstage/plugin-azure-devops": "0.1.24", - "@backstage/plugin-azure-devops-backend": "0.3.14", - "@backstage/plugin-azure-devops-common": "0.2.4", - "@backstage/plugin-badges": "0.2.32", - "@backstage/plugin-badges-backend": "0.1.29", - "@backstage/plugin-bazaar": "0.1.23", - "@backstage/plugin-bazaar-backend": "0.1.19", - "@backstage/plugin-bitbucket-cloud-common": "0.1.2", - "@backstage/plugin-bitrise": "0.1.35", - "@backstage/plugin-catalog": "1.5.0", - "@backstage/plugin-catalog-backend": "1.3.1", - "@backstage/plugin-catalog-backend-module-aws": "0.1.8", - "@backstage/plugin-catalog-backend-module-azure": "0.1.6", - "@backstage/plugin-catalog-backend-module-bitbucket": "0.2.2", - "@backstage/plugin-catalog-backend-module-bitbucket-cloud": "0.1.2", - "@backstage/plugin-catalog-backend-module-bitbucket-server": "0.1.0", - "@backstage/plugin-catalog-backend-module-gerrit": "0.1.3", - "@backstage/plugin-catalog-backend-module-github": "0.1.6", - "@backstage/plugin-catalog-backend-module-gitlab": "0.1.6", - "@backstage/plugin-catalog-backend-module-ldap": "0.5.2", - "@backstage/plugin-catalog-backend-module-msgraph": "0.4.1", - "@backstage/plugin-catalog-backend-module-openapi": "0.1.1", - "@backstage/plugin-catalog-common": "1.0.5", - "@internal/plugin-catalog-customized": "0.0.1", - "@backstage/plugin-catalog-graph": "0.2.20", - "@backstage/plugin-catalog-graphql": "0.3.12", - "@backstage/plugin-catalog-import": "0.8.11", - "@backstage/plugin-catalog-node": "1.0.1", - "@backstage/plugin-catalog-react": "1.1.3", - "@backstage/plugin-cicd-statistics": "0.1.10", - "@backstage/plugin-cicd-statistics-module-gitlab": "0.1.4", - "@backstage/plugin-circleci": "0.3.8", - "@backstage/plugin-cloudbuild": "0.3.8", - "@backstage/plugin-code-climate": "0.1.8", - "@backstage/plugin-code-coverage": "0.2.1", - "@backstage/plugin-code-coverage-backend": "0.2.1", - "@backstage/plugin-codescene": "0.1.3", - "@backstage/plugin-config-schema": "0.1.31", - "@backstage/plugin-cost-insights": "0.11.30", + "@backstage/plugin-apollo-explorer": "0.1.2", + "@backstage/plugin-app-backend": "0.3.36", + "@backstage/plugin-auth-backend": "0.16.0", + "@backstage/plugin-auth-node": "0.2.5", + "@backstage/plugin-azure-devops": "0.2.0", + "@backstage/plugin-azure-devops-backend": "0.3.15", + "@backstage/plugin-azure-devops-common": "0.3.0", + "@backstage/plugin-badges": "0.2.33", + "@backstage/plugin-badges-backend": "0.1.30", + "@backstage/plugin-bazaar": "0.1.24", + "@backstage/plugin-bazaar-backend": "0.1.20", + "@backstage/plugin-bitbucket-cloud-common": "0.1.3", + "@backstage/plugin-bitrise": "0.1.36", + "@backstage/plugin-catalog": "1.5.1", + "@backstage/plugin-catalog-backend": "1.4.0", + "@backstage/plugin-catalog-backend-module-aws": "0.1.9", + "@backstage/plugin-catalog-backend-module-azure": "0.1.7", + "@backstage/plugin-catalog-backend-module-bitbucket": "0.2.3", + "@backstage/plugin-catalog-backend-module-bitbucket-cloud": "0.1.3", + "@backstage/plugin-catalog-backend-module-bitbucket-server": "0.1.1", + "@backstage/plugin-catalog-backend-module-gerrit": "0.1.4", + "@backstage/plugin-catalog-backend-module-github": "0.1.7", + "@backstage/plugin-catalog-backend-module-gitlab": "0.1.7", + "@backstage/plugin-catalog-backend-module-ldap": "0.5.3", + "@backstage/plugin-catalog-backend-module-msgraph": "0.4.2", + "@backstage/plugin-catalog-backend-module-openapi": "0.1.2", + "@backstage/plugin-catalog-common": "1.0.6", + "@internal/plugin-catalog-customized": "0.0.2", + "@backstage/plugin-catalog-graph": "0.2.21", + "@backstage/plugin-catalog-graphql": "0.3.13", + "@backstage/plugin-catalog-import": "0.8.12", + "@backstage/plugin-catalog-node": "1.1.0", + "@backstage/plugin-catalog-react": "1.1.4", + "@backstage/plugin-cicd-statistics": "0.1.11", + "@backstage/plugin-cicd-statistics-module-gitlab": "0.1.5", + "@backstage/plugin-circleci": "0.3.9", + "@backstage/plugin-cloudbuild": "0.3.9", + "@backstage/plugin-code-climate": "0.1.9", + "@backstage/plugin-code-coverage": "0.2.2", + "@backstage/plugin-code-coverage-backend": "0.2.2", + "@backstage/plugin-codescene": "0.1.4", + "@backstage/plugin-config-schema": "0.1.32", + "@backstage/plugin-cost-insights": "0.11.31", "@backstage/plugin-cost-insights-common": "0.1.1", - "@backstage/plugin-dynatrace": "0.1.2", - "@internal/plugin-todo-list": "1.0.4", - "@internal/plugin-todo-list-backend": "1.0.4", - "@internal/plugin-todo-list-common": "1.0.3", - "@backstage/plugin-explore": "0.3.39", - "@backstage/plugin-explore-react": "0.0.20", - "@backstage/plugin-firehydrant": "0.1.25", - "@backstage/plugin-fossa": "0.2.40", - "@backstage/plugin-gcalendar": "0.3.4", - "@backstage/plugin-gcp-projects": "0.3.27", - "@backstage/plugin-git-release-manager": "0.3.21", - "@backstage/plugin-github-actions": "0.5.8", - "@backstage/plugin-github-deployments": "0.1.39", - "@backstage/plugin-github-issues": "0.1.0", - "@backstage/plugin-github-pull-requests-board": "0.1.2", - "@backstage/plugin-gitops-profiles": "0.3.26", - "@backstage/plugin-gocd": "0.1.14", - "@backstage/plugin-graphiql": "0.2.40", - "@backstage/plugin-graphql-backend": "0.1.25", - "@backstage/plugin-home": "0.4.24", - "@backstage/plugin-ilert": "0.1.34", - "@backstage/plugin-jenkins": "0.7.7", - "@backstage/plugin-jenkins-backend": "0.1.25", - "@backstage/plugin-jenkins-common": "0.1.7", - "@backstage/plugin-kafka": "0.3.8", - "@backstage/plugin-kafka-backend": "0.2.28", - "@backstage/plugin-kubernetes": "0.7.1", - "@backstage/plugin-kubernetes-backend": "0.7.1", - "@backstage/plugin-kubernetes-common": "0.4.1", - "@backstage/plugin-lighthouse": "0.3.8", - "@backstage/plugin-newrelic": "0.3.26", - "@backstage/plugin-newrelic-dashboard": "0.2.1", - "@backstage/plugin-org": "0.5.8", - "@backstage/plugin-pagerduty": "0.5.1", - "@backstage/plugin-periskop": "0.1.6", - "@backstage/plugin-periskop-backend": "0.1.6", - "@backstage/plugin-permission-backend": "0.5.10", - "@backstage/plugin-permission-common": "0.6.3", - "@backstage/plugin-permission-node": "0.6.4", - "@backstage/plugin-permission-react": "0.4.4", - "@backstage/plugin-proxy-backend": "0.2.29", - "@backstage/plugin-rollbar": "0.4.8", - "@backstage/plugin-rollbar-backend": "0.1.32", - "@backstage/plugin-scaffolder": "1.5.0", - "@backstage/plugin-scaffolder-backend": "1.5.0", - "@backstage/plugin-scaffolder-backend-module-cookiecutter": "0.2.10", - "@backstage/plugin-scaffolder-backend-module-rails": "0.4.3", - "@backstage/plugin-scaffolder-backend-module-yeoman": "0.2.8", - "@backstage/plugin-scaffolder-common": "1.1.2", - "@backstage/plugin-search": "1.0.1", - "@backstage/plugin-search-backend": "1.0.1", - "@backstage/plugin-search-backend-module-elasticsearch": "1.0.1", - "@backstage/plugin-search-backend-module-pg": "0.3.6", - "@backstage/plugin-search-backend-node": "1.0.1", - "@backstage/plugin-search-common": "1.0.0", - "@backstage/plugin-search-react": "1.0.1", - "@backstage/plugin-sentry": "0.4.1", - "@backstage/plugin-shortcuts": "0.3.0", - "@backstage/plugin-sonarqube": "0.4.0", - "@backstage/plugin-sonarqube-backend": "0.1.0", - "@backstage/plugin-splunk-on-call": "0.3.32", - "@backstage/plugin-stack-overflow": "0.1.4", - "@backstage/plugin-stack-overflow-backend": "0.1.4", - "@backstage/plugin-tech-insights": "0.2.4", - "@backstage/plugin-tech-insights-backend": "0.5.1", - "@backstage/plugin-tech-insights-backend-module-jsonfc": "0.1.19", + "@backstage/plugin-dynatrace": "0.2.0", + "@internal/plugin-todo-list": "1.0.5", + "@internal/plugin-todo-list-backend": "1.0.5", + "@internal/plugin-todo-list-common": "1.0.4", + "@backstage/plugin-explore": "0.3.40", + "@backstage/plugin-explore-react": "0.0.21", + "@backstage/plugin-firehydrant": "0.1.26", + "@backstage/plugin-fossa": "0.2.41", + "@backstage/plugin-gcalendar": "0.3.5", + "@backstage/plugin-gcp-projects": "0.3.28", + "@backstage/plugin-git-release-manager": "0.3.22", + "@backstage/plugin-github-actions": "0.5.9", + "@backstage/plugin-github-deployments": "0.1.40", + "@backstage/plugin-github-issues": "0.1.1", + "@backstage/plugin-github-pull-requests-board": "0.1.3", + "@backstage/plugin-gitops-profiles": "0.3.27", + "@backstage/plugin-gocd": "0.1.15", + "@backstage/plugin-graphiql": "0.2.41", + "@backstage/plugin-graphql-backend": "0.1.26", + "@backstage/plugin-home": "0.4.25", + "@backstage/plugin-ilert": "0.1.35", + "@backstage/plugin-jenkins": "0.7.8", + "@backstage/plugin-jenkins-backend": "0.1.26", + "@backstage/plugin-jenkins-common": "0.1.8", + "@backstage/plugin-kafka": "0.3.9", + "@backstage/plugin-kafka-backend": "0.2.29", + "@backstage/plugin-kubernetes": "0.7.2", + "@backstage/plugin-kubernetes-backend": "0.7.2", + "@backstage/plugin-kubernetes-common": "0.4.2", + "@backstage/plugin-lighthouse": "0.3.9", + "@backstage/plugin-newrelic": "0.3.27", + "@backstage/plugin-newrelic-dashboard": "0.2.2", + "@backstage/plugin-org": "0.5.9", + "@backstage/plugin-pagerduty": "0.5.2", + "@backstage/plugin-periskop": "0.1.7", + "@backstage/plugin-periskop-backend": "0.1.7", + "@backstage/plugin-permission-backend": "0.5.11", + "@backstage/plugin-permission-common": "0.6.4", + "@backstage/plugin-permission-node": "0.6.5", + "@backstage/plugin-permission-react": "0.4.5", + "@backstage/plugin-playlist": "0.1.0", + "@backstage/plugin-playlist-backend": "0.1.0", + "@backstage/plugin-playlist-common": "0.1.0", + "@backstage/plugin-proxy-backend": "0.2.30", + "@backstage/plugin-rollbar": "0.4.9", + "@backstage/plugin-rollbar-backend": "0.1.33", + "@backstage/plugin-scaffolder": "1.6.0", + "@backstage/plugin-scaffolder-backend": "1.6.0", + "@backstage/plugin-scaffolder-backend-module-cookiecutter": "0.2.11", + "@backstage/plugin-scaffolder-backend-module-rails": "0.4.4", + "@backstage/plugin-scaffolder-backend-module-yeoman": "0.2.9", + "@backstage/plugin-scaffolder-common": "1.2.0", + "@backstage/plugin-search": "1.0.2", + "@backstage/plugin-search-backend": "1.0.2", + "@backstage/plugin-search-backend-module-elasticsearch": "1.0.2", + "@backstage/plugin-search-backend-module-pg": "0.4.0", + "@backstage/plugin-search-backend-node": "1.0.2", + "@backstage/plugin-search-common": "1.0.1", + "@backstage/plugin-search-react": "1.1.0", + "@backstage/plugin-sentry": "0.4.2", + "@backstage/plugin-shortcuts": "0.3.1", + "@backstage/plugin-sonarqube": "0.4.1", + "@backstage/plugin-sonarqube-backend": "0.1.1", + "@backstage/plugin-splunk-on-call": "0.3.33", + "@backstage/plugin-stack-overflow": "0.1.5", + "@backstage/plugin-stack-overflow-backend": "0.1.5", + "@backstage/plugin-tech-insights": "0.3.0", + "@backstage/plugin-tech-insights-backend": "0.5.2", + "@backstage/plugin-tech-insights-backend-module-jsonfc": "0.1.20", "@backstage/plugin-tech-insights-common": "0.2.6", - "@backstage/plugin-tech-insights-node": "0.3.3", - "@backstage/plugin-tech-radar": "0.5.15", - "@backstage/plugin-techdocs": "1.3.1", - "@backstage/plugin-techdocs-addons-test-utils": "1.0.3", - "@backstage/plugin-techdocs-backend": "1.2.1", - "@backstage/plugin-techdocs-module-addons-contrib": "1.0.3", - "@backstage/plugin-techdocs-node": "1.3.0", - "@backstage/plugin-techdocs-react": "1.0.3", - "@backstage/plugin-todo": "0.2.10", - "@backstage/plugin-todo-backend": "0.1.32", - "@backstage/plugin-user-settings": "0.4.7", - "@backstage/plugin-vault": "0.1.2", - "@backstage/plugin-vault-backend": "0.2.1", - "@backstage/plugin-xcmetrics": "0.2.28" + "@backstage/plugin-tech-insights-node": "0.3.4", + "@backstage/plugin-tech-radar": "0.5.16", + "@backstage/plugin-techdocs": "1.3.2", + "@backstage/plugin-techdocs-addons-test-utils": "1.0.4", + "@backstage/plugin-techdocs-backend": "1.3.0", + "@backstage/plugin-techdocs-module-addons-contrib": "1.0.4", + "@backstage/plugin-techdocs-node": "1.4.0", + "@backstage/plugin-techdocs-react": "1.0.4", + "@backstage/plugin-todo": "0.2.11", + "@backstage/plugin-todo-backend": "0.1.33", + "@backstage/plugin-user-settings": "0.4.8", + "@backstage/plugin-user-settings-backend": "0.1.0", + "@backstage/plugin-vault": "0.1.3", + "@backstage/plugin-vault-backend": "0.2.2", + "@backstage/plugin-xcmetrics": "0.2.29" }, - "changesets": [ - "afraid-garlics-glow", - "afraid-horses-lick", - "afraid-radios-boil", - "beige-coins-type", - "beige-monkeys-add", - "beige-pumas-tap", - "big-dolls-reflect", - "big-spies-check", - "big-teachers-tell", - "blue-snakes-compete", - "brave-steaks-lay", - "chatty-cars-kick", - "clever-beans-turn", - "clever-turtles-work", - "cold-frogs-kiss", - "cool-cameras-count", - "cuddly-clocks-dance", - "cuddly-needles-marry", - "curly-hounds-wait", - "dry-games-end", - "dry-tips-build", - "dull-spoons-doubt", - "eight-shrimps-call", - "eight-spies-protect", - "eleven-bees-marry", - "empty-colts-whisper", - "famous-cups-roll", - "famous-hounds-sit", - "famous-pianos-kick", - "famous-wombats-happen", - "fast-paws-press", - "five-carrots-pay", - "flat-crabs-love", - "flat-humans-dance", - "flat-plums-shout", - "flat-walls-kiss", - "fresh-rabbits-juggle", - "funny-hounds-obey", - "funny-years-speak", - "gold-fishes-yawn", - "gold-hounds-vanish", - "gold-laws-attend", - "good-avocados-grow", - "good-papayas-dress", - "gorgeous-boats-prove", - "gorgeous-pillows-retire", - "gorgeous-swans-kiss", - "great-cats-sit", - "great-rules-march", - "grumpy-kiwis-juggle", - "happy-kiwis-look", - "heavy-ligers-laugh", - "hot-brooms-drive", - "hot-files-begin", - "hot-suits-glow", - "hungry-dogs-agree", - "itchy-brooms-end", - "itchy-kiwis-warn", - "large-books-deny", - "large-eagles-shop", - "large-trainers-float", - "late-turtles-listen", - "lazy-snakes-film", - "light-beans-share", - "light-donuts-obey", - "loud-comics-search", - "lovely-ants-invite", - "lucky-ads-worry", - "lucky-points-wash", - "many-rules-raise", - "mean-tomatoes-visit", - "metal-candles-tease", - "metal-crabs-wash", - "metal-weeks-kiss", - "moody-berries-sneeze", - "neat-kangaroos-turn", - "nervous-rivers-sneeze", - "new-taxis-vanish", - "old-lemons-switch", - "old-readers-provide", - "old-rockets-doubt", - "old-tables-joke", - "pink-feet-repeat", - "pink-moons-smell", - "popular-shirts-happen", - "purple-jeans-bathe", - "purple-plums-travel", - "purple-wolves-confess", - "quick-items-invite", - "quick-lamps-talk", - "rare-tips-glow", - "red-numbers-suffer", - "renovate-16f36a0", - "renovate-1a6cc1f", - "renovate-2925783", - "renovate-4f0c2e3", - "renovate-58c2860", - "renovate-7d3b357", - "renovate-c98c336", - "renovate-dbf54c0", - "renovate-f18a0fc", - "rich-cooks-camp", - "rich-melons-compete", - "rotten-books-crash", - "rude-books-rush", - "rude-tips-argue", - "rude-weeks-retire", - "search-feet-flash", - "search-planets-flash", - "search-zebras-tap", - "selfish-wasps-cough", - "shaggy-chicken-behave", - "shaggy-vans-repeat", - "sharp-swans-suffer", - "shiny-lobsters-fix", - "shiny-ties-leave", - "shiny-walls-kiss", - "short-mice-explode", - "silent-kings-live", - "slimy-stingrays-type", - "slimy-zebras-reply", - "slow-phones-count", - "small-lemons-brake", - "small-walls-promise", - "smart-sloths-search", - "smart-squids-change", - "smooth-yaks-hug", - "spicy-cherries-remember", - "spotty-points-build", - "strong-games-kiss", - "strong-planes-return", - "stupid-pigs-appear", - "sweet-fishes-taste", - "sweet-grapes-explain", - "swift-readers-sin", - "tall-trains-remain", - "tame-papayas-protect", - "tame-socks-sniff", - "tame-trainers-rule", - "tasty-clouds-cover", - "techdocs-feet-dress", - "techdocs-jeans-wait", - "tender-ladybugs-relax", - "tender-pumpkins-burn", - "thin-cows-watch", - "tiny-oranges-thank", - "tiny-rocks-flash", - "tough-dolphins-smile", - "twenty-dolls-smoke", - "two-planets-provide", - "veka-fingrar-drar", - "weak-camels-roll", - "weak-radios-sin", - "weak-yaks-learn", - "wild-sheep-roll", - "witty-cats-wink", - "witty-queens-happen", - "young-falcons-sleep", - "young-trees-rescue" - ] + "changesets": [] } diff --git a/.changeset/purple-jeans-bathe.md b/.changeset/purple-jeans-bathe.md deleted file mode 100644 index 39706db2c4..0000000000 --- a/.changeset/purple-jeans-bathe.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-app-api': patch ---- - -Updated `ServiceRegistry` to not initialize factories more than once. diff --git a/.changeset/purple-plums-travel.md b/.changeset/purple-plums-travel.md deleted file mode 100644 index 0077b15808..0000000000 --- a/.changeset/purple-plums-travel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Fixed a misconfiguration where all modules where treated as ESM by the React Refresh plugin for Webpack. diff --git a/.changeset/purple-wolves-confess.md b/.changeset/purple-wolves-confess.md deleted file mode 100644 index 33333c1a1b..0000000000 --- a/.changeset/purple-wolves-confess.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Removed internal dependencies on Lerna. It is now no longer necessary to have Lerna installed in a project to use all features of the Backstage CLI. diff --git a/.changeset/quick-items-invite.md b/.changeset/quick-items-invite.md deleted file mode 100644 index 33f90cb662..0000000000 --- a/.changeset/quick-items-invite.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-node': patch ---- - -Updated usage of experimental backend service APIs. diff --git a/.changeset/quick-lamps-talk.md b/.changeset/quick-lamps-talk.md deleted file mode 100644 index 3450113520..0000000000 --- a/.changeset/quick-lamps-talk.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-jenkins-backend': patch ---- - -Extend configuration so that extra headers can be sent to jenkins instance diff --git a/.changeset/rare-tips-glow.md b/.changeset/rare-tips-glow.md deleted file mode 100644 index 6667fd5871..0000000000 --- a/.changeset/rare-tips-glow.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-kubernetes': patch ---- - -Reset error state on success diff --git a/.changeset/red-numbers-suffer.md b/.changeset/red-numbers-suffer.md deleted file mode 100644 index c1baae1e92..0000000000 --- a/.changeset/red-numbers-suffer.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -'@backstage/plugin-allure': patch -'@backstage/plugin-apache-airflow': patch -'@backstage/plugin-app-backend': patch -'@backstage/plugin-auth-backend': patch -'@backstage/plugin-bitrise': patch -'@backstage/plugin-catalog': patch -'@backstage/plugin-catalog-graphql': patch -'@backstage/plugin-cicd-statistics': patch -'@backstage/plugin-circleci': patch -'@backstage/plugin-cloudbuild': patch -'@backstage/plugin-code-climate': patch -'@backstage/plugin-config-schema': patch -'@backstage/plugin-cost-insights': patch -'@backstage/plugin-dynatrace': patch -'@backstage/plugin-explore': patch -'@backstage/plugin-explore-react': patch -'@backstage/plugin-firehydrant': patch -'@backstage/plugin-gcalendar': patch -'@backstage/plugin-gcp-projects': patch -'@backstage/plugin-github-actions': patch -'@backstage/plugin-github-deployments': patch -'@backstage/plugin-github-pull-requests-board': patch -'@backstage/plugin-gitops-profiles': patch -'@backstage/plugin-graphql-backend': patch -'@backstage/plugin-home': patch -'@backstage/plugin-ilert': patch -'@backstage/plugin-jenkins-backend': patch -'@backstage/plugin-kubernetes-common': patch -'@backstage/plugin-newrelic': patch -'@backstage/plugin-newrelic-dashboard': patch -'@backstage/plugin-pagerduty': patch -'@backstage/plugin-rollbar': patch -'@backstage/plugin-rollbar-backend': patch -'@backstage/plugin-search-backend-module-pg': patch -'@backstage/plugin-sentry': patch -'@backstage/plugin-shortcuts': patch -'@backstage/plugin-splunk-on-call': patch -'@backstage/plugin-tech-radar': patch -'@backstage/plugin-user-settings': patch -'@backstage/plugin-xcmetrics': patch ---- - -Minor API signatures cleanup diff --git a/.changeset/renovate-16f36a0.md b/.changeset/renovate-16f36a0.md deleted file mode 100644 index 74c33ec0a7..0000000000 --- a/.changeset/renovate-16f36a0.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -'@backstage/backend-common': patch -'@backstage/plugin-app-backend': patch -'@backstage/plugin-graphql-backend': patch -'@backstage/plugin-kubernetes-backend': patch -'@backstage/plugin-vault-backend': patch ---- - -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. diff --git a/.changeset/renovate-1a6cc1f.md b/.changeset/renovate-1a6cc1f.md deleted file mode 100644 index ea50aeb8f5..0000000000 --- a/.changeset/renovate-1a6cc1f.md +++ /dev/null @@ -1,108 +0,0 @@ ---- -'@backstage/backend-common': patch -'@backstage/backend-test-utils': patch -'@backstage/catalog-client': patch -'@backstage/cli': patch -'@backstage/config-loader': patch -'@backstage/core-app-api': patch -'@backstage/core-components': patch -'@backstage/core-plugin-api': patch -'@backstage/integration-react': patch -'@backstage/integration': patch -'@backstage/release-manifests': patch -'@backstage/test-utils': patch -'@backstage/plugin-adr-backend': patch -'@backstage/plugin-adr': patch -'@backstage/plugin-airbrake-backend': patch -'@backstage/plugin-airbrake': patch -'@backstage/plugin-allure': patch -'@backstage/plugin-analytics-module-ga': patch -'@backstage/plugin-apache-airflow': patch -'@backstage/plugin-api-docs': patch -'@backstage/plugin-apollo-explorer': patch -'@backstage/plugin-app-backend': patch -'@backstage/plugin-auth-backend': patch -'@backstage/plugin-auth-node': patch -'@backstage/plugin-azure-devops-backend': patch -'@backstage/plugin-azure-devops': patch -'@backstage/plugin-badges': patch -'@backstage/plugin-bitbucket-cloud-common': patch -'@backstage/plugin-bitrise': patch -'@backstage/plugin-catalog-backend-module-azure': patch -'@backstage/plugin-catalog-backend-module-bitbucket-cloud': patch -'@backstage/plugin-catalog-backend-module-bitbucket-server': patch -'@backstage/plugin-catalog-backend-module-bitbucket': patch -'@backstage/plugin-catalog-backend-module-gerrit': patch -'@backstage/plugin-catalog-backend-module-github': patch -'@backstage/plugin-catalog-backend-module-gitlab': patch -'@backstage/plugin-catalog-backend-module-msgraph': patch -'@backstage/plugin-catalog-backend': patch -'@backstage/plugin-catalog-graphql': patch -'@backstage/plugin-catalog-import': patch -'@backstage/plugin-circleci': patch -'@backstage/plugin-cloudbuild': patch -'@backstage/plugin-code-climate': patch -'@backstage/plugin-code-coverage-backend': patch -'@backstage/plugin-code-coverage': patch -'@backstage/plugin-codescene': patch -'@backstage/plugin-config-schema': patch -'@backstage/plugin-cost-insights': patch -'@backstage/plugin-dynatrace': patch -'@backstage/plugin-explore-react': patch -'@backstage/plugin-explore': patch -'@backstage/plugin-firehydrant': patch -'@backstage/plugin-fossa': patch -'@backstage/plugin-gcalendar': patch -'@backstage/plugin-gcp-projects': patch -'@backstage/plugin-git-release-manager': patch -'@backstage/plugin-github-actions': patch -'@backstage/plugin-github-deployments': patch -'@backstage/plugin-github-issues': patch -'@backstage/plugin-github-pull-requests-board': patch -'@backstage/plugin-gitops-profiles': patch -'@backstage/plugin-gocd': patch -'@backstage/plugin-graphiql': patch -'@backstage/plugin-graphql-backend': patch -'@backstage/plugin-home': patch -'@backstage/plugin-ilert': patch -'@backstage/plugin-jenkins-backend': patch -'@backstage/plugin-jenkins': patch -'@backstage/plugin-kafka': patch -'@backstage/plugin-kubernetes': patch -'@backstage/plugin-lighthouse': patch -'@backstage/plugin-newrelic': patch -'@backstage/plugin-org': patch -'@backstage/plugin-pagerduty': patch -'@backstage/plugin-periskop-backend': patch -'@backstage/plugin-periskop': patch -'@backstage/plugin-permission-backend': patch -'@backstage/plugin-permission-common': patch -'@backstage/plugin-permission-node': patch -'@backstage/plugin-proxy-backend': patch -'@backstage/plugin-rollbar-backend': patch -'@backstage/plugin-rollbar': patch -'@backstage/plugin-scaffolder-backend-module-cookiecutter': patch -'@backstage/plugin-scaffolder-backend': patch -'@backstage/plugin-scaffolder': patch -'@backstage/plugin-search': patch -'@backstage/plugin-sentry': patch -'@backstage/plugin-shortcuts': patch -'@backstage/plugin-sonarqube-backend': patch -'@backstage/plugin-sonarqube': patch -'@backstage/plugin-splunk-on-call': patch -'@backstage/plugin-stack-overflow': patch -'@backstage/plugin-tech-insights': patch -'@backstage/plugin-tech-radar': patch -'@backstage/plugin-techdocs-addons-test-utils': patch -'@backstage/plugin-techdocs-backend': patch -'@backstage/plugin-techdocs-module-addons-contrib': patch -'@backstage/plugin-techdocs': patch -'@backstage/plugin-todo-backend': patch -'@backstage/plugin-todo': patch -'@backstage/plugin-user-settings': patch -'@backstage/plugin-vault-backend': patch -'@backstage/plugin-vault': patch -'@backstage/plugin-xcmetrics': patch ---- - -Updated dependency `msw` to `^0.47.0`. diff --git a/.changeset/renovate-2925783.md b/.changeset/renovate-2925783.md deleted file mode 100644 index 0dffcb1b15..0000000000 --- a/.changeset/renovate-2925783.md +++ /dev/null @@ -1,108 +0,0 @@ ---- -'@backstage/backend-common': patch -'@backstage/backend-test-utils': patch -'@backstage/catalog-client': patch -'@backstage/cli': patch -'@backstage/config-loader': patch -'@backstage/core-app-api': patch -'@backstage/core-components': patch -'@backstage/core-plugin-api': patch -'@backstage/integration-react': patch -'@backstage/integration': patch -'@backstage/release-manifests': patch -'@backstage/test-utils': patch -'@backstage/plugin-adr-backend': patch -'@backstage/plugin-adr': patch -'@backstage/plugin-airbrake-backend': patch -'@backstage/plugin-airbrake': patch -'@backstage/plugin-allure': patch -'@backstage/plugin-analytics-module-ga': patch -'@backstage/plugin-apache-airflow': patch -'@backstage/plugin-api-docs': patch -'@backstage/plugin-apollo-explorer': patch -'@backstage/plugin-app-backend': patch -'@backstage/plugin-auth-backend': patch -'@backstage/plugin-auth-node': patch -'@backstage/plugin-azure-devops-backend': patch -'@backstage/plugin-azure-devops': patch -'@backstage/plugin-badges': patch -'@backstage/plugin-bitbucket-cloud-common': patch -'@backstage/plugin-bitrise': patch -'@backstage/plugin-catalog-backend-module-azure': patch -'@backstage/plugin-catalog-backend-module-bitbucket-cloud': patch -'@backstage/plugin-catalog-backend-module-bitbucket-server': patch -'@backstage/plugin-catalog-backend-module-bitbucket': patch -'@backstage/plugin-catalog-backend-module-gerrit': patch -'@backstage/plugin-catalog-backend-module-github': patch -'@backstage/plugin-catalog-backend-module-gitlab': patch -'@backstage/plugin-catalog-backend-module-msgraph': patch -'@backstage/plugin-catalog-backend': patch -'@backstage/plugin-catalog-graphql': patch -'@backstage/plugin-catalog-import': patch -'@backstage/plugin-circleci': patch -'@backstage/plugin-cloudbuild': patch -'@backstage/plugin-code-climate': patch -'@backstage/plugin-code-coverage-backend': patch -'@backstage/plugin-code-coverage': patch -'@backstage/plugin-codescene': patch -'@backstage/plugin-config-schema': patch -'@backstage/plugin-cost-insights': patch -'@backstage/plugin-dynatrace': patch -'@backstage/plugin-explore-react': patch -'@backstage/plugin-explore': patch -'@backstage/plugin-firehydrant': patch -'@backstage/plugin-fossa': patch -'@backstage/plugin-gcalendar': patch -'@backstage/plugin-gcp-projects': patch -'@backstage/plugin-git-release-manager': patch -'@backstage/plugin-github-actions': patch -'@backstage/plugin-github-deployments': patch -'@backstage/plugin-github-issues': patch -'@backstage/plugin-github-pull-requests-board': patch -'@backstage/plugin-gitops-profiles': patch -'@backstage/plugin-gocd': patch -'@backstage/plugin-graphiql': patch -'@backstage/plugin-graphql-backend': patch -'@backstage/plugin-home': patch -'@backstage/plugin-ilert': patch -'@backstage/plugin-jenkins-backend': patch -'@backstage/plugin-jenkins': patch -'@backstage/plugin-kafka': patch -'@backstage/plugin-kubernetes': patch -'@backstage/plugin-lighthouse': patch -'@backstage/plugin-newrelic': patch -'@backstage/plugin-org': patch -'@backstage/plugin-pagerduty': patch -'@backstage/plugin-periskop-backend': patch -'@backstage/plugin-periskop': patch -'@backstage/plugin-permission-backend': patch -'@backstage/plugin-permission-common': patch -'@backstage/plugin-permission-node': patch -'@backstage/plugin-proxy-backend': patch -'@backstage/plugin-rollbar-backend': patch -'@backstage/plugin-rollbar': patch -'@backstage/plugin-scaffolder-backend-module-cookiecutter': patch -'@backstage/plugin-scaffolder-backend': patch -'@backstage/plugin-scaffolder': patch -'@backstage/plugin-search': patch -'@backstage/plugin-sentry': patch -'@backstage/plugin-shortcuts': patch -'@backstage/plugin-sonarqube-backend': patch -'@backstage/plugin-sonarqube': patch -'@backstage/plugin-splunk-on-call': patch -'@backstage/plugin-stack-overflow': patch -'@backstage/plugin-tech-insights': patch -'@backstage/plugin-tech-radar': patch -'@backstage/plugin-techdocs-addons-test-utils': patch -'@backstage/plugin-techdocs-backend': patch -'@backstage/plugin-techdocs-module-addons-contrib': patch -'@backstage/plugin-techdocs': patch -'@backstage/plugin-todo-backend': patch -'@backstage/plugin-todo': patch -'@backstage/plugin-user-settings': patch -'@backstage/plugin-vault-backend': patch -'@backstage/plugin-vault': patch -'@backstage/plugin-xcmetrics': patch ---- - -Updated dependency `msw` to `^0.46.0`. diff --git a/.changeset/renovate-4f0c2e3.md b/.changeset/renovate-4f0c2e3.md deleted file mode 100644 index 0aab9dc9a6..0000000000 --- a/.changeset/renovate-4f0c2e3.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -'@backstage/cli': minor ---- - -Updated dependency `eslint-plugin-jest` to `^27.0.0`. - -Note that this major update to the Jest plugin contains some breaking changes. -This means that some of your tests may start seeing some new lint errors. [Read -about them -here](https://github.com/jest-community/eslint-plugin-jest/blob/main/CHANGELOG.md#2700-2022-08-28). - -These are mostly possible to fix automatically. You can try to run `yarn backstage-cli repo lint --fix` in your repo root to have most or all of them -corrected. diff --git a/.changeset/renovate-58c2860.md b/.changeset/renovate-58c2860.md deleted file mode 100644 index a03ccdf6f8..0000000000 --- a/.changeset/renovate-58c2860.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-jenkins-backend': patch ---- - -Updated dependency `jenkins` to `^1.0.0`. diff --git a/.changeset/renovate-7d3b357.md b/.changeset/renovate-7d3b357.md deleted file mode 100644 index bdb86d12c2..0000000000 --- a/.changeset/renovate-7d3b357.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder': patch ---- - -Updated dependency `json-schema-library` to `^7.0.0`. diff --git a/.changeset/renovate-a02d90b.md b/.changeset/renovate-a02d90b.md new file mode 100644 index 0000000000..7bb69d9988 --- /dev/null +++ b/.changeset/renovate-a02d90b.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-api-docs': patch +--- + +Updated dependency `@asyncapi/react-component` to `1.0.0-next.42`. diff --git a/.changeset/renovate-c98c336.md b/.changeset/renovate-c98c336.md deleted file mode 100644 index b2139cfe20..0000000000 --- a/.changeset/renovate-c98c336.md +++ /dev/null @@ -1,108 +0,0 @@ ---- -'@backstage/backend-common': patch -'@backstage/backend-test-utils': patch -'@backstage/catalog-client': patch -'@backstage/cli': patch -'@backstage/config-loader': patch -'@backstage/core-app-api': patch -'@backstage/core-components': patch -'@backstage/core-plugin-api': patch -'@backstage/integration-react': patch -'@backstage/integration': patch -'@backstage/release-manifests': patch -'@backstage/test-utils': patch -'@backstage/plugin-adr-backend': patch -'@backstage/plugin-adr': patch -'@backstage/plugin-airbrake-backend': patch -'@backstage/plugin-airbrake': patch -'@backstage/plugin-allure': patch -'@backstage/plugin-analytics-module-ga': patch -'@backstage/plugin-apache-airflow': patch -'@backstage/plugin-api-docs': patch -'@backstage/plugin-apollo-explorer': patch -'@backstage/plugin-app-backend': patch -'@backstage/plugin-auth-backend': patch -'@backstage/plugin-auth-node': patch -'@backstage/plugin-azure-devops-backend': patch -'@backstage/plugin-azure-devops': patch -'@backstage/plugin-badges': patch -'@backstage/plugin-bitbucket-cloud-common': patch -'@backstage/plugin-bitrise': patch -'@backstage/plugin-catalog-backend-module-azure': patch -'@backstage/plugin-catalog-backend-module-bitbucket-cloud': patch -'@backstage/plugin-catalog-backend-module-bitbucket-server': patch -'@backstage/plugin-catalog-backend-module-bitbucket': patch -'@backstage/plugin-catalog-backend-module-gerrit': patch -'@backstage/plugin-catalog-backend-module-github': patch -'@backstage/plugin-catalog-backend-module-gitlab': patch -'@backstage/plugin-catalog-backend-module-msgraph': patch -'@backstage/plugin-catalog-backend': patch -'@backstage/plugin-catalog-graphql': patch -'@backstage/plugin-catalog-import': patch -'@backstage/plugin-circleci': patch -'@backstage/plugin-cloudbuild': patch -'@backstage/plugin-code-climate': patch -'@backstage/plugin-code-coverage-backend': patch -'@backstage/plugin-code-coverage': patch -'@backstage/plugin-codescene': patch -'@backstage/plugin-config-schema': patch -'@backstage/plugin-cost-insights': patch -'@backstage/plugin-dynatrace': patch -'@backstage/plugin-explore-react': patch -'@backstage/plugin-explore': patch -'@backstage/plugin-firehydrant': patch -'@backstage/plugin-fossa': patch -'@backstage/plugin-gcalendar': patch -'@backstage/plugin-gcp-projects': patch -'@backstage/plugin-git-release-manager': patch -'@backstage/plugin-github-actions': patch -'@backstage/plugin-github-deployments': patch -'@backstage/plugin-github-issues': patch -'@backstage/plugin-github-pull-requests-board': patch -'@backstage/plugin-gitops-profiles': patch -'@backstage/plugin-gocd': patch -'@backstage/plugin-graphiql': patch -'@backstage/plugin-graphql-backend': patch -'@backstage/plugin-home': patch -'@backstage/plugin-ilert': patch -'@backstage/plugin-jenkins-backend': patch -'@backstage/plugin-jenkins': patch -'@backstage/plugin-kafka': patch -'@backstage/plugin-kubernetes': patch -'@backstage/plugin-lighthouse': patch -'@backstage/plugin-newrelic': patch -'@backstage/plugin-org': patch -'@backstage/plugin-pagerduty': patch -'@backstage/plugin-periskop-backend': patch -'@backstage/plugin-periskop': patch -'@backstage/plugin-permission-backend': patch -'@backstage/plugin-permission-common': patch -'@backstage/plugin-permission-node': patch -'@backstage/plugin-proxy-backend': patch -'@backstage/plugin-rollbar-backend': patch -'@backstage/plugin-rollbar': patch -'@backstage/plugin-scaffolder-backend-module-cookiecutter': patch -'@backstage/plugin-scaffolder-backend': patch -'@backstage/plugin-scaffolder': patch -'@backstage/plugin-search': patch -'@backstage/plugin-sentry': patch -'@backstage/plugin-shortcuts': patch -'@backstage/plugin-sonarqube-backend': patch -'@backstage/plugin-sonarqube': patch -'@backstage/plugin-splunk-on-call': patch -'@backstage/plugin-stack-overflow': patch -'@backstage/plugin-tech-insights': patch -'@backstage/plugin-tech-radar': patch -'@backstage/plugin-techdocs-addons-test-utils': patch -'@backstage/plugin-techdocs-backend': patch -'@backstage/plugin-techdocs-module-addons-contrib': patch -'@backstage/plugin-techdocs': patch -'@backstage/plugin-todo-backend': patch -'@backstage/plugin-todo': patch -'@backstage/plugin-user-settings': patch -'@backstage/plugin-vault-backend': patch -'@backstage/plugin-vault': patch -'@backstage/plugin-xcmetrics': patch ---- - -Updated dependency `msw` to `^0.45.0`. diff --git a/.changeset/renovate-dbf54c0.md b/.changeset/renovate-dbf54c0.md deleted file mode 100644 index 5ddae2f31e..0000000000 --- a/.changeset/renovate-dbf54c0.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-search-backend-module-elasticsearch': patch ---- - -Updated dependency `aws-os-connection` to `^0.2.0`. diff --git a/.changeset/renovate-f18a0fc.md b/.changeset/renovate-f18a0fc.md deleted file mode 100644 index 6f17cb8c0f..0000000000 --- a/.changeset/renovate-f18a0fc.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Updated dependency `@types/minimatch` to `^5.0.0`. diff --git a/.changeset/rich-carrots-reflect.md b/.changeset/rich-carrots-reflect.md new file mode 100644 index 0000000000..13a67bcd56 --- /dev/null +++ b/.changeset/rich-carrots-reflect.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Switched the Jest transform for YAML files to use a custom one available at `@backstage/cli/config/jestYamlTransform.js`. diff --git a/.changeset/rich-cooks-camp.md b/.changeset/rich-cooks-camp.md deleted file mode 100644 index 04d86033f7..0000000000 --- a/.changeset/rich-cooks-camp.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-backend': patch ---- - -Cloudflare Access Provider: Add JWT to CloudflareAccessResult diff --git a/.changeset/rich-melons-compete.md b/.changeset/rich-melons-compete.md deleted file mode 100644 index 68297159f7..0000000000 --- a/.changeset/rich-melons-compete.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-gcalendar': patch ---- - -Upgrade `react-query:3` to `@tanstack/react-query:4` diff --git a/.changeset/rotten-books-crash.md b/.changeset/rotten-books-crash.md deleted file mode 100644 index b0c020a743..0000000000 --- a/.changeset/rotten-books-crash.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/dev-utils': patch ---- - -Removed the dependency and setup of `react-hot-loader`, since the `@backstage/cli` now uses `swc` with `React Refresh` instead. diff --git a/.changeset/rude-books-rush.md b/.changeset/rude-books-rush.md deleted file mode 100644 index a98e90e27e..0000000000 --- a/.changeset/rude-books-rush.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@backstage/backend-tasks': patch -'@backstage/plugin-app-backend': patch -'@backstage/plugin-bazaar-backend': patch -'@backstage/plugin-code-coverage-backend': patch -'@backstage/plugin-tech-insights-backend': patch ---- - -Fixed a bug where the database option to skip migrations was ignored. diff --git a/.changeset/rude-bulldogs-sleep.md b/.changeset/rude-bulldogs-sleep.md new file mode 100644 index 0000000000..8a2a0590b3 --- /dev/null +++ b/.changeset/rude-bulldogs-sleep.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Allow Placeholder value to be any value, not only string. diff --git a/.changeset/rude-tips-argue.md b/.changeset/rude-tips-argue.md deleted file mode 100644 index a66e0935b9..0000000000 --- a/.changeset/rude-tips-argue.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/integration': patch ---- - -Fixed bug in the `bitbucketServer` integration where token did not take precedence over supplied username and password which is described in the documentation. diff --git a/.changeset/rude-weeks-retire.md b/.changeset/rude-weeks-retire.md deleted file mode 100644 index c2073c5826..0000000000 --- a/.changeset/rude-weeks-retire.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': minor ---- - -Added the `refresh` function to the Connection of the entity providers. diff --git a/.changeset/search-feet-flash.md b/.changeset/search-feet-flash.md deleted file mode 100644 index c7423f0317..0000000000 --- a/.changeset/search-feet-flash.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -'@backstage/plugin-search-react': minor ---- - -Provides search autocomplete functionality through a `SearchAutocomplete` component. -A `SearchAutocompleteDefaultOption` can also be used to render options with icons, primary texts, and secondary texts. -Example: - -```jsx -import React, { ChangeEvent, useState, useCallback } from 'react'; -import useAsync from 'react-use/lib/useAsync'; - -import { Grid, Paper } from '@material-ui/core'; - -import { Page, Content } from '@backstage/core-components'; -import { SearchAutocomplete, SearchAutocompleteDefaultOption} from '@backstage/plugin-search-react'; - -const OptionsIcon = () => - -const SearchPage = () => { - const [inputValue, setInputValue] = useState(''); - - const options = useAsync(async () => { - // Gets and returns autocomplete options - }, [inputValue]) - - const useCallback((_event: ChangeEvent<{}>, newInputValue: string) => { - setInputValue(newInputValue); - }, [setInputValue]) - - return ( - - - - - - option.title} - renderOption={option => ( - } - primaryText={option.title} - secondaryText={option.text} - /> - )} - /> - - - - {'/* Filters and results are omitted */'} - - - ); -}; -``` diff --git a/.changeset/search-planets-flash.md b/.changeset/search-planets-flash.md deleted file mode 100644 index 49431128f9..0000000000 --- a/.changeset/search-planets-flash.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-search': patch ---- - -Use the new `inheritParentContextIfAvailable` search context property in `SearchModal` instead of manually checking if a parent context exists, this conditional statement was previously duplicated in more than one component like in `SearchBar` as well and is now only done in ` SearchContextProvider`. diff --git a/.changeset/search-zebras-tap.md b/.changeset/search-zebras-tap.md deleted file mode 100644 index 4593478a51..0000000000 --- a/.changeset/search-zebras-tap.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-search-react': minor ---- - -We noticed a repeated check for the existence of a parent context before creating a child search context in more the one component such as Search Modal and Search Bar and to remove code duplication we extract the conditional to the context provider, now you can use it passing an `inheritParentContextIfAvailable` prop to the `SearchContextProvider`. - -Note: This added property does not create a local context if there is a parent context and in this case, you cannot use it together with `initialState`, it will result in a type error because the parent context is already initialized. diff --git a/.changeset/selfish-wasps-cough.md b/.changeset/selfish-wasps-cough.md deleted file mode 100644 index cc00520385..0000000000 --- a/.changeset/selfish-wasps-cough.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Added `yarn new` as one of the scripts installed by default, which calls `backstage-cli new`. This script replaces `create-plugin`, which you can now remove if you want to. It is kept in the `create-app` template for backwards compatibility. - -The `remove-plugin` command has been removed, as it has been removed from the Backstage CLI. - -To apply these changes to an existing app, make the following change to the root `package.json`: - -```diff -- "remove-plugin": "backstage-cli remove-plugin" -+ "new": "backstage-cli new --scope internal" -``` diff --git a/.changeset/shaggy-books-smell.md b/.changeset/shaggy-books-smell.md new file mode 100644 index 0000000000..3f8aaa389c --- /dev/null +++ b/.changeset/shaggy-books-smell.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-tech-insights-node': patch +--- + +Updated package role to be `node-library`. diff --git a/.changeset/shaggy-chicken-behave.md b/.changeset/shaggy-chicken-behave.md deleted file mode 100644 index 41445b0930..0000000000 --- a/.changeset/shaggy-chicken-behave.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': minor -'@backstage/plugin-scaffolder-common': minor ---- - -add entity metadata to the template info type diff --git a/.changeset/shaggy-vans-repeat.md b/.changeset/shaggy-vans-repeat.md deleted file mode 100644 index fd865c702c..0000000000 --- a/.changeset/shaggy-vans-repeat.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -The options part of `DatabaseManager.fromConfig` now accepts an optional logger -field. You may want to supply that logger in your backend initialization code to -ensure that you can get relevant logging data when things happen related to the -connection pool. - -In `packages/backend/src/index.ts`: - -```diff - function makeCreateEnv(config: Config) { - const root = getRootLogger(); - ... -- const databaseManager = DatabaseManager.fromConfig(config); -+ const databaseManager = DatabaseManager.fromConfig(config, { logger: root }); -``` diff --git a/.changeset/sharp-swans-suffer.md b/.changeset/sharp-swans-suffer.md deleted file mode 100644 index 841d746634..0000000000 --- a/.changeset/sharp-swans-suffer.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder': minor ---- - -Added support for `async` validation for the `next` version of the plugin diff --git a/.changeset/shiny-lobsters-fix.md b/.changeset/shiny-lobsters-fix.md deleted file mode 100644 index 99e255acbe..0000000000 --- a/.changeset/shiny-lobsters-fix.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -'@backstage/plugin-azure-devops-backend': patch ---- - -`createRouter` now requires an additional reader: `UrlReader` argument - -```diff -export default async function createPlugin( - env: PluginEnvironment, -): Promise { - return createRouter({ - logger: env.logger, - config: env.config, -+ reader: env.reader, - }); -} -``` - -Remember to check if you have already provided these settings previously. - -#### [Azure DevOps] - -```yaml -# app-config.yaml -azureDevOps: - host: dev.azure.com - token: my-token - organization: my-company -``` - -#### [Azure Integrations] - -```yaml -# app-config.yaml -integrations: - azure: - - host: dev.azure.com - token: ${AZURE_TOKEN} -``` diff --git a/.changeset/shiny-ties-leave.md b/.changeset/shiny-ties-leave.md deleted file mode 100644 index 8e146e9af1..0000000000 --- a/.changeset/shiny-ties-leave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-github': patch ---- - -Add support for including (or excluding) Github repositories by topic diff --git a/.changeset/shiny-walls-kiss.md b/.changeset/shiny-walls-kiss.md deleted file mode 100644 index 0f13acb154..0000000000 --- a/.changeset/shiny-walls-kiss.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-stack-overflow': patch ---- - -Create a front end API. diff --git a/.changeset/short-mice-explode.md b/.changeset/short-mice-explode.md deleted file mode 100644 index 42ebfa9f5c..0000000000 --- a/.changeset/short-mice-explode.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-plugin-api': patch ---- - -The `createServiceFactory` method has been updated to return a higher-order factory that can accept options. diff --git a/.changeset/silent-kings-live.md b/.changeset/silent-kings-live.md deleted file mode 100644 index 7e55f5ae78..0000000000 --- a/.changeset/silent-kings-live.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Removed the depreacated `publish:file` action, use the template editor to test templates instead. diff --git a/.changeset/slimy-stingrays-type.md b/.changeset/slimy-stingrays-type.md deleted file mode 100644 index 9c520cf1d0..0000000000 --- a/.changeset/slimy-stingrays-type.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder': patch ---- - -fix uiSchema generation when using complex dependencies diff --git a/.changeset/slimy-zebras-reply.md b/.changeset/slimy-zebras-reply.md deleted file mode 100644 index 5b309f5129..0000000000 --- a/.changeset/slimy-zebras-reply.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-ldap': patch ---- - -Now the `searchStream` method in LDAP client awaits the callbacks diff --git a/.changeset/slow-phones-count.md b/.changeset/slow-phones-count.md deleted file mode 100644 index ce2f9c8432..0000000000 --- a/.changeset/slow-phones-count.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-app-api': patch ---- - -Updated service implementations and backend wiring to support scoped service. diff --git a/.changeset/small-lemons-brake.md b/.changeset/small-lemons-brake.md deleted file mode 100644 index ac7906fc28..0000000000 --- a/.changeset/small-lemons-brake.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': patch ---- - -Include entity ref into error message when catalog policies fail diff --git a/.changeset/small-walls-promise.md b/.changeset/small-walls-promise.md deleted file mode 100644 index 0455b0d776..0000000000 --- a/.changeset/small-walls-promise.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-tech-insights-backend': patch ---- - -Changed the description of the `techdocsAnnotationFactName` fact. diff --git a/.changeset/smart-sloths-search.md b/.changeset/smart-sloths-search.md deleted file mode 100644 index 542928debc..0000000000 --- a/.changeset/smart-sloths-search.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-auth-backend': minor ---- - -The auth0 integration is updated to use the `passport-auth0` library. The configuration under `auth.providers.auth0.\*` now supports an optional `audience` parameter; providing that allows you to connect to the correct API to get permissions, access tokens, and full profile information. - -[What is an Audience](https://community.auth0.com/t/what-is-the-audience/71414) diff --git a/.changeset/smart-squids-change.md b/.changeset/smart-squids-change.md deleted file mode 100644 index 51396114c9..0000000000 --- a/.changeset/smart-squids-change.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Added a new `backstage-cli repo clean` command that cleans the repo root and runs the clean script in all packages. diff --git a/.changeset/smooth-yaks-hug.md b/.changeset/smooth-yaks-hug.md deleted file mode 100644 index d93176540f..0000000000 --- a/.changeset/smooth-yaks-hug.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-github': patch ---- - -Added the ability to configure the host for the `GitHubEntityProvider` to use against GitHub Enterprise diff --git a/.changeset/soft-falcons-love.md b/.changeset/soft-falcons-love.md new file mode 100644 index 0000000000..56ed193501 --- /dev/null +++ b/.changeset/soft-falcons-love.md @@ -0,0 +1,11 @@ +--- +'@backstage/plugin-user-settings': minor +--- + +**BREAKING**: The `apiRef` passed to `ProviderSettingsItem` now needs to +implement `ProfileInfoApi & SessionApi`, rather than just the latter. This is +unlikely to have an effect on most users though, since the builtin auth +providers generally implement both. + +Fixed settings page showing providers as logged out when the user is using more +than one provider, and displayed some additional login information. diff --git a/.changeset/spicy-cherries-remember.md b/.changeset/spicy-cherries-remember.md deleted file mode 100644 index c742c7a1e8..0000000000 --- a/.changeset/spicy-cherries-remember.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/backend-app-api': patch -'@backstage/backend-defaults': patch -'@backstage/backend-test-utils': patch ---- - -Updated usages of `ServiceFactory`. diff --git a/.changeset/spotty-points-build.md b/.changeset/spotty-points-build.md deleted file mode 100644 index ffed46163d..0000000000 --- a/.changeset/spotty-points-build.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': patch ---- - -Limit the length of error messages that get written to the database and logs - to prevent performance issues diff --git a/.changeset/strong-games-kiss.md b/.changeset/strong-games-kiss.md deleted file mode 100644 index a5f6d5f864..0000000000 --- a/.changeset/strong-games-kiss.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': patch -'@backstage/plugin-catalog-node': patch ---- - -The experimental `CatalogProcessingExtensionPoint` now accepts multiple providers and processors at once. diff --git a/.changeset/strong-planes-return.md b/.changeset/strong-planes-return.md deleted file mode 100644 index 5b5648528a..0000000000 --- a/.changeset/strong-planes-return.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-tech-insights-backend': patch -'@backstage/plugin-tech-insights-node': patch ---- - -Support for timeout in FactRetrieverRegistrationOptions diff --git a/.changeset/stupid-pigs-appear.md b/.changeset/stupid-pigs-appear.md deleted file mode 100644 index bd34f984d1..0000000000 --- a/.changeset/stupid-pigs-appear.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Added alpha `scaffolderPlugin` to be used with experimental backend system. diff --git a/.changeset/sweet-fishes-taste.md b/.changeset/sweet-fishes-taste.md deleted file mode 100644 index 8d1fcfc790..0000000000 --- a/.changeset/sweet-fishes-taste.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-github-pull-requests-board': patch ---- - -Add optional `pullRequestLimit` prop to `EntityTeamPullRequestsCard` and `EntityTeamPullRequestsContent` to limit the number of PRs shown per repository. Excluding this prop will default the number of pull requests shown to 10 per repository (the existing functionality). diff --git a/.changeset/sweet-grapes-explain.md b/.changeset/sweet-grapes-explain.md deleted file mode 100644 index 014fbb3d41..0000000000 --- a/.changeset/sweet-grapes-explain.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/integration': patch ---- - -Improved caching around github app tokens. -Tokens are now cached for 50 minutes, not 10. -Calls to get app installations are also included in this cache. -If you have more than one github app configured, consider adding `allowedInstallationOwners` to your apps configuration to gain the most benefit from these performance changes. diff --git a/.changeset/sweet-insects-camp.md b/.changeset/sweet-insects-camp.md new file mode 100644 index 0000000000..4f91a196e8 --- /dev/null +++ b/.changeset/sweet-insects-camp.md @@ -0,0 +1,11 @@ +--- +'@backstage/cli': minor +--- + +**BREAKING**: Bumped `jest`, `jest-runtime`, and `jest-environment-jsdom` to v29. This is up from v27, so check out both the [v28](https://jestjs.io/docs/28.x/upgrading-to-jest28) and [v29](https://jestjs.io/docs/upgrading-to-jest29) (later [here](https://jestjs.io/docs/29.x/upgrading-to-jest29)) migration guides. + +Particular changes that where encountered in the main Backstage repo are: + +- The updated snapshot format. +- `jest.useFakeTimers('legacy')` is now `jest.useFakeTimers({ legacyFakeTimers: true })`. +- Error objects collected by `withLogCollector` from `@backstage/test-utils` are now objects with a `detail` property rather than a string. diff --git a/.changeset/swift-readers-sin.md b/.changeset/swift-readers-sin.md deleted file mode 100644 index 05bd05a94c..0000000000 --- a/.changeset/swift-readers-sin.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -Allow custom images in the empty state component diff --git a/.changeset/tall-trains-remain.md b/.changeset/tall-trains-remain.md deleted file mode 100644 index 9a94672656..0000000000 --- a/.changeset/tall-trains-remain.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-app-api': patch ---- - -Updated `FlatRoutes` to be compatible with React Router v6 stable. diff --git a/.changeset/tame-papayas-protect.md b/.changeset/tame-papayas-protect.md deleted file mode 100644 index 9a0266748a..0000000000 --- a/.changeset/tame-papayas-protect.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-plugin-api': patch ---- - -When defining a new `ServiceRef` you can now also include a `defaultFactory`, which will be used to construct instances of the service in case there is no explicit factory defined. diff --git a/.changeset/tame-socks-sniff.md b/.changeset/tame-socks-sniff.md deleted file mode 100644 index b6cca23380..0000000000 --- a/.changeset/tame-socks-sniff.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/app-defaults': patch -'@backstage/test-utils': patch ---- - -Add missing peer dependencies diff --git a/.changeset/tame-trainers-rule.md b/.changeset/tame-trainers-rule.md deleted file mode 100644 index c51eb868d4..0000000000 --- a/.changeset/tame-trainers-rule.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Disable octokit throttling in publish:github:pull-request diff --git a/.changeset/tasty-clouds-cover.md b/.changeset/tasty-clouds-cover.md deleted file mode 100644 index 8cc703c822..0000000000 --- a/.changeset/tasty-clouds-cover.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Added dependency on `@types/jest` v27. The `@types/jest` dependency has also been removed from the plugin template and should be removed from any of your own internal packages. If you wish to override the version of `@types/jest` or `jest`, use Yarn resolutions. diff --git a/.changeset/techdocs-feet-dress.md b/.changeset/techdocs-feet-dress.md deleted file mode 100644 index d2b2a625af..0000000000 --- a/.changeset/techdocs-feet-dress.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs': patch ---- - -Use the new `SearchAutocomplete` component in the `TechDocsSearch` component to maintain consistency across search experiences and avoid code duplication. diff --git a/.changeset/techdocs-jeans-wait.md b/.changeset/techdocs-jeans-wait.md deleted file mode 100644 index b4d9007754..0000000000 --- a/.changeset/techdocs-jeans-wait.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs': patch ---- - -Always update the title and sub-title when the location changes on a `TechDocs` reader page. diff --git a/.changeset/tender-ladybugs-relax.md b/.changeset/tender-ladybugs-relax.md deleted file mode 100644 index 2aefa09dc0..0000000000 --- a/.changeset/tender-ladybugs-relax.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-stack-overflow': patch ---- - -Support showing HTML entity references from the API response before rendering the question title to the list component. diff --git a/.changeset/tender-pumpkins-burn.md b/.changeset/tender-pumpkins-burn.md deleted file mode 100644 index e431614707..0000000000 --- a/.changeset/tender-pumpkins-burn.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs': patch ---- - -Fixed a bug where scrolling for anchors where the id starts with number didn't work for the current page. diff --git a/.changeset/thin-cows-watch.md b/.changeset/thin-cows-watch.md deleted file mode 100644 index 675a27769b..0000000000 --- a/.changeset/thin-cows-watch.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-permission-backend': patch -'@backstage/plugin-scaffolder-backend': patch ---- - -Uptake the `IdentityApi` change to use `getIdentity` instead of `authenticate` for retrieving the logged in users identity. diff --git a/.changeset/tiny-mails-bathe.md b/.changeset/tiny-mails-bathe.md new file mode 100644 index 0000000000..868c2a8d36 --- /dev/null +++ b/.changeset/tiny-mails-bathe.md @@ -0,0 +1,14 @@ +--- +'@backstage/create-app': patch +--- + +Updated the root `test` scripts to use `backstage-cli repo test`. + +To apply this change to an existing app, make the following change to the root `package.json`: + +```diff +- "test": "backstage-cli test", +- "test:all": "lerna run test -- --coverage", ++ "test": "backstage-cli repo test", ++ "test:all": "backstage-cli repo test --coverage", +``` diff --git a/.changeset/tiny-oranges-thank.md b/.changeset/tiny-oranges-thank.md deleted file mode 100644 index 179aeea1c4..0000000000 --- a/.changeset/tiny-oranges-thank.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-tech-insights-backend': patch ---- - -Modify Tech insight initialization to expose FactRetrieverEngine. Enables users to trigger fact retrieval manually or reschedule retrievers on runtime. diff --git a/.changeset/tiny-rocks-flash.md b/.changeset/tiny-rocks-flash.md deleted file mode 100644 index 32b467a6af..0000000000 --- a/.changeset/tiny-rocks-flash.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-app-api': patch ---- - -Improved error messaging when failing to instantiate services. diff --git a/.changeset/tough-dolphins-smile.md b/.changeset/tough-dolphins-smile.md deleted file mode 100644 index bb4f0a39a8..0000000000 --- a/.changeset/tough-dolphins-smile.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -'@backstage/catalog-client': patch -'@backstage/core-plugin-api': patch -'@backstage/plugin-api-docs': patch -'@backstage/plugin-apollo-explorer': patch -'@backstage/plugin-azure-devops-backend': patch -'@backstage/plugin-badges': patch -'@backstage/plugin-badges-backend': patch -'@backstage/plugin-catalog-react': patch -'@backstage/plugin-circleci': patch -'@backstage/plugin-cloudbuild': patch -'@backstage/plugin-kubernetes': patch -'@backstage/plugin-scaffolder-backend': patch -'@backstage/plugin-search-backend-module-elasticsearch': patch -'@backstage/plugin-sonarqube-backend': patch -'@backstage/plugin-techdocs': patch ---- - -Minor API signatures cleanup diff --git a/.changeset/twenty-dolls-smoke.md b/.changeset/twenty-dolls-smoke.md deleted file mode 100644 index 7456bd5557..0000000000 --- a/.changeset/twenty-dolls-smoke.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-common': patch ---- - -Workaround for a rare race condition in tests. diff --git a/.changeset/two-planets-provide.md b/.changeset/two-planets-provide.md deleted file mode 100644 index 920eebc01d..0000000000 --- a/.changeset/two-planets-provide.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder': minor ---- - -Implementing review step for the scaffolder under `create/next` diff --git a/.changeset/veka-fingrar-drar.md b/.changeset/veka-fingrar-drar.md deleted file mode 100644 index cff2f45919..0000000000 --- a/.changeset/veka-fingrar-drar.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -'@backstage/core-app-api': patch ---- - -If you'd like to send analytics events to multiple implementations, you may now -do so using the `MultipleAnalyticsApi` implementation provided by this package. - -```tsx -import { MultipleAnalyticsApi } from '@backstage/core-app-api'; -import { - analyticsApiRef, - configApiRef, - storageApiRef, - identityApiRef, -} from '@internal/backstage/core-plugin-api'; -import { CustomAnalyticsApi } from '@internal/analytics'; -import { VendorAnalyticsApi } from '@vendor/analytics'; - -createApiFactory({ - api: analyticsApiRef, - deps: { configApi: configApiRef, identityApi: identityApiRef, storageApi: storageApiRef }, - factory: ({ configApi, identityApi, storageApi }) => - MultipleAnalyticsApi.fromApis([ - VendorAnalyticsApi.fromConfig(configApi, { identityApi }), - CustomAnalyticsApi.fromConfig(configApi, { identityApi, storageApi }), - ]), -}), -``` diff --git a/.changeset/weak-camels-roll.md b/.changeset/weak-camels-roll.md deleted file mode 100644 index 90636605ec..0000000000 --- a/.changeset/weak-camels-roll.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Updated the root `package.json` to use the new `backstage-cli repo clean` command. - -To apply this change to an existing project, make the following change to the root `package.json`: - -```diff -- "clean": "backstage-cli clean && lerna run clean", -+ "clean": "backstage-cli repo clean", -``` diff --git a/.changeset/weak-radios-sin.md b/.changeset/weak-radios-sin.md deleted file mode 100644 index e2aac006d4..0000000000 --- a/.changeset/weak-radios-sin.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Updated `versions:bump` command to be compatible with Yarn 3. diff --git a/.changeset/weak-yaks-learn.md b/.changeset/weak-yaks-learn.md deleted file mode 100644 index 7a94e10d68..0000000000 --- a/.changeset/weak-yaks-learn.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -'@backstage/plugin-azure-devops': minor -'@backstage/plugin-azure-devops-common': minor ---- - -Added README card `EntityAzureReadmeCard` for Azure Devops. - -To get the README component working you'll need to do the following two steps: - -1. First we need to add the @backstage/plugin-azure-devops package to your frontend app: - - ```bash - # From your Backstage root directory - yarn add --cwd packages/app @backstage/plugin-azure-devops - ``` - -2. Second we need to add the `EntityAzureReadmeCard` extension to the entity page in your app: - - ```tsx - // In packages/app/src/components/catalog/EntityPage.tsx - import { - EntityAzureReadmeCard, - isAzureDevOpsAvailable, - } from '@backstage/plugin-azure-devops'; - - // As it is a card, you can customize it the way you prefer - // For example in the Service section - - const overviewContent = ( - - - - - ... - - - - - - - - ); - ``` - -**Notes:** - -- 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% diff --git a/.changeset/wild-sheep-roll.md b/.changeset/wild-sheep-roll.md deleted file mode 100644 index 1551100b2a..0000000000 --- a/.changeset/wild-sheep-roll.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/core-components': patch -'@backstage/plugin-adr': patch -'@backstage/plugin-apache-airflow': patch -'@backstage/plugin-api-docs': patch ---- - -Minor cleanup of the public API surface to reduce the number of warnings diff --git a/.changeset/witty-cats-wink.md b/.changeset/witty-cats-wink.md deleted file mode 100644 index 82f6d3098f..0000000000 --- a/.changeset/witty-cats-wink.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-msgraph': patch ---- - -Fix typo diff --git a/.changeset/witty-queens-happen.md b/.changeset/witty-queens-happen.md deleted file mode 100644 index 969bd2c79e..0000000000 --- a/.changeset/witty-queens-happen.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-adr': patch ---- - -Fix parsing of ADR location which includes a trailing slash diff --git a/.changeset/young-falcons-sleep.md b/.changeset/young-falcons-sleep.md deleted file mode 100644 index d7bcef96e6..0000000000 --- a/.changeset/young-falcons-sleep.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -The number of task workers used to execute templates now default to 3, rather than 1. diff --git a/.changeset/young-trees-rescue.md b/.changeset/young-trees-rescue.md deleted file mode 100644 index d2ea5b3aeb..0000000000 --- a/.changeset/young-trees-rescue.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Added `EntityLinksCard` to the system `EntityPage`. - -For an existing installation where you want to display the links card for entity pages of kind `system` you should make the following adjustment to `packages/app/src/components/catalog/EntityPage.tsx` - -```diff -const systemPage = ( - ... - - - -+ -+ -+ -- -+ - - - ... -); -``` diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index f00771d29d..cb1dd5d322 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -16,6 +16,8 @@ yarn.lock @backstage/reviewers @backst /docs/plugins/integrating-search-into-plugins.md @backstage/reviewers @backstage/techdocs-core /packages/techdocs-cli @backstage/reviewers @backstage/techdocs-core /packages/techdocs-cli-embedded-app @backstage/reviewers @backstage/techdocs-core +/plugins/adr @backstage/reviewers @kuangp +/plugins/adr-* @backstage/reviewers @kuangp /plugins/allure @backstage/reviewers @deepak-bhardwaj-ps /plugins/apache-airflow @backstage/reviewers @cmpadden /plugins/api-docs @backstage/reviewers @backstage/sda-se-reviewers @@ -47,6 +49,8 @@ yarn.lock @backstage/reviewers @backst /plugins/kubernetes @backstage/reviewers @backstage/warpspeed /plugins/kubernetes-* @backstage/reviewers @backstage/warpspeed /plugins/newrelic-dashboard @backstage/reviewers @mufaddal7 +/plugins/playlist @backstage/reviewers @kuangp +/plugins/playlist-* @backstage/reviewers @kuangp /plugins/scaffolder-backend-module-rails @backstage/reviewers @angeliski /plugins/scaffolder-backend-module-yeoman @backstage/reviewers @pawelmitka /plugins/search @backstage/reviewers @backstage/techdocs-core @@ -56,6 +60,7 @@ yarn.lock @backstage/reviewers @backst /plugins/stack-overflow-backend @backstage/reviewers @backstage/techdocs-core /plugins/techdocs @backstage/reviewers @backstage/techdocs-core /plugins/techdocs-* @backstage/reviewers @backstage/techdocs-core +/plugins/user-settings-backend @backstage/reviewers @backstage/sda-se-reviewers /tech-insights-backend @backstage/reviewers @xantier @iain-b /tech-insights-backend-module-jsonfc @backstage/reviewers @xantier @iain-b /tech-insights-tech-insights-common @backstage/reviewers @xantier @iain-b diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d63a8b6d77..3c6ac696e9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -197,7 +197,7 @@ jobs: - name: test changed packages if: ${{ steps.yarn-lock.outcome == 'success' }} - run: yarn lerna run test --since origin/master -- --coverage --runInBand + run: yarn backstage-cli repo test --maxWorkers=2 --workerIdleMemoryLimit=1300M --since origin/master env: BACKSTAGE_NEXT_TESTS: 1 BACKSTAGE_TEST_DISABLE_DOCKER: 1 @@ -208,7 +208,7 @@ jobs: - name: test all packages (and upload coverage) if: ${{ steps.yarn-lock.outcome == 'failure' }} run: | - yarn lerna run test -- --coverage --runInBand + yarn backstage-cli repo test --maxWorkers=2 --workerIdleMemoryLimit=1300M --coverage bash <(curl -s https://codecov.io/bash) -N $(git rev-parse FETCH_HEAD) env: BACKSTAGE_NEXT_TESTS: 1 diff --git a/.github/workflows/deploy_nightly.yml b/.github/workflows/deploy_nightly.yml index e776c47537..0432876aca 100644 --- a/.github/workflows/deploy_nightly.yml +++ b/.github/workflows/deploy_nightly.yml @@ -55,7 +55,7 @@ jobs: # not flagged as the latest release, which means that people will not get this # version of the package unless requested explicitly - name: publish nightly release - run: yarn changeset publish --tag nightly + run: yarn workspaces foreach -v --no-private npm publish --tag nightly env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/deploy_packages.yml b/.github/workflows/deploy_packages.yml index 6fa34e408f..063a6107b6 100644 --- a/.github/workflows/deploy_packages.yml +++ b/.github/workflows/deploy_packages.yml @@ -97,7 +97,7 @@ jobs: - name: test (and upload coverage) run: | - yarn lerna run test -- --coverage --runInBand + yarn backstage-cli repo test --maxWorkers=2 --workerIdleMemoryLimit=1300M --coverage bash <(curl -s https://codecov.io/bash) # Upload code coverage for some specific flags. Also see .codecov.yml bash <(curl -s https://codecov.io/bash) -f packages/core-app-api/coverage/* -F core-app-api @@ -163,9 +163,9 @@ jobs: - name: publish run: | if [ -f ".changeset/pre.json" ]; then - yarn lerna publish from-package --yes --dist-tag next + yarn workspaces foreach -v --exclude=root --no-private npm publish --tag next else - yarn lerna publish from-package --yes + yarn workspaces foreach -v --exclude=root --no-private npm publish fi env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/verify_windows.yml b/.github/workflows/verify_windows.yml index 0b12caf2fc..8bbaa645bf 100644 --- a/.github/workflows/verify_windows.yml +++ b/.github/workflows/verify_windows.yml @@ -46,7 +46,7 @@ jobs: run: yarn lint:type-deps - name: test - run: yarn lerna run test + run: yarn backstage-cli repo test --maxWorkers=2 --workerIdleMemoryLimit=1300M env: BACKSTAGE_NEXT_TESTS: 1 BACKSTAGE_TEST_DISABLE_DOCKER: 1 diff --git a/ADOPTERS.md b/ADOPTERS.md index 48c69d21bd..4378eb14f9 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -202,7 +202,7 @@ _You can do this by using the [Adopter form](https://form.typeform.com/to/zcOaKi | [Skillz](https://skillz.com/) | [Peiman Jafari](https://github.com/peimanja) | Internal developers portal for technical documentations, components ownership and relationship, software templates and integrations with internal tools | | [Telus](https://www.telus.com/en/) | [Leo Li](mailto:leo.li@telus.com), [Laurent Robichaud](mailto:laurent.robichaud@telus.com), [Seb Barre](https://github.com/sbarre) | Simplifying the developer experience through centralized team member portals. Our current focus includes the adoption of Tech Docs, Software Catalog, Software Templates, the plethora of plugins, and contributing features back to Backstage. 🤖 | | [Fidelity Investments](https://fidelity.com) | [Ankita Upadhyay](mailto:ankita.upadhyay@fmr.com) | Getting started with the adoption for Monorepo projects | -| [Verisk](https://verisk.com) | [Callen Barton](mailto:cbarton@verisk.com) | Developer portal to quickly create and deploy microservices. | +| [Verisk](https://verisk.com) | [Callen Barton](mailto:#xw_architecture@verisk.com), [Kevin Johnson](mailto:#xw_architecture@verisk.com) | Developer portal to quickly create and deploy microservices. | | [iodigital](https://iodigital.com) | [Jan-Willem Mulder](mailto:jan-willem.mulder@iodigital.com) | Internal developer portal for discovery of applications, projects and teams. Using several plugins like the Software Catalog and Tech Insights for promoting best practices and supporting our SDLC toolchain | | [Fanatics](https://www.fanaticsinc.com/) | [Rory Scott](mailto:rscott@fanatics.com) | Internal Portal consolidating documentation, making it easier to manage applications, internal developer community platform, and self-service cloud infrastructure + pipelines. | | [Appfolio](https://appfolio.com) | [Andy Vaughn](mailto:andy.vaughn@appfolio.com) | Internal software catalog, tech radar, documentation portal to disambiguate software and domain ownership, foster exploration of available developer platform services and tools, improve communication, democratize documentation and knowledge sharing, and coordinate the software lifecycle; all in service of a best-in-class developer experience. | diff --git a/app-config.yaml b/app-config.yaml index 7c93d9cbd2..22ca1fcaff 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -444,3 +444,6 @@ apacheAirflow: gocd: baseUrl: https://your.gocd.instance.com + +permission: + enabled: true diff --git a/cypress/yarn.lock b/cypress/yarn.lock index 2dae48bd39..dd9856750c 100644 --- a/cypress/yarn.lock +++ b/cypress/yarn.lock @@ -1,1131 +1,1526 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@colors/colors@1.5.0": - version "1.5.0" - resolved "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" - integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== - -"@cypress/request@^2.88.10": - version "2.88.10" - resolved "https://registry.npmjs.org/@cypress/request/-/request-2.88.10.tgz#b66d76b07f860d3a4b8d7a0604d020c662752cce" - integrity sha512-Zp7F+R93N0yZyG34GutyTNr+okam7s/Fzc1+i3kcqOP8vk6OuajuE9qZJ6Rs+10/1JFtXFYMdyarnU1rZuJesg== - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.8.0" - caseless "~0.12.0" - combined-stream "~1.0.6" - extend "~3.0.2" - forever-agent "~0.6.1" - form-data "~2.3.2" - http-signature "~1.3.6" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.19" - performance-now "^2.1.0" - qs "~6.5.2" - safe-buffer "^5.1.2" - tough-cookie "~2.5.0" - tunnel-agent "^0.6.0" - uuid "^8.3.2" - -"@cypress/xvfb@^1.2.4": - version "1.2.4" - resolved "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz#2daf42e8275b39f4aa53c14214e557bd14e7748a" - integrity sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q== - dependencies: - debug "^3.1.0" - lodash.once "^4.1.1" - -"@types/node@*": - version "18.7.14" - resolved "https://registry.npmjs.org/@types/node/-/node-18.7.14.tgz#0fe081752a3333392d00586d815485a17c2cf3c9" - integrity sha512-6bbDaETVi8oyIARulOE9qF1/Qdi/23z6emrUh0fNJRUmjznqrixD4MpGDdgOFk5Xb0m2H6Xu42JGdvAxaJR/wA== - -"@types/node@^14.14.31": - version "14.18.26" - resolved "https://registry.npmjs.org/@types/node/-/node-14.18.26.tgz#239e19f8b4ea1a9eb710528061c1d733dc561996" - integrity sha512-0b+utRBSYj8L7XAp0d+DX7lI4cSmowNaaTkk6/1SKzbKkG+doLuPusB9EOvzLJ8ahJSk03bTLIL6cWaEd4dBKA== - -"@types/sinonjs__fake-timers@8.1.1": - version "8.1.1" - resolved "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz#b49c2c70150141a15e0fa7e79cf1f92a72934ce3" - integrity sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g== - -"@types/sizzle@^2.3.2": - version "2.3.3" - resolved "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz#ff5e2f1902969d305225a047c8a0fd5c915cebef" - integrity sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ== - -"@types/yauzl@^2.9.1": - version "2.10.0" - resolved "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz#b3248295276cf8c6f153ebe6a9aba0c988cb2599" - integrity sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw== - dependencies: - "@types/node" "*" - -aggregate-error@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" - integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== - dependencies: - clean-stack "^2.0.0" - indent-string "^4.0.0" - -ansi-colors@^4.1.1: - version "4.1.3" - resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" - integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== - -ansi-escapes@^4.3.0: - version "4.3.2" - resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" - integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== - dependencies: - type-fest "^0.21.3" - -ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - -ansi-styles@^4.0.0, ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -arch@^2.2.0: - version "2.2.0" - resolved "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11" - integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ== - -asn1@~0.2.3: - version "0.2.6" - resolved "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" - integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== - dependencies: - safer-buffer "~2.1.0" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw== - -astral-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" - integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== - -async@^3.2.0: - version "3.2.4" - resolved "https://registry.npmjs.org/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c" - integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ== - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== - -at-least-node@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" - integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== - -aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - integrity sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA== - -aws4@^1.8.0: - version "1.11.0" - resolved "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" - integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -base64-js@^1.3.1: - version "1.5.1" - resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" - integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== - -bcrypt-pbkdf@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" - integrity sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w== - dependencies: - tweetnacl "^0.14.3" - -blob-util@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/blob-util/-/blob-util-2.0.2.tgz#3b4e3c281111bb7f11128518006cdc60b403a1eb" - integrity sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ== - -bluebird@^3.7.2: - version "3.7.2" - resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" - integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -buffer-crc32@~0.2.3: - version "0.2.13" - resolved "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" - integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== - -buffer@^5.6.0: - version "5.7.1" - resolved "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" - integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.1.13" - -cachedir@^2.3.0: - version "2.3.0" - resolved "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz#0c75892a052198f0b21c7c1804d8331edfcae0e8" - integrity sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw== - -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw== - -chalk@^4.1.0: - version "4.1.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -check-more-types@^2.24.0: - version "2.24.0" - resolved "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz#1420ffb10fd444dcfc79b43891bbfffd32a84600" - integrity sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA== - -ci-info@^3.2.0: - version "3.3.2" - resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.3.2.tgz#6d2967ffa407466481c6c90b6e16b3098f080128" - integrity sha512-xmDt/QIAdeZ9+nfdPsaBCpMvHNLFiLdjj59qjqn+6iPe6YmHGQ35sBnQ8uslRBXFmXkiZQOJRjvQeoGppoTjjg== - -clean-stack@^2.0.0: - version "2.2.0" - resolved "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" - integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== - -cli-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" - integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== - dependencies: - restore-cursor "^3.1.0" - -cli-table3@~0.6.1: - version "0.6.2" - resolved "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.2.tgz#aaf5df9d8b5bf12634dc8b3040806a0c07120d2a" - integrity sha512-QyavHCaIC80cMivimWu4aWHilIpiDpfm3hGmqAmXVL1UsnbLuBSMd21hTX6VY4ZSDSM73ESLeF8TOYId3rBTbw== - dependencies: - string-width "^4.2.0" - optionalDependencies: - "@colors/colors" "1.5.0" - -cli-truncate@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7" - integrity sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg== - dependencies: - slice-ansi "^3.0.0" - string-width "^4.2.0" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -colorette@^2.0.16: - version "2.0.19" - resolved "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798" - integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ== - -combined-stream@^1.0.6, combined-stream@~1.0.6: - version "1.0.8" - resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" - -commander@^5.1.0: - version "5.1.0" - resolved "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" - integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== - -common-tags@^1.8.0: - version "1.8.2" - resolved "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz#94ebb3c076d26032745fd54face7f688ef5ac9c6" - integrity sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA== - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== - -core-util-is@1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ== - -cross-spawn@^7.0.0: - version "7.0.3" - resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -cypress@^10.0.0: - version "10.7.0" - resolved "https://registry.npmjs.org/cypress/-/cypress-10.7.0.tgz#2d37f8b9751c6de33ee48639cb7e67a2ce593231" - integrity sha512-gTFvjrUoBnqPPOu9Vl5SBHuFlzx/Wxg/ZXIz2H4lzoOLFelKeF7mbwYUOzgzgF0oieU2WhJAestQdkgwJMMTvQ== - dependencies: - "@cypress/request" "^2.88.10" - "@cypress/xvfb" "^1.2.4" - "@types/node" "^14.14.31" - "@types/sinonjs__fake-timers" "8.1.1" - "@types/sizzle" "^2.3.2" - arch "^2.2.0" - blob-util "^2.0.2" - bluebird "^3.7.2" - buffer "^5.6.0" - cachedir "^2.3.0" - chalk "^4.1.0" - check-more-types "^2.24.0" - cli-cursor "^3.1.0" - cli-table3 "~0.6.1" - commander "^5.1.0" - common-tags "^1.8.0" - dayjs "^1.10.4" - debug "^4.3.2" - enquirer "^2.3.6" - eventemitter2 "^6.4.3" - execa "4.1.0" - executable "^4.1.1" - extract-zip "2.0.1" - figures "^3.2.0" - fs-extra "^9.1.0" - getos "^3.2.1" - is-ci "^3.0.0" - is-installed-globally "~0.4.0" - lazy-ass "^1.6.0" - listr2 "^3.8.3" - lodash "^4.17.21" - log-symbols "^4.0.0" - minimist "^1.2.6" - ospath "^1.2.2" - pretty-bytes "^5.6.0" - proxy-from-env "1.0.0" - request-progress "^3.0.0" - semver "^7.3.2" - supports-color "^8.1.1" - tmp "~0.2.1" - untildify "^4.0.0" - yauzl "^2.10.0" - -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - integrity sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g== - dependencies: - assert-plus "^1.0.0" - -dayjs@^1.10.4: - version "1.11.5" - resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.5.tgz#00e8cc627f231f9499c19b38af49f56dc0ac5e93" - integrity sha512-CAdX5Q3YW3Gclyo5Vpqkgpj8fSdLQcRuzfX6mC6Phy0nfJ0eGYOeS7m4mt2plDWLAtA4TqTakvbboHvUxfe4iA== - -debug@^3.1.0: - version "3.2.7" - resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" - integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== - dependencies: - ms "^2.1.1" - -debug@^4.1.1, debug@^4.3.2: - version "4.3.4" - resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== - -ecc-jsbn@~0.1.1: - version "0.1.2" - resolved "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" - integrity sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw== - dependencies: - jsbn "~0.1.0" - safer-buffer "^2.1.0" - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -end-of-stream@^1.1.0: - version "1.4.4" - resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" - integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== - dependencies: - once "^1.4.0" - -enquirer@^2.3.6: - version "2.3.6" - resolved "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" - integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== - dependencies: - ansi-colors "^4.1.1" - -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== - -eventemitter2@^6.4.3: - version "6.4.7" - resolved "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.7.tgz#a7f6c4d7abf28a14c1ef3442f21cb306a054271d" - integrity sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg== - -execa@4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" - integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA== - dependencies: - cross-spawn "^7.0.0" - get-stream "^5.0.0" - human-signals "^1.1.1" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.0" - onetime "^5.1.0" - signal-exit "^3.0.2" - strip-final-newline "^2.0.0" - -executable@^4.1.1: - version "4.1.1" - resolved "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz#41532bff361d3e57af4d763b70582db18f5d133c" - integrity sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg== - dependencies: - pify "^2.2.0" - -extend@~3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - -extract-zip@2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a" - integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg== - dependencies: - debug "^4.1.1" - get-stream "^5.1.0" - yauzl "^2.10.0" - optionalDependencies: - "@types/yauzl" "^2.9.1" - -extsprintf@1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - integrity sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g== - -extsprintf@^1.2.0: - version "1.4.1" - resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" - integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== - -fd-slicer@~1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" - integrity sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g== - dependencies: - pend "~1.2.0" - -figures@^3.2.0: - version "3.2.0" - resolved "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" - integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== - dependencies: - escape-string-regexp "^1.0.5" - -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - integrity sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw== - -form-data@~2.3.2: - version "2.3.3" - resolved "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" - integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" - -fs-extra@^9.1.0: - version "9.1.0" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" - integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== - dependencies: - at-least-node "^1.0.0" - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== - -get-stream@^5.0.0, get-stream@^5.1.0: - version "5.2.0" - resolved "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" - integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== - dependencies: - pump "^3.0.0" - -getos@^3.2.1: - version "3.2.1" - resolved "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz#0134d1f4e00eb46144c5a9c0ac4dc087cbb27dc5" - integrity sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q== - dependencies: - async "^3.2.0" - -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - integrity sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng== - dependencies: - assert-plus "^1.0.0" - -glob@^7.1.3: - version "7.2.3" - resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" - integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.1.1" - once "^1.3.0" - path-is-absolute "^1.0.0" - -global-dirs@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz#70a76fe84ea315ab37b1f5576cbde7d48ef72686" - integrity sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA== - dependencies: - ini "2.0.0" - -graceful-fs@^4.1.6, graceful-fs@^4.2.0: - version "4.2.10" - resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" - integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -http-signature@~1.3.6: - version "1.3.6" - resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz#cb6fbfdf86d1c974f343be94e87f7fc128662cf9" - integrity sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw== - dependencies: - assert-plus "^1.0.0" - jsprim "^2.0.2" - sshpk "^1.14.1" - -human-signals@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" - integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== - -ieee754@^1.1.13: - version "1.2.1" - resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" - integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== - -indent-string@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" - integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2: - version "2.0.4" - resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -ini@2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5" - integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA== - -is-ci@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz#db6ecbed1bd659c43dac0f45661e7674103d1867" - integrity sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ== - dependencies: - ci-info "^3.2.0" - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -is-installed-globally@~0.4.0: - version "0.4.0" - resolved "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz#9a0fd407949c30f86eb6959ef1b7994ed0b7b520" - integrity sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ== - dependencies: - global-dirs "^3.0.0" - is-path-inside "^3.0.2" - -is-path-inside@^3.0.2: - version "3.0.3" - resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" - integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== - -is-stream@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" - integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== - -is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== - -is-unicode-supported@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" - integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== - -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g== - -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - integrity sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg== - -json-schema@0.4.0: - version "0.4.0" - resolved "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" - integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== - -json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== - -jsonfile@^6.0.1: - version "6.1.0" - resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" - integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== - dependencies: - universalify "^2.0.0" - optionalDependencies: - graceful-fs "^4.1.6" - -jsprim@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz#77ca23dbcd4135cd364800d22ff82c2185803d4d" - integrity sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ== - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.4.0" - verror "1.10.0" - -lazy-ass@^1.6.0: - version "1.6.0" - resolved "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz#7999655e8646c17f089fdd187d150d3324d54513" - integrity sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw== - -listr2@^3.8.3: - version "3.14.0" - resolved "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz#23101cc62e1375fd5836b248276d1d2b51fdbe9e" - integrity sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g== - dependencies: - cli-truncate "^2.1.0" - colorette "^2.0.16" - log-update "^4.0.0" - p-map "^4.0.0" - rfdc "^1.3.0" - rxjs "^7.5.1" - through "^2.3.8" - wrap-ansi "^7.0.0" - -lodash.once@^4.1.1: - version "4.1.1" - resolved "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" - integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== - -lodash@^4.17.21: - version "4.17.21" - resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -log-symbols@^4.0.0: - version "4.1.0" - resolved "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" - integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== - dependencies: - chalk "^4.1.0" - is-unicode-supported "^0.1.0" - -log-update@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1" - integrity sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg== - dependencies: - ansi-escapes "^4.3.0" - cli-cursor "^3.1.0" - slice-ansi "^4.0.0" - wrap-ansi "^6.2.0" - -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - -merge-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" - integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== - -mime-db@1.52.0: - version "1.52.0" - resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" - integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== - -mime-types@^2.1.12, mime-types@~2.1.19: - version "2.1.35" - resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" - integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== - dependencies: - mime-db "1.52.0" - -mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== - -minimatch@^3.1.1: - version "3.1.2" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -minimist@^1.2.6: - version "1.2.6" - resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" - integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -ms@^2.1.1: - version "2.1.3" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - -npm-run-path@^4.0.0: - version "4.0.1" - resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" - integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== - dependencies: - path-key "^3.0.0" - -once@^1.3.0, once@^1.3.1, once@^1.4.0: - version "1.4.0" - resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== - dependencies: - wrappy "1" - -onetime@^5.1.0: - version "5.1.2" - resolved "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" - integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== - dependencies: - mimic-fn "^2.1.0" - -ospath@^1.2.2: - version "1.2.2" - resolved "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz#1276639774a3f8ef2572f7fe4280e0ea4550c07b" - integrity sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA== - -p-map@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" - integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== - dependencies: - aggregate-error "^3.0.0" - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== - -path-key@^3.0.0, path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -pend@~1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" - integrity sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg== - -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== - -pify@^2.2.0: - version "2.3.0" - resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== - -pretty-bytes@^5.6.0: - version "5.6.0" - resolved "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb" - integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg== - -proxy-from-env@1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee" - integrity sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A== - -psl@^1.1.28: - version "1.9.0" - resolved "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" - integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== - -pump@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" - integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -punycode@^2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - -qs@~6.5.2: - version "6.5.3" - resolved "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad" - integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== - -request-progress@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz#4ca754081c7fec63f505e4faa825aa06cd669dbe" - integrity sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg== - dependencies: - throttleit "^1.0.0" - -restore-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" - integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== - dependencies: - onetime "^5.1.0" - signal-exit "^3.0.2" - -rfdc@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" - integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== - -rimraf@^3.0.0: - version "3.0.2" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - -rxjs@^7.5.1: - version "7.5.6" - resolved "https://registry.npmjs.org/rxjs/-/rxjs-7.5.6.tgz#0446577557862afd6903517ce7cae79ecb9662bc" - integrity sha512-dnyv2/YsXhnm461G+R/Pe5bWP41Nm6LBXEYWI6eiFP4fiwx6WRI/CD0zbdVAudd9xwLEF2IDcKXLHit0FYjUzw== - dependencies: - tslib "^2.1.0" - -safe-buffer@^5.0.1, safe-buffer@^5.1.2: - version "5.2.1" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: - version "2.1.2" - resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -semver@^7.3.2: - version "7.3.7" - resolved "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" - integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== - dependencies: - lru-cache "^6.0.0" - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -signal-exit@^3.0.2: - version "3.0.7" - resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" - integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== - -slice-ansi@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787" - integrity sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ== - dependencies: - ansi-styles "^4.0.0" - astral-regex "^2.0.0" - is-fullwidth-code-point "^3.0.0" - -slice-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" - integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== - dependencies: - ansi-styles "^4.0.0" - astral-regex "^2.0.0" - is-fullwidth-code-point "^3.0.0" - -sshpk@^1.14.1: - version "1.17.0" - resolved "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz#578082d92d4fe612b13007496e543fa0fbcbe4c5" - integrity sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ== - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - bcrypt-pbkdf "^1.0.0" - dashdash "^1.12.0" - ecc-jsbn "~0.1.1" - getpass "^0.1.1" - jsbn "~0.1.0" - safer-buffer "^2.0.2" - tweetnacl "~0.14.0" - -string-width@^4.1.0, string-width@^4.2.0: - version "4.2.3" - resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-final-newline@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" - integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== - -supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -supports-color@^8.1.1: - version "8.1.1" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" - integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== - dependencies: - has-flag "^4.0.0" - -throttleit@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c" - integrity sha512-rkTVqu6IjfQ/6+uNuuc3sZek4CEYxTJom3IktzgdSxcZqdARuebbA/f4QmAxMQIxqq9ZLEUkSYqvuk1I6VKq4g== - -through@^2.3.8: - version "2.3.8" - resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== - -tmp@~0.2.1: - version "0.2.1" - resolved "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" - integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== - dependencies: - rimraf "^3.0.0" - -tough-cookie@~2.5.0: - version "2.5.0" - resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" - integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== - dependencies: - psl "^1.1.28" - punycode "^2.1.1" - -tslib@^2.1.0: - version "2.4.0" - resolved "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" - integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== - -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w== - dependencies: - safe-buffer "^5.0.1" - -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA== - -type-fest@^0.21.3: - version "0.21.3" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" - integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== - -typescript@^4.1.3: - version "4.8.2" - resolved "https://registry.npmjs.org/typescript/-/typescript-4.8.2.tgz#e3b33d5ccfb5914e4eeab6699cf208adee3fd790" - integrity sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw== - -universalify@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" - integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== - -untildify@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" - integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== - -uuid@^8.3.2: - version "8.3.2" - resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" - integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== - -verror@1.10.0: - version "1.10.0" - resolved "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - integrity sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw== - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - -which@^2.0.1: - version "2.0.2" - resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -wrap-ansi@^6.2.0: - version "6.2.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" - integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== - -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - -yauzl@^2.10.0: - version "2.10.0" - resolved "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" - integrity sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g== - dependencies: - buffer-crc32 "~0.2.3" - fd-slicer "~1.1.0" +# This file is generated by running "yarn install" inside your project. +# Manual changes might be lost - proceed with caution! + +__metadata: + version: 6 + cacheKey: 8 + +"@backstage/cypress-tests@workspace:.": + version: 0.0.0-use.local + resolution: "@backstage/cypress-tests@workspace:." + dependencies: + cypress: ^10.0.0 + typescript: ^4.1.3 + languageName: unknown + linkType: soft + +"@colors/colors@npm:1.5.0": + version: 1.5.0 + resolution: "@colors/colors@npm:1.5.0" + checksum: d64d5260bed1d5012ae3fc617d38d1afc0329fec05342f4e6b838f46998855ba56e0a73833f4a80fa8378c84810da254f76a8a19c39d038260dc06dc4e007425 + languageName: node + linkType: hard + +"@cypress/request@npm:^2.88.10": + version: 2.88.10 + resolution: "@cypress/request@npm:2.88.10" + dependencies: + aws-sign2: ~0.7.0 + aws4: ^1.8.0 + caseless: ~0.12.0 + combined-stream: ~1.0.6 + extend: ~3.0.2 + forever-agent: ~0.6.1 + form-data: ~2.3.2 + http-signature: ~1.3.6 + is-typedarray: ~1.0.0 + isstream: ~0.1.2 + json-stringify-safe: ~5.0.1 + mime-types: ~2.1.19 + performance-now: ^2.1.0 + qs: ~6.5.2 + safe-buffer: ^5.1.2 + tough-cookie: ~2.5.0 + tunnel-agent: ^0.6.0 + uuid: ^8.3.2 + checksum: 69c3e3b332e9be4866a900f6bcca5d274d8cea6c99707fbcce061de8dbab11c9b1e39f4c017f6e83e6e682717781d4f6106fd6b7cf9546580fcfac353b6676cf + languageName: node + linkType: hard + +"@cypress/xvfb@npm:^1.2.4": + version: 1.2.4 + resolution: "@cypress/xvfb@npm:1.2.4" + dependencies: + debug: ^3.1.0 + lodash.once: ^4.1.1 + checksum: 7bdcdaeb1bb692ec9d9bf8ec52538aa0bead6764753f4a067a171a511807a43fab016f7285a56bef6a606c2467ff3f1365e1ad2d2d583b81beed849ee1573fd1 + languageName: node + linkType: hard + +"@types/node@npm:*": + version: 18.7.14 + resolution: "@types/node@npm:18.7.14" + checksum: 99cf28ff854100158de875cca23c7acc3cc01dfee526a52b90b7f36767c821bcbaf2be0a98a70f06f3b78f3c60639168ff949d725b61e2e124f9f71f1fb8043d + languageName: node + linkType: hard + +"@types/node@npm:^14.14.31": + version: 14.18.26 + resolution: "@types/node@npm:14.18.26" + checksum: c6ac3f9d4f6f77c0fa5ac17757779ad4d9835abfe3af5708b7552597cb5c7c1103e83499ccaf767a1cfa70040990bcf3f58761c547051dc8d5077f3c419091b1 + languageName: node + linkType: hard + +"@types/sinonjs__fake-timers@npm:8.1.1": + version: 8.1.1 + resolution: "@types/sinonjs__fake-timers@npm:8.1.1" + checksum: ca09d54d47091d87020824a73f026300fa06b17cd9f2f9b9387f28b549364b141ef194ee28db762f6588de71d8febcd17f753163cb7ea116b8387c18e80ebd5c + languageName: node + linkType: hard + +"@types/sizzle@npm:^2.3.2": + version: 2.3.3 + resolution: "@types/sizzle@npm:2.3.3" + checksum: 586a9fb1f6ff3e325e0f2cc1596a460615f0bc8a28f6e276ac9b509401039dd242fa8b34496d3a30c52f5b495873922d09a9e76c50c2ab2bcc70ba3fb9c4e160 + languageName: node + linkType: hard + +"@types/yauzl@npm:^2.9.1": + version: 2.10.0 + resolution: "@types/yauzl@npm:2.10.0" + dependencies: + "@types/node": "*" + checksum: 55d27ae5d346ea260e40121675c24e112ef0247649073848e5d4e03182713ae4ec8142b98f61a1c6cbe7d3b72fa99bbadb65d8b01873e5e605cdc30f1ff70ef2 + languageName: node + linkType: hard + +"aggregate-error@npm:^3.0.0": + version: 3.1.0 + resolution: "aggregate-error@npm:3.1.0" + dependencies: + clean-stack: ^2.0.0 + indent-string: ^4.0.0 + checksum: 1101a33f21baa27a2fa8e04b698271e64616b886795fd43c31068c07533c7b3facfcaf4e9e0cab3624bd88f729a592f1c901a1a229c9e490eafce411a8644b79 + languageName: node + linkType: hard + +"ansi-colors@npm:^4.1.1": + version: 4.1.3 + resolution: "ansi-colors@npm:4.1.3" + checksum: a9c2ec842038a1fabc7db9ece7d3177e2fe1c5dc6f0c51ecfbf5f39911427b89c00b5dc6b8bd95f82a26e9b16aaae2e83d45f060e98070ce4d1333038edceb0e + languageName: node + linkType: hard + +"ansi-escapes@npm:^4.3.0": + version: 4.3.2 + resolution: "ansi-escapes@npm:4.3.2" + dependencies: + type-fest: ^0.21.3 + checksum: 93111c42189c0a6bed9cdb4d7f2829548e943827ee8479c74d6e0b22ee127b2a21d3f8b5ca57723b8ef78ce011fbfc2784350eb2bde3ccfccf2f575fa8489815 + languageName: node + linkType: hard + +"ansi-regex@npm:^5.0.1": + version: 5.0.1 + resolution: "ansi-regex@npm:5.0.1" + checksum: 2aa4bb54caf2d622f1afdad09441695af2a83aa3fe8b8afa581d205e57ed4261c183c4d3877cee25794443fde5876417d859c108078ab788d6af7e4fe52eb66b + languageName: node + linkType: hard + +"ansi-styles@npm:^4.0.0, ansi-styles@npm:^4.1.0": + version: 4.3.0 + resolution: "ansi-styles@npm:4.3.0" + dependencies: + color-convert: ^2.0.1 + checksum: 513b44c3b2105dd14cc42a19271e80f386466c4be574bccf60b627432f9198571ebf4ab1e4c3ba17347658f4ee1711c163d574248c0c1cdc2d5917a0ad582ec4 + languageName: node + linkType: hard + +"arch@npm:^2.2.0": + version: 2.2.0 + resolution: "arch@npm:2.2.0" + checksum: e21b7635029fe8e9cdd5a026f9a6c659103e63fff423834323cdf836a1bb240a72d0c39ca8c470f84643385cf581bd8eda2cad8bf493e27e54bd9783abe9101f + languageName: node + linkType: hard + +"asn1@npm:~0.2.3": + version: 0.2.6 + resolution: "asn1@npm:0.2.6" + dependencies: + safer-buffer: ~2.1.0 + checksum: 39f2ae343b03c15ad4f238ba561e626602a3de8d94ae536c46a4a93e69578826305366dc09fbb9b56aec39b4982a463682f259c38e59f6fa380cd72cd61e493d + languageName: node + linkType: hard + +"assert-plus@npm:1.0.0, assert-plus@npm:^1.0.0": + version: 1.0.0 + resolution: "assert-plus@npm:1.0.0" + checksum: 19b4340cb8f0e6a981c07225eacac0e9d52c2644c080198765d63398f0075f83bbc0c8e95474d54224e297555ad0d631c1dcd058adb1ddc2437b41a6b424ac64 + languageName: node + linkType: hard + +"astral-regex@npm:^2.0.0": + version: 2.0.0 + resolution: "astral-regex@npm:2.0.0" + checksum: 876231688c66400473ba505731df37ea436e574dd524520294cc3bbc54ea40334865e01fa0d074d74d036ee874ee7e62f486ea38bc421ee8e6a871c06f011766 + languageName: node + linkType: hard + +"async@npm:^3.2.0": + version: 3.2.4 + resolution: "async@npm:3.2.4" + checksum: 43d07459a4e1d09b84a20772414aa684ff4de085cbcaec6eea3c7a8f8150e8c62aa6cd4e699fe8ee93c3a5b324e777d34642531875a0817a35697522c1b02e89 + languageName: node + linkType: hard + +"asynckit@npm:^0.4.0": + version: 0.4.0 + resolution: "asynckit@npm:0.4.0" + checksum: 7b78c451df768adba04e2d02e63e2d0bf3b07adcd6e42b4cf665cb7ce899bedd344c69a1dcbce355b5f972d597b25aaa1c1742b52cffd9caccb22f348114f6be + languageName: node + linkType: hard + +"at-least-node@npm:^1.0.0": + version: 1.0.0 + resolution: "at-least-node@npm:1.0.0" + checksum: 463e2f8e43384f1afb54bc68485c436d7622acec08b6fad269b421cb1d29cebb5af751426793d0961ed243146fe4dc983402f6d5a51b720b277818dbf6f2e49e + languageName: node + linkType: hard + +"aws-sign2@npm:~0.7.0": + version: 0.7.0 + resolution: "aws-sign2@npm:0.7.0" + checksum: b148b0bb0778098ad8cf7e5fc619768bcb51236707ca1d3e5b49e41b171166d8be9fdc2ea2ae43d7decf02989d0aaa3a9c4caa6f320af95d684de9b548a71525 + languageName: node + linkType: hard + +"aws4@npm:^1.8.0": + version: 1.11.0 + resolution: "aws4@npm:1.11.0" + checksum: 5a00d045fd0385926d20ebebcfba5ec79d4482fe706f63c27b324d489a04c68edb0db99ed991e19eda09cb8c97dc2452059a34d97545cebf591d7a2b5a10999f + languageName: node + linkType: hard + +"balanced-match@npm:^1.0.0": + version: 1.0.2 + resolution: "balanced-match@npm:1.0.2" + checksum: 9706c088a283058a8a99e0bf91b0a2f75497f185980d9ffa8b304de1d9e58ebda7c72c07ebf01dadedaac5b2907b2c6f566f660d62bd336c3468e960403b9d65 + languageName: node + linkType: hard + +"base64-js@npm:^1.3.1": + version: 1.5.1 + resolution: "base64-js@npm:1.5.1" + checksum: 669632eb3745404c2f822a18fc3a0122d2f9a7a13f7fb8b5823ee19d1d2ff9ee5b52c53367176ea4ad093c332fd5ab4bd0ebae5a8e27917a4105a4cfc86b1005 + languageName: node + linkType: hard + +"bcrypt-pbkdf@npm:^1.0.0": + version: 1.0.2 + resolution: "bcrypt-pbkdf@npm:1.0.2" + dependencies: + tweetnacl: ^0.14.3 + checksum: 4edfc9fe7d07019609ccf797a2af28351736e9d012c8402a07120c4453a3b789a15f2ee1530dc49eee8f7eb9379331a8dd4b3766042b9e502f74a68e7f662291 + languageName: node + linkType: hard + +"blob-util@npm:^2.0.2": + version: 2.0.2 + resolution: "blob-util@npm:2.0.2" + checksum: d543e6b92e4ca715ca33c78e89a07a2290d43e5b2bc897d7ec588c5c7bbf59df93e45225ac0c9258aa6ce4320358990f99c9288f1c48280f8ec5d7a2e088d19b + languageName: node + linkType: hard + +"bluebird@npm:^3.7.2": + version: 3.7.2 + resolution: "bluebird@npm:3.7.2" + checksum: 869417503c722e7dc54ca46715f70e15f4d9c602a423a02c825570862d12935be59ed9c7ba34a9b31f186c017c23cac6b54e35446f8353059c101da73eac22ef + languageName: node + linkType: hard + +"brace-expansion@npm:^1.1.7": + version: 1.1.11 + resolution: "brace-expansion@npm:1.1.11" + dependencies: + balanced-match: ^1.0.0 + concat-map: 0.0.1 + checksum: faf34a7bb0c3fcf4b59c7808bc5d2a96a40988addf2e7e09dfbb67a2251800e0d14cd2bfc1aa79174f2f5095c54ff27f46fb1289fe2d77dac755b5eb3434cc07 + languageName: node + linkType: hard + +"buffer-crc32@npm:~0.2.3": + version: 0.2.13 + resolution: "buffer-crc32@npm:0.2.13" + checksum: 06252347ae6daca3453b94e4b2f1d3754a3b146a111d81c68924c22d91889a40623264e95e67955b1cb4a68cbedf317abeabb5140a9766ed248973096db5ce1c + languageName: node + linkType: hard + +"buffer@npm:^5.6.0": + version: 5.7.1 + resolution: "buffer@npm:5.7.1" + dependencies: + base64-js: ^1.3.1 + ieee754: ^1.1.13 + checksum: e2cf8429e1c4c7b8cbd30834ac09bd61da46ce35f5c22a78e6c2f04497d6d25541b16881e30a019c6fd3154150650ccee27a308eff3e26229d788bbdeb08ab84 + languageName: node + linkType: hard + +"cachedir@npm:^2.3.0": + version: 2.3.0 + resolution: "cachedir@npm:2.3.0" + checksum: ec90cb0f2e6336e266aa748dbadf3da9e0b20e843e43f1591acab7a3f1451337dc2f26cb9dd833ae8cfefeffeeb43ef5b5ff62782a685f4e3c2305dd98482fcb + languageName: node + linkType: hard + +"caseless@npm:~0.12.0": + version: 0.12.0 + resolution: "caseless@npm:0.12.0" + checksum: b43bd4c440aa1e8ee6baefee8063b4850fd0d7b378f6aabc796c9ec8cb26d27fb30b46885350777d9bd079c5256c0e1329ad0dc7c2817e0bb466810ebb353751 + languageName: node + linkType: hard + +"chalk@npm:^4.1.0": + version: 4.1.2 + resolution: "chalk@npm:4.1.2" + dependencies: + ansi-styles: ^4.1.0 + supports-color: ^7.1.0 + checksum: fe75c9d5c76a7a98d45495b91b2172fa3b7a09e0cc9370e5c8feb1c567b85c4288e2b3fded7cfdd7359ac28d6b3844feb8b82b8686842e93d23c827c417e83fc + languageName: node + linkType: hard + +"check-more-types@npm:^2.24.0": + version: 2.24.0 + resolution: "check-more-types@npm:2.24.0" + checksum: b09080ec3404d20a4b0ead828994b2e5913236ef44ed3033a27062af0004cf7d2091fbde4b396bf13b7ce02fb018bc9960b48305e6ab2304cd82d73ed7a51ef4 + languageName: node + linkType: hard + +"ci-info@npm:^3.2.0": + version: 3.3.2 + resolution: "ci-info@npm:3.3.2" + checksum: fd81f1edd2d3b0f6cb077b2e84365136d87b9db8c055928c1ad69da8a76c2c2f19cba8ea51b90238302157ca927f91f92b653e933f2398dde4867500f08d6e62 + languageName: node + linkType: hard + +"clean-stack@npm:^2.0.0": + version: 2.2.0 + resolution: "clean-stack@npm:2.2.0" + checksum: 2ac8cd2b2f5ec986a3c743935ec85b07bc174d5421a5efc8017e1f146a1cf5f781ae962618f416352103b32c9cd7e203276e8c28241bbe946160cab16149fb68 + languageName: node + linkType: hard + +"cli-cursor@npm:^3.1.0": + version: 3.1.0 + resolution: "cli-cursor@npm:3.1.0" + dependencies: + restore-cursor: ^3.1.0 + checksum: 2692784c6cd2fd85cfdbd11f53aea73a463a6d64a77c3e098b2b4697a20443f430c220629e1ca3b195ea5ac4a97a74c2ee411f3807abf6df2b66211fec0c0a29 + languageName: node + linkType: hard + +"cli-table3@npm:~0.6.1": + version: 0.6.2 + resolution: "cli-table3@npm:0.6.2" + dependencies: + "@colors/colors": 1.5.0 + string-width: ^4.2.0 + dependenciesMeta: + "@colors/colors": + optional: true + checksum: 2f82391698b8a2a2a5e45d2adcfea5d93e557207f90455a8d4c1aac688e9b18a204d9eb4ba1d322fa123b17d64ea3dc5e11de8b005529f3c3e7dbeb27cb4d9be + languageName: node + linkType: hard + +"cli-truncate@npm:^2.1.0": + version: 2.1.0 + resolution: "cli-truncate@npm:2.1.0" + dependencies: + slice-ansi: ^3.0.0 + string-width: ^4.2.0 + checksum: bf1e4e6195392dc718bf9cd71f317b6300dc4a9191d052f31046b8773230ece4fa09458813bf0e3455a5e68c0690d2ea2c197d14a8b85a7b5e01c97f4b5feb5d + languageName: node + linkType: hard + +"color-convert@npm:^2.0.1": + version: 2.0.1 + resolution: "color-convert@npm:2.0.1" + dependencies: + color-name: ~1.1.4 + checksum: 79e6bdb9fd479a205c71d89574fccfb22bd9053bd98c6c4d870d65c132e5e904e6034978e55b43d69fcaa7433af2016ee203ce76eeba9cfa554b373e7f7db336 + languageName: node + linkType: hard + +"color-name@npm:~1.1.4": + version: 1.1.4 + resolution: "color-name@npm:1.1.4" + checksum: b0445859521eb4021cd0fb0cc1a75cecf67fceecae89b63f62b201cca8d345baf8b952c966862a9d9a2632987d4f6581f0ec8d957dfacece86f0a7919316f610 + languageName: node + linkType: hard + +"colorette@npm:^2.0.16": + version: 2.0.19 + resolution: "colorette@npm:2.0.19" + checksum: 888cf5493f781e5fcf54ce4d49e9d7d698f96ea2b2ef67906834bb319a392c667f9ec69f4a10e268d2946d13a9503d2d19b3abaaaf174e3451bfe91fb9d82427 + languageName: node + linkType: hard + +"combined-stream@npm:^1.0.6, combined-stream@npm:~1.0.6": + version: 1.0.8 + resolution: "combined-stream@npm:1.0.8" + dependencies: + delayed-stream: ~1.0.0 + checksum: 49fa4aeb4916567e33ea81d088f6584749fc90c7abec76fd516bf1c5aa5c79f3584b5ba3de6b86d26ddd64bae5329c4c7479343250cfe71c75bb366eae53bb7c + languageName: node + linkType: hard + +"commander@npm:^5.1.0": + version: 5.1.0 + resolution: "commander@npm:5.1.0" + checksum: 0b7fec1712fbcc6230fcb161d8d73b4730fa91a21dc089515489402ad78810547683f058e2a9835929c212fead1d6a6ade70db28bbb03edbc2829a9ab7d69447 + languageName: node + linkType: hard + +"common-tags@npm:^1.8.0": + version: 1.8.2 + resolution: "common-tags@npm:1.8.2" + checksum: 767a6255a84bbc47df49a60ab583053bb29a7d9687066a18500a516188a062c4e4cd52de341f22de0b07062e699b1b8fe3cfa1cb55b241cb9301aeb4f45b4dff + languageName: node + linkType: hard + +"concat-map@npm:0.0.1": + version: 0.0.1 + resolution: "concat-map@npm:0.0.1" + checksum: 902a9f5d8967a3e2faf138d5cb784b9979bad2e6db5357c5b21c568df4ebe62bcb15108af1b2253744844eb964fc023fbd9afbbbb6ddd0bcc204c6fb5b7bf3af + languageName: node + linkType: hard + +"core-util-is@npm:1.0.2": + version: 1.0.2 + resolution: "core-util-is@npm:1.0.2" + checksum: 7a4c925b497a2c91421e25bf76d6d8190f0b2359a9200dbeed136e63b2931d6294d3b1893eda378883ed363cd950f44a12a401384c609839ea616befb7927dab + languageName: node + linkType: hard + +"cross-spawn@npm:^7.0.0": + version: 7.0.3 + resolution: "cross-spawn@npm:7.0.3" + dependencies: + path-key: ^3.1.0 + shebang-command: ^2.0.0 + which: ^2.0.1 + checksum: 671cc7c7288c3a8406f3c69a3ae2fc85555c04169e9d611def9a675635472614f1c0ed0ef80955d5b6d4e724f6ced67f0ad1bb006c2ea643488fcfef994d7f52 + languageName: node + linkType: hard + +"cypress@npm:^10.0.0": + version: 10.8.0 + resolution: "cypress@npm:10.8.0" + dependencies: + "@cypress/request": ^2.88.10 + "@cypress/xvfb": ^1.2.4 + "@types/node": ^14.14.31 + "@types/sinonjs__fake-timers": 8.1.1 + "@types/sizzle": ^2.3.2 + arch: ^2.2.0 + blob-util: ^2.0.2 + bluebird: ^3.7.2 + buffer: ^5.6.0 + cachedir: ^2.3.0 + chalk: ^4.1.0 + check-more-types: ^2.24.0 + cli-cursor: ^3.1.0 + cli-table3: ~0.6.1 + commander: ^5.1.0 + common-tags: ^1.8.0 + dayjs: ^1.10.4 + debug: ^4.3.2 + enquirer: ^2.3.6 + eventemitter2: 6.4.7 + execa: 4.1.0 + executable: ^4.1.1 + extract-zip: 2.0.1 + figures: ^3.2.0 + fs-extra: ^9.1.0 + getos: ^3.2.1 + is-ci: ^3.0.0 + is-installed-globally: ~0.4.0 + lazy-ass: ^1.6.0 + listr2: ^3.8.3 + lodash: ^4.17.21 + log-symbols: ^4.0.0 + minimist: ^1.2.6 + ospath: ^1.2.2 + pretty-bytes: ^5.6.0 + proxy-from-env: 1.0.0 + request-progress: ^3.0.0 + semver: ^7.3.2 + supports-color: ^8.1.1 + tmp: ~0.2.1 + untildify: ^4.0.0 + yauzl: ^2.10.0 + bin: + cypress: bin/cypress + checksum: c052690049980e7721e6fca563b724fde839d87d83c1478dfe26ce7d230992717c2c4028e7157bfb39ec274473e51929f49e5aab6a23c2b25cde2a439b1c3cf9 + languageName: node + linkType: hard + +"dashdash@npm:^1.12.0": + version: 1.14.1 + resolution: "dashdash@npm:1.14.1" + dependencies: + assert-plus: ^1.0.0 + checksum: 3634c249570f7f34e3d34f866c93f866c5b417f0dd616275decae08147dcdf8fccfaa5947380ccfb0473998ea3a8057c0b4cd90c875740ee685d0624b2983598 + languageName: node + linkType: hard + +"dayjs@npm:^1.10.4": + version: 1.11.5 + resolution: "dayjs@npm:1.11.5" + checksum: e3bbaa7b4883b31be4bf75a181f1447fbb19800c29b332852125aab96baeff3ac232dcba8b88c4ea17d3b636c99dac5fb9d1af4bb6ae26615698bbc4a852dffb + languageName: node + linkType: hard + +"debug@npm:^3.1.0": + version: 3.2.7 + resolution: "debug@npm:3.2.7" + dependencies: + ms: ^2.1.1 + checksum: b3d8c5940799914d30314b7c3304a43305fd0715581a919dacb8b3176d024a782062368405b47491516d2091d6462d4d11f2f4974a405048094f8bfebfa3071c + languageName: node + linkType: hard + +"debug@npm:^4.1.1, debug@npm:^4.3.2": + version: 4.3.4 + resolution: "debug@npm:4.3.4" + dependencies: + ms: 2.1.2 + peerDependenciesMeta: + supports-color: + optional: true + checksum: 3dbad3f94ea64f34431a9cbf0bafb61853eda57bff2880036153438f50fb5a84f27683ba0d8e5426bf41a8c6ff03879488120cf5b3a761e77953169c0600a708 + languageName: node + linkType: hard + +"delayed-stream@npm:~1.0.0": + version: 1.0.0 + resolution: "delayed-stream@npm:1.0.0" + checksum: 46fe6e83e2cb1d85ba50bd52803c68be9bd953282fa7096f51fc29edd5d67ff84ff753c51966061e5ba7cb5e47ef6d36a91924eddb7f3f3483b1c560f77a0020 + languageName: node + linkType: hard + +"ecc-jsbn@npm:~0.1.1": + version: 0.1.2 + resolution: "ecc-jsbn@npm:0.1.2" + dependencies: + jsbn: ~0.1.0 + safer-buffer: ^2.1.0 + checksum: 22fef4b6203e5f31d425f5b711eb389e4c6c2723402e389af394f8411b76a488fa414d309d866e2b577ce3e8462d344205545c88a8143cc21752a5172818888a + languageName: node + linkType: hard + +"emoji-regex@npm:^8.0.0": + version: 8.0.0 + resolution: "emoji-regex@npm:8.0.0" + checksum: d4c5c39d5a9868b5fa152f00cada8a936868fd3367f33f71be515ecee4c803132d11b31a6222b2571b1e5f7e13890156a94880345594d0ce7e3c9895f560f192 + languageName: node + linkType: hard + +"end-of-stream@npm:^1.1.0": + version: 1.4.4 + resolution: "end-of-stream@npm:1.4.4" + dependencies: + once: ^1.4.0 + checksum: 530a5a5a1e517e962854a31693dbb5c0b2fc40b46dad2a56a2deec656ca040631124f4795823acc68238147805f8b021abbe221f4afed5ef3c8e8efc2024908b + languageName: node + linkType: hard + +"enquirer@npm:^2.3.6": + version: 2.3.6 + resolution: "enquirer@npm:2.3.6" + dependencies: + ansi-colors: ^4.1.1 + checksum: 1c0911e14a6f8d26721c91e01db06092a5f7675159f0261d69c403396a385afd13dd76825e7678f66daffa930cfaa8d45f506fb35f818a2788463d022af1b884 + languageName: node + linkType: hard + +"escape-string-regexp@npm:^1.0.5": + version: 1.0.5 + resolution: "escape-string-regexp@npm:1.0.5" + checksum: 6092fda75c63b110c706b6a9bfde8a612ad595b628f0bd2147eea1d3406723020810e591effc7db1da91d80a71a737a313567c5abb3813e8d9c71f4aa595b410 + languageName: node + linkType: hard + +"eventemitter2@npm:6.4.7": + version: 6.4.7 + resolution: "eventemitter2@npm:6.4.7" + checksum: 1b36a77e139d6965ebf3a36c01fa00c089ae6b80faa1911e52888f40b3a7057b36a2cc45dcd1ad87cda3798fe7b97a0aabcbb8175a8b96092a23bb7d0f039e66 + languageName: node + linkType: hard + +"execa@npm:4.1.0": + version: 4.1.0 + resolution: "execa@npm:4.1.0" + dependencies: + cross-spawn: ^7.0.0 + get-stream: ^5.0.0 + human-signals: ^1.1.1 + is-stream: ^2.0.0 + merge-stream: ^2.0.0 + npm-run-path: ^4.0.0 + onetime: ^5.1.0 + signal-exit: ^3.0.2 + strip-final-newline: ^2.0.0 + checksum: e30d298934d9c52f90f3847704fd8224e849a081ab2b517bbc02f5f7732c24e56a21f14cb96a08256deffeb2d12b2b7cb7e2b014a12fb36f8d3357e06417ed55 + languageName: node + linkType: hard + +"executable@npm:^4.1.1": + version: 4.1.1 + resolution: "executable@npm:4.1.1" + dependencies: + pify: ^2.2.0 + checksum: f01927ce59bccec804e171bf859a26e362c1f50aa9ebc69f7cafdcce3859d29d4b6267fd47237c18b0a1830614bd3f0ee14b7380d9bad18a4e7af9b5f0b6984f + languageName: node + linkType: hard + +"extend@npm:~3.0.2": + version: 3.0.2 + resolution: "extend@npm:3.0.2" + checksum: a50a8309ca65ea5d426382ff09f33586527882cf532931cb08ca786ea3146c0553310bda688710ff61d7668eba9f96b923fe1420cdf56a2c3eaf30fcab87b515 + languageName: node + linkType: hard + +"extract-zip@npm:2.0.1": + version: 2.0.1 + resolution: "extract-zip@npm:2.0.1" + dependencies: + "@types/yauzl": ^2.9.1 + debug: ^4.1.1 + get-stream: ^5.1.0 + yauzl: ^2.10.0 + dependenciesMeta: + "@types/yauzl": + optional: true + bin: + extract-zip: cli.js + checksum: 8cbda9debdd6d6980819cc69734d874ddd71051c9fe5bde1ef307ebcedfe949ba57b004894b585f758b7c9eeeea0e3d87f2dda89b7d25320459c2c9643ebb635 + languageName: node + linkType: hard + +"extsprintf@npm:1.3.0": + version: 1.3.0 + resolution: "extsprintf@npm:1.3.0" + checksum: cee7a4a1e34cffeeec18559109de92c27517e5641991ec6bab849aa64e3081022903dd53084f2080d0d2530803aa5ee84f1e9de642c365452f9e67be8f958ce2 + languageName: node + linkType: hard + +"extsprintf@npm:^1.2.0": + version: 1.4.1 + resolution: "extsprintf@npm:1.4.1" + checksum: a2f29b241914a8d2bad64363de684821b6b1609d06ae68d5b539e4de6b28659715b5bea94a7265201603713b7027d35399d10b0548f09071c5513e65e8323d33 + languageName: node + linkType: hard + +"fd-slicer@npm:~1.1.0": + version: 1.1.0 + resolution: "fd-slicer@npm:1.1.0" + dependencies: + pend: ~1.2.0 + checksum: c8585fd5713f4476eb8261150900d2cb7f6ff2d87f8feb306ccc8a1122efd152f1783bdb2b8dc891395744583436bfd8081d8e63ece0ec8687eeefea394d4ff2 + languageName: node + linkType: hard + +"figures@npm:^3.2.0": + version: 3.2.0 + resolution: "figures@npm:3.2.0" + dependencies: + escape-string-regexp: ^1.0.5 + checksum: 85a6ad29e9aca80b49b817e7c89ecc4716ff14e3779d9835af554db91bac41c0f289c418923519392a1e582b4d10482ad282021330cd045bb7b80c84152f2a2b + languageName: node + linkType: hard + +"forever-agent@npm:~0.6.1": + version: 0.6.1 + resolution: "forever-agent@npm:0.6.1" + checksum: 766ae6e220f5fe23676bb4c6a99387cec5b7b62ceb99e10923376e27bfea72f3c3aeec2ba5f45f3f7ba65d6616965aa7c20b15002b6860833bb6e394dea546a8 + languageName: node + linkType: hard + +"form-data@npm:~2.3.2": + version: 2.3.3 + resolution: "form-data@npm:2.3.3" + dependencies: + asynckit: ^0.4.0 + combined-stream: ^1.0.6 + mime-types: ^2.1.12 + checksum: 10c1780fa13dbe1ff3100114c2ce1f9307f8be10b14bf16e103815356ff567b6be39d70fc4a40f8990b9660012dc24b0f5e1dde1b6426166eb23a445ba068ca3 + languageName: node + linkType: hard + +"fs-extra@npm:^9.1.0": + version: 9.1.0 + resolution: "fs-extra@npm:9.1.0" + dependencies: + at-least-node: ^1.0.0 + graceful-fs: ^4.2.0 + jsonfile: ^6.0.1 + universalify: ^2.0.0 + checksum: ba71ba32e0faa74ab931b7a0031d1523c66a73e225de7426e275e238e312d07313d2da2d33e34a52aa406c8763ade5712eb3ec9ba4d9edce652bcacdc29e6b20 + languageName: node + linkType: hard + +"fs.realpath@npm:^1.0.0": + version: 1.0.0 + resolution: "fs.realpath@npm:1.0.0" + checksum: 99ddea01a7e75aa276c250a04eedeffe5662bce66c65c07164ad6264f9de18fb21be9433ead460e54cff20e31721c811f4fb5d70591799df5f85dce6d6746fd0 + languageName: node + linkType: hard + +"get-stream@npm:^5.0.0, get-stream@npm:^5.1.0": + version: 5.2.0 + resolution: "get-stream@npm:5.2.0" + dependencies: + pump: ^3.0.0 + checksum: 8bc1a23174a06b2b4ce600df38d6c98d2ef6d84e020c1ddad632ad75bac4e092eeb40e4c09e0761c35fc2dbc5e7fff5dab5e763a383582c4a167dd69a905bd12 + languageName: node + linkType: hard + +"getos@npm:^3.2.1": + version: 3.2.1 + resolution: "getos@npm:3.2.1" + dependencies: + async: ^3.2.0 + checksum: 42fd78a66d47cebd3e09de5566cc0044e034b08f4a000a310dbd89a77b02c65d8f4002554bfa495ea5bdc4fa9d515f5ac785a7cc474ba45383cc697f865eeaf1 + languageName: node + linkType: hard + +"getpass@npm:^0.1.1": + version: 0.1.7 + resolution: "getpass@npm:0.1.7" + dependencies: + assert-plus: ^1.0.0 + checksum: ab18d55661db264e3eac6012c2d3daeafaab7a501c035ae0ccb193c3c23e9849c6e29b6ac762b9c2adae460266f925d55a3a2a3a3c8b94be2f222df94d70c046 + languageName: node + linkType: hard + +"glob@npm:^7.1.3": + version: 7.2.3 + resolution: "glob@npm:7.2.3" + dependencies: + fs.realpath: ^1.0.0 + inflight: ^1.0.4 + inherits: 2 + minimatch: ^3.1.1 + once: ^1.3.0 + path-is-absolute: ^1.0.0 + checksum: 29452e97b38fa704dabb1d1045350fb2467cf0277e155aa9ff7077e90ad81d1ea9d53d3ee63bd37c05b09a065e90f16aec4a65f5b8de401d1dac40bc5605d133 + languageName: node + linkType: hard + +"global-dirs@npm:^3.0.0": + version: 3.0.0 + resolution: "global-dirs@npm:3.0.0" + dependencies: + ini: 2.0.0 + checksum: 953c17cf14bf6ee0e2100ae82a0d779934eed8a3ec5c94a7a4f37c5b3b592c31ea015fb9a15cf32484de13c79f4a814f3015152f3e1d65976cfbe47c1bfe4a88 + languageName: node + linkType: hard + +"graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0": + version: 4.2.10 + resolution: "graceful-fs@npm:4.2.10" + checksum: 3f109d70ae123951905d85032ebeae3c2a5a7a997430df00ea30df0e3a6c60cf6689b109654d6fdacd28810a053348c4d14642da1d075049e6be1ba5216218da + languageName: node + linkType: hard + +"has-flag@npm:^4.0.0": + version: 4.0.0 + resolution: "has-flag@npm:4.0.0" + checksum: 261a1357037ead75e338156b1f9452c016a37dcd3283a972a30d9e4a87441ba372c8b81f818cd0fbcd9c0354b4ae7e18b9e1afa1971164aef6d18c2b6095a8ad + languageName: node + linkType: hard + +"http-signature@npm:~1.3.6": + version: 1.3.6 + resolution: "http-signature@npm:1.3.6" + dependencies: + assert-plus: ^1.0.0 + jsprim: ^2.0.2 + sshpk: ^1.14.1 + checksum: 10be2af4764e71fee0281392937050201ee576ac755c543f570d6d87134ce5e858663fe999a7adb3e4e368e1e356d0d7fec6b9542295b875726ff615188e7a0c + languageName: node + linkType: hard + +"human-signals@npm:^1.1.1": + version: 1.1.1 + resolution: "human-signals@npm:1.1.1" + checksum: d587647c9e8ec24e02821b6be7de5a0fc37f591f6c4e319b3054b43fd4c35a70a94c46fc74d8c1a43c47fde157d23acd7421f375e1c1365b09a16835b8300205 + languageName: node + linkType: hard + +"ieee754@npm:^1.1.13": + version: 1.2.1 + resolution: "ieee754@npm:1.2.1" + checksum: 5144c0c9815e54ada181d80a0b810221a253562422e7c6c3a60b1901154184f49326ec239d618c416c1c5945a2e197107aee8d986a3dd836b53dffefd99b5e7e + languageName: node + linkType: hard + +"indent-string@npm:^4.0.0": + version: 4.0.0 + resolution: "indent-string@npm:4.0.0" + checksum: 824cfb9929d031dabf059bebfe08cf3137365e112019086ed3dcff6a0a7b698cb80cf67ccccde0e25b9e2d7527aa6cc1fed1ac490c752162496caba3e6699612 + languageName: node + linkType: hard + +"inflight@npm:^1.0.4": + version: 1.0.6 + resolution: "inflight@npm:1.0.6" + dependencies: + once: ^1.3.0 + wrappy: 1 + checksum: f4f76aa072ce19fae87ce1ef7d221e709afb59d445e05d47fba710e85470923a75de35bfae47da6de1b18afc3ce83d70facf44cfb0aff89f0a3f45c0a0244dfd + languageName: node + linkType: hard + +"inherits@npm:2": + version: 2.0.4 + resolution: "inherits@npm:2.0.4" + checksum: 4a48a733847879d6cf6691860a6b1e3f0f4754176e4d71494c41f3475553768b10f84b5ce1d40fbd0e34e6bfbb864ee35858ad4dd2cf31e02fc4a154b724d7f1 + languageName: node + linkType: hard + +"ini@npm:2.0.0": + version: 2.0.0 + resolution: "ini@npm:2.0.0" + checksum: e7aadc5fb2e4aefc666d74ee2160c073995a4061556b1b5b4241ecb19ad609243b9cceafe91bae49c219519394bbd31512516cb22a3b1ca6e66d869e0447e84e + languageName: node + linkType: hard + +"is-ci@npm:^3.0.0": + version: 3.0.1 + resolution: "is-ci@npm:3.0.1" + dependencies: + ci-info: ^3.2.0 + bin: + is-ci: bin.js + checksum: 192c66dc7826d58f803ecae624860dccf1899fc1f3ac5505284c0a5cf5f889046ffeb958fa651e5725d5705c5bcb14f055b79150ea5fcad7456a9569de60260e + languageName: node + linkType: hard + +"is-fullwidth-code-point@npm:^3.0.0": + version: 3.0.0 + resolution: "is-fullwidth-code-point@npm:3.0.0" + checksum: 44a30c29457c7fb8f00297bce733f0a64cd22eca270f83e58c105e0d015e45c019491a4ab2faef91ab51d4738c670daff901c799f6a700e27f7314029e99e348 + languageName: node + linkType: hard + +"is-installed-globally@npm:~0.4.0": + version: 0.4.0 + resolution: "is-installed-globally@npm:0.4.0" + dependencies: + global-dirs: ^3.0.0 + is-path-inside: ^3.0.2 + checksum: 3359840d5982d22e9b350034237b2cda2a12bac1b48a721912e1ab8e0631dd07d45a2797a120b7b87552759a65ba03e819f1bd63f2d7ab8657ec0b44ee0bf399 + languageName: node + linkType: hard + +"is-path-inside@npm:^3.0.2": + version: 3.0.3 + resolution: "is-path-inside@npm:3.0.3" + checksum: abd50f06186a052b349c15e55b182326f1936c89a78bf6c8f2b707412517c097ce04bc49a0ca221787bc44e1049f51f09a2ffb63d22899051988d3a618ba13e9 + languageName: node + linkType: hard + +"is-stream@npm:^2.0.0": + version: 2.0.1 + resolution: "is-stream@npm:2.0.1" + checksum: b8e05ccdf96ac330ea83c12450304d4a591f9958c11fd17bed240af8d5ffe08aedafa4c0f4cfccd4d28dc9d4d129daca1023633d5c11601a6cbc77521f6fae66 + languageName: node + linkType: hard + +"is-typedarray@npm:~1.0.0": + version: 1.0.0 + resolution: "is-typedarray@npm:1.0.0" + checksum: 3508c6cd0a9ee2e0df2fa2e9baabcdc89e911c7bd5cf64604586697212feec525aa21050e48affb5ffc3df20f0f5d2e2cf79b08caa64e1ccc9578e251763aef7 + languageName: node + linkType: hard + +"is-unicode-supported@npm:^0.1.0": + version: 0.1.0 + resolution: "is-unicode-supported@npm:0.1.0" + checksum: a2aab86ee7712f5c2f999180daaba5f361bdad1efadc9610ff5b8ab5495b86e4f627839d085c6530363c6d6d4ecbde340fb8e54bdb83da4ba8e0865ed5513c52 + languageName: node + linkType: hard + +"isexe@npm:^2.0.0": + version: 2.0.0 + resolution: "isexe@npm:2.0.0" + checksum: 26bf6c5480dda5161c820c5b5c751ae1e766c587b1f951ea3fcfc973bafb7831ae5b54a31a69bd670220e42e99ec154475025a468eae58ea262f813fdc8d1c62 + languageName: node + linkType: hard + +"isstream@npm:~0.1.2": + version: 0.1.2 + resolution: "isstream@npm:0.1.2" + checksum: 1eb2fe63a729f7bdd8a559ab552c69055f4f48eb5c2f03724430587c6f450783c8f1cd936c1c952d0a927925180fcc892ebd5b174236cf1065d4bd5bdb37e963 + languageName: node + linkType: hard + +"jsbn@npm:~0.1.0": + version: 0.1.1 + resolution: "jsbn@npm:0.1.1" + checksum: e5ff29c1b8d965017ef3f9c219dacd6e40ad355c664e277d31246c90545a02e6047018c16c60a00f36d561b3647215c41894f5d869ada6908a2e0ce4200c88f2 + languageName: node + linkType: hard + +"json-schema@npm:0.4.0": + version: 0.4.0 + resolution: "json-schema@npm:0.4.0" + checksum: 66389434c3469e698da0df2e7ac5a3281bcff75e797a5c127db7c5b56270e01ae13d9afa3c03344f76e32e81678337a8c912bdbb75101c62e487dc3778461d72 + languageName: node + linkType: hard + +"json-stringify-safe@npm:~5.0.1": + version: 5.0.1 + resolution: "json-stringify-safe@npm:5.0.1" + checksum: 48ec0adad5280b8a96bb93f4563aa1667fd7a36334f79149abd42446d0989f2ddc58274b479f4819f1f00617957e6344c886c55d05a4e15ebb4ab931e4a6a8ee + languageName: node + linkType: hard + +"jsonfile@npm:^6.0.1": + version: 6.1.0 + resolution: "jsonfile@npm:6.1.0" + dependencies: + graceful-fs: ^4.1.6 + universalify: ^2.0.0 + dependenciesMeta: + graceful-fs: + optional: true + checksum: 7af3b8e1ac8fe7f1eccc6263c6ca14e1966fcbc74b618d3c78a0a2075579487547b94f72b7a1114e844a1e15bb00d440e5d1720bfc4612d790a6f285d5ea8354 + languageName: node + linkType: hard + +"jsprim@npm:^2.0.2": + version: 2.0.2 + resolution: "jsprim@npm:2.0.2" + dependencies: + assert-plus: 1.0.0 + extsprintf: 1.3.0 + json-schema: 0.4.0 + verror: 1.10.0 + checksum: d175f6b1991e160cb0aa39bc857da780e035611986b5492f32395411879fdaf4e513d98677f08f7352dac93a16b66b8361c674b86a3fa406e2e7af6b26321838 + languageName: node + linkType: hard + +"lazy-ass@npm:^1.6.0": + version: 1.6.0 + resolution: "lazy-ass@npm:1.6.0" + checksum: 5a3ebb17915b03452320804466345382a6c25ac782ec4874fecdb2385793896cd459be2f187dc7def8899180c32ee0ab9a1aa7fe52193ac3ff3fe29bb0591729 + languageName: node + linkType: hard + +"listr2@npm:^3.8.3": + version: 3.14.0 + resolution: "listr2@npm:3.14.0" + dependencies: + cli-truncate: ^2.1.0 + colorette: ^2.0.16 + log-update: ^4.0.0 + p-map: ^4.0.0 + rfdc: ^1.3.0 + rxjs: ^7.5.1 + through: ^2.3.8 + wrap-ansi: ^7.0.0 + peerDependencies: + enquirer: ">= 2.3.0 < 3" + peerDependenciesMeta: + enquirer: + optional: true + checksum: fdb8b2d6bdf5df9371ebd5082bee46c6d0ca3d1e5f2b11fbb5a127839855d5f3da9d4968fce94f0a5ec67cac2459766abbb1faeef621065ebb1829b11ef9476d + languageName: node + linkType: hard + +"lodash.once@npm:^4.1.1": + version: 4.1.1 + resolution: "lodash.once@npm:4.1.1" + checksum: d768fa9f9b4e1dc6453be99b753906f58990e0c45e7b2ca5a3b40a33111e5d17f6edf2f768786e2716af90a8e78f8f91431ab8435f761fef00f9b0c256f6d245 + languageName: node + linkType: hard + +"lodash@npm:^4.17.21": + version: 4.17.21 + resolution: "lodash@npm:4.17.21" + checksum: eb835a2e51d381e561e508ce932ea50a8e5a68f4ebdd771ea240d3048244a8d13658acbd502cd4829768c56f2e16bdd4340b9ea141297d472517b83868e677f7 + languageName: node + linkType: hard + +"log-symbols@npm:^4.0.0": + version: 4.1.0 + resolution: "log-symbols@npm:4.1.0" + dependencies: + chalk: ^4.1.0 + is-unicode-supported: ^0.1.0 + checksum: fce1497b3135a0198803f9f07464165e9eb83ed02ceb2273930a6f8a508951178d8cf4f0378e9d28300a2ed2bc49050995d2bd5f53ab716bb15ac84d58c6ef74 + languageName: node + linkType: hard + +"log-update@npm:^4.0.0": + version: 4.0.0 + resolution: "log-update@npm:4.0.0" + dependencies: + ansi-escapes: ^4.3.0 + cli-cursor: ^3.1.0 + slice-ansi: ^4.0.0 + wrap-ansi: ^6.2.0 + checksum: ae2f85bbabc1906034154fb7d4c4477c79b3e703d22d78adee8b3862fa913942772e7fa11713e3d96fb46de4e3cabefbf5d0a544344f03b58d3c4bff52aa9eb2 + languageName: node + linkType: hard + +"lru-cache@npm:^6.0.0": + version: 6.0.0 + resolution: "lru-cache@npm:6.0.0" + dependencies: + yallist: ^4.0.0 + checksum: f97f499f898f23e4585742138a22f22526254fdba6d75d41a1c2526b3b6cc5747ef59c5612ba7375f42aca4f8461950e925ba08c991ead0651b4918b7c978297 + languageName: node + linkType: hard + +"merge-stream@npm:^2.0.0": + version: 2.0.0 + resolution: "merge-stream@npm:2.0.0" + checksum: 6fa4dcc8d86629705cea944a4b88ef4cb0e07656ebf223fa287443256414283dd25d91c1cd84c77987f2aec5927af1a9db6085757cb43d90eb170ebf4b47f4f4 + languageName: node + linkType: hard + +"mime-db@npm:1.52.0": + version: 1.52.0 + resolution: "mime-db@npm:1.52.0" + checksum: 0d99a03585f8b39d68182803b12ac601d9c01abfa28ec56204fa330bc9f3d1c5e14beb049bafadb3dbdf646dfb94b87e24d4ec7b31b7279ef906a8ea9b6a513f + languageName: node + linkType: hard + +"mime-types@npm:^2.1.12, mime-types@npm:~2.1.19": + version: 2.1.35 + resolution: "mime-types@npm:2.1.35" + dependencies: + mime-db: 1.52.0 + checksum: 89a5b7f1def9f3af5dad6496c5ed50191ae4331cc5389d7c521c8ad28d5fdad2d06fd81baf38fed813dc4e46bb55c8145bb0ff406330818c9cf712fb2e9b3836 + languageName: node + linkType: hard + +"mimic-fn@npm:^2.1.0": + version: 2.1.0 + resolution: "mimic-fn@npm:2.1.0" + checksum: d2421a3444848ce7f84bd49115ddacff29c15745db73f54041edc906c14b131a38d05298dae3081667627a59b2eb1ca4b436ff2e1b80f69679522410418b478a + languageName: node + linkType: hard + +"minimatch@npm:^3.1.1": + version: 3.1.2 + resolution: "minimatch@npm:3.1.2" + dependencies: + brace-expansion: ^1.1.7 + checksum: c154e566406683e7bcb746e000b84d74465b3a832c45d59912b9b55cd50dee66e5c4b1e5566dba26154040e51672f9aa450a9aef0c97cfc7336b78b7afb9540a + languageName: node + linkType: hard + +"minimist@npm:^1.2.6": + version: 1.2.6 + resolution: "minimist@npm:1.2.6" + checksum: d15428cd1e11eb14e1233bcfb88ae07ed7a147de251441d61158619dfb32c4d7e9061d09cab4825fdee18ecd6fce323228c8c47b5ba7cd20af378ca4048fb3fb + languageName: node + linkType: hard + +"ms@npm:2.1.2": + version: 2.1.2 + resolution: "ms@npm:2.1.2" + checksum: 673cdb2c3133eb050c745908d8ce632ed2c02d85640e2edb3ace856a2266a813b30c613569bf3354fdf4ea7d1a1494add3bfa95e2713baa27d0c2c71fc44f58f + languageName: node + linkType: hard + +"ms@npm:^2.1.1": + version: 2.1.3 + resolution: "ms@npm:2.1.3" + checksum: aa92de608021b242401676e35cfa5aa42dd70cbdc082b916da7fb925c542173e36bce97ea3e804923fe92c0ad991434e4a38327e15a1b5b5f945d66df615ae6d + languageName: node + linkType: hard + +"npm-run-path@npm:^4.0.0": + version: 4.0.1 + resolution: "npm-run-path@npm:4.0.1" + dependencies: + path-key: ^3.0.0 + checksum: 5374c0cea4b0bbfdfae62da7bbdf1e1558d338335f4cacf2515c282ff358ff27b2ecb91ffa5330a8b14390ac66a1e146e10700440c1ab868208430f56b5f4d23 + languageName: node + linkType: hard + +"once@npm:^1.3.0, once@npm:^1.3.1, once@npm:^1.4.0": + version: 1.4.0 + resolution: "once@npm:1.4.0" + dependencies: + wrappy: 1 + checksum: cd0a88501333edd640d95f0d2700fbde6bff20b3d4d9bdc521bdd31af0656b5706570d6c6afe532045a20bb8dc0849f8332d6f2a416e0ba6d3d3b98806c7db68 + languageName: node + linkType: hard + +"onetime@npm:^5.1.0": + version: 5.1.2 + resolution: "onetime@npm:5.1.2" + dependencies: + mimic-fn: ^2.1.0 + checksum: 2478859ef817fc5d4e9c2f9e5728512ddd1dbc9fb7829ad263765bb6d3b91ce699d6e2332eef6b7dff183c2f490bd3349f1666427eaba4469fba0ac38dfd0d34 + languageName: node + linkType: hard + +"ospath@npm:^1.2.2": + version: 1.2.2 + resolution: "ospath@npm:1.2.2" + checksum: 505f48a4f4f1c557d6c656ec985707726e3714721680139be037613e903aa8c8fa4ddd8d1342006f9b2dc0065e6e20f8b7bea2ee05354f31257044790367b347 + languageName: node + linkType: hard + +"p-map@npm:^4.0.0": + version: 4.0.0 + resolution: "p-map@npm:4.0.0" + dependencies: + aggregate-error: ^3.0.0 + checksum: cb0ab21ec0f32ddffd31dfc250e3afa61e103ef43d957cc45497afe37513634589316de4eb88abdfd969fe6410c22c0b93ab24328833b8eb1ccc087fc0442a1c + languageName: node + linkType: hard + +"path-is-absolute@npm:^1.0.0": + version: 1.0.1 + resolution: "path-is-absolute@npm:1.0.1" + checksum: 060840f92cf8effa293bcc1bea81281bd7d363731d214cbe5c227df207c34cd727430f70c6037b5159c8a870b9157cba65e775446b0ab06fd5ecc7e54615a3b8 + languageName: node + linkType: hard + +"path-key@npm:^3.0.0, path-key@npm:^3.1.0": + version: 3.1.1 + resolution: "path-key@npm:3.1.1" + checksum: 55cd7a9dd4b343412a8386a743f9c746ef196e57c823d90ca3ab917f90ab9f13dd0ded27252ba49dbdfcab2b091d998bc446f6220cd3cea65db407502a740020 + languageName: node + linkType: hard + +"pend@npm:~1.2.0": + version: 1.2.0 + resolution: "pend@npm:1.2.0" + checksum: 6c72f5243303d9c60bd98e6446ba7d30ae29e3d56fdb6fae8767e8ba6386f33ee284c97efe3230a0d0217e2b1723b8ab490b1bbf34fcbb2180dbc8a9de47850d + languageName: node + linkType: hard + +"performance-now@npm:^2.1.0": + version: 2.1.0 + resolution: "performance-now@npm:2.1.0" + checksum: 534e641aa8f7cba160f0afec0599b6cecefbb516a2e837b512be0adbe6c1da5550e89c78059c7fabc5c9ffdf6627edabe23eb7c518c4500067a898fa65c2b550 + languageName: node + linkType: hard + +"pify@npm:^2.2.0": + version: 2.3.0 + resolution: "pify@npm:2.3.0" + checksum: 9503aaeaf4577acc58642ad1d25c45c6d90288596238fb68f82811c08104c800e5a7870398e9f015d82b44ecbcbef3dc3d4251a1cbb582f6e5959fe09884b2ba + languageName: node + linkType: hard + +"pretty-bytes@npm:^5.6.0": + version: 5.6.0 + resolution: "pretty-bytes@npm:5.6.0" + checksum: 9c082500d1e93434b5b291bd651662936b8bd6204ec9fa17d563116a192d6d86b98f6d328526b4e8d783c07d5499e2614a807520249692da9ec81564b2f439cd + languageName: node + linkType: hard + +"proxy-from-env@npm:1.0.0": + version: 1.0.0 + resolution: "proxy-from-env@npm:1.0.0" + checksum: 292e28d1de0c315958d71d8315eb546dd3cd8c8cbc2dab7c54eeb9f5c17f421771964ad0b5e1f77011bab2305bdae42e1757ce33bdb1ccc3e87732322a8efcf1 + languageName: node + linkType: hard + +"psl@npm:^1.1.28": + version: 1.9.0 + resolution: "psl@npm:1.9.0" + checksum: 20c4277f640c93d393130673f392618e9a8044c6c7bf61c53917a0fddb4952790f5f362c6c730a9c32b124813e173733f9895add8d26f566ed0ea0654b2e711d + languageName: node + linkType: hard + +"pump@npm:^3.0.0": + version: 3.0.0 + resolution: "pump@npm:3.0.0" + dependencies: + end-of-stream: ^1.1.0 + once: ^1.3.1 + checksum: e42e9229fba14732593a718b04cb5e1cfef8254544870997e0ecd9732b189a48e1256e4e5478148ecb47c8511dca2b09eae56b4d0aad8009e6fac8072923cfc9 + languageName: node + linkType: hard + +"punycode@npm:^2.1.1": + version: 2.1.1 + resolution: "punycode@npm:2.1.1" + checksum: 823bf443c6dd14f669984dea25757b37993f67e8d94698996064035edd43bed8a5a17a9f12e439c2b35df1078c6bec05a6c86e336209eb1061e8025c481168e8 + languageName: node + linkType: hard + +"qs@npm:~6.5.2": + version: 6.5.3 + resolution: "qs@npm:6.5.3" + checksum: 6f20bf08cabd90c458e50855559539a28d00b2f2e7dddcb66082b16a43188418cb3cb77cbd09268bcef6022935650f0534357b8af9eeb29bf0f27ccb17655692 + languageName: node + linkType: hard + +"request-progress@npm:^3.0.0": + version: 3.0.0 + resolution: "request-progress@npm:3.0.0" + dependencies: + throttleit: ^1.0.0 + checksum: 6ea1761dcc8a8b7b5894afd478c0286aa31bd69438d7050294bd4fd0d0b3e09b5cde417d38deef9c49809039c337d8744e4bb49d8632b0c3e4ffa5e8a687e0fd + languageName: node + linkType: hard + +"restore-cursor@npm:^3.1.0": + version: 3.1.0 + resolution: "restore-cursor@npm:3.1.0" + dependencies: + onetime: ^5.1.0 + signal-exit: ^3.0.2 + checksum: f877dd8741796b909f2a82454ec111afb84eb45890eb49ac947d87991379406b3b83ff9673a46012fca0d7844bb989f45cc5b788254cf1a39b6b5a9659de0630 + languageName: node + linkType: hard + +"rfdc@npm:^1.3.0": + version: 1.3.0 + resolution: "rfdc@npm:1.3.0" + checksum: fb2ba8512e43519983b4c61bd3fa77c0f410eff6bae68b08614437bc3f35f91362215f7b4a73cbda6f67330b5746ce07db5dd9850ad3edc91271ad6deea0df32 + languageName: node + linkType: hard + +"rimraf@npm:^3.0.0": + version: 3.0.2 + resolution: "rimraf@npm:3.0.2" + dependencies: + glob: ^7.1.3 + bin: + rimraf: bin.js + checksum: 87f4164e396f0171b0a3386cc1877a817f572148ee13a7e113b238e48e8a9f2f31d009a92ec38a591ff1567d9662c6b67fd8818a2dbbaed74bc26a87a2a4a9a0 + languageName: node + linkType: hard + +"rxjs@npm:^7.5.1": + version: 7.5.6 + resolution: "rxjs@npm:7.5.6" + dependencies: + tslib: ^2.1.0 + checksum: fc05f01364a74dac57490fb3e07ea63b422af04017fae1db641a009073f902ef69f285c5daac31359620dc8d9aee7d81e42b370ca2a8573d1feae0b04329383b + languageName: node + linkType: hard + +"safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.2": + version: 5.2.1 + resolution: "safe-buffer@npm:5.2.1" + checksum: b99c4b41fdd67a6aaf280fcd05e9ffb0813654894223afb78a31f14a19ad220bba8aba1cb14eddce1fcfb037155fe6de4e861784eb434f7d11ed58d1e70dd491 + languageName: node + linkType: hard + +"safer-buffer@npm:^2.0.2, safer-buffer@npm:^2.1.0, safer-buffer@npm:~2.1.0": + version: 2.1.2 + resolution: "safer-buffer@npm:2.1.2" + checksum: cab8f25ae6f1434abee8d80023d7e72b598cf1327164ddab31003c51215526801e40b66c5e65d658a0af1e9d6478cadcb4c745f4bd6751f97d8644786c0978b0 + languageName: node + linkType: hard + +"semver@npm:^7.3.2": + version: 7.3.7 + resolution: "semver@npm:7.3.7" + dependencies: + lru-cache: ^6.0.0 + bin: + semver: bin/semver.js + checksum: 2fa3e877568cd6ce769c75c211beaed1f9fce80b28338cadd9d0b6c40f2e2862bafd62c19a6cff42f3d54292b7c623277bcab8816a2b5521cf15210d43e75232 + languageName: node + linkType: hard + +"shebang-command@npm:^2.0.0": + version: 2.0.0 + resolution: "shebang-command@npm:2.0.0" + dependencies: + shebang-regex: ^3.0.0 + checksum: 6b52fe87271c12968f6a054e60f6bde5f0f3d2db483a1e5c3e12d657c488a15474121a1d55cd958f6df026a54374ec38a4a963988c213b7570e1d51575cea7fa + languageName: node + linkType: hard + +"shebang-regex@npm:^3.0.0": + version: 3.0.0 + resolution: "shebang-regex@npm:3.0.0" + checksum: 1a2bcae50de99034fcd92ad4212d8e01eedf52c7ec7830eedcf886622804fe36884278f2be8be0ea5fde3fd1c23911643a4e0f726c8685b61871c8908af01222 + languageName: node + linkType: hard + +"signal-exit@npm:^3.0.2": + version: 3.0.7 + resolution: "signal-exit@npm:3.0.7" + checksum: a2f098f247adc367dffc27845853e9959b9e88b01cb301658cfe4194352d8d2bb32e18467c786a7fe15f1d44b233ea35633d076d5e737870b7139949d1ab6318 + languageName: node + linkType: hard + +"slice-ansi@npm:^3.0.0": + version: 3.0.0 + resolution: "slice-ansi@npm:3.0.0" + dependencies: + ansi-styles: ^4.0.0 + astral-regex: ^2.0.0 + is-fullwidth-code-point: ^3.0.0 + checksum: 5ec6d022d12e016347e9e3e98a7eb2a592213a43a65f1b61b74d2c78288da0aded781f665807a9f3876b9daa9ad94f64f77d7633a0458876c3a4fdc4eb223f24 + languageName: node + linkType: hard + +"slice-ansi@npm:^4.0.0": + version: 4.0.0 + resolution: "slice-ansi@npm:4.0.0" + dependencies: + ansi-styles: ^4.0.0 + astral-regex: ^2.0.0 + is-fullwidth-code-point: ^3.0.0 + checksum: 4a82d7f085b0e1b070e004941ada3c40d3818563ac44766cca4ceadd2080427d337554f9f99a13aaeb3b4a94d9964d9466c807b3d7b7541d1ec37ee32d308756 + languageName: node + linkType: hard + +"sshpk@npm:^1.14.1": + version: 1.17.0 + resolution: "sshpk@npm:1.17.0" + dependencies: + asn1: ~0.2.3 + assert-plus: ^1.0.0 + bcrypt-pbkdf: ^1.0.0 + dashdash: ^1.12.0 + ecc-jsbn: ~0.1.1 + getpass: ^0.1.1 + jsbn: ~0.1.0 + safer-buffer: ^2.0.2 + tweetnacl: ~0.14.0 + bin: + sshpk-conv: bin/sshpk-conv + sshpk-sign: bin/sshpk-sign + sshpk-verify: bin/sshpk-verify + checksum: ba109f65c8e6c35133b8e6ed5576abeff8aa8d614824b7275ec3ca308f081fef483607c28d97780c1e235818b0f93ed8c8b56d0a5968d5a23fd6af57718c7597 + languageName: node + linkType: hard + +"string-width@npm:^4.1.0, string-width@npm:^4.2.0": + version: 4.2.3 + resolution: "string-width@npm:4.2.3" + dependencies: + emoji-regex: ^8.0.0 + is-fullwidth-code-point: ^3.0.0 + strip-ansi: ^6.0.1 + checksum: e52c10dc3fbfcd6c3a15f159f54a90024241d0f149cf8aed2982a2d801d2e64df0bf1dc351cf8e95c3319323f9f220c16e740b06faecd53e2462df1d2b5443fb + languageName: node + linkType: hard + +"strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": + version: 6.0.1 + resolution: "strip-ansi@npm:6.0.1" + dependencies: + ansi-regex: ^5.0.1 + checksum: f3cd25890aef3ba6e1a74e20896c21a46f482e93df4a06567cebf2b57edabb15133f1f94e57434e0a958d61186087b1008e89c94875d019910a213181a14fc8c + languageName: node + linkType: hard + +"strip-final-newline@npm:^2.0.0": + version: 2.0.0 + resolution: "strip-final-newline@npm:2.0.0" + checksum: 69412b5e25731e1938184b5d489c32e340605bb611d6140344abc3421b7f3c6f9984b21dff296dfcf056681b82caa3bb4cc996a965ce37bcfad663e92eae9c64 + languageName: node + linkType: hard + +"supports-color@npm:^7.1.0": + version: 7.2.0 + resolution: "supports-color@npm:7.2.0" + dependencies: + has-flag: ^4.0.0 + checksum: 3dda818de06ebbe5b9653e07842d9479f3555ebc77e9a0280caf5a14fb877ffee9ed57007c3b78f5a6324b8dbeec648d9e97a24e2ed9fdb81ddc69ea07100f4a + languageName: node + linkType: hard + +"supports-color@npm:^8.1.1": + version: 8.1.1 + resolution: "supports-color@npm:8.1.1" + dependencies: + has-flag: ^4.0.0 + checksum: c052193a7e43c6cdc741eb7f378df605636e01ad434badf7324f17fb60c69a880d8d8fcdcb562cf94c2350e57b937d7425ab5b8326c67c2adc48f7c87c1db406 + languageName: node + linkType: hard + +"throttleit@npm:^1.0.0": + version: 1.0.0 + resolution: "throttleit@npm:1.0.0" + checksum: 1b2db4d2454202d589e8236c07a69d2fab838876d370030ebea237c34c0a7d1d9cf11c29f994531ebb00efd31e9728291042b7754f2798a8352ec4463455b659 + languageName: node + linkType: hard + +"through@npm:^2.3.8": + version: 2.3.8 + resolution: "through@npm:2.3.8" + checksum: a38c3e059853c494af95d50c072b83f8b676a9ba2818dcc5b108ef252230735c54e0185437618596c790bbba8fcdaef5b290405981ffa09dce67b1f1bf190cbd + languageName: node + linkType: hard + +"tmp@npm:~0.2.1": + version: 0.2.1 + resolution: "tmp@npm:0.2.1" + dependencies: + rimraf: ^3.0.0 + checksum: 8b1214654182575124498c87ca986ac53dc76ff36e8f0e0b67139a8d221eaecfdec108c0e6ec54d76f49f1f72ab9325500b246f562b926f85bcdfca8bf35df9e + languageName: node + linkType: hard + +"tough-cookie@npm:~2.5.0": + version: 2.5.0 + resolution: "tough-cookie@npm:2.5.0" + dependencies: + psl: ^1.1.28 + punycode: ^2.1.1 + checksum: 16a8cd090224dd176eee23837cbe7573ca0fa297d7e468ab5e1c02d49a4e9a97bb05fef11320605eac516f91d54c57838a25864e8680e27b069a5231d8264977 + languageName: node + linkType: hard + +"tslib@npm:^2.1.0": + version: 2.4.0 + resolution: "tslib@npm:2.4.0" + checksum: 8c4aa6a3c5a754bf76aefc38026134180c053b7bd2f81338cb5e5ebf96fefa0f417bff221592bf801077f5bf990562f6264fecbc42cd3309b33872cb6fc3b113 + languageName: node + linkType: hard + +"tunnel-agent@npm:^0.6.0": + version: 0.6.0 + resolution: "tunnel-agent@npm:0.6.0" + dependencies: + safe-buffer: ^5.0.1 + checksum: 05f6510358f8afc62a057b8b692f05d70c1782b70db86d6a1e0d5e28a32389e52fa6e7707b6c5ecccacc031462e4bc35af85ecfe4bbc341767917b7cf6965711 + languageName: node + linkType: hard + +"tweetnacl@npm:^0.14.3, tweetnacl@npm:~0.14.0": + version: 0.14.5 + resolution: "tweetnacl@npm:0.14.5" + checksum: 6061daba1724f59473d99a7bb82e13f211cdf6e31315510ae9656fefd4779851cb927adad90f3b488c8ed77c106adc0421ea8055f6f976ff21b27c5c4e918487 + languageName: node + linkType: hard + +"type-fest@npm:^0.21.3": + version: 0.21.3 + resolution: "type-fest@npm:0.21.3" + checksum: e6b32a3b3877f04339bae01c193b273c62ba7bfc9e325b8703c4ee1b32dc8fe4ef5dfa54bf78265e069f7667d058e360ae0f37be5af9f153b22382cd55a9afe0 + languageName: node + linkType: hard + +"typescript@npm:^4.1.3": + version: 4.8.2 + resolution: "typescript@npm:4.8.2" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 7f5b81d0d558c9067f952c7af52ab7f19c2e70a916817929e4a5b256c93990bf3178eccb1ac8a850bc75df35f6781b6f4cb3370ce20d8b1ded92ed462348f628 + languageName: node + linkType: hard + +"typescript@patch:typescript@^4.1.3#~builtin": + version: 4.8.2 + resolution: "typescript@patch:typescript@npm%3A4.8.2#~builtin::version=4.8.2&hash=a1c5e5" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 5cb0f02f414f5405f4b0e7ee1fd7fa9177b6a8783c9017b6cad85f56ce4c4f93e0e6f2ce37e863cb597d44227cd009474c9fbd85bf7a50004e5557426cb58079 + languageName: node + linkType: hard + +"universalify@npm:^2.0.0": + version: 2.0.0 + resolution: "universalify@npm:2.0.0" + checksum: 2406a4edf4a8830aa6813278bab1f953a8e40f2f63a37873ffa9a3bc8f9745d06cc8e88f3572cb899b7e509013f7f6fcc3e37e8a6d914167a5381d8440518c44 + languageName: node + linkType: hard + +"untildify@npm:^4.0.0": + version: 4.0.0 + resolution: "untildify@npm:4.0.0" + checksum: 39ced9c418a74f73f0a56e1ba4634b4d959422dff61f4c72a8e39f60b99380c1b45ed776fbaa0a4101b157e4310d873ad7d114e8534ca02609b4916bb4187fb9 + languageName: node + linkType: hard + +"uuid@npm:^8.3.2": + version: 8.3.2 + resolution: "uuid@npm:8.3.2" + bin: + uuid: dist/bin/uuid + checksum: 5575a8a75c13120e2f10e6ddc801b2c7ed7d8f3c8ac22c7ed0c7b2ba6383ec0abda88c905085d630e251719e0777045ae3236f04c812184b7c765f63a70e58df + languageName: node + linkType: hard + +"verror@npm:1.10.0": + version: 1.10.0 + resolution: "verror@npm:1.10.0" + dependencies: + assert-plus: ^1.0.0 + core-util-is: 1.0.2 + extsprintf: ^1.2.0 + checksum: c431df0bedf2088b227a4e051e0ff4ca54df2c114096b0c01e1cbaadb021c30a04d7dd5b41ab277bcd51246ca135bf931d4c4c796ecae7a4fef6d744ecef36ea + languageName: node + linkType: hard + +"which@npm:^2.0.1": + version: 2.0.2 + resolution: "which@npm:2.0.2" + dependencies: + isexe: ^2.0.0 + bin: + node-which: ./bin/node-which + checksum: 1a5c563d3c1b52d5f893c8b61afe11abc3bab4afac492e8da5bde69d550de701cf9806235f20a47b5c8fa8a1d6a9135841de2596535e998027a54589000e66d1 + languageName: node + linkType: hard + +"wrap-ansi@npm:^6.2.0": + version: 6.2.0 + resolution: "wrap-ansi@npm:6.2.0" + dependencies: + ansi-styles: ^4.0.0 + string-width: ^4.1.0 + strip-ansi: ^6.0.0 + checksum: 6cd96a410161ff617b63581a08376f0cb9162375adeb7956e10c8cd397821f7eb2a6de24eb22a0b28401300bf228c86e50617cd568209b5f6775b93c97d2fe3a + languageName: node + linkType: hard + +"wrap-ansi@npm:^7.0.0": + version: 7.0.0 + resolution: "wrap-ansi@npm:7.0.0" + dependencies: + ansi-styles: ^4.0.0 + string-width: ^4.1.0 + strip-ansi: ^6.0.0 + checksum: a790b846fd4505de962ba728a21aaeda189b8ee1c7568ca5e817d85930e06ef8d1689d49dbf0e881e8ef84436af3a88bc49115c2e2788d841ff1b8b5b51a608b + languageName: node + linkType: hard + +"wrappy@npm:1": + version: 1.0.2 + resolution: "wrappy@npm:1.0.2" + checksum: 159da4805f7e84a3d003d8841557196034155008f817172d4e986bd591f74aa82aa7db55929a54222309e01079a65a92a9e6414da5a6aa4b01ee44a511ac3ee5 + languageName: node + linkType: hard + +"yallist@npm:^4.0.0": + version: 4.0.0 + resolution: "yallist@npm:4.0.0" + checksum: 343617202af32df2a15a3be36a5a8c0c8545208f3d3dfbc6bb7c3e3b7e8c6f8e7485432e4f3b88da3031a6e20afa7c711eded32ddfb122896ac5d914e75848d5 + languageName: node + linkType: hard + +"yauzl@npm:^2.10.0": + version: 2.10.0 + resolution: "yauzl@npm:2.10.0" + dependencies: + buffer-crc32: ~0.2.3 + fd-slicer: ~1.1.0 + checksum: 7f21fe0bbad6e2cb130044a5d1d0d5a0e5bf3d8d4f8c4e6ee12163ce798fee3de7388d22a7a0907f563ac5f9d40f8699a223d3d5c1718da90b0156da6904022b + languageName: node + linkType: hard diff --git a/docs/auth/auth-backend.md b/docs/auth/auth-backend.md deleted file mode 100644 index 6d8b95ac9f..0000000000 --- a/docs/auth/auth-backend.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -id: auth-backend -title: Auth backend -description: Documentation on Auth backend ---- - -## TODO diff --git a/docs/auth/index.md b/docs/auth/index.md index 8d303c776d..ab04d3ed87 100644 --- a/docs/auth/index.md +++ b/docs/auth/index.md @@ -65,7 +65,7 @@ the local `auth.environment` setting will be selected. > and access to a Backstage Identity Token, which can be passed to backend > plugins. -Using an authentication provide for sign-in is something you need to configure +Using an authentication provider for sign-in is something you need to configure both in the frontend app, as well as the `auth` backend plugin. For information on how to configure the backend app, see [Sign-in Identities and Resolvers](./identity-resolver.md). The rest of this section will focus on how to configure sign-in for the frontend app. diff --git a/docs/deployment/docker.md b/docs/deployment/docker.md index d46aff1b06..d35e7dd593 100644 --- a/docs/deployment/docker.md +++ b/docs/deployment/docker.md @@ -16,7 +16,8 @@ are stateless, so for a production deployment you will want to set up and connect to an external PostgreSQL instance where the backend plugins can store their state, rather than using SQLite. -By default, in an app created with `@backstage/create-app`, the frontend is +This section assumes that an [app](https://backstage.io/docs/getting-started/create-an-app) +has already been created with `@backstage/create-app`, in which the frontend is bundled and served from the backend. This is done using the `@backstage/plugin-app-backend` plugin, which also injects the frontend configuration into the app. This means that you only need to build and deploy a diff --git a/docs/features/kubernetes/authentication.md b/docs/features/kubernetes/authentication.md index 7669d967ed..d44d3a4a64 100644 --- a/docs/features/kubernetes/authentication.md +++ b/docs/features/kubernetes/authentication.md @@ -18,7 +18,7 @@ The providers currently available are divided into server side and client side. ## Server Side Providers These providers authenticate your _application_ with the cluster, meaning anyone that is -logged in into your backstage app will be granted the same access to Kubernetes objects. +logged in into your backstage app will be granted the same access to Kubernetes objects, including guest users. The providers available as server side are: @@ -28,6 +28,33 @@ The providers available as server side are: - `localKubectlProxy` - `serviceAccount` +### Azure + +The Azure server side authentication provider works by authenticating on the server with +the Azure CLI, please note that [Azure AD Authentication][1] is a requirement and has to +be enabled in your AKS cluster, then follow these steps: + +- [Install the Azure CLI][2] in the environment where the backstage application will run. +- Login with your Azure/Microsoft account with `az login` in the server's terminal. +- Go to your AKS cluster's resource page in Azure Console and follow the steps in the + `Connect` tab to set the subscription and get your credentials for `kubectl` integration. +- Configure your cluster to use the `azure` auth provider like this: + +```yaml +kubernetes: + clusterLocatorMethods: + - type: 'config' + clusters: + - name: My AKS cluster + url: ${AZURE_CLUSTER_API_SERVER_ADDRESS} + authProvider: azure + skipTLSVerify: true +``` + +To get the API server address for your Azure cluster, go to the Azure console page for the +cluster resource, go to `Overview` > `Properties` tab > `Networking` section and copy paste +the API server address directly in that `url` field. + ## Client Side Providers These providers authenticate your _user_ with the cluster. Each Backstage user will be @@ -41,3 +68,6 @@ The providers available as client side are: - `google` - `oidc` + +[1]: https://docs.microsoft.com/en-us/azure/aks/managed-aad +[2]: https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest diff --git a/docs/features/software-templates/writing-custom-actions.md b/docs/features/software-templates/writing-custom-actions.md index a9e1d297f3..b35ceb907d 100644 --- a/docs/features/software-templates/writing-custom-actions.md +++ b/docs/features/software-templates/writing-custom-actions.md @@ -156,15 +156,16 @@ export default async function createPlugin( Here is a list of Open Source custom actions that you can add to your Backstage scaffolder backend: -| Name | Package | Owner | -| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- | -| Yeoman | [plugin-scaffolder-backend-module-yeoman](https://www.npmjs.com/package/@backstage/plugin-scaffolder-backend-module-yeoman) | [Backstage](https://backstage.io) | -| Cookiecutter | [plugin-scaffolder-backend-module-cookiecutter](https://www.npmjs.com/package/@backstage/plugin-scaffolder-backend-module-cookiecutter) | [Backstage](https://backstage.io) | -| Rails | [plugin-scaffolder-backend-module-rails](https://www.npmjs.com/package/@backstage/plugin-scaffolder-backend-module-rails) | [Backstage](https://backstage.io) | -| HTTP requests | [scaffolder-backend-module-http-request](https://www.npmjs.com/package/@roadiehq/scaffolder-backend-module-http-request) | [Roadie](https://roadie.io) | -| Utility actions | [scaffolder-backend-module-utils](https://www.npmjs.com/package/@roadiehq/scaffolder-backend-module-utils) | [Roadie](https://roadie.io) | -| AWS cli actions | [scaffolder-backend-module-aws](https://www.npmjs.com/package/@roadiehq/scaffolder-backend-module-aws) | [Roadie](https://roadie.io) | -| Scaffolder .NET Actions | [plugin-scaffolder-dotnet-backend](https://www.npmjs.com/package/@plusultra/plugin-scaffolder-dotnet-backend) | [Alef Carlos](https://github.com/alefcarlos) | -| Scaffolder Git Actions | [plugin-scaffolder-git-actions](https://www.npmjs.com/package/@mdude2314/backstage-plugin-scaffolder-git-actions) | [Drew Hill](https://github.com/arhill05) | +| Name | Package | Owner | +| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ | +| Yeoman | [plugin-scaffolder-backend-module-yeoman](https://www.npmjs.com/package/@backstage/plugin-scaffolder-backend-module-yeoman) | [Backstage](https://backstage.io) | +| Cookiecutter | [plugin-scaffolder-backend-module-cookiecutter](https://www.npmjs.com/package/@backstage/plugin-scaffolder-backend-module-cookiecutter) | [Backstage](https://backstage.io) | +| Rails | [plugin-scaffolder-backend-module-rails](https://www.npmjs.com/package/@backstage/plugin-scaffolder-backend-module-rails) | [Backstage](https://backstage.io) | +| HTTP requests | [scaffolder-backend-module-http-request](https://www.npmjs.com/package/@roadiehq/scaffolder-backend-module-http-request) | [Roadie](https://roadie.io) | +| Utility actions | [scaffolder-backend-module-utils](https://www.npmjs.com/package/@roadiehq/scaffolder-backend-module-utils) | [Roadie](https://roadie.io) | +| AWS cli actions | [scaffolder-backend-module-aws](https://www.npmjs.com/package/@roadiehq/scaffolder-backend-module-aws) | [Roadie](https://roadie.io) | +| Scaffolder .NET Actions | [plugin-scaffolder-dotnet-backend](https://www.npmjs.com/package/@plusultra/plugin-scaffolder-dotnet-backend) | [Alef Carlos](https://github.com/alefcarlos) | +| Scaffolder Git Actions | [plugin-scaffolder-git-actions](https://www.npmjs.com/package/@mdude2314/backstage-plugin-scaffolder-git-actions) | [Drew Hill](https://github.com/arhill05) | +| Azure Pipeline Actions | [scaffolder-backend-module-azure-pipelines](https://www.npmjs.com/package/@parfuemerie-douglas/scaffolder-backend-module-azure-pipelines) | [Parfümerie Douglas](https://github.com/Parfuemerie-Douglas) | Have fun! 🚀 diff --git a/docs/getting-started/configuration.md b/docs/getting-started/configuration.md index 3413f32875..9ce65294ad 100644 --- a/docs/getting-started/configuration.md +++ b/docs/getting-started/configuration.md @@ -165,7 +165,7 @@ Open `packages/app/src/App.tsx` and below the last `import` line, add: ```typescript import { githubAuthApiRef } from '@backstage/core-plugin-api'; -import { SignInProviderConfig, SignInPage } from '@backstage/core-components'; +import { SignInPage } from '@backstage/core-components'; ``` Search for `const app = createApp({` in this file, and below `apis,` add: diff --git a/docs/getting-started/index.md b/docs/getting-started/index.md index d560b97eae..ade73d3f68 100644 --- a/docs/getting-started/index.md +++ b/docs/getting-started/index.md @@ -25,7 +25,7 @@ guide to do a repository-based installation. [Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/) - An account with elevated rights to install the dependencies - `curl` or `wget` installed -- Node.js [Active LTS Release](https://nodejs.org/en/about/releases/) installed using one of these +- Node.js [Active LTS Release](https://nodejs.org/en/blog/release/) installed using one of these methods: - Using `nvm` (recommended) - [Installing nvm](https://github.com/nvm-sh/nvm#install--update-script) diff --git a/docs/permissions/frontend-integration.md b/docs/permissions/frontend-integration.md new file mode 100644 index 0000000000..2a429ea120 --- /dev/null +++ b/docs/permissions/frontend-integration.md @@ -0,0 +1,38 @@ +--- +id: frontend-integration +title: Frontend Integration +description: How to place your Backstage frontend components behind authorization +--- + +Now that we understand how to [author a permission policy](./writing-a-policy.md), let's consider cases where we'll need to supplement our policy with authorization checks on the frontend. + +In most cases, actual functionality that live within various plugins will already have been placed behind authorization by the plugin authors. The permission backend will use your permission policy to return an authorization result, and the plugin frontend will correspondingly show/hide/disable the relevant UI component. + +However, there are some cases where the integrator needs to supplement the policy on the frontend. One example is app level routing. + +If your Backstage permission policy may return a `DENY` for users requesting the `catalogEntityCreatePermission`, it may make sense, for example, to remove access to the `/catalog-import` page entirely: + +```diff +// packages/app/src/App.tsx + +... + ++ import { PermissionedRoute } from '@backstage/plugin-permission-react'; ++ import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common'; + +... + +- } /> ++ ++ ++ ++ } ++ /> +... + +``` + +With this change, users who are denied the `catalogEntityCreatePermission` should now be unable to access the `/catalog-import` page. diff --git a/docs/releases/v1.6.0-changelog.md b/docs/releases/v1.6.0-changelog.md new file mode 100644 index 0000000000..4172c19244 --- /dev/null +++ b/docs/releases/v1.6.0-changelog.md @@ -0,0 +1,3550 @@ +# Release v1.6.0 + +## @backstage/catalog-client@1.1.0 + +### Minor Changes + +- 65d1d4343f: Adding `validateEntity` method that calls `/validate-entity` endpoint. + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- ef9ab322de: Minor API signatures cleanup +- Updated dependencies + - @backstage/catalog-model@1.1.1 + - @backstage/errors@1.1.1 + +## @backstage/cli@0.19.0 + +### Minor Changes + +- 1fe6823bb5: Updated dependency `eslint-plugin-jest` to `^27.0.0`. + + Note that this major update to the Jest plugin contains some breaking changes. + This means that some of your tests may start seeing some new lint errors. [Read + about them + here](https://github.com/jest-community/eslint-plugin-jest/blob/main/CHANGELOG.md#2700-2022-08-28). + + These are mostly possible to fix automatically. You can try to run `yarn backstage-cli repo lint --fix` in your repo root to have most or all of them + corrected. + +### Patch Changes + +- 8d886dd33e: The `create-plugin` and `create` commands have both been deprecated in favor of a new `new` command. The `new` command is functionally identical to `create`, but the new naming makes it possible to use as yarn script, since `yarn create` is reserved. + +- cc63eb8611: Sort entries in skeleton.tar.gz for better docker layer caching + +- 548053614a: Deprecated the `plugin:diff` command. If you wish to keep running similar checks in your project we recommend using bespoke scripts. A useful utility for such scripts is `@manypkg/get-packages`, which helps you enumerate all packages in a monorepo. + +- 513b4dd4ef: The `versions:bump` command will now update dependency ranges in `package.json`, even if the new version is within the current range. + +- 221e951298: Added support for custom certificate for webpack dev server. + +- 934cc34563: Avoid validating the backend configuration schema when loading static configuration for building the frontend. + +- 3d4f5daadf: Remove use of deprecated trimLeft/trimRight + +- 817f3196f6: Added a new `migrate react-router-deps` command to aid in the migration to React Router v6 stable. + +- 742cb4f3d7: Fix issue when using `.jsx` files inside tests + +- e7600bdb04: Tweaked workspace packaging to not rewrite existing `package.json` files. + +- 6ae0f6a719: Switch out `sucrase` for `swc` for transpilation. + + `sucrase` is a little more relaxed when it comes to supporting the ways of mocking in `jest`. You might have to make some changes to your tests to meet the `jest` standard and spec if your tests seems to start failing. + + Mocks that look like this are invalid, and they will throw a reference error in line with the `jest` documentation [here on example 3](https://jestjs.io/docs/es6-class-mocks#calling-jestmock-with-the-module-factory-parameter) + + ```ts + const mockCommandExists = jest.fn(); + jest.mock('command-exists', () => mockCommandExists); + ``` + + You might need to update these mocks to look a little like the following to defer the call to the `jest.fn()` spy until the mock is called. + + ```ts + const mockCommandExists = jest.fn(); + jest.mock( + 'command-exists', + () => + (...args: any[]) => + commandExists(...args), + ); + ``` + + Also, imports are immutable. So it means that you might get some errors when trying to use `jest.spyOn` with starred imports. You might see an error like this: + + ```log + TypeError: Cannot redefine property: executeFrameHandlerStrategy + at Function.defineProperty () + + 20 | import { AuthResolverContext } from '../types'; + 21 | + > 22 | const mockFrameHandler = jest.spyOn( + | ^ + 23 | helpers, + 24 | 'executeFrameHandlerStrategy', + 25 | ) as unknown as jest.MockedFunction< + ``` + + This happens when you try to do `import * as something from './something'` and then `jest.spyOn(something, 'test)`. You will need to add a `jest.mock` call to mock out the required starred import to return `jest.fn()` functions from the start. Something like this fixes the above test: + + ```ts + jest.mock('../../helpers', () => ({ + executeFrameHandlerStrategy: jest.fn(), + })); + ``` + + You can also remove any occurrence of `hot(App)` and any import of `react-hot-loader` if you're using the that package locally, as all this has now been replaced with [React Refresh](https://www.npmjs.com/package/react-refresh) which you will get out of the box with the new CLI. + + **Note** If you're experiencing difficulties with running tests after the migration, please reach out to us on Discord to see if we can help, or raise an issue. But in the meantime you can switch back to the existing behaviour by using the following config in your root `package.json`. + + ```json + "jest": { + "transform": { + "\\.(js|jsx|ts|tsx|mjs|cjs)$": "@backstage/cli/config/jestSucraseTransform.js", + "\\.(bmp|gif|jpg|jpeg|png|frag|xml|svg|eot|woff|woff2|ttf)$": "@backstage/cli/config/jestFileTransform.js", + "\\.(yaml)$": "jest-transform-yaml" + } + } + ``` + +- 1cb078ad9f: Fixed a misconfiguration where all modules where treated as ESM by the React Refresh plugin for Webpack. + +- 1fd4f2746f: Removed internal dependencies on Lerna. It is now no longer necessary to have Lerna installed in a project to use all features of the Backstage CLI. + +- 667d917488: Updated dependency `msw` to `^0.47.0`. + +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. + +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. + +- 33fbd9f9a4: Updated dependency `@types/minimatch` to `^5.0.0`. + +- 68c2697077: Added a new `backstage-cli repo clean` command that cleans the repo root and runs the clean script in all packages. + +- 7d47def9c4: Added dependency on `@types/jest` v27. The `@types/jest` dependency has also been removed from the plugin template and should be removed from any of your own internal packages. If you wish to override the version of `@types/jest` or `jest`, use Yarn resolutions. + +- a7e82c9b01: Updated `versions:bump` command to be compatible with Yarn 3. + +- Updated dependencies + - @backstage/config-loader@1.1.4 + - @backstage/cli-common@0.1.10 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + - @backstage/release-manifests@0.0.6 + +## @backstage/core-app-api@1.1.0 + +### Minor Changes + +- a448fea691: Updated the routing system to be compatible with React Router v6 stable. + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. + +- f9ec4e46e3: When using React Router v6 stable, it is now possible for components within the `Route` element tree to have `path` props, although they will be ignored. + +- 7d47def9c4: Removed dependency on `@types/jest`. + +- 744fea158b: Added `getSystemIcons()` function to the `AppContext` available through `useApp` that will pull a list of all the icons that have been registered in the App. + +- 667d917488: Updated dependency `msw` to `^0.47.0`. + +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. + +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. + +- 8448b53dd6: Clarify that the `WebStorage` observable returns `JsonValue` items. + +- 70299c99d5: Updated `FlatRoutes` to be compatible with React Router v6 stable. + +- e9d40ebf54: If you'd like to send analytics events to multiple implementations, you may now + do so using the `MultipleAnalyticsApi` implementation provided by this package. + + ```tsx + import { MultipleAnalyticsApi } from '@backstage/core-app-api'; + import { + analyticsApiRef, + configApiRef, + storageApiRef, + identityApiRef, + } from '@internal/backstage/core-plugin-api'; + import { CustomAnalyticsApi } from '@internal/analytics'; + import { VendorAnalyticsApi } from '@vendor/analytics'; + + createApiFactory({ + api: analyticsApiRef, + deps: { configApi: configApiRef, identityApi: identityApiRef, storageApi: storageApiRef }, + factory: ({ configApi, identityApi, storageApi }) => + MultipleAnalyticsApi.fromApis([ + VendorAnalyticsApi.fromConfig(configApi, { identityApi }), + CustomAnalyticsApi.fromConfig(configApi, { identityApi, storageApi }), + ]), + }), + ``` + +- Updated dependencies + - @backstage/core-plugin-api@1.0.6 + - @backstage/config@1.0.2 + +## @backstage/test-utils@1.2.0 + +### Minor Changes + +- 817f3196f6: Elements rendered in a test app are no longer wrapped in a `Routes` and `Route` element, as this is not compatible with React Router v6 stable. + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- d9e39544be: Add missing peer dependencies +- Updated dependencies + - @backstage/core-app-api@1.1.0 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-permission-react@0.4.5 + - @backstage/config@1.0.2 + - @backstage/plugin-permission-common@0.6.4 + +## @backstage/plugin-auth-backend@0.16.0 + +### Minor Changes + +- 2fc41ebf07: Removed the previously deprecated class `AtlassianAuthProvider`. Please use `providers.atlassian.create(...)` instead. +- a291688bc5: Renamed the `RedirectInfo` type to `OAuthStartResponse` +- 8600855fbf: The auth0 integration is updated to use the `passport-auth0` library. The configuration under `auth.providers.auth0.\*` now supports an optional `audience` parameter; providing that allows you to connect to the correct API to get permissions, access tokens, and full profile information. + + [What is an Audience](https://community.auth0.com/t/what-is-the-audience/71414) + +### Patch Changes + +- 5b011fb2e6: Allow adding misc claims to JWT +- 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`. +- e1ebaeb332: Cloudflare Access Provider: Add JWT to CloudflareAccessResult +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/plugin-auth-node@0.2.5 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + +## @backstage/plugin-azure-devops@0.2.0 + +### Minor Changes + +- 6c1c59b96e: Added README card `EntityAzureReadmeCard` for Azure Devops. + + To get the README component working you'll need to do the following two steps: + + 1. First we need to add the @backstage/plugin-azure-devops package to your frontend app: + + ```bash + # From your Backstage root directory + yarn add --cwd packages/app @backstage/plugin-azure-devops + ``` + + 2. Second we need to add the `EntityAzureReadmeCard` extension to the entity page in your app: + + ```tsx + // In packages/app/src/components/catalog/EntityPage.tsx + import { + EntityAzureReadmeCard, + isAzureDevOpsAvailable, + } from '@backstage/plugin-azure-devops'; + + // As it is a card, you can customize it the way you prefer + // For example in the Service section + + const overviewContent = ( + + + + + ... + + + + + + + + ); + ``` + + **Notes:** + + - 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% + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 3f739be9d9: Minor API signatures cleanup +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/plugin-azure-devops-common@0.3.0 + - @backstage/catalog-model@1.1.1 + - @backstage/errors@1.1.1 + +## @backstage/plugin-azure-devops-common@0.3.0 + +### Minor Changes + +- 6c1c59b96e: Added README card `EntityAzureReadmeCard` for Azure Devops. + + To get the README component working you'll need to do the following two steps: + + 1. First we need to add the @backstage/plugin-azure-devops package to your frontend app: + + ```bash + # From your Backstage root directory + yarn add --cwd packages/app @backstage/plugin-azure-devops + ``` + + 2. Second we need to add the `EntityAzureReadmeCard` extension to the entity page in your app: + + ```tsx + // In packages/app/src/components/catalog/EntityPage.tsx + import { + EntityAzureReadmeCard, + isAzureDevOpsAvailable, + } from '@backstage/plugin-azure-devops'; + + // As it is a card, you can customize it the way you prefer + // For example in the Service section + + const overviewContent = ( + + + + + ... + + + + + + + + ); + ``` + + **Notes:** + + - 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% + +### Patch Changes + +- 3f739be9d9: Minor API signatures cleanup + +## @backstage/plugin-catalog-backend@1.4.0 + +### Minor Changes + +- dd395335bc: Allow unknown typed location from being registered via the location service by configuration settings +- 651c9d6800: The search index now does retain fields that have a very long value, but in the form of just a null. This makes it possible to at least filter for their existence. +- 6e63bc43f2: Added the `refresh` function to the Connection of the entity providers. + +### Patch Changes + +- eadf56bbbf: Bump `git-url-parse` version to `^13.0.0` +- 07dda0b746: Add optional value to `hasAnnotation` permission rule +- 243533ecdc: Added support to mysql on some raw queries +- ce77e78c93: Fixes a bug to be able to utilize refresh keys after the entity is loaded from cache +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- 679f7c5e95: Include entity ref into error message when catalog policies fail +- 06e2b077a1: Limit the length of error messages that get written to the database and logs - to prevent performance issues +- 62788b2ee8: The experimental `CatalogProcessingExtensionPoint` now accepts multiple providers and processors at once. +- Updated dependencies + - @backstage/backend-plugin-api@0.1.2 + - @backstage/backend-common@0.15.1 + - @backstage/plugin-permission-node@0.6.5 + - @backstage/plugin-catalog-node@1.1.0 + - @backstage/integration@1.3.1 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + - @backstage/plugin-permission-common@0.6.4 + - @backstage/plugin-scaffolder-common@1.2.0 + - @backstage/plugin-catalog-common@1.0.6 + - @backstage/plugin-search-common@1.0.1 + +## @backstage/plugin-catalog-node@1.1.0 + +### Minor Changes + +- 9743bc788c: Added refresh function to the `EntityProviderConnection` to be able to schedule refreshes from entity providers. + +### Patch Changes + +- 7d7d947352: Adds experimental `catalogServiceRef` for obtaining a `CatalogClient` in the new backend system. +- 409ed984e8: Updated usage of experimental backend service APIs. +- 62788b2ee8: The experimental `CatalogProcessingExtensionPoint` now accepts multiple providers and processors at once. +- Updated dependencies + - @backstage/backend-plugin-api@0.1.2 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/errors@1.1.1 + +## @backstage/plugin-dynatrace@0.2.0 + +### Minor Changes + +- e44c0b3811: New features: + + - Some visual improvements to the table that displays Problems + - Added support for viewing recent Synthetics results using + - Added some additional linking to the configured Dynatrace instance + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 148568b5c2: Switched to using node-fetch instead of cross-fetch as is standard for our backend packages +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/catalog-model@1.1.1 + +## @backstage/plugin-playlist@0.1.0 + +### Minor Changes + +- d3737da337: Implement playlist plugin, check out the `README.md` for more details! + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/plugin-permission-react@0.4.5 + - @backstage/plugin-search-react@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/errors@1.1.1 + - @backstage/plugin-permission-common@0.6.4 + - @backstage/plugin-playlist-common@0.1.0 + - @backstage/plugin-catalog-common@1.0.6 + +## @backstage/plugin-playlist-backend@0.1.0 + +### Minor Changes + +- d3737da337: Implement playlist plugin, check out the `README.md` for more details! + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/plugin-auth-node@0.2.5 + - @backstage/plugin-permission-node@0.6.5 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + - @backstage/plugin-permission-common@0.6.4 + - @backstage/backend-test-utils@0.1.28 + - @backstage/plugin-playlist-common@0.1.0 + +## @backstage/plugin-playlist-common@0.1.0 + +### Minor Changes + +- d3737da337: Implement playlist plugin, check out the `README.md` for more details! + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.6.4 + +## @backstage/plugin-scaffolder@1.6.0 + +### Minor Changes + +- 3424a8075d: Added support for `async` validation for the `next` version of the plugin +- ad036784e9: Ability to modify the layout of the step form +- 192d856495: Implementing review step for the scaffolder under `create/next` + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- eadf56bbbf: Bump `git-url-parse` version to `^13.0.0` +- 9ffb75616d: Fix bug with empty strings in `EntityPicker` +- 3f739be9d9: Minor API signatures cleanup +- 763fb81e82: Internal refactor to use more type safe code when dealing with route parameters. +- a66d44b72b: Fixing bug when the workspace would not be automatically saved when using `allowedOwners` +- 7d47def9c4: Removed dependency on `@types/jest`. +- 6522e459aa: Support displaying and ordering by counts in `EntityTagPicker` field. Add the `showCounts` option to enable this. Also support configuring `helperText`. +- f0510a20b5: Addition of a dismissible Error Banner in Scaffolder page +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- 9097278df2: Updated dependency `json-schema-library` to `^7.0.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- de336de9cd: fix uiSchema generation when using complex dependencies +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/plugin-permission-react@0.4.5 + - @backstage/integration@1.3.1 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + - @backstage/integration-react@1.1.4 + - @backstage/plugin-scaffolder-common@1.2.0 + - @backstage/plugin-catalog-common@1.0.6 + +## @backstage/plugin-scaffolder-backend@1.6.0 + +### Minor Changes + +- ea2eee9e6a: Add the option for a homepage when using the `github:publish` action + +- 8872cc735d: Fixed a bug in plugin-scaffolder-backend where it ignores the skip migration database options. + + To use this new implementation you need to create the instance of `DatabaseTaskStore` using the `PluginDatabaseManager` instead of `Knex`; + + import { DatabaseManager, getRootLogger, loadBackendConfig } from '@backstage/backend-common'; + import { DatabaseTaskStore } from '@backstage/plugin-scaffolder-backend'; + + const config = await loadBackendConfig({ argv: process.argv, logger: getRootLogger() }); + const databaseManager = DatabaseManager.fromConfig(config, { migrations: { skip: true } }); + const databaseTaskStore = await DatabaseTaskStore.create(databaseManager); + +- 7db9613671: Added `projectId` for gitlab projects to be displayed in the `gitlab:publish` output + +- d1f7ba58e3: Added `repositoryId` output when create a repository in Azure + +- 1ff817b3f0: add entity metadata to the template info type + +### Patch Changes + +- eadf56bbbf: Bump `git-url-parse` version to `^13.0.0` +- de8ee4afe3: Provide information about the user into scaffolder template action's context +- 096631e571: Added support for handling broken symlinks within the scaffolder backend. This is intended for templates that may hold a symlink that is invalid at build time but valid within the destination repo. +- 0d8d650e32: Applied the fix from version 1.5.1 of this package, which is part of the v1.5.1 release of Backstage. +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- 2df9955f4a: Removed the depreacated `publish:file` action, use the template editor to test templates instead. +- 0ecc9a6784: Properly set `ctx.isDryRun` when running actions in dry run mode. Also always log action inputs for debugging purposes when running in dry run mode. +- 6b9f6c0a4d: Added alpha `scaffolderPlugin` to be used with experimental backend system. +- 83c037cd46: Disable octokit throttling in publish:github:pull-request +- 2cbd533426: Uptake the `IdentityApi` change to use `getIdentity` instead of `authenticate` for retrieving the logged in users identity. +- ef9ab322de: Minor API signatures cleanup +- 50467bc15b: The number of task workers used to execute templates now default to 3, rather than 1. +- Updated dependencies + - @backstage/backend-plugin-api@0.1.2 + - @backstage/backend-common@0.15.1 + - @backstage/plugin-auth-node@0.2.5 + - @backstage/plugin-catalog-node@1.1.0 + - @backstage/integration@1.3.1 + - @backstage/plugin-catalog-backend@1.4.0 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + - @backstage/plugin-scaffolder-common@1.2.0 + +## @backstage/plugin-scaffolder-common@1.2.0 + +### Minor Changes + +- 1ff817b3f0: add entity metadata to the template info type + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.1 + +## @backstage/plugin-search-backend-module-pg@0.4.0 + +### Minor Changes + +- 8872cc735d: Fixed a bug in search-backend-module-pg where it ignores the skip migration database options when using the database. + + To use this new implementation you need to create the instance of `DatabaseDocumentStore` using the `PluginDatabaseManager` instead of `Knex`; + + import { DatabaseManager, getRootLogger, loadBackendConfig } from '@backstage/backend-common'; + import { DatabaseDocumentStore } from '@backstage/plugin-search-backend-module-pg'; + + const config = await loadBackendConfig({ argv: process.argv, logger: getRootLogger() }); + const databaseManager = DatabaseManager.fromConfig(config, { migrations: { skip: true } }); + const databaseDocumentStore = await DatabaseDocumentStore.create(databaseManager); + +### Patch Changes + +- d669d89206: Minor API signatures cleanup +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/plugin-search-backend-node@1.0.2 + - @backstage/config@1.0.2 + - @backstage/plugin-search-common@1.0.1 + +## @backstage/plugin-search-react@1.1.0 + +### Minor Changes + +- 97f2b8f3fd: The `` component now accepts a optional `query` prop to request results from the search api: + + > Note: If a query prop is not defined, the results will by default be consumed from the context. + + Example: + + ```jsx + import React, { useState, useCallback } from 'react'; + + import { Grid, List, Paper } from '@material-ui/core'; + + import { Page, Header, Content, Lifecycle } from '@backstage/core-components'; + import { + DefaultResultListItem, + SearchBarBase, + SearchResult, + } from '@backstage/plugin-search-react'; + + const SearchPage = () => { + const [query, setQuery] = useState({ + term: '', + types: [], + filters: {}, + }); + + const handleChange = useCallback( + (term: string) => { + setQuery(prevQuery => ({ ...prevQuery, term })); + }, + [setQuery], + ); + + return ( + +
} /> + + + + + + + + + + {({ results }) => ( + + {results.map(({ document }) => ( + + ))} + + )} + + + + + + ); + }; + ``` + + Additionally, a search page can also be composed using these two new results layout components: + + ```jsx + // Example rendering results as list + + {({ results }) => ( + { + switch (type) { + case 'custom-result-item': + return ( + + ); + default: + return ( + + ); + } + }} + /> + )} + + ``` + + ```jsx + // Example rendering results as groups + + {({ results }) => ( + <> + } + title="Custom" + link="See all custom results" + resultItems={results.filter( + ({ type }) => type === 'custom-result-item', + )} + renderResultItem={({ document }) => ( + + )} + /> + } + title="Default" + resultItems={results.filter( + ({ type }) => type !== 'custom-result-item', + )} + renderResultItem={({ document }) => ( + + )} + /> + + )} + + ``` + + A `SearchResultList` and `SearchResultGroup` components were also created for users who have search pages with multiple queries, both are specializations of `SearchResult` and also accept a `query` as a prop as well: + + ```jsx + // Example using the + const SearchPage = () => { + const query = { + term: 'example', + }; + + return ( + { + switch (type) { + case 'custom': + return ( + } + result={document} + highlight={highlight} + rank={rank} + /> + ); + default: + return ( + + ); + } + }} + /> + ); + }; + ``` + + ```jsx + // Example using the for creating a component that search and group software catalog results + import React, { useState, useCallback } from 'react'; + + import { MenuItem } from '@material-ui/core'; + + import { JsonValue } from '@backstage/types'; + import { CatalogIcon } from '@backstage/core-components'; + import { CatalogSearchResultListItem } from '@backstage/plugin-catalog'; + import { + SearchResultGroup, + SearchResultGroupTextFilterField, + SearchResultGroupSelectFilterField, + } from @backstage/plugin-search-react; + import { SearchQuery } from '@backstage/plugin-search-common'; + + const CatalogResultsGroup = () => { + const [query, setQuery] = useState>({ + types: ['software-catalog'], + }); + + const filterOptions = [ + { + label: 'Lifecycle', + value: 'lifecycle', + }, + { + label: 'Owner', + value: 'owner', + }, + ]; + + const handleFilterAdd = useCallback( + (key: string) => () => { + setQuery(prevQuery => { + const { filters: prevFilters, ...rest } = prevQuery; + const newFilters = { ...prevFilters, [key]: undefined }; + return { ...rest, filters: newFilters }; + }); + }, + [], + ); + + const handleFilterChange = useCallback( + (key: string) => (value: JsonValue) => { + setQuery(prevQuery => { + const { filters: prevFilters, ...rest } = prevQuery; + const newFilters = { ...prevFilters, [key]: value }; + return { ...rest, filters: newFilters }; + }); + }, + [], + ); + + const handleFilterDelete = useCallback( + (key: string) => () => { + setQuery(prevQuery => { + const { filters: prevFilters, ...rest } = prevQuery; + const newFilters = { ...prevFilters }; + delete newFilters[key]; + return { ...rest, filters: newFilters }; + }); + }, + [], + ); + + return ( + } + title="Software Catalog" + link="See all software catalog results" + filterOptions={filterOptions} + renderFilterOption={({ label, value }) => ( + + {label} + + )} + renderFilterField={(key: string) => { + switch (key) { + case 'lifecycle': + return ( + + Production + Experimental + + ); + case 'owner': + return ( + + ); + default: + return null; + } + } + renderResultItem={({ document, highlight, rank }) => ( + + )} + /> + ); + }; + ``` + +- 18f60427f2: Provides search autocomplete functionality through a `SearchAutocomplete` component. + A `SearchAutocompleteDefaultOption` can also be used to render options with icons, primary texts, and secondary texts. + Example: + + ```jsx + import React, { ChangeEvent, useState, useCallback } from 'react'; + import useAsync from 'react-use/lib/useAsync'; + + import { Grid, Paper } from '@material-ui/core'; + + import { Page, Content } from '@backstage/core-components'; + import { SearchAutocomplete, SearchAutocompleteDefaultOption} from '@backstage/plugin-search-react'; + + const OptionsIcon = () => + + const SearchPage = () => { + const [inputValue, setInputValue] = useState(''); + + const options = useAsync(async () => { + // Gets and returns autocomplete options + }, [inputValue]) + + const useCallback((_event: ChangeEvent<{}>, newInputValue: string) => { + setInputValue(newInputValue); + }, [setInputValue]) + + return ( + + + + + + option.title} + renderOption={option => ( + } + primaryText={option.title} + secondaryText={option.text} + /> + )} + /> + + + + {'/* Filters and results are omitted */'} + + + ); + }; + ``` + +- ca8d5a6eae: We noticed a repeated check for the existence of a parent context before creating a child search context in more the one component such as Search Modal and Search Bar and to remove code duplication we extract the conditional to the context provider, now you can use it passing an `inheritParentContextIfAvailable` prop to the `SearchContextProvider`. + + Note: This added property does not create a local context if there is a parent context and in this case, you cannot use it together with `initialState`, it will result in a type error because the parent context is already initialized. + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- d3737da337: Reset page cursor on search filter change +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-search-common@1.0.1 + +## @backstage/plugin-tech-insights@0.3.0 + +### Minor Changes + +- f7e99ac1d8: Added the possibility to display check results of different types on a single scorecard. + + - **BREAKING** Removed the `getScorecardsDefinition` method from the `TechInsightsApi` interface. Added the `getCheckResultRenderers` method that returns rendering components for given types. + - **BREAKING** The `CheckResultRenderer` type now exposes the `component` factory method that creates a React component used to display a result of a provided check result. + - The `TechInsightsClient` constructor accepts now the optional `renderers` parameter that can be used to inject a custom renderer. + - **BREAKING** The `title` parameter in the `EntityTechInsightsScorecardContent` and `EntityTechInsightsScorecardCard` components is now mandatory. + - The `jsonRulesEngineCheckResultRenderer` used to render `json-rules-engine` check results is exported. + - The `BooleanCheck` component that can be used to render other check results types is also exported. + + If you were overriding the `getScorecardsDefinition` method to adjust the rendering of check results, you should now provide a custom renderer using `renderers` parameter in the `TechInsightsClient` class. + + See the [README](https://github.com/backstage/backstage/tree/master/plugins/tech-insights/README.md) for more details. + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 3f739be9d9: Minor API signatures cleanup +- 763fb81e82: Internal refactor to use more type safe code when dealing with route parameters. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + - @backstage/errors@1.1.1 + +## @backstage/plugin-techdocs-backend@1.3.0 + +### Minor Changes + +- aa524a5377: Add `projectId` config option to GCP Cloud Storage techdocs publisher. This will allow users to override the project ID, instead of implicitly using the same one as found in a credentials bundle. + +### Patch Changes + +- 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/plugin-techdocs-node@1.4.0 + - @backstage/integration@1.3.1 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + - @backstage/plugin-permission-common@0.6.4 + - @backstage/plugin-catalog-common@1.0.6 + - @backstage/plugin-search-common@1.0.1 + +## @backstage/plugin-techdocs-node@1.4.0 + +### Minor Changes + +- aa524a5377: Add `projectId` config option to GCP Cloud Storage techdocs publisher. This will allow users to override the project ID, instead of implicitly using the same one as found in a credentials bundle. + +### Patch Changes + +- 33ac0c0546: Fix Techdocs S3 and GCS publisher to include bucketRootPath in requests +- eadf56bbbf: Bump `git-url-parse` version to `^13.0.0` +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/integration@1.3.1 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + - @backstage/plugin-search-common@1.0.1 + +## @backstage/plugin-user-settings-backend@0.1.0 + +### Minor Changes + +- 108cdc3912: Added new plugin `@backstage/plugin-user-settings-backend` to store user related + settings in the database. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/plugin-auth-node@0.2.5 + - @backstage/catalog-model@1.1.1 + - @backstage/errors@1.1.1 + +## @backstage/app-defaults@1.0.6 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- d9e39544be: Add missing peer dependencies +- Updated dependencies + - @backstage/core-app-api@1.1.0 + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-permission-react@0.4.5 + +## @backstage/backend-app-api@0.2.1 + +### Patch Changes + +- 2c57c0c499: Made `ApiRef.defaultFactory` internal. +- 854ba37357: Updated to support new `ServiceFactory` formats. +- af6bb42c68: Updated `ServiceRegistry` to not initialize factories more than once. +- 409ed984e8: Updated service implementations and backend wiring to support scoped service. +- de3347ca74: Updated usages of `ServiceFactory`. +- 1f384c5644: Improved error messaging when failing to instantiate services. +- Updated dependencies + - @backstage/backend-plugin-api@0.1.2 + - @backstage/backend-common@0.15.1 + - @backstage/plugin-permission-node@0.6.5 + - @backstage/backend-tasks@0.3.5 + - @backstage/errors@1.1.1 + +## @backstage/backend-common@0.15.1 + +### Patch Changes + +- 399286d7dd: Workaround support for `swc` instead of `sucrase` + +- eadf56bbbf: Bump `git-url-parse` version to `^13.0.0` + +- c3c90280be: Added a keep-alive refresh loop to the `DatabaseManager`, keeping the connection + pool up. + +- c3c90280be: The options part of `DatabaseManager.fromConfig` now accepts an optional logger + field. + +- 3d4f5daadf: Remove use of deprecated trimLeft/trimRight + +- bf3cc134eb: Implemented KubernetesContainerRunner: a ContainerRunner implementation that leverages Jobs on a kubernetes cluster + + ```ts + const kubeConfig = new KubeConfig(); + kubeConfig.loadFromDefault(); + + const options: KubernetesContainerRunnerOptions = { + kubeConfig, + // namespace where Jobs will be created + namespace: 'default', + // Jobs name will be prefixed with this name + name: 'my-runner', + // An existing Kubernetes volume that will be used + // as base for mounts + mountBase: { + volumeName: 'workdir', + // Every mount must start with the base path + // see example below + basePath: '/workdir', + }, + // Define a Pod template for the Jobs. It has to include + // a volume definition named as the mountBase volumeName + podTemplate: { + spec: { + containers: [], + volumes: [ + { + name: 'workdir', + persistentVolumeClaim: { + claimName: 'workdir-claim', + }, + }, + ], + }, + }, + }; + const containerRunner = new KubernetesContainerRunner(options); + + const runOptions: RunContainerOptions = { + imageName: 'golang:1.17', + args: ['echo', 'hello world'], + mountDirs: { + '/workdir/app': '/app', + }, + }; + containerRunner.runContainer(runOptions); + ``` + +- e3b1993788: Added port ranges in allowed hosts: + + ```yaml + reading: + allow: + - host: *.examples.org:900-1000 + ``` + +- 2f52e74b49: Got rid of usages of the uppercase String type + +- 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`. + +- 709f468330: The `branch` command has been added to the `isomorphic-git` wrapper. + +- 0c780278e0: Fix for entries being skipped or incomplete when reading large zip archives. + +- 96689fbdcb: Workaround for a rare race condition in tests. + +- Updated dependencies + - @backstage/integration@1.3.1 + - @backstage/config-loader@1.1.4 + - @backstage/cli-common@0.1.10 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + +## @backstage/backend-defaults@0.1.1 + +### Patch Changes + +- 854ba37357: Updated to support new `ServiceFactory` formats. +- de3347ca74: Updated usages of `ServiceFactory`. +- Updated dependencies + - @backstage/backend-app-api@0.2.1 + - @backstage/backend-plugin-api@0.1.2 + +## @backstage/backend-plugin-api@0.1.2 + +### Patch Changes + +- 2c57c0c499: Made `ApiRef.defaultFactory` internal. +- 91eed37a39: Updated `createBackendPlugin` and `createBackendModule` to properly forward lack of options. +- 409ed984e8: Service are now scoped to either `'plugin'` or `'root'` scope. Service factories have been updated to provide dependency instances directly rather than factory functions. +- eef91a2558: Simplified the `ServiceFactory` type and removed `AnyServiceFactory`. +- 854ba37357: The `createServiceFactory` method has been updated to return a higher-order factory that can accept options. +- 68513f169a: When defining a new `ServiceRef` you can now also include a `defaultFactory`, which will be used to construct instances of the service in case there is no explicit factory defined. +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/backend-tasks@0.3.5 + - @backstage/config@1.0.2 + - @backstage/plugin-permission-common@0.6.4 + +## @backstage/backend-tasks@0.3.5 + +### Patch Changes + +- 243533ecdc: Added support to mysql on some raw queries +- 8872cc735d: Fixed a bug where the database option to skip migrations was ignored. +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + +## @backstage/backend-test-utils@0.1.28 + +### Patch Changes + +- 854ba37357: Updated to support new `ServiceFactory` formats. +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- de3347ca74: Updated usages of `ServiceFactory`. +- Updated dependencies + - @backstage/cli@0.19.0 + - @backstage/backend-app-api@0.2.1 + - @backstage/backend-plugin-api@0.1.2 + - @backstage/backend-common@0.15.1 + - @backstage/config@1.0.2 + +## @backstage/catalog-model@1.1.1 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- Updated dependencies + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + +## @backstage/cli-common@0.1.10 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. + +## @backstage/codemods@0.1.39 + +### Patch Changes + +- Updated dependencies + - @backstage/cli-common@0.1.10 + +## @backstage/config@1.0.2 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. + +## @backstage/config-loader@1.1.4 + +### Patch Changes + +- 5ecca7e44b: No longer log when reloading remote config. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/cli-common@0.1.10 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + +## @backstage/core-components@0.11.1 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- d3737da337: Export `HeaderActionMenu` and expose default `Table` icons via `Table.icons` +- 7d47def9c4: Removed dependency on `@types/jest`. +- b29c44d895: Adds code to generate ids for headers parsed through the MarkdownContent component. +- 37e8c5e128: The `RoutedTabs` component has been updated to be compatible with React Router v6 stable. +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- 13f23f6510: Allow custom images in the empty state component +- 023d14c52b: Fix overflow bug on MicDrop image for 404 page by moving the image and making it relative rather than absolute +- c8bb0ff8ce: Minor cleanup of the public API surface to reduce the number of warnings +- Updated dependencies + - @backstage/core-plugin-api@1.0.6 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + +## @backstage/core-plugin-api@1.0.6 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 744fea158b: Added `getSystemIcons()` function to the `AppContext` available through `useApp` that will pull a list of all the icons that have been registered in the App. +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- ef9ab322de: Minor API signatures cleanup +- Updated dependencies + - @backstage/config@1.0.2 + +## @backstage/create-app@0.4.31 + +### Patch Changes + +- 6ff94d60d5: Removed usage of the deprecated `diff` command in the root `package.json`. + + To make this change in an existing app, make the following change in the root `package.json`: + + ```diff + - "diff": "lerna run diff --", + ``` + +- c1f1a4c760: The Backstage packages and plugins have all been updated to support React Router v6 stable. The `create-app` template has not been migrated yet, but if you want to migrate your own app or plugins, check out the [migration guide](https://backstage.io/docs/tutorials/react-router-stable-migration). + +- e83de28e36: Fix typo in the documentation + +- 7d47def9c4: Removed dependency on `@types/jest`. + +- 208d6780c9: The `packages/backend/Dockerfile` received a couple of updates, it now looks as follows: + + ```Dockerfile + FROM node:16-bullseye-slim + + # Install sqlite3 dependencies. You can skip this if you don't use sqlite3 in the image, + # in which case you should also move better-sqlite3 to "devDependencies" in package.json. + RUN apt-get update && \ + apt-get install -y --no-install-recommends libsqlite3-dev python3 build-essential && \ + rm -rf /var/lib/apt/lists/* && \ + yarn config set python /usr/bin/python3 + + # From here on we use the least-privileged `node` user to run the backend. + USER node + WORKDIR /app + + # This switches many Node.js dependencies to production mode. + ENV NODE_ENV production + + # Copy repo skeleton first, to avoid unnecessary docker cache invalidation. + # The skeleton contains the package.json of each package in the monorepo, + # and along with yarn.lock and the root package.json, that's enough to run yarn install. + COPY --chown=node:node yarn.lock package.json packages/backend/dist/skeleton.tar.gz ./ + RUN tar xzf skeleton.tar.gz && rm skeleton.tar.gz + + RUN yarn install --frozen-lockfile --production --network-timeout 300000 && rm -rf "$(yarn cache dir)" + + # Then copy the rest of the backend bundle, along with any other files we might want. + COPY --chown=node:node packages/backend/dist/bundle.tar.gz app-config*.yaml ./ + RUN tar xzf bundle.tar.gz && rm bundle.tar.gz + + CMD ["node", "packages/backend", "--config", "app-config.yaml", "--config", "app-config.production.yaml"] + ``` + + The two notable changes are that a `USER node` instruction has been added and the ordering of instructions has been changed accordingly. This means that the app will now be running using the least-privileged `node` user. In order for this to work we now need to make sure that all app files are owned by the `node` user, which we do by adding the `--chown=node:node` option to the `COPY` instructions. + + The second change is the addition of `ENV NODE_ENV production`, which ensured that all Node.js modules run in production mode. If you apply this change to an existing app, note that one of the more significant changes is that this switches the log formatting to use the default production format, JSON. Rather than your log lines looking like this: + + ```log + 2022-08-10T11:36:05.478Z catalog info Performing database migration type=plugin + ``` + + They will now look like this: + + ```log + {"level":"info","message":"Performing database migration","plugin":"catalog","service":"backstage","type":"plugin"} + ``` + + If you wish to keep the existing format, you can override this change by applying the following change to `packages/backend/src/index.ts`: + + ```diff + getRootLogger, + + setRootLogger, + + createRootLogger, + + coloredFormat, + useHotMemoize, + ... + ServerTokenManager, + } from '@backstage/backend-common'; + + ... + + async function main() { + + setRootLogger(createRootLogger({ format: coloredFormat })); + + + const config = await loadBackendConfig({ + ``` + +- 49416194e8: Adds `IdentityApi` configuration to `create-app` scaffolding templates. + + To migrate to the new `IdentityApi`, edit the `packages/backend/src/index.ts` adding the following import: + + ```typescript + import { DefaultIdentityClient } from '@backstage/plugin-auth-node'; + ``` + + Use the factory function to create an `IdentityApi` in the `makeCreateEnv` function and return it from the + function as follows: + + ```typescript + function makeCreateEnv(config: Config) { + ... + const identity = DefaultIdentityClient.create({ + discovery, + }); + ... + + return { + ..., + identity + } + } + ``` + + Backend plugins can be upgraded to work with this new `IdentityApi`. + + Add `identity` to the `RouterOptions` type. + + ```typescript + export interface RouterOptions { + ... + identity: IdentityApi; + } + ``` + + Then you can use the `IdentityApi` from the plugin. + + ```typescript + export async function createRouter( + options: RouterOptions, + ): Promise { + const { identity } = options; + + router.get('/user', async (req, res) => { + const user = await identity.getIdentity({ request: req }); + ... + ``` + +- 8d886dd33e: Added `yarn new` as one of the scripts installed by default, which calls `backstage-cli new`. This script replaces `create-plugin`, which you can now remove if you want to. It is kept in the `create-app` template for backwards compatibility. + + The `remove-plugin` command has been removed, as it has been removed from the Backstage CLI. + + To apply these changes to an existing app, make the following change to the root `package.json`: + + ```diff + - "remove-plugin": "backstage-cli remove-plugin" + + "new": "backstage-cli new --scope internal" + ``` + +- c3c90280be: The options part of `DatabaseManager.fromConfig` now accepts an optional logger + field. You may want to supply that logger in your backend initialization code to + ensure that you can get relevant logging data when things happen related to the + connection pool. + + In `packages/backend/src/index.ts`: + + ```diff + function makeCreateEnv(config: Config) { + const root = getRootLogger(); + ... + - const databaseManager = DatabaseManager.fromConfig(config); + + const databaseManager = DatabaseManager.fromConfig(config, { logger: root }); + ``` + +- a578558180: Updated the root `package.json` to use the new `backstage-cli repo clean` command. + + To apply this change to an existing project, make the following change to the root `package.json`: + + ```diff + - "clean": "backstage-cli clean && lerna run clean", + + "clean": "backstage-cli repo clean", + ``` + +- c0a08fd08c: Added `EntityLinksCard` to the system `EntityPage`. + + For an existing installation where you want to display the links card for entity pages of kind `system` you should make the following adjustment to `packages/app/src/components/catalog/EntityPage.tsx` + + ```diff + const systemPage = ( + ... + + + + + + + + + + - + + + + + ... + ); + ``` + +- Updated dependencies + - @backstage/cli-common@0.1.10 + +## @backstage/dev-utils@1.0.6 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 329ed2b9c7: Fixed routing when using React Router v6 stable. +- 4c5e85ddf3: Removed the dependency and setup of `react-hot-loader`, since the `@backstage/cli` now uses `swc` with `React Refresh` instead. +- Updated dependencies + - @backstage/app-defaults@1.0.6 + - @backstage/core-app-api@1.1.0 + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/test-utils@1.2.0 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + - @backstage/integration-react@1.1.4 + +## @backstage/errors@1.1.1 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. + +## @backstage/integration@1.3.1 + +### Patch Changes + +- eadf56bbbf: Bump `git-url-parse` version to `^13.0.0` +- 7d47def9c4: Removed dependency on `@types/jest`. +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- 42918e085c: Fixed bug in the `bitbucketServer` integration where token did not take precedence over supplied username and password which is described in the documentation. +- f76f22c649: Improved caching around github app tokens. + Tokens are now cached for 50 minutes, not 10. + Calls to get app installations are also included in this cache. + If you have more than one github app configured, consider adding `allowedInstallationOwners` to your apps configuration to gain the most benefit from these performance changes. +- Updated dependencies + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + +## @backstage/integration-react@1.1.4 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/integration@1.3.1 + - @backstage/config@1.0.2 + +## @backstage/release-manifests@0.0.6 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. + +## @techdocs/cli@1.2.1 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/plugin-techdocs-node@1.4.0 + - @backstage/catalog-model@1.1.1 + - @backstage/cli-common@0.1.10 + - @backstage/config@1.0.2 + +## @backstage/plugin-adr@0.2.1 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- eadf56bbbf: Bump `git-url-parse` version to `^13.0.0` +- 7d47def9c4: Removed dependency on `@types/jest`. +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- c8bb0ff8ce: Minor cleanup of the public API surface to reduce the number of warnings +- b489de83b1: Fix parsing of ADR location which includes a trailing slash +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/plugin-search-react@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/integration-react@1.1.4 + - @backstage/plugin-adr-common@0.2.1 + - @backstage/plugin-search-common@1.0.1 + +## @backstage/plugin-adr-backend@0.2.1 + +### Patch Changes + +- b489de83b1: Continue processing subsequent entities when an error occurs in collator +- 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/integration@1.3.1 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + - @backstage/plugin-adr-common@0.2.1 + - @backstage/plugin-search-common@1.0.1 + +## @backstage/plugin-adr-common@0.2.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.3.1 + - @backstage/catalog-model@1.1.1 + - @backstage/plugin-search-common@1.0.1 + +## @backstage/plugin-airbrake@0.3.9 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/dev-utils@1.0.6 + - @backstage/test-utils@1.2.0 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + +## @backstage/plugin-airbrake-backend@0.2.9 + +### Patch Changes + +- 148568b5c2: Switched to using node-fetch instead of cross-fetch as is standard for our backend packages +- 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-allure@0.1.25 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + +## @backstage/plugin-analytics-module-ga@0.1.20 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/config@1.0.2 + +## @backstage/plugin-apache-airflow@0.2.2 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 2f52e74b49: Got rid of usages of the uppercase String type +- 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`. +- c8bb0ff8ce: Minor cleanup of the public API surface to reduce the number of warnings +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + +## @backstage/plugin-api-docs@0.8.9 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- ef9ab322de: Minor API signatures cleanup +- c8bb0ff8ce: Minor cleanup of the public API surface to reduce the number of warnings +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/plugin-catalog@1.5.1 + - @backstage/catalog-model@1.1.1 + +## @backstage/plugin-apollo-explorer@0.1.2 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- ef9ab322de: Minor API signatures cleanup +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + +## @backstage/plugin-app-backend@0.3.36 + +### 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`. + +- 8872cc735d: Fixed a bug where the database option to skip migrations was ignored. + +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/config-loader@1.1.4 + - @backstage/config@1.0.2 + +## @backstage/plugin-auth-node@0.2.5 + +### Patch Changes + +- 9212439d15: Minor update to tests +- 2cbd533426: `IdentityClient` is now deprecated. Please migrate to `IdentityApi` and `DefaultIdentityClient` instead. The authenticate function on `DefaultIdentityClient` is also deprecated. Please use `getIdentity` instead. +- 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/errors@1.1.1 + +## @backstage/plugin-azure-devops-backend@0.3.15 + +### Patch Changes + +- 3f739be9d9: 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`. + +- cb1cfc018b: `createRouter` now requires an additional reader: `UrlReader` argument + + ```diff + export default async function createPlugin( + env: PluginEnvironment, + ): Promise { + return createRouter({ + logger: env.logger, + config: env.config, + + reader: env.reader, + }); + } + ``` + + Remember to check if you have already provided these settings previously. + + #### [Azure DevOps] + + ```yaml + # app-config.yaml + azureDevOps: + host: dev.azure.com + token: my-token + organization: my-company + ``` + + #### [Azure Integrations] + + ```yaml + # app-config.yaml + integrations: + azure: + - host: dev.azure.com + token: ${AZURE_TOKEN} + ``` + +- ef9ab322de: Minor API signatures cleanup + +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/plugin-azure-devops-common@0.3.0 + - @backstage/config@1.0.2 + +## @backstage/plugin-badges@0.2.33 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- ef9ab322de: Minor API signatures cleanup +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + - @backstage/errors@1.1.1 + +## @backstage/plugin-badges-backend@0.1.30 + +### Patch Changes + +- ef9ab322de: Minor API signatures cleanup +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + +## @backstage/plugin-bazaar@0.1.24 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 1dd12349d1: Fixed broken routing by removing the wrapping `Router` from the `RoutedTabs` children. +- Updated dependencies + - @backstage/cli@0.19.0 + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/plugin-catalog@1.5.1 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + +## @backstage/plugin-bazaar-backend@0.1.20 + +### Patch Changes + +- 8872cc735d: Fixed a bug where the database option to skip migrations was ignored. +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/config@1.0.2 + - @backstage/backend-test-utils@0.1.28 + +## @backstage/plugin-bitbucket-cloud-common@0.1.3 + +### Patch Changes + +- 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/integration@1.3.1 + +## @backstage/plugin-bitrise@0.1.36 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + +## @backstage/plugin-catalog@1.5.1 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- d669d89206: Minor API signatures cleanup +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/plugin-search-react@1.1.0 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/errors@1.1.1 + - @backstage/integration-react@1.1.4 + - @backstage/plugin-catalog-common@1.0.6 + - @backstage/plugin-search-common@1.0.1 + +## @backstage/plugin-catalog-backend-module-aws@0.1.9 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/integration@1.3.1 + - @backstage/plugin-catalog-backend@1.4.0 + - @backstage/backend-tasks@0.3.5 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + +## @backstage/plugin-catalog-backend-module-azure@0.1.7 + +### Patch Changes + +- 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/integration@1.3.1 + - @backstage/plugin-catalog-backend@1.4.0 + - @backstage/backend-tasks@0.3.5 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + +## @backstage/plugin-catalog-backend-module-bitbucket@0.2.3 + +### Patch Changes + +- 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/integration@1.3.1 + - @backstage/plugin-catalog-backend@1.4.0 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + - @backstage/plugin-bitbucket-cloud-common@0.1.3 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.1.3 + +### Patch Changes + +- 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/integration@1.3.1 + - @backstage/plugin-catalog-backend@1.4.0 + - @backstage/backend-tasks@0.3.5 + - @backstage/config@1.0.2 + - @backstage/plugin-bitbucket-cloud-common@0.1.3 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.1.1 + +### Patch Changes + +- 148568b5c2: Switched to using node-fetch instead of cross-fetch as is standard for our backend packages +- 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/integration@1.3.1 + - @backstage/plugin-catalog-backend@1.4.0 + - @backstage/backend-tasks@0.3.5 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + +## @backstage/plugin-catalog-backend-module-gerrit@0.1.4 + +### Patch Changes + +- 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/integration@1.3.1 + - @backstage/plugin-catalog-backend@1.4.0 + - @backstage/backend-tasks@0.3.5 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + +## @backstage/plugin-catalog-backend-module-github@0.1.7 + +### Patch Changes + +- 3c4a388537: New experimental alpha exports for use with the upcoming backend system. +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- 3a62594a11: Add support for including (or excluding) Github repositories by topic +- 287a64bf97: Added the ability to configure the host for the `GitHubEntityProvider` to use against GitHub Enterprise +- 91e2abbd46: Remove the duplicated `scheduleFn` initialization in `GitHubEntityProvider`. +- Updated dependencies + - @backstage/backend-plugin-api@0.1.2 + - @backstage/backend-common@0.15.1 + - @backstage/plugin-catalog-node@1.1.0 + - @backstage/integration@1.3.1 + - @backstage/plugin-catalog-backend@1.4.0 + - @backstage/backend-tasks@0.3.5 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + +## @backstage/plugin-catalog-backend-module-gitlab@0.1.7 + +### Patch Changes + +- 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/integration@1.3.1 + - @backstage/plugin-catalog-backend@1.4.0 + - @backstage/backend-tasks@0.3.5 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + +## @backstage/plugin-catalog-backend-module-ldap@0.5.3 + +### Patch Changes + +- 7fa54c3c77: Added ae-dir LDAP vendor to correctly extract DN. +- c54fcea9af: Now the `searchStream` method in LDAP client awaits the callbacks +- Updated dependencies + - @backstage/plugin-catalog-backend@1.4.0 + - @backstage/backend-tasks@0.3.5 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + +## @backstage/plugin-catalog-backend-module-msgraph@0.4.2 + +### Patch Changes + +- c1d32d2b76: Fixed a bug in the `MicrosoftGraphEntityProvider` that ignored the `userExpand` and `groupExpand` configuration parameters +- d80aab31ae: Added $select attribute to user query +- a246d5a9b8: Read `queryMode` from the `microsoftGraphOrg` config +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- 4c82b955fc: Fix typo +- Updated dependencies + - @backstage/plugin-catalog-backend@1.4.0 + - @backstage/backend-tasks@0.3.5 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + +## @backstage/plugin-catalog-backend-module-openapi@0.1.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/plugin-catalog-node@1.1.0 + - @backstage/integration@1.3.1 + - @backstage/plugin-catalog-backend@1.4.0 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + +## @backstage/plugin-catalog-common@1.0.6 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.6.4 + - @backstage/plugin-search-common@1.0.1 + +## @backstage/plugin-catalog-graph@0.2.21 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + +## @backstage/plugin-catalog-graphql@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 + +## @backstage/plugin-catalog-import@0.8.12 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- eadf56bbbf: Bump `git-url-parse` version to `^13.0.0` +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/integration@1.3.1 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + - @backstage/integration-react@1.1.4 + +## @backstage/plugin-catalog-react@1.1.4 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- f6033d1121: humanizeEntityRef function can now be forced to include default namespace +- c86741a052: Support showing counts in option labels of the `EntityTagPicker`. You can enable this by adding the `showCounts` property +- 7d47def9c4: Removed dependency on `@types/jest`. +- a6d551fad9: Properly handle free-text entity filtering in the case of empty tag arrays +- ef9ab322de: Minor API signatures cleanup +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-permission-react@0.4.5 + - @backstage/integration@1.3.1 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/errors@1.1.1 + - @backstage/plugin-permission-common@0.6.4 + - @backstage/plugin-catalog-common@1.0.6 + +## @backstage/plugin-cicd-statistics@0.1.11 + +### Patch Changes + +- d669d89206: Minor API signatures cleanup +- Updated dependencies + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + +## @backstage/plugin-cicd-statistics-module-gitlab@0.1.5 + +### Patch Changes + +- 71b7464a7c: Fixing typo in the Readme file: `'@backstage plugin-cicd-statistics-module-gitlab';` -> `'@backstage/plugin-cicd-statistics-module-gitlab';` +- a98f5d4c21: add the ability to add CICD default options to createGitlabApi constructor +- Updated dependencies + - @backstage/core-plugin-api@1.0.6 + - @backstage/catalog-model@1.1.1 + - @backstage/plugin-cicd-statistics@0.1.11 + +## @backstage/plugin-circleci@0.3.9 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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`. +- ef9ab322de: Minor API signatures cleanup +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + +## @backstage/plugin-cloudbuild@0.3.9 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 3f739be9d9: Minor API signatures cleanup +- 763fb81e82: Internal refactor to use more type safe code when dealing with route parameters. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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`. +- ef9ab322de: Minor API signatures cleanup +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + +## @backstage/plugin-code-climate@0.1.9 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + +## @backstage/plugin-code-coverage@0.2.2 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + +## @backstage/plugin-code-coverage-backend@0.2.2 + +### Patch Changes + +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- 8872cc735d: Fixed a bug where the database option to skip migrations was ignored. +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/integration@1.3.1 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + +## @backstage/plugin-codescene@0.1.4 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + +## @backstage/plugin-config-schema@0.1.32 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + +## @backstage/plugin-cost-insights@0.11.31 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 9318bf15d4: The `CostInsightsHeader`component now uses group names if available +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + +## @backstage/plugin-explore@0.3.40 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 3f739be9d9: Minor API signatures cleanup +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + - @backstage/plugin-explore-react@0.0.21 + +## @backstage/plugin-explore-react@0.0.21 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-plugin-api@1.0.6 + +## @backstage/plugin-firehydrant@0.1.26 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + +## @backstage/plugin-fossa@0.2.41 + +### Patch Changes + +- 3f739be9d9: Minor API signatures cleanup +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + - @backstage/errors@1.1.1 + +## @backstage/plugin-gcalendar@0.3.5 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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`. +- a69ac5b63a: Upgrade `react-query:3` to `@tanstack/react-query:4` +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/errors@1.1.1 + +## @backstage/plugin-gcp-projects@0.3.28 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + +## @backstage/plugin-git-release-manager@0.3.22 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 3f739be9d9: Minor API signatures cleanup +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/integration@1.3.1 + +## @backstage/plugin-github-actions@0.5.9 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 1bdb0bf24b: Modify RecentWorkflowRunsCard use constructed route instead of hardcoded route. +- 3f739be9d9: Minor API signatures cleanup +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/integration@1.3.1 + - @backstage/catalog-model@1.1.1 + +## @backstage/plugin-github-deployments@0.1.40 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/integration@1.3.1 + - @backstage/catalog-model@1.1.1 + - @backstage/errors@1.1.1 + - @backstage/integration-react@1.1.4 + +## @backstage/plugin-github-issues@0.1.1 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/integration@1.3.1 + - @backstage/catalog-model@1.1.1 + - @backstage/errors@1.1.1 + +## @backstage/plugin-github-pull-requests-board@0.1.3 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 2665ee4ed4: Clarified GitHub app permissions required by plugin +- 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`. +- 723113296b: Add optional `pullRequestLimit` prop to `EntityTeamPullRequestsCard` and `EntityTeamPullRequestsContent` to limit the number of PRs shown per repository. Excluding this prop will default the number of pull requests shown to 10 per repository (the existing functionality). +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/integration@1.3.1 + - @backstage/catalog-model@1.1.1 + +## @backstage/plugin-gitops-profiles@0.3.27 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + +## @backstage/plugin-gocd@0.1.15 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + - @backstage/errors@1.1.1 + +## @backstage/plugin-graphiql@0.2.41 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + +## @backstage/plugin-graphql-backend@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 + +## @backstage/plugin-home@0.4.25 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/plugin-stack-overflow@0.1.5 + +## @backstage/plugin-ilert@0.1.35 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + - @backstage/errors@1.1.1 + +## @backstage/plugin-jenkins@0.7.8 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 3f739be9d9: Minor API signatures cleanup +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + - @backstage/errors@1.1.1 + - @backstage/plugin-jenkins-common@0.1.8 + +## @backstage/plugin-jenkins-backend@0.1.26 + +### Patch Changes + +- 618c06f838: Add example on how to pass through permissions +- a966ed8385: Unwrap error message when getting projects +- 47952621dc: Extend configuration so that extra headers can be sent to jenkins instance +- d669d89206: Minor API signatures cleanup +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- 69ec1cf39f: Updated dependency `jenkins` to `^1.0.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- e55d855a6b: Jenkins plugin works again +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/plugin-auth-node@0.2.5 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + - @backstage/plugin-permission-common@0.6.4 + - @backstage/plugin-jenkins-common@0.1.8 + +## @backstage/plugin-jenkins-common@0.1.8 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.6.4 + - @backstage/plugin-catalog-common@1.0.6 + +## @backstage/plugin-kafka@0.3.9 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- f6be17460d: Minor API signatures cleanup +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + +## @backstage/plugin-kafka-backend@0.2.29 + +### Patch Changes + +- f6be17460d: Minor API signatures cleanup +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + +## @backstage/plugin-kubernetes@0.7.2 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 0768d6dece: add new kubernetes backend endpoints to kubernetes backend client +- 19a27929fb: Reset error state on success +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- ef9ab322de: Minor API signatures cleanup +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/plugin-kubernetes-common@0.4.2 + +## @backstage/plugin-kubernetes-backend@0.7.2 + +### Patch Changes + +- 8902c2e39d: chore: Exporting KubernetesClientProvider and everything in kubernetes-auth-translator as requested in issue #10457 + +- a57d29d572: Adds skipMetricsLookup to the kubernetes-backend schema + +- 0768d6dece: add new kubernetes backend endpoints to kubernetes backend client + +- 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 + - @backstage/plugin-auth-node@0.2.5 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + - @backstage/plugin-kubernetes-common@0.4.2 + +## @backstage/plugin-kubernetes-common@0.4.2 + +### Patch Changes + +- 0768d6dece: add new kubernetes backend endpoints to kubernetes backend client +- d669d89206: Minor API signatures cleanup +- Updated dependencies + - @backstage/catalog-model@1.1.1 + +## @backstage/plugin-lighthouse@0.3.9 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- f6be17460d: Minor API signatures cleanup +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + +## @backstage/plugin-newrelic@0.3.27 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + +## @backstage/plugin-newrelic-dashboard@0.2.2 + +### Patch Changes + +- 3f739be9d9: Minor API signatures cleanup +- d669d89206: Minor API signatures cleanup +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + - @backstage/errors@1.1.1 + +## @backstage/plugin-org@0.5.9 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- ab6650ede9: Added an edit button to the `UserProfileCard` that is enabled when the `backstage.io/edit-url` is present, this matches how the `GroupProfileCard` works +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + +## @backstage/plugin-pagerduty@0.5.2 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 3f739be9d9: Minor API signatures cleanup +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + - @backstage/errors@1.1.1 + +## @backstage/plugin-periskop@0.1.7 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + - @backstage/errors@1.1.1 + +## @backstage/plugin-periskop-backend@0.1.7 + +### Patch Changes + +- 148568b5c2: Switched to using node-fetch instead of cross-fetch as is standard for our backend packages +- 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-permission-backend@0.5.11 + +### Patch Changes + +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- 2cbd533426: Uptake the `IdentityApi` change to use `getIdentity` instead of `authenticate` for retrieving the logged in users identity. +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/plugin-auth-node@0.2.5 + - @backstage/plugin-permission-node@0.6.5 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + - @backstage/plugin-permission-common@0.6.4 + +## @backstage/plugin-permission-common@0.6.4 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/config@1.0.2 + - @backstage/errors@1.1.1 + +## @backstage/plugin-permission-node@0.6.5 + +### Patch Changes + +- 9212439d15: Minor update to tests +- 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/plugin-auth-node@0.2.5 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + - @backstage/plugin-permission-common@0.6.4 + +## @backstage/plugin-permission-react@0.4.5 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. + +- 7d47def9c4: Removed dependency on `@types/jest`. + +- 817f3196f6: **DEPRECATION**: The `PermissionedRoute` component has been deprecated in favor of the new `RequirePermission` component. This is because the usage pattern of `PermissionedRoute` is not compatible with React Router v6 stable. + + Embed the type from `react-router` instead of exporting it directly. + +- Updated dependencies + - @backstage/core-plugin-api@1.0.6 + - @backstage/config@1.0.2 + - @backstage/plugin-permission-common@0.6.4 + +## @backstage/plugin-proxy-backend@0.2.30 + +### Patch Changes + +- f6be17460d: 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/backend-common@0.15.1 + - @backstage/config@1.0.2 + +## @backstage/plugin-rollbar@0.4.9 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + +## @backstage/plugin-rollbar-backend@0.1.33 + +### 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/backend-common@0.15.1 + - @backstage/config@1.0.2 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.2.11 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/plugin-scaffolder-backend@1.6.0 + - @backstage/integration@1.3.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-rails@0.4.4 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/plugin-scaffolder-backend@1.6.0 + - @backstage/integration@1.3.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.2.9 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.6.0 + - @backstage/config@1.0.2 + +## @backstage/plugin-search@1.0.2 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- 18f60427f2: Use the new `inheritParentContextIfAvailable` search context property in `SearchModal` instead of manually checking if a parent context exists, this conditional statement was previously duplicated in more than one component like in `SearchBar` as well and is now only done in ` SearchContextProvider`. +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/plugin-search-react@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + - @backstage/plugin-search-common@1.0.1 + +## @backstage/plugin-search-backend@1.0.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/plugin-auth-node@0.2.5 + - @backstage/plugin-permission-node@0.6.5 + - @backstage/plugin-search-backend-node@1.0.2 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + - @backstage/plugin-permission-common@0.6.4 + - @backstage/plugin-search-common@1.0.1 + +## @backstage/plugin-search-backend-module-elasticsearch@1.0.2 + +### Patch Changes + +- 1bea488bd4: Updated dependency `aws-os-connection` to `^0.2.0`. +- ef9ab322de: Minor API signatures cleanup +- Updated dependencies + - @backstage/plugin-search-backend-node@1.0.2 + - @backstage/config@1.0.2 + - @backstage/plugin-search-common@1.0.1 + +## @backstage/plugin-search-backend-node@1.0.2 + +### Patch Changes + +- 3f739be9d9: Minor API signatures cleanup +- a1124adf5e: Fixed bug in LunrSearchEngine where stopwords in title is causing in-doc search not working +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/backend-tasks@0.3.5 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + - @backstage/plugin-permission-common@0.6.4 + - @backstage/plugin-search-common@1.0.1 + +## @backstage/plugin-search-common@1.0.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.6.4 + +## @backstage/plugin-sentry@0.4.2 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 3f739be9d9: Minor API signatures cleanup +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + +## @backstage/plugin-shortcuts@0.3.1 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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`. +- 8a57ffc0fa: Ensure that a stable observable is used in the shortcuts API +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + +## @backstage/plugin-sonarqube@0.4.1 + +### Patch Changes + +- 3f739be9d9: Minor API signatures cleanup +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + +## @backstage/plugin-sonarqube-backend@0.1.1 + +### Patch Changes + +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- ef9ab322de: Minor API signatures cleanup +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + +## @backstage/plugin-splunk-on-call@0.3.33 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + +## @backstage/plugin-stack-overflow@0.1.5 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- b8190af939: Create a front end API. +- a720c44070: Support showing HTML entity references from the API response before rendering the question title to the list component. +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-home@0.4.25 + - @backstage/config@1.0.2 + - @backstage/plugin-search-common@1.0.1 + +## @backstage/plugin-stack-overflow-backend@0.1.5 + +### Patch Changes + +- 79040f73f7: Now requests all questions available using pagination. Default max page is set to 100, with a configurable `maxPage` option on the collator. +- 148568b5c2: Switched to using node-fetch instead of cross-fetch as is standard for our backend packages +- Updated dependencies + - @backstage/cli@0.19.0 + - @backstage/config@1.0.2 + - @backstage/plugin-search-common@1.0.1 + +## @backstage/plugin-tech-insights-backend@0.5.2 + +### Patch Changes + +- 8872cc735d: Fixed a bug where the database option to skip migrations was ignored. +- 12c6a07c2a: Changed the description of the `techdocsAnnotationFactName` fact. +- 2e0689e536: Support for timeout in FactRetrieverRegistrationOptions +- 9e8e9f5243: Modify Tech insight initialization to expose FactRetrieverEngine. Enables users to trigger fact retrieval manually or reschedule retrievers on runtime. +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/plugin-tech-insights-node@0.3.4 + - @backstage/backend-tasks@0.3.5 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + +## @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.20 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/plugin-tech-insights-node@0.3.4 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + +## @backstage/plugin-tech-insights-node@0.3.4 + +### Patch Changes + +- 3f739be9d9: Minor API signatures cleanup +- 2e0689e536: Support for timeout in FactRetrieverRegistrationOptions +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/backend-tasks@0.3.5 + - @backstage/config@1.0.2 + +## @backstage/plugin-tech-radar@0.5.16 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + +## @backstage/plugin-techdocs@1.3.2 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- eadf56bbbf: Bump `git-url-parse` version to `^13.0.0` +- 3f739be9d9: Minor API signatures cleanup +- 763fb81e82: Internal refactor to use more type safe code when dealing with route parameters. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 817f3196f6: Updated the `TechDocsReaderPage` to be compatible with React Router v6 stable. +- 7a95c705fa: Fixed a bug where addons wouldn't render on sub pages when using React Route v6 stable. +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- ca8d5a6eae: Use the new `SearchAutocomplete` component in the `TechDocsSearch` component to maintain consistency across search experiences and avoid code duplication. +- 829f14a9b0: Always update the title and sub-title when the location changes on a `TechDocs` reader page. +- e97d616f08: Fixed a bug where scrolling for anchors where the id starts with number didn't work for the current page. +- ef9ab322de: Minor API signatures cleanup +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/plugin-search-react@1.1.0 + - @backstage/plugin-techdocs-react@1.0.4 + - @backstage/integration@1.3.1 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + - @backstage/integration-react@1.1.4 + - @backstage/plugin-search-common@1.0.1 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.4 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-app-api@1.1.0 + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/test-utils@1.2.0 + - @backstage/plugin-catalog@1.5.1 + - @backstage/plugin-search-react@1.1.0 + - @backstage/plugin-techdocs-react@1.0.4 + - @backstage/plugin-techdocs@1.3.2 + - @backstage/integration-react@1.1.4 + +## @backstage/plugin-techdocs-module-addons-contrib@1.0.4 + +### Patch Changes + +- eadf56bbbf: Bump `git-url-parse` version to `^13.0.0` +- 3f739be9d9: Minor API signatures cleanup +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-techdocs-react@1.0.4 + - @backstage/integration@1.3.1 + - @backstage/integration-react@1.1.4 + +## @backstage/plugin-techdocs-react@1.0.4 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + +## @backstage/plugin-todo@0.2.11 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + - @backstage/errors@1.1.1 + +## @backstage/plugin-todo-backend@0.1.33 + +### Patch Changes + +- 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/integration@1.3.1 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + +## @backstage/plugin-user-settings@0.4.8 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 3f739be9d9: Minor API signatures cleanup +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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`. +- 8448b53dd6: Added a `UserSettingsStorage` implementation of the `StorageApi` for use as + drop-in replacement for the `WebStorage`, in conjunction with the newly created + `@backstage/plugin-user-settings-backend`. +- Updated dependencies + - @backstage/core-app-api@1.1.0 + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/errors@1.1.1 + +## @backstage/plugin-vault@0.1.3 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + - @backstage/errors@1.1.1 + +## @backstage/plugin-vault-backend@0.2.2 + +### Patch Changes + +- 3f739be9d9: Minor API signatures cleanup + +- 148568b5c2: Switched to using node-fetch instead of cross-fetch as is standard for our backend packages + +- 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/backend-tasks@0.3.5 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + - @backstage/backend-test-utils@0.1.28 + +## @backstage/plugin-xcmetrics@0.2.29 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/errors@1.1.1 + +## example-app@0.2.75 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.19.0 + - @backstage/app-defaults@1.0.6 + - @backstage/core-app-api@1.1.0 + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-airbrake@0.3.9 + - @backstage/plugin-api-docs@0.8.9 + - @backstage/plugin-azure-devops@0.2.0 + - @backstage/plugin-badges@0.2.33 + - @backstage/plugin-catalog-graph@0.2.21 + - @backstage/plugin-catalog-import@0.8.12 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/plugin-circleci@0.3.9 + - @backstage/plugin-cloudbuild@0.3.9 + - @backstage/plugin-code-coverage@0.2.2 + - @backstage/plugin-cost-insights@0.11.31 + - @backstage/plugin-explore@0.3.40 + - @backstage/plugin-gcp-projects@0.3.28 + - @backstage/plugin-github-actions@0.5.9 + - @backstage/plugin-graphiql@0.2.41 + - @backstage/plugin-home@0.4.25 + - @backstage/plugin-jenkins@0.7.8 + - @backstage/plugin-kafka@0.3.9 + - @backstage/plugin-kubernetes@0.7.2 + - @backstage/plugin-lighthouse@0.3.9 + - @backstage/plugin-org@0.5.9 + - @backstage/plugin-pagerduty@0.5.2 + - @backstage/plugin-permission-react@0.4.5 + - @backstage/plugin-rollbar@0.4.9 + - @backstage/plugin-scaffolder@1.6.0 + - @backstage/plugin-search-react@1.1.0 + - @backstage/plugin-search@1.0.2 + - @backstage/plugin-sentry@0.4.2 + - @backstage/plugin-shortcuts@0.3.1 + - @backstage/plugin-tech-insights@0.3.0 + - @backstage/plugin-techdocs-react@1.0.4 + - @backstage/plugin-techdocs@1.3.2 + - @backstage/plugin-todo@0.2.11 + - @backstage/plugin-user-settings@0.4.8 + - @backstage/plugin-techdocs-module-addons-contrib@1.0.4 + - @backstage/plugin-newrelic-dashboard@0.2.2 + - @backstage/plugin-dynatrace@0.2.0 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/integration-react@1.1.4 + - @backstage/plugin-apache-airflow@0.2.2 + - @backstage/plugin-gcalendar@0.3.5 + - @backstage/plugin-gocd@0.1.15 + - @backstage/plugin-newrelic@0.3.27 + - @backstage/plugin-stack-overflow@0.1.5 + - @backstage/plugin-tech-radar@0.5.16 + - @backstage/plugin-playlist@0.1.0 + - @backstage/plugin-catalog-common@1.0.6 + - @internal/plugin-catalog-customized@0.0.2 + - @backstage/plugin-search-common@1.0.1 + +## example-backend@0.2.75 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/plugin-scaffolder-backend@1.6.0 + - @backstage/plugin-auth-node@0.2.5 + - @backstage/plugin-permission-node@0.6.5 + - @backstage/plugin-kubernetes-backend@0.7.2 + - @backstage/plugin-kafka-backend@0.2.29 + - @backstage/plugin-proxy-backend@0.2.30 + - @backstage/plugin-auth-backend@0.16.0 + - @backstage/integration@1.3.1 + - @backstage/plugin-catalog-backend@1.4.0 + - @backstage/plugin-azure-devops-backend@0.3.15 + - @backstage/plugin-search-backend-node@1.0.2 + - @backstage/plugin-tech-insights-node@0.3.4 + - @backstage/backend-tasks@0.3.5 + - @backstage/plugin-techdocs-backend@1.3.0 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/plugin-permission-common@0.6.4 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.4 + - @backstage/plugin-search-backend-module-pg@0.4.0 + - @backstage/plugin-jenkins-backend@0.1.26 + - @backstage/plugin-playlist-backend@0.1.0 + - @backstage/plugin-app-backend@0.3.36 + - @backstage/plugin-graphql-backend@0.1.26 + - @backstage/plugin-rollbar-backend@0.1.33 + - @backstage/plugin-code-coverage-backend@0.2.2 + - @backstage/plugin-permission-backend@0.5.11 + - @backstage/plugin-todo-backend@0.1.33 + - @backstage/plugin-search-backend-module-elasticsearch@1.0.2 + - @backstage/plugin-tech-insights-backend@0.5.2 + - @backstage/plugin-badges-backend@0.1.30 + - example-app@0.2.75 + - @backstage/plugin-search-backend@1.0.2 + - @backstage/plugin-search-common@1.0.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.20 + +## example-backend-next@0.0.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.6.0 + - @backstage/plugin-catalog-backend@1.4.0 + - @backstage/backend-defaults@0.1.1 + +## techdocs-cli-embedded-app@0.2.74 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.19.0 + - @backstage/app-defaults@1.0.6 + - @backstage/core-app-api@1.1.0 + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/test-utils@1.2.0 + - @backstage/plugin-catalog@1.5.1 + - @backstage/plugin-techdocs-react@1.0.4 + - @backstage/plugin-techdocs@1.3.2 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/integration-react@1.1.4 + +## @internal/plugin-catalog-customized@0.0.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/plugin-catalog@1.5.1 + +## @internal/plugin-todo-list@1.0.5 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + +## @internal/plugin-todo-list-backend@1.0.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/plugin-auth-node@0.2.5 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + +## @internal/plugin-todo-list-common@1.0.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.6.4 diff --git a/docs/releases/v1.6.0.md b/docs/releases/v1.6.0.md new file mode 100644 index 0000000000..a1ece6bf94 --- /dev/null +++ b/docs/releases/v1.6.0.md @@ -0,0 +1,60 @@ +--- +id: v1.6.0 +title: v1.6.0 +description: Backstage Release v1.6.0 +--- + +These are the release notes for the v1.6.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 + +### Moved to `swc` for transpilation + +We’ve replaced `sucrase` with [`swc`](https://swc.rs/) for transpilation in the Backstage CLI. While `swc` has slightly slower transpilation times, it’s a library backed by a larger community, and allows us to take advantage of [React Refresh](https://www.npmjs.com/package/react-refresh) out of the box. There’s a few things that could possibly break installations of Backstage and compilation, you can read more about it in the [changelog](https://github.com/backstage/backstage/blob/515aadf8840591860e4bbdcc7d99cef8f9d7ac3c/docs/releases/v1.6.0-changelog.md#patch-changes-1) + +### React Router Stable Compatibility + +Backstage has for a long time been using React Router version `6.0.0-beta.0`. We adopted this unstable version because v6 had some new features that fit really well with Backstage, particularly relative routing. Because we jumped on this early and unstable version, we knew that we would at some point need a breaking migration to the stable version of React Router v6, which is the point we're at now! + +The migration is controlled by each app, meaning this release will not force you to migrate straight away, you can do so at your own pace. Check out the [migration guide](https://backstage.io/docs/tutorials/react-router-stable-migration) for all you need to know! + +### Yarn 3 Support + +It is now possible to migrate Backstage projects to use Yarn 3. See the [migration guide](https://backstage.io/docs/tutorials/yarn-migration) for more information. Migrating to Yarn 3 is optional, and Backstage projects created with `@backstage/create-app` will still use classic Yarn by default. + +### New plugin: `@backstage/plugin-user-settings-backend` + +The `user-settings` plugin now has an associated backend. This allows for the persistence of settings in your database, essentially in the form of a basic per-user key-value JSON store. + +As this backend was added, `user-settings` also gained a `UserSettingsStore` class that implements the `storageApiRef` Utility API. If you install the backend as well as this frontend API, your starred entities and other storage-API-based features will no longer just be persisted in your browser’s local storage, but centrally so that all your devices can leverage them. + +Contributed by [@dschwank](https://github.com/dschwank) in [#13570](https://github.com/backstage/backstage/pull/13570) + +### New plugin: `@backstage/plugin-playlist` + +This plugin can be used to create custom collections of Entities that can be shared throughout Backstage or for private usage. + +Contributed by [@kuangp](https://github.com/kuangp) in [#12870](https://github.com/backstage/backstage/pull/12870) + +## Security Fixes + +Be sure to upgrade to the latest version of `@backstage/plugin-scaffolder-backend`, as it contains an explicit bump of a transitive dependency where a vulnerability was discovered. If you subscribe to CVE notifications you will already have received this update. + +## 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/bFESRKVt) for discussions and support +- [Changelog](https://github.com/backstage/backstage/tree/master/docs/releases/v1.6.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://mailchi.mp/spotify/backstage-community) if you want to be informed about what is happening in the world of Backstage. diff --git a/docs/tutorials/yarn-migration.md b/docs/tutorials/yarn-migration.md index 3bba18f945..7f898c7b98 100644 --- a/docs/tutorials/yarn-migration.md +++ b/docs/tutorials/yarn-migration.md @@ -73,4 +73,23 @@ The `--production` flag to `yarn install` has been removed in Yarn 3, instead yo RUN yarn workspaces focus --all --production && rm -rf "$(yarn cache clean)" ``` +Additionally, `yarn config` has been reworked from being able to store any arbitrary key-value pairs to only supporting a handful of predefined pairs. Previously, we would set our preferred `python3` interpreter to work around [any issues related to node-gyp](https://github.com/backstage/backstage/issues/11583) so we need to provide an appropriate substitute. + +```diff +FROM node:16-bullseye-slim + ++# Set Python interpreter for `node-gyp` to use ++ENV PYTHON /usr/bin/python3 + +# Install sqlite3 dependencies. You can skip this if you don't use sqlite3 in the image, +# in which case you should also move better-sqlite3 to "devDependencies" in package.json. +RUN apt-get update && \ + apt-get install -y --no-install-recommends libsqlite3-dev python3 build-essential && \ +- rm -rf /var/lib/apt/lists/* && \ +- yarn config set python /usr/bin/python3 ++ rm -rf /var/lib/apt/lists/* +``` + +You'll want to make sure that the `PYTHON` environment variable is declared relatively early, before any instances of `Yarn` are invoked as `node-gyp` is indirectly triggered by some modules during installation. + If you have any internal CLI tools in your project that are exposed through `"bin"` entries in `package.json`, then you'll need to add these packages as dependencies in your project root `package.json`. This is to make sure Yarn picks up the executables and makes them available through `yarn `. diff --git a/microsite/data/plugins/playlist.yaml b/microsite/data/plugins/playlist.yaml new file mode 100644 index 0000000000..3d69103d69 --- /dev/null +++ b/microsite/data/plugins/playlist.yaml @@ -0,0 +1,9 @@ +--- +title: Playlist +author: Phil Kuang +authorUrl: https://github.com/kuangp +category: Discovery +description: Create, share, and follow custom collections of entities available in the Backstage catalog. +documentation: https://github.com/backstage/backstage/tree/master/plugins/playlist +iconUrl: img/playlist-logo.png +npmPackageName: '@backstage/plugin-playlist' diff --git a/microsite/pages/en/live.js b/microsite/pages/en/live.js index 2483b2f8bf..43b5a0eb67 100644 --- a/microsite/pages/en/live.js +++ b/microsite/pages/en/live.js @@ -34,7 +34,7 @@ const Background = props => { diff --git a/microsite/sidebars.json b/microsite/sidebars.json index ba35f8b76b..8e77594376 100644 --- a/microsite/sidebars.json +++ b/microsite/sidebars.json @@ -1,6 +1,7 @@ { "releases": { "Release Notes": [ + "releases/v1.6.0", "releases/v1.5.0", "releases/v1.4.0", "releases/v1.3.0", @@ -275,7 +276,6 @@ ] }, "auth/identity-resolver", - "auth/auth-backend", "auth/oauth", "auth/add-auth-provider", "auth/troubleshooting", @@ -286,6 +286,7 @@ "permissions/concepts", "permissions/getting-started", "permissions/writing-a-policy", + "permissions/frontend-integration", "permissions/custom-rules", { "type": "subcategory", diff --git a/microsite/static/img/playlist-logo.png b/microsite/static/img/playlist-logo.png new file mode 100644 index 0000000000..333a9f832a Binary files /dev/null and b/microsite/static/img/playlist-logo.png differ diff --git a/mkdocs.yml b/mkdocs.yml index 0d386e63fa..c0a8e3a182 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -161,7 +161,6 @@ nav: - OAuth2Proxy: 'auth/oauth2-proxy/provider.md' - Bitbucket: 'auth/bitbucket/provider.md' - Sign in resolvers: 'auth/identity-resolver.md' - - Auth backend: 'auth/auth-backend.md' - OAuth and OpenID Connect: 'auth/oauth.md' - Contributing New Providers: 'auth/add-auth-provider.md' - Troubleshooting Auth: 'auth/troubleshooting.md' diff --git a/package.json b/package.json index a0de99bfad..31b0c194d2 100644 --- a/package.json +++ b/package.json @@ -15,8 +15,8 @@ "tsc": "tsc", "tsc:full": "backstage-cli repo clean && tsc --skipLibCheck false --incremental false", "clean": "backstage-cli repo clean", - "test": "backstage-cli test", - "test:all": "lerna run test -- --coverage", + "test": "backstage-cli repo test", + "test:all": "backstage-cli repo test --coverage", "lint": "backstage-cli repo lint --since origin/master", "lint:docs": "node ./scripts/check-docs-quality", "lint:all": "backstage-cli repo lint", @@ -26,7 +26,6 @@ "create-plugin": "echo \"use 'yarn new' instead\"", "release": "node scripts/prepare-release.js && changeset version && yarn prettier --write '{packages,plugins}/*/{package.json,CHANGELOG.md}' '.changeset/*.json' && yarn install --no-immutable", "prettier:check": "prettier --check .", - "lerna": "lerna", "storybook": "yarn ./storybook run start", "snyk:test": "npx snyk test --yarn-workspaces --strict-out-of-sync=false", "snyk:test:package": "yarn snyk:test --include", @@ -45,7 +44,7 @@ "@types/react": "^17", "@types/react-dom": "^17" }, - "version": "1.6.0-next.3", + "version": "1.6.0", "dependencies": { "@manypkg/get-packages": "^1.1.3", "@microsoft/api-documenter": "^7.17.11", @@ -71,7 +70,6 @@ "eslint-plugin-notice": "^0.9.10", "fs-extra": "10.1.0", "husky": "^8.0.0", - "lerna": "~5.0.0", "lint-staged": "^13.0.0", "minimist": "^1.2.5", "prettier": "^2.2.1", diff --git a/packages/app-defaults/CHANGELOG.md b/packages/app-defaults/CHANGELOG.md index c9216bf2a4..6d9d3fc029 100644 --- a/packages/app-defaults/CHANGELOG.md +++ b/packages/app-defaults/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/app-defaults +## 1.0.6 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- d9e39544be: Add missing peer dependencies +- Updated dependencies + - @backstage/core-app-api@1.1.0 + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-permission-react@0.4.5 + ## 1.0.6-next.2 ### Patch Changes diff --git a/packages/app-defaults/package.json b/packages/app-defaults/package.json index c83e31b057..0742d2cb13 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.0.6-next.2", + "version": "1.0.6", "publishConfig": { "access": "public", "main": "dist/index.esm.js", @@ -32,11 +32,11 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/plugin-permission-react": "^0.4.5-next.2", - "@backstage/theme": "^0.2.16", + "@backstage/core-app-api": "workspace:^", + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/plugin-permission-react": "workspace:^", + "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1" }, @@ -47,8 +47,8 @@ "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@types/node": "^16.11.26", diff --git a/packages/app/CHANGELOG.md b/packages/app/CHANGELOG.md index f763210b27..e5c37fb1d9 100644 --- a/packages/app/CHANGELOG.md +++ b/packages/app/CHANGELOG.md @@ -1,5 +1,66 @@ # example-app +## 0.2.75 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.19.0 + - @backstage/app-defaults@1.0.6 + - @backstage/core-app-api@1.1.0 + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-airbrake@0.3.9 + - @backstage/plugin-api-docs@0.8.9 + - @backstage/plugin-azure-devops@0.2.0 + - @backstage/plugin-badges@0.2.33 + - @backstage/plugin-catalog-graph@0.2.21 + - @backstage/plugin-catalog-import@0.8.12 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/plugin-circleci@0.3.9 + - @backstage/plugin-cloudbuild@0.3.9 + - @backstage/plugin-code-coverage@0.2.2 + - @backstage/plugin-cost-insights@0.11.31 + - @backstage/plugin-explore@0.3.40 + - @backstage/plugin-gcp-projects@0.3.28 + - @backstage/plugin-github-actions@0.5.9 + - @backstage/plugin-graphiql@0.2.41 + - @backstage/plugin-home@0.4.25 + - @backstage/plugin-jenkins@0.7.8 + - @backstage/plugin-kafka@0.3.9 + - @backstage/plugin-kubernetes@0.7.2 + - @backstage/plugin-lighthouse@0.3.9 + - @backstage/plugin-org@0.5.9 + - @backstage/plugin-pagerduty@0.5.2 + - @backstage/plugin-permission-react@0.4.5 + - @backstage/plugin-rollbar@0.4.9 + - @backstage/plugin-scaffolder@1.6.0 + - @backstage/plugin-search-react@1.1.0 + - @backstage/plugin-search@1.0.2 + - @backstage/plugin-sentry@0.4.2 + - @backstage/plugin-shortcuts@0.3.1 + - @backstage/plugin-tech-insights@0.3.0 + - @backstage/plugin-techdocs-react@1.0.4 + - @backstage/plugin-techdocs@1.3.2 + - @backstage/plugin-todo@0.2.11 + - @backstage/plugin-user-settings@0.4.8 + - @backstage/plugin-techdocs-module-addons-contrib@1.0.4 + - @backstage/plugin-newrelic-dashboard@0.2.2 + - @backstage/plugin-dynatrace@0.2.0 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/integration-react@1.1.4 + - @backstage/plugin-apache-airflow@0.2.2 + - @backstage/plugin-gcalendar@0.3.5 + - @backstage/plugin-gocd@0.1.15 + - @backstage/plugin-newrelic@0.3.27 + - @backstage/plugin-stack-overflow@0.1.5 + - @backstage/plugin-tech-radar@0.5.16 + - @backstage/plugin-playlist@0.1.0 + - @backstage/plugin-catalog-common@1.0.6 + - @internal/plugin-catalog-customized@0.0.2 + - @backstage/plugin-search-common@1.0.1 + ## 0.2.75-next.3 ### Patch Changes diff --git a/packages/app/package.json b/packages/app/package.json index df68e1032c..ad24f23c45 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,67 +1,68 @@ { "name": "example-app", - "version": "0.2.75-next.3", + "version": "0.2.75", "private": true, "backstage": { "role": "frontend" }, "bundled": true, "dependencies": { - "@backstage/app-defaults": "^1.0.6-next.2", - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/cli": "^0.19.0-next.3", - "@backstage/config": "^1.0.2-next.0", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/integration-react": "^1.1.4-next.2", - "@backstage/plugin-airbrake": "^0.3.9-next.3", - "@backstage/plugin-apache-airflow": "^0.2.2-next.3", - "@backstage/plugin-api-docs": "^0.8.9-next.3", - "@backstage/plugin-azure-devops": "^0.2.0-next.3", - "@backstage/plugin-badges": "^0.2.33-next.3", - "@backstage/plugin-catalog-common": "^1.0.6-next.0", - "@backstage/plugin-catalog-graph": "^0.2.21-next.2", - "@backstage/plugin-catalog-import": "^0.8.12-next.3", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", - "@backstage/plugin-circleci": "^0.3.9-next.3", - "@backstage/plugin-cloudbuild": "^0.3.9-next.3", - "@backstage/plugin-code-coverage": "^0.2.2-next.3", - "@backstage/plugin-cost-insights": "^0.11.31-next.3", - "@backstage/plugin-dynatrace": "^0.2.0-next.3", - "@backstage/plugin-explore": "^0.3.40-next.3", - "@backstage/plugin-gcalendar": "^0.3.5-next.3", - "@backstage/plugin-gcp-projects": "^0.3.28-next.3", - "@backstage/plugin-github-actions": "^0.5.9-next.3", - "@backstage/plugin-gocd": "^0.1.15-next.2", - "@backstage/plugin-graphiql": "^0.2.41-next.3", - "@backstage/plugin-home": "^0.4.25-next.3", - "@backstage/plugin-jenkins": "^0.7.8-next.3", - "@backstage/plugin-kafka": "^0.3.9-next.3", - "@backstage/plugin-kubernetes": "^0.7.2-next.3", - "@backstage/plugin-lighthouse": "^0.3.9-next.3", - "@backstage/plugin-newrelic": "^0.3.27-next.3", - "@backstage/plugin-newrelic-dashboard": "^0.2.2-next.2", - "@backstage/plugin-org": "^0.5.9-next.3", - "@backstage/plugin-pagerduty": "0.5.2-next.3", - "@backstage/plugin-permission-react": "^0.4.5-next.2", - "@backstage/plugin-rollbar": "^0.4.9-next.3", - "@backstage/plugin-scaffolder": "^1.6.0-next.3", - "@backstage/plugin-search": "^1.0.2-next.3", - "@backstage/plugin-search-common": "^1.0.1-next.0", - "@backstage/plugin-search-react": "^1.1.0-next.2", - "@backstage/plugin-sentry": "^0.4.2-next.3", - "@backstage/plugin-shortcuts": "^0.3.1-next.3", - "@backstage/plugin-stack-overflow": "^0.1.5-next.3", - "@backstage/plugin-tech-insights": "^0.3.0-next.3", - "@backstage/plugin-tech-radar": "^0.5.16-next.3", - "@backstage/plugin-techdocs": "^1.3.2-next.3", - "@backstage/plugin-techdocs-module-addons-contrib": "^1.0.4-next.2", - "@backstage/plugin-techdocs-react": "^1.0.4-next.2", - "@backstage/plugin-todo": "^0.2.11-next.3", - "@backstage/plugin-user-settings": "^0.4.8-next.3", - "@backstage/theme": "^0.2.16", - "@internal/plugin-catalog-customized": "0.0.2-next.0", + "@backstage/app-defaults": "workspace:^", + "@backstage/catalog-model": "workspace:^", + "@backstage/cli": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/integration-react": "workspace:^", + "@backstage/plugin-airbrake": "workspace:^", + "@backstage/plugin-apache-airflow": "workspace:^", + "@backstage/plugin-api-docs": "workspace:^", + "@backstage/plugin-azure-devops": "workspace:^", + "@backstage/plugin-badges": "workspace:^", + "@backstage/plugin-catalog-common": "workspace:^", + "@backstage/plugin-catalog-graph": "workspace:^", + "@backstage/plugin-catalog-import": "workspace:^", + "@backstage/plugin-catalog-react": "workspace:^", + "@backstage/plugin-circleci": "workspace:^", + "@backstage/plugin-cloudbuild": "workspace:^", + "@backstage/plugin-code-coverage": "workspace:^", + "@backstage/plugin-cost-insights": "workspace:^", + "@backstage/plugin-dynatrace": "workspace:^", + "@backstage/plugin-explore": "workspace:^", + "@backstage/plugin-gcalendar": "workspace:^", + "@backstage/plugin-gcp-projects": "workspace:^", + "@backstage/plugin-github-actions": "workspace:^", + "@backstage/plugin-gocd": "workspace:^", + "@backstage/plugin-graphiql": "workspace:^", + "@backstage/plugin-home": "workspace:^", + "@backstage/plugin-jenkins": "workspace:^", + "@backstage/plugin-kafka": "workspace:^", + "@backstage/plugin-kubernetes": "workspace:^", + "@backstage/plugin-lighthouse": "workspace:^", + "@backstage/plugin-newrelic": "workspace:^", + "@backstage/plugin-newrelic-dashboard": "workspace:^", + "@backstage/plugin-org": "workspace:^", + "@backstage/plugin-pagerduty": "workspace:^", + "@backstage/plugin-permission-react": "workspace:^", + "@backstage/plugin-playlist": "workspace:^", + "@backstage/plugin-rollbar": "workspace:^", + "@backstage/plugin-scaffolder": "workspace:^", + "@backstage/plugin-search": "workspace:^", + "@backstage/plugin-search-common": "workspace:^", + "@backstage/plugin-search-react": "workspace:^", + "@backstage/plugin-sentry": "workspace:^", + "@backstage/plugin-shortcuts": "workspace:^", + "@backstage/plugin-stack-overflow": "workspace:^", + "@backstage/plugin-tech-insights": "workspace:^", + "@backstage/plugin-tech-radar": "workspace:^", + "@backstage/plugin-techdocs": "workspace:^", + "@backstage/plugin-techdocs-module-addons-contrib": "workspace:^", + "@backstage/plugin-techdocs-react": "workspace:^", + "@backstage/plugin-todo": "workspace:^", + "@backstage/plugin-user-settings": "workspace:^", + "@backstage/theme": "workspace:^", + "@internal/plugin-catalog-customized": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -80,7 +81,7 @@ "zen-observable": "^0.8.15" }, "devDependencies": { - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/test-utils": "workspace:^", "@rjsf/core": "^3.2.1", "@testing-library/cypress": "^8.0.2", "@testing-library/jest-dom": "^5.10.1", diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index 53f1a9fe8f..2e6b0d59a6 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -64,6 +64,7 @@ import { ScaffolderPage, NextScaffolderPage, scaffolderPlugin, + ScaffolderLayouts, } from '@backstage/plugin-scaffolder'; import { SearchPage } from '@backstage/plugin-search'; import { TechRadarPage } from '@backstage/plugin-tech-radar'; @@ -103,6 +104,8 @@ import { techDocsPage } from './components/techdocs/TechDocsPage'; import { ApacheAirflowPage } from '@backstage/plugin-apache-airflow'; import { RequirePermission } from '@backstage/plugin-permission-react'; import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common'; +import { PlaylistIndexPage } from '@backstage/plugin-playlist'; +import { TwoColumnLayout } from './components/scaffolder/customScaffolderLayouts'; const app = createApp({ apis, @@ -218,6 +221,9 @@ const routes = ( + + + } /> } /> + } /> ); diff --git a/packages/app/src/components/Root/Root.tsx b/packages/app/src/components/Root/Root.tsx index 30da01841c..8b5f0932fb 100644 --- a/packages/app/src/components/Root/Root.tsx +++ b/packages/app/src/components/Root/Root.tsx @@ -22,6 +22,7 @@ import RuleIcon from '@material-ui/icons/AssignmentTurnedIn'; import MapIcon from '@material-ui/icons/MyLocation'; import LayersIcon from '@material-ui/icons/Layers'; import LibraryBooks from '@material-ui/icons/LibraryBooks'; +import PlaylistPlayIcon from '@material-ui/icons/PlaylistPlay'; import CreateComponentIcon from '@material-ui/icons/AddCircleOutline'; import SearchIcon from '@material-ui/icons/Search'; import MenuIcon from '@material-ui/icons/Menu'; @@ -105,6 +106,7 @@ export const Root = ({ children }: PropsWithChildren<{}>) => ( /> + {/* End global nav */} diff --git a/packages/app/src/components/catalog/EntityPage.tsx b/packages/app/src/components/catalog/EntityPage.tsx index e15df4bc6c..c2f297a2d7 100644 --- a/packages/app/src/components/catalog/EntityPage.tsx +++ b/packages/app/src/components/catalog/EntityPage.tsx @@ -104,6 +104,7 @@ import { EntityPagerDutyCard, isPagerDutyAvailable, } from '@backstage/plugin-pagerduty'; +import { EntityPlaylistDialog } from '@backstage/plugin-playlist'; import { EntityRollbarContent, isRollbarAvailable, @@ -114,6 +115,7 @@ import { EntityTechInsightsScorecardCard } from '@backstage/plugin-tech-insights import { EntityTodoContent } from '@backstage/plugin-todo'; import { Button, Grid } from '@material-ui/core'; import BadgeIcon from '@material-ui/icons/CallToAction'; +import PlaylistAddIcon from '@material-ui/icons/PlaylistAdd'; import { EntityGithubInsightsContent, @@ -155,6 +157,7 @@ const customEntityFilterKind = ['Component', 'API', 'System']; const EntityLayoutWrapper = (props: { children?: ReactNode }) => { const [badgesDialogOpen, setBadgesDialogOpen] = useState(false); + const [playlistDialogOpen, setPlaylistDialogOpen] = useState(false); const extraMenuItems = useMemo(() => { return [ @@ -163,6 +166,11 @@ const EntityLayoutWrapper = (props: { children?: ReactNode }) => { Icon: BadgeIcon, onClick: () => setBadgesDialogOpen(true), }, + { + title: 'Add to playlist', + Icon: PlaylistAddIcon, + onClick: () => setPlaylistDialogOpen(true), + }, ]; }, []); @@ -180,6 +188,10 @@ const EntityLayoutWrapper = (props: { children?: ReactNode }) => { open={badgesDialogOpen} onClose={() => setBadgesDialogOpen(false)} /> + setPlaylistDialogOpen(false)} + /> ); }; diff --git a/packages/app/src/components/scaffolder/customScaffolderLayouts.tsx b/packages/app/src/components/scaffolder/customScaffolderLayouts.tsx new file mode 100644 index 0000000000..8dc6e5340a --- /dev/null +++ b/packages/app/src/components/scaffolder/customScaffolderLayouts.tsx @@ -0,0 +1,54 @@ +/* + * 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 { + createScaffolderLayout, + LayoutTemplate, + scaffolderPlugin, +} from '@backstage/plugin-scaffolder'; +import { Grid } from '@material-ui/core'; + +const TwoColumn: LayoutTemplate = ({ properties, description, title }) => { + const mid = Math.ceil(properties.length / 2); + const left = properties.slice(0, mid); + const right = properties.slice(mid); + return ( + <> +

{title}

+

In two column layout!!

+ + {left.map(prop => ( + + {prop.content} + + ))} + {right.map(prop => ( + + {prop.content} + + ))} + + {description} + + ); +}; + +export const TwoColumnLayout = scaffolderPlugin.provide( + createScaffolderLayout({ + name: 'TwoColumn', + component: TwoColumn, + }), +); diff --git a/packages/app/src/components/scaffolder/defaultPreviewTemplate.ts b/packages/app/src/components/scaffolder/defaultPreviewTemplate.ts index 2e23b08e53..56f34779de 100644 --- a/packages/app/src/components/scaffolder/defaultPreviewTemplate.ts +++ b/packages/app/src/components/scaffolder/defaultPreviewTemplate.ts @@ -17,6 +17,7 @@ export const defaultPreviewTemplate = `# Edit the template parameters below to see how they will render in the scaffolder form UI parameters: - title: Fill in some steps + ui:ObjectFieldTemplate: TwoColumn required: - name properties: diff --git a/packages/backend-app-api/CHANGELOG.md b/packages/backend-app-api/CHANGELOG.md index a9ab990f92..801ec9aba6 100644 --- a/packages/backend-app-api/CHANGELOG.md +++ b/packages/backend-app-api/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/backend-app-api +## 0.2.1 + +### Patch Changes + +- 2c57c0c499: Made `ApiRef.defaultFactory` internal. +- 854ba37357: Updated to support new `ServiceFactory` formats. +- af6bb42c68: Updated `ServiceRegistry` to not initialize factories more than once. +- 409ed984e8: Updated service implementations and backend wiring to support scoped service. +- de3347ca74: Updated usages of `ServiceFactory`. +- 1f384c5644: Improved error messaging when failing to instantiate services. +- Updated dependencies + - @backstage/backend-plugin-api@0.1.2 + - @backstage/backend-common@0.15.1 + - @backstage/plugin-permission-node@0.6.5 + - @backstage/backend-tasks@0.3.5 + - @backstage/errors@1.1.1 + ## 0.2.1-next.2 ### Patch Changes diff --git a/packages/backend-app-api/package.json b/packages/backend-app-api/package.json index a028af090f..2878de5aa3 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.2.1-next.2", + "version": "0.2.1", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { @@ -33,17 +33,17 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/backend-plugin-api": "^0.1.2-next.2", - "@backstage/backend-tasks": "^0.3.5-next.1", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/plugin-permission-node": "^0.6.5-next.3", + "@backstage/backend-common": "workspace:^", + "@backstage/backend-plugin-api": "workspace:^", + "@backstage/backend-tasks": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/plugin-permission-node": "workspace:^", "express": "^4.17.1", "express-promise-router": "^4.1.0", "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3" + "@backstage/cli": "workspace:^" }, "files": [ "dist", diff --git a/packages/backend-common/CHANGELOG.md b/packages/backend-common/CHANGELOG.md index aaa90ac704..4e51ad3b8f 100644 --- a/packages/backend-common/CHANGELOG.md +++ b/packages/backend-common/CHANGELOG.md @@ -1,5 +1,93 @@ # @backstage/backend-common +## 0.15.1 + +### Patch Changes + +- 399286d7dd: Workaround support for `swc` instead of `sucrase` +- eadf56bbbf: Bump `git-url-parse` version to `^13.0.0` +- c3c90280be: Added a keep-alive refresh loop to the `DatabaseManager`, keeping the connection + pool up. +- c3c90280be: The options part of `DatabaseManager.fromConfig` now accepts an optional logger + field. +- 3d4f5daadf: Remove use of deprecated trimLeft/trimRight +- bf3cc134eb: Implemented KubernetesContainerRunner: a ContainerRunner implementation that leverages Jobs on a kubernetes cluster + + ```ts + const kubeConfig = new KubeConfig(); + kubeConfig.loadFromDefault(); + + const options: KubernetesContainerRunnerOptions = { + kubeConfig, + // namespace where Jobs will be created + namespace: 'default', + // Jobs name will be prefixed with this name + name: 'my-runner', + // An existing Kubernetes volume that will be used + // as base for mounts + mountBase: { + volumeName: 'workdir', + // Every mount must start with the base path + // see example below + basePath: '/workdir', + }, + // Define a Pod template for the Jobs. It has to include + // a volume definition named as the mountBase volumeName + podTemplate: { + spec: { + containers: [], + volumes: [ + { + name: 'workdir', + persistentVolumeClaim: { + claimName: 'workdir-claim', + }, + }, + ], + }, + }, + }; + const containerRunner = new KubernetesContainerRunner(options); + + const runOptions: RunContainerOptions = { + imageName: 'golang:1.17', + args: ['echo', 'hello world'], + mountDirs: { + '/workdir/app': '/app', + }, + }; + containerRunner.runContainer(runOptions); + ``` + +- e3b1993788: Added port ranges in allowed hosts: + + ```yaml + reading: + allow: + - host: *.examples.org:900-1000 + ``` + +- 2f52e74b49: Got rid of usages of the uppercase String type +- 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`. +- 709f468330: The `branch` command has been added to the `isomorphic-git` wrapper. +- 0c780278e0: Fix for entries being skipped or incomplete when reading large zip archives. +- 96689fbdcb: Workaround for a rare race condition in tests. +- Updated dependencies + - @backstage/integration@1.3.1 + - @backstage/config-loader@1.1.4 + - @backstage/cli-common@0.1.10 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + ## 0.15.1-next.3 ### Patch Changes diff --git a/packages/backend-common/api-report.md b/packages/backend-common/api-report.md index 40bd885fe8..600e3edef8 100644 --- a/packages/backend-common/api-report.md +++ b/packages/backend-common/api-report.md @@ -342,6 +342,8 @@ export class Git { force?: boolean; }): Promise; // (undocumented) + branch(options: { dir: string; ref: string }): Promise; + // (undocumented) checkout(options: { dir: string; ref: string }): Promise; clone(options: { url: string; diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index 81dc37caca..35e1ccdf10 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.15.1-next.3", + "version": "0.15.1", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { @@ -34,12 +34,12 @@ "test:kubernetes": "backstage-cli package test -t KubernetesContainerRunner --no-watch" }, "dependencies": { - "@backstage/cli-common": "^0.1.10-next.0", - "@backstage/config": "^1.0.2-next.0", - "@backstage/config-loader": "^1.1.4-next.2", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/integration": "^1.3.1-next.2", - "@backstage/types": "^1.0.0", + "@backstage/cli-common": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/config-loader": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/integration": "workspace:^", + "@backstage/types": "workspace:^", "@google-cloud/storage": "^6.0.0", "@keyv/redis": "^2.2.3", "@kubernetes/client-node": "^0.17.0", @@ -94,8 +94,8 @@ } }, "devDependencies": { - "@backstage/backend-test-utils": "^0.1.28-next.3", - "@backstage/cli": "^0.19.0-next.3", + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", "@types/archiver": "^5.1.0", "@types/base64-stream": "^1.0.2", "@types/compression": "^1.7.0", diff --git a/packages/backend-common/src/reading/tree/ZipArchiveResponse.test.ts b/packages/backend-common/src/reading/tree/ZipArchiveResponse.test.ts index 427c237802..e45a25db66 100644 --- a/packages/backend-common/src/reading/tree/ZipArchiveResponse.test.ts +++ b/packages/backend-common/src/reading/tree/ZipArchiveResponse.test.ts @@ -16,6 +16,8 @@ import fs from 'fs-extra'; import mockFs from 'mock-fs'; +import { Readable } from 'stream'; +import { create as createArchive } from 'archiver'; import { resolve as resolvePath } from 'path'; import { ZipArchiveResponse } from './ZipArchiveResponse'; @@ -161,6 +163,48 @@ describe('ZipArchiveResponse', () => { ).resolves.toBe(false); }); + it('should extract a large archive', async () => { + const fileCount = 10; + const fileSize = 1000 * 1000; + const filePath = await new Promise((resolve, reject) => { + const outFile = '/large-archive.zip'; + const archive = createArchive('zip'); + + archive.on('error', reject); + archive.on('end', () => resolve(outFile)); + archive.pipe(fs.createWriteStream(outFile)); + archive.on('warning', w => console.warn('WARN', w)); + + for (let i = 0; i < fileCount; i++) { + // Workaround for https://github.com/archiverjs/node-archiver/issues/542 + // TODO(Rugvip): Without this workaround the archive entries end up with an uncompressed size of 0. + // That in turn causes yauzl to hang on extraction, because the internal transform error is ignored. + const stream = new Readable(); + stream.push(Buffer.alloc(fileSize, i)); + stream.push(null); + archive.append(stream, { name: `file-${i}.data` }); + } + + archive.finalize(); + }); + + const stream = fs.createReadStream(filePath); + + const res = new ZipArchiveResponse(stream, '', '/tmp', 'etag'); + const dir = await res.dir({ + targetDir: '/out', + }); + + expect(dir).toBe('/out'); + const files = await fs.readdir(dir); + expect(files).toHaveLength(fileCount); + + for (const file of files) { + const stat = await fs.stat(resolvePath(dir, file)); + expect(stat.size).toBe(fileSize); + } + }); + it('should throw on invalid archive', async () => { const stream = fs.createReadStream('/test-archive-corrupted.zip'); diff --git a/packages/backend-common/src/reading/tree/ZipArchiveResponse.ts b/packages/backend-common/src/reading/tree/ZipArchiveResponse.ts index 4100af3d57..5a1c5f9688 100644 --- a/packages/backend-common/src/reading/tree/ZipArchiveResponse.ts +++ b/packages/backend-common/src/reading/tree/ZipArchiveResponse.ts @@ -124,9 +124,11 @@ export class ZipArchiveResponse implements ReadTreeResponse { } await callback(entry, readStream); + zipfile.readEntry(); }); + } else { + zipfile.readEntry(); } - zipfile.readEntry(); }); zipfile.once('end', () => resolve()); zipfile.on('error', e => reject(e)); diff --git a/packages/backend-common/src/scm/git.test.ts b/packages/backend-common/src/scm/git.test.ts index e9c66a896e..fdd3c7dbc8 100644 --- a/packages/backend-common/src/scm/git.test.ts +++ b/packages/backend-common/src/scm/git.test.ts @@ -95,6 +95,22 @@ describe('Git', () => { }); }); + describe('branch', () => { + it('should call isomorphic-git with the correct arguments', async () => { + const git = Git.fromAuth({}); + const dir = 'mockdirectory'; + const ref = 'master'; + + await git.branch({ dir, ref }); + + expect(isomorphic.branch).toHaveBeenCalledWith({ + fs, + dir, + ref, + }); + }); + }); + describe('commit', () => { it('should call isomorphic-git with the correct arguments', async () => { const git = Git.fromAuth({}); diff --git a/packages/backend-common/src/scm/git.ts b/packages/backend-common/src/scm/git.ts index 8a72c7af89..0c9252cb64 100644 --- a/packages/backend-common/src/scm/git.ts +++ b/packages/backend-common/src/scm/git.ts @@ -94,6 +94,13 @@ export class Git { return git.checkout({ fs, dir, ref }); } + async branch(options: { dir: string; ref: string }): Promise { + const { dir, ref } = options; + this.config.logger?.info(`Creating branch {dir=${dir},ref=${ref}`); + + return git.branch({ fs, dir, ref }); + } + async commit(options: { dir: string; message: string; diff --git a/packages/backend-defaults/CHANGELOG.md b/packages/backend-defaults/CHANGELOG.md index 9684395ce0..2e8ef65792 100644 --- a/packages/backend-defaults/CHANGELOG.md +++ b/packages/backend-defaults/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/backend-defaults +## 0.1.1 + +### Patch Changes + +- 854ba37357: Updated to support new `ServiceFactory` formats. +- de3347ca74: Updated usages of `ServiceFactory`. +- Updated dependencies + - @backstage/backend-app-api@0.2.1 + - @backstage/backend-plugin-api@0.1.2 + ## 0.1.1-next.1 ### Patch Changes diff --git a/packages/backend-defaults/package.json b/packages/backend-defaults/package.json index e754b74c4d..23652120e2 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.1.1-next.1", + "version": "0.1.1", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { @@ -32,11 +32,11 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/backend-app-api": "^0.2.1-next.2", - "@backstage/backend-plugin-api": "^0.1.2-next.2" + "@backstage/backend-app-api": "workspace:^", + "@backstage/backend-plugin-api": "workspace:^" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3" + "@backstage/cli": "workspace:^" }, "files": [ "dist" diff --git a/packages/backend-next/CHANGELOG.md b/packages/backend-next/CHANGELOG.md index e74e609f00..a37fc48dac 100644 --- a/packages/backend-next/CHANGELOG.md +++ b/packages/backend-next/CHANGELOG.md @@ -1,5 +1,14 @@ # example-backend-next +## 0.0.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.6.0 + - @backstage/plugin-catalog-backend@1.4.0 + - @backstage/backend-defaults@0.1.1 + ## 0.0.3-next.1 ### Patch Changes diff --git a/packages/backend-next/package.json b/packages/backend-next/package.json index 175a945c31..4e989c81cf 100644 --- a/packages/backend-next/package.json +++ b/packages/backend-next/package.json @@ -1,6 +1,6 @@ { "name": "example-backend-next", - "version": "0.0.3-next.1", + "version": "0.0.3", "main": "dist/index.cjs.js", "types": "src/index.ts", "license": "Apache-2.0", @@ -25,12 +25,12 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-defaults": "^0.1.1-next.0", - "@backstage/plugin-catalog-backend": "^1.4.0-next.1", - "@backstage/plugin-scaffolder-backend": "^1.6.0-next.1" + "@backstage/backend-defaults": "workspace:^", + "@backstage/plugin-catalog-backend": "workspace:^", + "@backstage/plugin-scaffolder-backend": "workspace:^" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.1" + "@backstage/cli": "workspace:^" }, "files": [ "dist" diff --git a/packages/backend-plugin-api/CHANGELOG.md b/packages/backend-plugin-api/CHANGELOG.md index b0dadbf61c..33e3b36268 100644 --- a/packages/backend-plugin-api/CHANGELOG.md +++ b/packages/backend-plugin-api/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/backend-plugin-api +## 0.1.2 + +### Patch Changes + +- 2c57c0c499: Made `ApiRef.defaultFactory` internal. +- 91eed37a39: Updated `createBackendPlugin` and `createBackendModule` to properly forward lack of options. +- 409ed984e8: Service are now scoped to either `'plugin'` or `'root'` scope. Service factories have been updated to provide dependency instances directly rather than factory functions. +- eef91a2558: Simplified the `ServiceFactory` type and removed `AnyServiceFactory`. +- 854ba37357: The `createServiceFactory` method has been updated to return a higher-order factory that can accept options. +- 68513f169a: When defining a new `ServiceRef` you can now also include a `defaultFactory`, which will be used to construct instances of the service in case there is no explicit factory defined. +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/backend-tasks@0.3.5 + - @backstage/config@1.0.2 + - @backstage/plugin-permission-common@0.6.4 + ## 0.1.2-next.2 ### Patch Changes diff --git a/packages/backend-plugin-api/package.json b/packages/backend-plugin-api/package.json index e9593dec3d..18c6c842fc 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.1.2-next.2", + "version": "0.1.2", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { @@ -33,17 +33,17 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/backend-tasks": "^0.3.5-next.1", - "@backstage/config": "^1.0.2-next.0", - "@backstage/plugin-permission-common": "^0.6.4-next.2", + "@backstage/backend-common": "workspace:^", + "@backstage/backend-tasks": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/plugin-permission-common": "workspace:^", "@types/express": "^4.17.6", "express": "^4.17.1", "winston": "^3.2.1", "winston-transport": "^4.5.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3" + "@backstage/cli": "workspace:^" }, "files": [ "dist", diff --git a/packages/backend-tasks/CHANGELOG.md b/packages/backend-tasks/CHANGELOG.md index 2307fd5d57..0510a54825 100644 --- a/packages/backend-tasks/CHANGELOG.md +++ b/packages/backend-tasks/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/backend-tasks +## 0.3.5 + +### Patch Changes + +- 243533ecdc: Added support to mysql on some raw queries +- 8872cc735d: Fixed a bug where the database option to skip migrations was ignored. +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + ## 0.3.5-next.1 ### Patch Changes diff --git a/packages/backend-tasks/package.json b/packages/backend-tasks/package.json index 444616660a..88b8cf0345 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.3.5-next.1", + "version": "0.3.5", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { @@ -32,10 +32,10 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/config": "^1.0.2-next.0", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/types": "^1.0.0", + "@backstage/backend-common": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/types": "workspace:^", "@types/luxon": "^3.0.0", "cron": "^2.0.0", "knex": "^2.0.0", @@ -47,8 +47,8 @@ "zod": "^3.9.5" }, "devDependencies": { - "@backstage/backend-test-utils": "^0.1.28-next.3", - "@backstage/cli": "^0.19.0-next.3", + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", "@types/cron": "^2.0.0", "wait-for-expect": "^3.0.2" }, diff --git a/packages/backend-test-utils/CHANGELOG.md b/packages/backend-test-utils/CHANGELOG.md index 5ec06645b0..27e41be568 100644 --- a/packages/backend-test-utils/CHANGELOG.md +++ b/packages/backend-test-utils/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/backend-test-utils +## 0.1.28 + +### Patch Changes + +- 854ba37357: Updated to support new `ServiceFactory` formats. +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- de3347ca74: Updated usages of `ServiceFactory`. +- Updated dependencies + - @backstage/cli@0.19.0 + - @backstage/backend-app-api@0.2.1 + - @backstage/backend-plugin-api@0.1.2 + - @backstage/backend-common@0.15.1 + - @backstage/config@1.0.2 + ## 0.1.28-next.3 ### Patch Changes diff --git a/packages/backend-test-utils/package.json b/packages/backend-test-utils/package.json index 374860a387..b1006b8464 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.1.28-next.3", + "version": "0.1.28", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { @@ -34,11 +34,11 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/backend-app-api": "^0.2.1-next.2", - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/backend-plugin-api": "^0.1.2-next.2", - "@backstage/cli": "^0.19.0-next.3", - "@backstage/config": "^1.0.2-next.0", + "@backstage/backend-app-api": "workspace:^", + "@backstage/backend-common": "workspace:^", + "@backstage/backend-plugin-api": "workspace:^", + "@backstage/cli": "workspace:^", + "@backstage/config": "workspace:^", "better-sqlite3": "^7.5.0", "knex": "^2.0.0", "msw": "^0.47.0", @@ -48,7 +48,7 @@ "uuid": "^8.0.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3" + "@backstage/cli": "workspace:^" }, "files": [ "dist", diff --git a/packages/backend/CHANGELOG.md b/packages/backend/CHANGELOG.md index 7b20372856..b196b1df9e 100644 --- a/packages/backend/CHANGELOG.md +++ b/packages/backend/CHANGELOG.md @@ -1,5 +1,47 @@ # example-backend +## 0.2.75 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/plugin-scaffolder-backend@1.6.0 + - @backstage/plugin-auth-node@0.2.5 + - @backstage/plugin-permission-node@0.6.5 + - @backstage/plugin-kubernetes-backend@0.7.2 + - @backstage/plugin-kafka-backend@0.2.29 + - @backstage/plugin-proxy-backend@0.2.30 + - @backstage/plugin-auth-backend@0.16.0 + - @backstage/integration@1.3.1 + - @backstage/plugin-catalog-backend@1.4.0 + - @backstage/plugin-azure-devops-backend@0.3.15 + - @backstage/plugin-search-backend-node@1.0.2 + - @backstage/plugin-tech-insights-node@0.3.4 + - @backstage/backend-tasks@0.3.5 + - @backstage/plugin-techdocs-backend@1.3.0 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/plugin-permission-common@0.6.4 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.4 + - @backstage/plugin-search-backend-module-pg@0.4.0 + - @backstage/plugin-jenkins-backend@0.1.26 + - @backstage/plugin-playlist-backend@0.1.0 + - @backstage/plugin-app-backend@0.3.36 + - @backstage/plugin-graphql-backend@0.1.26 + - @backstage/plugin-rollbar-backend@0.1.33 + - @backstage/plugin-code-coverage-backend@0.2.2 + - @backstage/plugin-permission-backend@0.5.11 + - @backstage/plugin-todo-backend@0.1.33 + - @backstage/plugin-search-backend-module-elasticsearch@1.0.2 + - @backstage/plugin-tech-insights-backend@0.5.2 + - @backstage/plugin-badges-backend@0.1.30 + - example-app@0.2.75 + - @backstage/plugin-search-backend@1.0.2 + - @backstage/plugin-search-common@1.0.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.20 + ## 0.2.75-next.3 ### Patch Changes diff --git a/packages/backend/Dockerfile b/packages/backend/Dockerfile index 7ed0121467..21ff07deb4 100644 --- a/packages/backend/Dockerfile +++ b/packages/backend/Dockerfile @@ -19,15 +19,17 @@ RUN apt-get update && \ yarn config set python /usr/bin/python3 # From here on we use the least-privileged `node` user to run the backend. -USER node WORKDIR /app +RUN chown node:node /app +USER node + # This switches many Node.js dependencies to production mode. ENV NODE_ENV production # Copy over Yarn 3 configuration, release, and plugins -COPY .yarn ./.yarn -COPY .yarnrc.yml ./ +COPY --chown=node:node .yarn ./.yarn +COPY --chown=node:node .yarnrc.yml ./ # Copy repo skeleton first, to avoid unnecessary docker cache invalidation. # The skeleton contains the package.json of each package in the monorepo, diff --git a/packages/backend/package.json b/packages/backend/package.json index a8ae29ee18..54bf8c586e 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -1,6 +1,6 @@ { "name": "example-backend", - "version": "0.2.75-next.3", + "version": "0.2.75", "main": "dist/index.cjs.js", "types": "src/index.ts", "license": "Apache-2.0", @@ -26,40 +26,41 @@ "build-image": "docker build ../.. -f Dockerfile --tag example-backend" }, "dependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/backend-tasks": "^0.3.5-next.1", - "@backstage/catalog-client": "^1.1.0-next.2", - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/config": "^1.0.2-next.0", - "@backstage/integration": "^1.3.1-next.2", - "@backstage/plugin-app-backend": "^0.3.36-next.3", - "@backstage/plugin-auth-backend": "^0.16.0-next.3", - "@backstage/plugin-auth-node": "^0.2.5-next.3", - "@backstage/plugin-azure-devops-backend": "^0.3.15-next.2", - "@backstage/plugin-badges-backend": "^0.1.30-next.1", - "@backstage/plugin-catalog-backend": "^1.4.0-next.3", - "@backstage/plugin-code-coverage-backend": "^0.2.2-next.2", - "@backstage/plugin-graphql-backend": "^0.1.26-next.3", - "@backstage/plugin-jenkins-backend": "^0.1.26-next.3", - "@backstage/plugin-kafka-backend": "^0.2.29-next.1", - "@backstage/plugin-kubernetes-backend": "^0.7.2-next.3", - "@backstage/plugin-permission-backend": "^0.5.11-next.2", - "@backstage/plugin-permission-common": "^0.6.4-next.2", - "@backstage/plugin-permission-node": "^0.6.5-next.3", - "@backstage/plugin-proxy-backend": "^0.2.30-next.2", - "@backstage/plugin-rollbar-backend": "^0.1.33-next.3", - "@backstage/plugin-scaffolder-backend": "^1.6.0-next.3", - "@backstage/plugin-scaffolder-backend-module-rails": "^0.4.4-next.1", - "@backstage/plugin-search-backend": "^1.0.2-next.1", - "@backstage/plugin-search-backend-module-elasticsearch": "^1.0.2-next.2", - "@backstage/plugin-search-backend-module-pg": "^0.4.0-next.2", - "@backstage/plugin-search-backend-node": "^1.0.2-next.2", - "@backstage/plugin-search-common": "^1.0.1-next.0", - "@backstage/plugin-tech-insights-backend": "^0.5.2-next.2", - "@backstage/plugin-tech-insights-backend-module-jsonfc": "^0.1.20-next.1", - "@backstage/plugin-tech-insights-node": "^0.3.4-next.1", - "@backstage/plugin-techdocs-backend": "^1.3.0-next.2", - "@backstage/plugin-todo-backend": "^0.1.33-next.2", + "@backstage/backend-common": "workspace:^", + "@backstage/backend-tasks": "workspace:^", + "@backstage/catalog-client": "workspace:^", + "@backstage/catalog-model": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/integration": "workspace:^", + "@backstage/plugin-app-backend": "workspace:^", + "@backstage/plugin-auth-backend": "workspace:^", + "@backstage/plugin-auth-node": "workspace:^", + "@backstage/plugin-azure-devops-backend": "workspace:^", + "@backstage/plugin-badges-backend": "workspace:^", + "@backstage/plugin-catalog-backend": "workspace:^", + "@backstage/plugin-code-coverage-backend": "workspace:^", + "@backstage/plugin-graphql-backend": "workspace:^", + "@backstage/plugin-jenkins-backend": "workspace:^", + "@backstage/plugin-kafka-backend": "workspace:^", + "@backstage/plugin-kubernetes-backend": "workspace:^", + "@backstage/plugin-permission-backend": "workspace:^", + "@backstage/plugin-permission-common": "workspace:^", + "@backstage/plugin-permission-node": "workspace:^", + "@backstage/plugin-playlist-backend": "workspace:^", + "@backstage/plugin-proxy-backend": "workspace:^", + "@backstage/plugin-rollbar-backend": "workspace:^", + "@backstage/plugin-scaffolder-backend": "workspace:^", + "@backstage/plugin-scaffolder-backend-module-rails": "workspace:^", + "@backstage/plugin-search-backend": "workspace:^", + "@backstage/plugin-search-backend-module-elasticsearch": "workspace:^", + "@backstage/plugin-search-backend-module-pg": "workspace:^", + "@backstage/plugin-search-backend-node": "workspace:^", + "@backstage/plugin-search-common": "workspace:^", + "@backstage/plugin-tech-insights-backend": "workspace:^", + "@backstage/plugin-tech-insights-backend-module-jsonfc": "workspace:^", + "@backstage/plugin-tech-insights-node": "workspace:^", + "@backstage/plugin-techdocs-backend": "workspace:^", + "@backstage/plugin-todo-backend": "workspace:^", "@gitbeaker/node": "^35.1.0", "@octokit/rest": "^19.0.3", "azure-devops-node-api": "^11.0.1", @@ -76,7 +77,7 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", + "@backstage/cli": "workspace:^", "@types/dockerode": "^3.3.0", "@types/express": "^4.17.6", "@types/express-serve-static-core": "^4.17.5", diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index de3f435508..cb9c9bf580 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -57,6 +57,7 @@ import app from './plugins/app'; import badges from './plugins/badges'; import jenkins from './plugins/jenkins'; import permission from './plugins/permission'; +import playlist from './plugins/playlist'; import { PluginEnvironment } from './types'; import { ServerPermissionClient } from '@backstage/plugin-permission-node'; import { DefaultIdentityClient } from '@backstage/plugin-auth-node'; @@ -139,6 +140,7 @@ async function main() { createEnv('tech-insights'), ); const permissionEnv = useHotMemoize(module, () => createEnv('permission')); + const playlistEnv = useHotMemoize(module, () => createEnv('playlist')); const apiRouter = Router(); apiRouter.use('/catalog', await catalog(catalogEnv)); @@ -158,6 +160,7 @@ async function main() { apiRouter.use('/badges', await badges(badgesEnv)); apiRouter.use('/jenkins', await jenkins(jenkinsEnv)); apiRouter.use('/permission', await permission(permissionEnv)); + apiRouter.use('/playlist', await playlist(playlistEnv)); apiRouter.use(notFoundHandler()); const service = createServiceBuilder(module) diff --git a/packages/backend/src/plugins/permission.ts b/packages/backend/src/plugins/permission.ts index 0d3dcc588d..7192a1ddec 100644 --- a/packages/backend/src/plugins/permission.ts +++ b/packages/backend/src/plugins/permission.ts @@ -14,17 +14,34 @@ * limitations under the License. */ +import { BackstageIdentityResponse } from '@backstage/plugin-auth-node'; import { createRouter } from '@backstage/plugin-permission-backend'; import { AuthorizeResult, PolicyDecision, } from '@backstage/plugin-permission-common'; -import { PermissionPolicy } from '@backstage/plugin-permission-node'; +import { + PermissionPolicy, + PolicyQuery, +} from '@backstage/plugin-permission-node'; +import { + DefaultPlaylistPermissionPolicy, + isPlaylistPermission, +} from '@backstage/plugin-playlist-backend'; import { Router } from 'express'; import { PluginEnvironment } from '../types'; -class AllowAllPermissionPolicy implements PermissionPolicy { - async handle(): Promise { +class ExamplePermissionPolicy implements PermissionPolicy { + private playlistPermissionPolicy = new DefaultPlaylistPermissionPolicy(); + + async handle( + request: PolicyQuery, + user?: BackstageIdentityResponse, + ): Promise { + if (isPlaylistPermission(request.permission)) { + return this.playlistPermissionPolicy.handle(request, user); + } + return { result: AuthorizeResult.ALLOW, }; @@ -38,7 +55,7 @@ export default async function createPlugin( config: env.config, logger: env.logger, discovery: env.discovery, - policy: new AllowAllPermissionPolicy(), + policy: new ExamplePermissionPolicy(), identity: env.identity, }); } diff --git a/packages/backend/src/plugins/playlist.ts b/packages/backend/src/plugins/playlist.ts new file mode 100644 index 0000000000..6cae6a30ab --- /dev/null +++ b/packages/backend/src/plugins/playlist.ts @@ -0,0 +1,31 @@ +/* + * 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 { createRouter } from '@backstage/plugin-playlist-backend'; +import { Router } from 'express'; +import { PluginEnvironment } from '../types'; + +export default async function createPlugin( + env: PluginEnvironment, +): Promise { + return await createRouter({ + database: env.database, + discovery: env.discovery, + identity: env.identity, + logger: env.logger, + permissions: env.permissions, + }); +} diff --git a/packages/backend/src/types.ts b/packages/backend/src/types.ts index 831eaebb66..895581c702 100644 --- a/packages/backend/src/types.ts +++ b/packages/backend/src/types.ts @@ -24,11 +24,8 @@ import { UrlReader, } from '@backstage/backend-common'; import { PluginTaskScheduler } from '@backstage/backend-tasks'; -import { - PermissionAuthorizer, - PermissionEvaluator, -} from '@backstage/plugin-permission-common'; import { IdentityApi } from '@backstage/plugin-auth-node'; +import { PermissionEvaluator } from '@backstage/plugin-permission-common'; export type PluginEnvironment = { logger: Logger; @@ -38,7 +35,7 @@ export type PluginEnvironment = { reader: UrlReader; discovery: PluginEndpointDiscovery; tokenManager: TokenManager; - permissions: PermissionEvaluator | PermissionAuthorizer; + permissions: PermissionEvaluator; scheduler: PluginTaskScheduler; identity: IdentityApi; }; diff --git a/packages/catalog-client/CHANGELOG.md b/packages/catalog-client/CHANGELOG.md index 6cbcab0a4e..774325ff44 100644 --- a/packages/catalog-client/CHANGELOG.md +++ b/packages/catalog-client/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/catalog-client +## 1.1.0 + +### Minor Changes + +- 65d1d4343f: Adding `validateEntity` method that calls `/validate-entity` endpoint. + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- ef9ab322de: Minor API signatures cleanup +- Updated dependencies + - @backstage/catalog-model@1.1.1 + - @backstage/errors@1.1.1 + ## 1.1.0-next.2 ### Minor Changes diff --git a/packages/catalog-client/package.json b/packages/catalog-client/package.json index 3a06074a4d..fb1de71062 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.1.0-next.2", + "version": "1.1.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,12 +32,12 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/errors": "^1.1.1-next.0", + "@backstage/catalog-model": "workspace:^", + "@backstage/errors": "workspace:^", "cross-fetch": "^3.1.5" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", + "@backstage/cli": "workspace:^", "msw": "^0.47.0" }, "files": [ diff --git a/packages/catalog-model/CHANGELOG.md b/packages/catalog-model/CHANGELOG.md index 25d5866002..d3f9fe4af8 100644 --- a/packages/catalog-model/CHANGELOG.md +++ b/packages/catalog-model/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/catalog-model +## 1.1.1 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- Updated dependencies + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + ## 1.1.1-next.0 ### Patch Changes diff --git a/packages/catalog-model/package.json b/packages/catalog-model/package.json index 28df6e58fc..ce2abee20a 100644 --- a/packages/catalog-model/package.json +++ b/packages/catalog-model/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/catalog-model", "description": "Types and validators that help describe the model of a Backstage Catalog", - "version": "1.1.1-next.0", + "version": "1.1.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,16 +33,16 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/config": "^1.0.2-next.0", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/types": "^1.0.0", + "@backstage/config": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/types": "workspace:^", "ajv": "^8.10.0", "json-schema": "^0.4.0", "lodash": "^4.17.21", "uuid": "^8.0.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", + "@backstage/cli": "workspace:^", "@types/json-schema": "^7.0.5", "@types/lodash": "^4.14.151", "yaml": "^2.0.0" diff --git a/packages/cli-common/CHANGELOG.md b/packages/cli-common/CHANGELOG.md index 05362b7a31..30a8fd70bb 100644 --- a/packages/cli-common/CHANGELOG.md +++ b/packages/cli-common/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/cli-common +## 0.1.10 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. + ## 0.1.10-next.0 ### Patch Changes diff --git a/packages/cli-common/package.json b/packages/cli-common/package.json index 965c62ce38..3b229071cf 100644 --- a/packages/cli-common/package.json +++ b/packages/cli-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/cli-common", "description": "Common functionality used by cli, backend, and create-app", - "version": "0.1.10-next.0", + "version": "0.1.10", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { @@ -32,7 +32,7 @@ "start": "backstage-cli package start" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", + "@backstage/cli": "workspace:^", "@types/node": "^16.0.0" }, "files": [ diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 52ba0a24c6..0f36ba5e56 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,107 @@ # @backstage/cli +## 0.19.0 + +### Minor Changes + +- 1fe6823bb5: Updated dependency `eslint-plugin-jest` to `^27.0.0`. + + Note that this major update to the Jest plugin contains some breaking changes. + This means that some of your tests may start seeing some new lint errors. [Read + about them + here](https://github.com/jest-community/eslint-plugin-jest/blob/main/CHANGELOG.md#2700-2022-08-28). + + These are mostly possible to fix automatically. You can try to run `yarn backstage-cli repo lint --fix` in your repo root to have most or all of them + corrected. + +### Patch Changes + +- 8d886dd33e: The `create-plugin` and `create` commands have both been deprecated in favor of a new `new` command. The `new` command is functionally identical to `create`, but the new naming makes it possible to use as yarn script, since `yarn create` is reserved. +- cc63eb8611: Sort entries in skeleton.tar.gz for better docker layer caching +- 548053614a: Deprecated the `plugin:diff` command. If you wish to keep running similar checks in your project we recommend using bespoke scripts. A useful utility for such scripts is `@manypkg/get-packages`, which helps you enumerate all packages in a monorepo. +- 513b4dd4ef: The `versions:bump` command will now update dependency ranges in `package.json`, even if the new version is within the current range. +- 221e951298: Added support for custom certificate for webpack dev server. +- 934cc34563: Avoid validating the backend configuration schema when loading static configuration for building the frontend. +- 3d4f5daadf: Remove use of deprecated trimLeft/trimRight +- 817f3196f6: Added a new `migrate react-router-deps` command to aid in the migration to React Router v6 stable. +- 742cb4f3d7: Fix issue when using `.jsx` files inside tests +- e7600bdb04: Tweaked workspace packaging to not rewrite existing `package.json` files. +- 6ae0f6a719: Switch out `sucrase` for `swc` for transpilation. + + `sucrase` is a little more relaxed when it comes to supporting the ways of mocking in `jest`. You might have to make some changes to your tests to meet the `jest` standard and spec if your tests seems to start failing. + + Mocks that look like this are invalid, and they will throw a reference error in line with the `jest` documentation [here on example 3](https://jestjs.io/docs/es6-class-mocks#calling-jestmock-with-the-module-factory-parameter) + + ```ts + const mockCommandExists = jest.fn(); + jest.mock('command-exists', () => mockCommandExists); + ``` + + You might need to update these mocks to look a little like the following to defer the call to the `jest.fn()` spy until the mock is called. + + ```ts + const mockCommandExists = jest.fn(); + jest.mock( + 'command-exists', + () => + (...args: any[]) => + commandExists(...args), + ); + ``` + + Also, imports are immutable. So it means that you might get some errors when trying to use `jest.spyOn` with starred imports. You might see an error like this: + + ```log + TypeError: Cannot redefine property: executeFrameHandlerStrategy + at Function.defineProperty () + + 20 | import { AuthResolverContext } from '../types'; + 21 | + > 22 | const mockFrameHandler = jest.spyOn( + | ^ + 23 | helpers, + 24 | 'executeFrameHandlerStrategy', + 25 | ) as unknown as jest.MockedFunction< + ``` + + This happens when you try to do `import * as something from './something'` and then `jest.spyOn(something, 'test)`. You will need to add a `jest.mock` call to mock out the required starred import to return `jest.fn()` functions from the start. Something like this fixes the above test: + + ```ts + jest.mock('../../helpers', () => ({ + executeFrameHandlerStrategy: jest.fn(), + })); + ``` + + You can also remove any occurrence of `hot(App)` and any import of `react-hot-loader` if you're using the that package locally, as all this has now been replaced with [React Refresh](https://www.npmjs.com/package/react-refresh) which you will get out of the box with the new CLI. + + **Note** If you're experiencing difficulties with running tests after the migration, please reach out to us on Discord to see if we can help, or raise an issue. But in the meantime you can switch back to the existing behaviour by using the following config in your root `package.json`. + + ```json + "jest": { + "transform": { + "\\.(js|jsx|ts|tsx|mjs|cjs)$": "@backstage/cli/config/jestSucraseTransform.js", + "\\.(bmp|gif|jpg|jpeg|png|frag|xml|svg|eot|woff|woff2|ttf)$": "@backstage/cli/config/jestFileTransform.js", + "\\.(yaml)$": "jest-transform-yaml" + } + } + ``` + +- 1cb078ad9f: Fixed a misconfiguration where all modules where treated as ESM by the React Refresh plugin for Webpack. +- 1fd4f2746f: Removed internal dependencies on Lerna. It is now no longer necessary to have Lerna installed in a project to use all features of the Backstage CLI. +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- 33fbd9f9a4: Updated dependency `@types/minimatch` to `^5.0.0`. +- 68c2697077: Added a new `backstage-cli repo clean` command that cleans the repo root and runs the clean script in all packages. +- 7d47def9c4: Added dependency on `@types/jest` v27. The `@types/jest` dependency has also been removed from the plugin template and should be removed from any of your own internal packages. If you wish to override the version of `@types/jest` or `jest`, use Yarn resolutions. +- a7e82c9b01: Updated `versions:bump` command to be compatible with Yarn 3. +- Updated dependencies + - @backstage/config-loader@1.1.4 + - @backstage/cli-common@0.1.10 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + - @backstage/release-manifests@0.0.6 + ## 0.19.0-next.3 ### Patch Changes diff --git a/packages/cli/cli-report.md b/packages/cli/cli-report.md index 9a67e8245d..9afd12fb48 100644 --- a/packages/cli/cli-report.md +++ b/packages/cli/cli-report.md @@ -276,7 +276,7 @@ Usage: backstage-cli [--config=] [TestPathPattern] Options: -h, --help - -v, --version + --version --all --automock -b, --bail @@ -289,7 +289,6 @@ Options: --clearMocks --collectCoverage --collectCoverageFrom - --collectCoverageOnlyFrom --color --colors -c, --config @@ -312,6 +311,7 @@ Options: --globalTeardown --globals --haste + --ignoreProjects --init --injectGlobals --json @@ -348,6 +348,7 @@ Options: --selectProjects --setupFiles --setupFilesAfterEnv + --shard --showConfig --silent --skipFilter @@ -365,8 +366,6 @@ Options: --testRunner --testSequencer --testTimeout - --testURL - --timers --transform --transformIgnorePatterns --unmockedModulePathPatterns @@ -391,6 +390,7 @@ Commands: build [options] lint [options] clean + test [options] help [command] ``` @@ -426,6 +426,17 @@ Options: -h, --help ``` +### `backstage-cli repo test` + +``` +Usage: backstage-cli repo test [options] + +Options: + --since + --jest-help + -h, --help +``` + ### `backstage-cli test` ``` @@ -433,7 +444,7 @@ Usage: backstage-cli [--config=] [TestPathPattern] Options: -h, --help - -v, --version + --version --all --automock -b, --bail @@ -446,7 +457,6 @@ Options: --clearMocks --collectCoverage --collectCoverageFrom - --collectCoverageOnlyFrom --color --colors -c, --config @@ -469,6 +479,7 @@ Options: --globalTeardown --globals --haste + --ignoreProjects --init --injectGlobals --json @@ -505,6 +516,7 @@ Options: --selectProjects --setupFiles --setupFilesAfterEnv + --shard --showConfig --silent --skipFilter @@ -522,8 +534,6 @@ Options: --testRunner --testSequencer --testTimeout - --testURL - --timers --transform --transformIgnorePatterns --unmockedModulePathPatterns diff --git a/packages/cli/config/jest.js b/packages/cli/config/jest.js index 9d113989ff..8b6c37bda4 100644 --- a/packages/cli/config/jest.js +++ b/packages/cli/config/jest.js @@ -27,7 +27,6 @@ const envOptions = { const transformIgnorePattern = [ '@material-ui', - '@rjsf', 'ajv', 'core-js', 'jest-.*', @@ -189,13 +188,13 @@ async function getProjectConfig(targetPath, displayName) { ], '\\.(bmp|gif|jpg|jpeg|png|frag|xml|svg|eot|woff|woff2|ttf)$': require.resolve('./jestFileTransform.js'), - '\\.(yaml)$': require.resolve('jest-transform-yaml'), + '\\.(yaml)$': require.resolve('./jestYamlTransform'), }, // A bit more opinionated testMatch: ['**/*.test.{js,jsx,ts,tsx,mjs,cjs}'], - moduleLoader: envOptions.nextTests + runtime: envOptions.nextTests ? require.resolve('./jestCachingModuleLoader') : undefined, @@ -210,16 +209,16 @@ async function getProjectConfig(targetPath, displayName) { const config = Object.assign(options, ...pkgJsonConfigs); - // The config name is a cache key that lets us share the jest cache across projects. - // If no explicit name was configured, generated one based on the configuration. - if (!config.name) { + // The config id is a cache key that lets us share the jest cache across projects. + // If no explicit id was configured, generated one based on the configuration. + if (!config.id) { const configHash = crypto .createHash('md5') .update(version) .update(Buffer.alloc(1)) .update(JSON.stringify(config.transform)) .digest('hex'); - config.name = `backstage_cli_${configHash}`; + config.id = `backstage_cli_${configHash}`; } return config; diff --git a/packages/cli/config/jestFileTransform.js b/packages/cli/config/jestFileTransform.js index bdd29fc296..d003c5b567 100644 --- a/packages/cli/config/jestFileTransform.js +++ b/packages/cli/config/jestFileTransform.js @@ -21,7 +21,8 @@ module.exports = { const assetFilename = JSON.stringify(path.basename(filename)); if (filename.match(/\.icon\.svg$/)) { - return `const React = require('react'); + return { + code: `const React = require('react'); const SvgIcon = require('@material-ui/core/SvgIcon').default; module.exports = { __esModule: true, @@ -34,9 +35,10 @@ module.exports = { children: ${assetFilename} }) }) - };`; + };`, + }; } - return `module.exports = ${assetFilename};`; + return { code: `module.exports = ${assetFilename};` }; }, }; diff --git a/packages/cli/config/jestSucraseTransform.js b/packages/cli/config/jestSucraseTransform.js index d0400f4f3b..99ebc04877 100644 --- a/packages/cli/config/jestSucraseTransform.js +++ b/packages/cli/config/jestSucraseTransform.js @@ -64,10 +64,10 @@ function createTransformer(config) { } // We only return the `map` result if source maps are enabled, as they // have a negative impact on the coverage accuracy. - return code; + return { code }; } - return source; + return { code: source }; }; // TODO: contribute something like this to @sucrase/jest-plugin diff --git a/packages/cli/config/jestSwcTransform.js b/packages/cli/config/jestSwcTransform.js index c87948978d..c44d0fe4b0 100644 --- a/packages/cli/config/jestSwcTransform.js +++ b/packages/cli/config/jestSwcTransform.js @@ -21,7 +21,7 @@ function createTransformer(config) { const swcTransformer = createSwcTransformer(config); const process = (source, filePath, jestOptions) => { if (filePath.endsWith('.js') && !ESM_REGEX.test(source)) { - return source; + return { code: source }; } return swcTransformer.process(source, filePath, jestOptions); diff --git a/packages/cli/config/jestYamlTransform.js b/packages/cli/config/jestYamlTransform.js new file mode 100644 index 0000000000..1235f8a4b7 --- /dev/null +++ b/packages/cli/config/jestYamlTransform.js @@ -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. + */ + +const yaml = require('yaml'); +const crypto = require('crypto'); + +function createTransformer(config) { + const process = source => { + const json = JSON.stringify(yaml.parse(source), null, 2); + return { code: `module.exports = ${json}`, map: null }; + }; + + const getCacheKey = sourceText => { + return crypto + .createHash('md5') + .update(sourceText) + .update(Buffer.alloc(1)) + .update(JSON.stringify(config)) + .update(Buffer.alloc(1)) + .update('1') // increment whenever the transform logic in this file changes + .digest('hex'); + }; + + return { process, getCacheKey }; +} + +module.exports = { createTransformer }; diff --git a/packages/cli/package.json b/packages/cli/package.json index 9a412d401f..b07f2a0263 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.19.0-next.3", + "version": "0.19.0", "publishConfig": { "access": "public" }, @@ -30,12 +30,12 @@ "backstage-cli": "bin/backstage-cli" }, "dependencies": { - "@backstage/cli-common": "^0.1.10-next.0", - "@backstage/config": "^1.0.2-next.0", - "@backstage/config-loader": "^1.1.4-next.2", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/release-manifests": "^0.0.6-next.2", - "@backstage/types": "^1.0.0", + "@backstage/cli-common": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/config-loader": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/release-manifests": "workspace:^", + "@backstage/types": "workspace:^", "@manypkg/get-packages": "^1.1.3", "@octokit/request": "^6.0.0", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.7", @@ -55,7 +55,7 @@ "@swc/core": "^1.2.239", "@swc/helpers": "^0.4.7", "@swc/jest": "^0.2.22", - "@types/jest": "^27", + "@types/jest": "^29.0.0", "@types/webpack-env": "^1.15.2", "@typescript-eslint/eslint-plugin": "^5.9.0", "@typescript-eslint/parser": "^5.9.0", @@ -89,10 +89,10 @@ "handlebars": "^4.7.3", "html-webpack-plugin": "^5.3.1", "inquirer": "^8.2.0", - "jest": "^27.5.1", + "jest": "^29.0.2", "jest-css-modules": "^2.1.0", - "jest-runtime": "^27.5.1", - "jest-transform-yaml": "^1.0.0", + "jest-environment-jsdom": "^29.0.2", + "jest-runtime": "^29.0.2", "json-schema": "^0.4.0", "lodash": "^4.17.21", "mini-css-extract-plugin": "^2.4.2", @@ -129,14 +129,14 @@ "zod": "^3.11.6" }, "devDependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/config": "^1.0.2-next.0", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", - "@backstage/theme": "^0.2.16", + "@backstage/backend-common": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", + "@backstage/theme": "workspace:^", "@types/diff": "^5.0.0", "@types/express": "^4.17.6", "@types/fs-extra": "^9.0.1", diff --git a/packages/cli/src/commands/index.ts b/packages/cli/src/commands/index.ts index 8f3317c437..266b4fd9f1 100644 --- a/packages/cli/src/commands/index.ts +++ b/packages/cli/src/commands/index.ts @@ -72,6 +72,20 @@ export function registerRepoCommand(program: Command) { .action( lazy(() => import('./repo/list-deprecations').then(m => m.command)), ); + + command + .command('test') + .allowUnknownOption(true) // Allows the command to run, but we still need to parse raw args + .option( + '--since ', + 'Only test packages that changed since the specified ref', + ) + .option( + '--jest-help', + 'Show help for Jest CLI options, which are passed through', + ) + .description('Run tests, forwarding args to Jest, defaulting to watch mode') + .action(lazy(() => import('./repo/test').then(m => m.command))); } export function registerScriptCommand(program: Command) { diff --git a/packages/cli/src/commands/repo/test.ts b/packages/cli/src/commands/repo/test.ts new file mode 100644 index 0000000000..578cb15e83 --- /dev/null +++ b/packages/cli/src/commands/repo/test.ts @@ -0,0 +1,134 @@ +/* + * 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 { Command, OptionValues } from 'commander'; +import { PackageGraph } from '../../lib/monorepo'; +import { paths } from '../../lib/paths'; +import { runCheck } from '../../lib/run'; + +function includesAnyOf(hayStack: string[], ...needles: string[]) { + for (const needle of needles) { + if (hayStack.includes(needle)) { + return true; + } + } + return false; +} + +function removeOptionArg(args: string[], option: string) { + let changed = false; + do { + changed = false; + + const index = args.indexOf(option); + if (index >= 0) { + changed = true; + args.splice(index, 2); + } + const indexEq = args.findIndex(arg => arg.startsWith(`${option}=`)); + if (indexEq >= 0) { + changed = true; + args.splice(indexEq, 1); + } + } while (changed); +} + +export async function command(opts: OptionValues, cmd: Command): Promise { + // all args are forwarded to jest + let parent = cmd; + while (parent.parent) { + parent = parent.parent; + } + const allArgs = parent.args as string[]; + const args = allArgs.slice(allArgs.indexOf('test') + 1); + + // Only include our config if caller isn't passing their own config + if (!includesAnyOf(args, '-c', '--config')) { + args.push('--config', paths.resolveOwn('config/jest.js')); + } + + if (!includesAnyOf(args, '--no-passWithNoTests', '--passWithNoTests=false')) { + args.push('--passWithNoTests'); + } + + // Run in watch mode unless in CI, coverage mode, or running all tests + if ( + !process.env.CI && + !args.includes('--coverage') && + // explicitly no watching + !includesAnyOf(args, '--no-watch', '--watch=false', '--watchAll=false') && + // already watching + !includesAnyOf(args, '--watch', '--watchAll') + ) { + const isGitRepo = () => + runCheck('git', 'rev-parse', '--is-inside-work-tree'); + const isMercurialRepo = () => runCheck('hg', '--cwd', '.', 'root'); + + if ((await isGitRepo()) || (await isMercurialRepo())) { + args.push('--watch'); + } else { + args.push('--watchAll'); + } + } + + if (opts.since) { + removeOptionArg(args, '--since'); + } + + if (opts.since && !args.some(arg => arg.startsWith('--selectProjects'))) { + const packages = await PackageGraph.listTargetPackages(); + const graph = PackageGraph.fromPackages(packages); + const changedPackages = await graph.listChangedPackages({ + ref: opts.since, + }); + + const packageNames = Array.from( + graph.collectPackageNames( + changedPackages.map(pkg => pkg.name), + pkg => pkg.allLocalDependents.keys(), + ), + ); + + if (packageNames.length === 0) { + console.log(`No packages changed since ${opts.since}`); + return; + } + + args.push('--selectProjects', ...packageNames); + } + + // This is the only thing that is not implemented by jest.run(), so we do it here instead + // https://github.com/facebook/jest/blob/cd8828f7bbec6e55b4df5e41e853a5133c4a3ee1/packages/jest-cli/bin/jest.js#L12 + if (!process.env.NODE_ENV) { + (process.env as any).NODE_ENV = 'test'; + } + + // This is to have a consistent timezone for when running tests that involve checking + // the formatting of date/times. + // https://stackoverflow.com/questions/56261381/how-do-i-set-a-timezone-in-my-jest-config + if (!process.env.TZ) { + process.env.TZ = 'UTC'; + } + + // This ensures that the process doesn't exit too early before stdout is flushed + if (args.includes('--jest-help')) { + removeOptionArg(args, '--jest-help'); + args.push('--help'); + (process.stdout as any)._handle.setBlocking(true); + } + + await require('jest').run(args); +} diff --git a/packages/cli/src/commands/test.ts b/packages/cli/src/commands/test.ts index ec1bf8a7a0..b55919b2ce 100644 --- a/packages/cli/src/commands/test.ts +++ b/packages/cli/src/commands/test.ts @@ -78,6 +78,7 @@ export default async (_opts: OptionValues, cmd: Command) => { process.env.TZ = 'UTC'; } + // This ensures that the process doesn't exit too early before stdout is flushed if (args.includes('--help')) { (process.stdout as any)._handle.setBlocking(true); } diff --git a/packages/cli/src/lib/packager/createDistWorkspace.ts b/packages/cli/src/lib/packager/createDistWorkspace.ts index 53e00ab6d9..5451a873f7 100644 --- a/packages/cli/src/lib/packager/createDistWorkspace.ts +++ b/packages/cli/src/lib/packager/createDistWorkspace.ts @@ -22,7 +22,7 @@ import { relative as relativePath, } from 'path'; import { tmpdir } from 'os'; -import tar, { CreateOptions } from 'tar'; +import tar, { CreateOptions, FileOptions } from 'tar'; import partition from 'lodash/partition'; import { paths } from '../paths'; import { run } from '../run'; @@ -214,10 +214,12 @@ export async function createDistWorkspace( } if (options.skeleton) { - const skeletonFiles = targets.map(target => { - const dir = relativePath(paths.targetRoot, target.dir); - return joinPath(dir, 'package.json'); - }); + const skeletonFiles = targets + .map(target => { + const dir = relativePath(paths.targetRoot, target.dir); + return joinPath(dir, 'package.json'); + }) + .sort(); await tar.create( { @@ -226,7 +228,7 @@ export async function createDistWorkspace( portable: true, noMtime: true, gzip: options.skeleton.endsWith('.gz'), - } as CreateOptions & { noMtime: boolean }, + } as CreateOptions & FileOptions & { noMtime: boolean }, skeletonFiles, ); } diff --git a/packages/cli/src/lib/version.ts b/packages/cli/src/lib/version.ts index 1cddf773f4..5a199236f5 100644 --- a/packages/cli/src/lib/version.ts +++ b/packages/cli/src/lib/version.ts @@ -81,6 +81,14 @@ export function createPackageVersionProvider(lockfile?: Lockfile) { ) { return '*'; } + + for (const specifier of ['^', '~', '*']) { + const range = `workspace:${specifier}`; + if (lockfileEntries?.some(entry => entry.range === range)) { + return range; + } + } + const validRanges = lockfileEntries?.filter(entry => semver.satisfies(targetVersion, entry.range), ); diff --git a/packages/cli/src/lib/versioning/Lockfile.test.ts b/packages/cli/src/lib/versioning/Lockfile.test.ts index bad7ab6719..4621b43372 100644 --- a/packages/cli/src/lib/versioning/Lockfile.test.ts +++ b/packages/cli/src/lib/versioning/Lockfile.test.ts @@ -170,7 +170,7 @@ a@^1: integrity: sha512-xyz resolved: "https://my-registry/a-1.0.01.tgz#abc123" -b@2.0.x: +"b@2.0.x, b@^2.0.1": version: 2.0.1 b@^2: @@ -185,7 +185,7 @@ a@^1: integrity: sha512-xyz resolved: "https://my-registry/a-1.0.01.tgz#abc123" -b@2.0.x: +"b@2.0.x, b@^2.0.1": version: 2.0.1 b@^2: @@ -206,6 +206,7 @@ describe('New Lockfile', () => { expect(lockfile.get('a')).toEqual([{ range: '^1', version: '1.0.1' }]); expect(lockfile.get('b')).toEqual([ { range: '2.0.x', version: '2.0.1' }, + { range: '^2.0.1', version: '2.0.1' }, { range: '^2', version: '2.0.0' }, ]); expect(lockfile.toString()).toBe(mockANew); diff --git a/packages/cli/src/lib/versioning/Lockfile.ts b/packages/cli/src/lib/versioning/Lockfile.ts index 278778b6a6..016593ea8d 100644 --- a/packages/cli/src/lib/versioning/Lockfile.ts +++ b/packages/cli/src/lib/versioning/Lockfile.ts @@ -122,7 +122,7 @@ export class Lockfile { for (const [key, value] of Object.entries(data)) { if (SPECIAL_OBJECT_KEYS.includes(key)) continue; - const [, name, range] = ENTRY_PATTERN.exec(key) ?? []; + const [, name, ranges] = ENTRY_PATTERN.exec(key) ?? []; if (!name) { throw new Error(`Failed to parse yarn.lock entry '${key}'`); } @@ -132,7 +132,15 @@ export class Lockfile { queries = []; packages.set(name, queries); } - queries.push({ range, version: value.version }); + for (let range of ranges.split(/\s*,\s*/)) { + if (range.startsWith(`${name}@`)) { + range = range.slice(`${name}@`.length); + } + if (range.startsWith('npm:')) { + range = range.slice('npm:'.length); + } + queries.push({ range, version: value.version }); + } } return new Lockfile(path, packages, data, legacy); diff --git a/packages/cli/src/tests/yaml-fixture.yaml b/packages/cli/src/tests/yaml-fixture.yaml new file mode 100644 index 0000000000..e93744d8dc --- /dev/null +++ b/packages/cli/src/tests/yaml-fixture.yaml @@ -0,0 +1,2 @@ +x: + y: 'z' diff --git a/packages/cli/src/tests/yaml.test.ts b/packages/cli/src/tests/yaml.test.ts new file mode 100644 index 0000000000..cb96fdf954 --- /dev/null +++ b/packages/cli/src/tests/yaml.test.ts @@ -0,0 +1,23 @@ +/* + * 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 yaml from './yaml-fixture.yaml'; + +describe('tests', () => { + it('should load yaml', () => { + expect(yaml).toEqual({ x: { y: 'z' } }); + }); +}); diff --git a/packages/cli/templates/default-backend-plugin/package.json.hbs b/packages/cli/templates/default-backend-plugin/package.json.hbs index fcc903b148..0a72a5d415 100644 --- a/packages/cli/templates/default-backend-plugin/package.json.hbs +++ b/packages/cli/templates/default-backend-plugin/package.json.hbs @@ -30,18 +30,18 @@ "dependencies": { "@backstage/backend-common": "{{versionQuery '@backstage/backend-common'}}", "@backstage/config": "{{versionQuery '@backstage/config'}}", - "@types/express": "{{versionQuery '@types/express' '4.17.6'}}", - "express": "{{versionQuery 'express' '4.17.1'}}", + "@types/express": "{{versionQuery '@types/express' '4.17.13'}}", + "express": "{{versionQuery 'express' '4.18.1'}}", "express-promise-router": "{{versionQuery 'express-promise-router' '4.1.0'}}", - "winston": "{{versionQuery 'winston' '3.2.1'}}", + "winston": "{{versionQuery 'winston' '3.8.1'}}", "node-fetch": "{{versionQuery 'node-fetch' '2.6.7'}}", "yn": "{{versionQuery 'yn' '4.0.0'}}" }, "devDependencies": { "@backstage/cli": "{{versionQuery '@backstage/cli'}}", - "@types/supertest": "{{versionQuery '@types/supertest' '2.0.8'}}", - "supertest": "{{versionQuery 'supertest' '4.0.2'}}", - "msw": "{{versionQuery 'msw' '0.46.0'}}" + "@types/supertest": "{{versionQuery '@types/supertest' '2.0.12'}}", + "supertest": "{{versionQuery 'supertest' '6.2.4'}}", + "msw": "{{versionQuery 'msw' '0.47.0'}}" }, "files": [ "dist" diff --git a/packages/cli/templates/default-plugin/package.json.hbs b/packages/cli/templates/default-plugin/package.json.hbs index a1c1245b38..c60ba63f2b 100644 --- a/packages/cli/templates/default-plugin/package.json.hbs +++ b/packages/cli/templates/default-plugin/package.json.hbs @@ -48,7 +48,7 @@ "@testing-library/react": "{{versionQuery '@testing-library/react' '12.1.3'}}", "@testing-library/user-event": "{{versionQuery '@testing-library/user-event' '14.0.0'}}", "@types/node": "{{versionQuery '@types/node' '16.11.26'}}", - "msw": "{{versionQuery 'msw' '0.46.0'}}", + "msw": "{{versionQuery 'msw' '0.47.0'}}", "cross-fetch": "{{versionQuery 'cross-fetch' '3.1.5'}}" }, "files": [ diff --git a/packages/codemods/CHANGELOG.md b/packages/codemods/CHANGELOG.md index 43b2bb2d8a..957910660a 100644 --- a/packages/codemods/CHANGELOG.md +++ b/packages/codemods/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/codemods +## 0.1.39 + +### Patch Changes + +- Updated dependencies + - @backstage/cli-common@0.1.10 + ## 0.1.39-next.0 ### Patch Changes diff --git a/packages/codemods/package.json b/packages/codemods/package.json index 2e7bd09dbc..4be7e5a31c 100644 --- a/packages/codemods/package.json +++ b/packages/codemods/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/codemods", "description": "A collection of codemods for Backstage projects", - "version": "0.1.39-next.0", + "version": "0.1.39", "publishConfig": { "access": "public", "main": "dist/index.cjs.js" @@ -33,13 +33,13 @@ "backstage-codemods": "bin/backstage-codemods" }, "dependencies": { - "@backstage/cli-common": "^0.1.10-next.0", + "@backstage/cli-common": "workspace:^", "chalk": "^4.0.0", "jscodeshift": "^0.13.0", "jscodeshift-add-imports": "^1.0.10" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", + "@backstage/cli": "workspace:^", "@types/jscodeshift": "^0.11.0", "@types/node": "^16.11.26", "commander": "^9.1.0", diff --git a/packages/config-loader/CHANGELOG.md b/packages/config-loader/CHANGELOG.md index c46763bccd..f3cc482178 100644 --- a/packages/config-loader/CHANGELOG.md +++ b/packages/config-loader/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/config-loader +## 1.1.4 + +### Patch Changes + +- 5ecca7e44b: No longer log when reloading remote config. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/cli-common@0.1.10 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + ## 1.1.4-next.2 ### Patch Changes diff --git a/packages/config-loader/package.json b/packages/config-loader/package.json index 3f0644e3d6..15d622cf5d 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.1.4-next.2", + "version": "1.1.4", "publishConfig": { "access": "public", "main": "dist/index.cjs.js", @@ -33,10 +33,10 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/cli-common": "^0.1.10-next.0", - "@backstage/config": "^1.0.2-next.0", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/types": "^1.0.0", + "@backstage/cli-common": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/types": "workspace:^", "@types/json-schema": "^7.0.6", "ajv": "^8.10.0", "chokidar": "^3.5.2", @@ -50,7 +50,7 @@ "yup": "^0.32.9" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", + "@backstage/cli": "workspace:^", "@types/json-schema-merge-allof": "^0.6.0", "@types/mock-fs": "^4.10.0", "@types/node": "^16.11.26", diff --git a/packages/config/CHANGELOG.md b/packages/config/CHANGELOG.md index 9b9ea96dd1..7774d1aa5c 100644 --- a/packages/config/CHANGELOG.md +++ b/packages/config/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/config +## 1.0.2 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. + ## 1.0.2-next.0 ### Patch Changes diff --git a/packages/config/package.json b/packages/config/package.json index 9610495455..fec1fa88ad 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/config", "description": "Config API used by Backstage core, backend, and CLI", - "version": "1.0.2-next.0", + "version": "1.0.2", "publishConfig": { "access": "public", "main": "dist/index.cjs.js", @@ -32,12 +32,12 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/types": "^1.0.0", + "@backstage/types": "workspace:^", "lodash": "^4.17.21" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/test-utils": "workspace:^", "@types/node": "^16.0.0" }, "files": [ diff --git a/packages/core-app-api/CHANGELOG.md b/packages/core-app-api/CHANGELOG.md index 47740e9e7b..5ec66460c6 100644 --- a/packages/core-app-api/CHANGELOG.md +++ b/packages/core-app-api/CHANGELOG.md @@ -1,5 +1,51 @@ # @backstage/core-app-api +## 1.1.0 + +### Minor Changes + +- a448fea691: Updated the routing system to be compatible with React Router v6 stable. + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- f9ec4e46e3: When using React Router v6 stable, it is now possible for components within the `Route` element tree to have `path` props, although they will be ignored. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 744fea158b: Added `getSystemIcons()` function to the `AppContext` available through `useApp` that will pull a list of all the icons that have been registered in the App. +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- 8448b53dd6: Clarify that the `WebStorage` observable returns `JsonValue` items. +- 70299c99d5: Updated `FlatRoutes` to be compatible with React Router v6 stable. +- e9d40ebf54: If you'd like to send analytics events to multiple implementations, you may now + do so using the `MultipleAnalyticsApi` implementation provided by this package. + + ```tsx + import { MultipleAnalyticsApi } from '@backstage/core-app-api'; + import { + analyticsApiRef, + configApiRef, + storageApiRef, + identityApiRef, + } from '@internal/backstage/core-plugin-api'; + import { CustomAnalyticsApi } from '@internal/analytics'; + import { VendorAnalyticsApi } from '@vendor/analytics'; + + createApiFactory({ + api: analyticsApiRef, + deps: { configApi: configApiRef, identityApi: identityApiRef, storageApi: storageApiRef }, + factory: ({ configApi, identityApi, storageApi }) => + MultipleAnalyticsApi.fromApis([ + VendorAnalyticsApi.fromConfig(configApi, { identityApi }), + CustomAnalyticsApi.fromConfig(configApi, { identityApi, storageApi }), + ]), + }), + ``` + +- Updated dependencies + - @backstage/core-plugin-api@1.0.6 + - @backstage/config@1.0.2 + ## 1.1.0-next.3 ### Patch Changes diff --git a/packages/core-app-api/api-report.md b/packages/core-app-api/api-report.md index f2bc4b6665..4d1db6fde1 100644 --- a/packages/core-app-api/api-report.md +++ b/packages/core-app-api/api-report.md @@ -556,7 +556,9 @@ export class WebStorage implements StorageApi { // (undocumented) get(key: string): T | undefined; // (undocumented) - observe$(key: string): Observable>; + observe$( + key: string, + ): Observable>; // (undocumented) remove(key: string): Promise; // (undocumented) diff --git a/packages/core-app-api/package.json b/packages/core-app-api/package.json index 8532997477..d3f8f04fc2 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.1.0-next.3", + "version": "1.1.0", "publishConfig": { "access": "public", "main": "dist/index.esm.js", @@ -32,10 +32,10 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/config": "^1.0.2-next.0", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/types": "^1.0.0", - "@backstage/version-bridge": "^1.0.1", + "@backstage/config": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/types": "workspace:^", + "@backstage/version-bridge": "workspace:^", "@types/prop-types": "^15.7.3", "prop-types": "^15.7.2", "react-use": "^17.2.4", @@ -48,8 +48,8 @@ "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/react-hooks": "^8.0.0", diff --git a/packages/core-app-api/src/apis/implementations/StorageApi/WebStorage.ts b/packages/core-app-api/src/apis/implementations/StorageApi/WebStorage.ts index ac3d3f20f2..b0cbfbd883 100644 --- a/packages/core-app-api/src/apis/implementations/StorageApi/WebStorage.ts +++ b/packages/core-app-api/src/apis/implementations/StorageApi/WebStorage.ts @@ -86,7 +86,9 @@ export class WebStorage implements StorageApi { this.notifyChanges(key); } - observe$(key: string): Observable> { + observe$( + key: string, + ): Observable> { return this.observable.filter(({ key: messageKey }) => messageKey === key); } diff --git a/packages/core-app-api/src/apis/system/ApiProvider.test.tsx b/packages/core-app-api/src/apis/system/ApiProvider.test.tsx index c08674adfe..a6118f0f68 100644 --- a/packages/core-app-api/src/apis/system/ApiProvider.test.tsx +++ b/packages/core-app-api/src/apis/system/ApiProvider.test.tsx @@ -118,9 +118,10 @@ describe('ApiProvider', () => { }).toThrow(/^API context is not available/); }).error, ).toEqual([ - expect.stringMatching( - /^Error: Uncaught \[Error: API context is not available/, - ), + expect.objectContaining({ + detail: new Error('API context is not available'), + type: 'unhandled exception', + }), expect.stringMatching( /^The above error occurred in the component/, ), @@ -133,9 +134,10 @@ describe('ApiProvider', () => { }).toThrow(/^API context is not available/); }).error, ).toEqual([ - expect.stringMatching( - /^Error: Uncaught \[Error: API context is not available/, - ), + expect.objectContaining({ + detail: new Error('API context is not available'), + type: 'unhandled exception', + }), expect.stringMatching( /^The above error occurred in the component/, ), @@ -154,9 +156,10 @@ describe('ApiProvider', () => { }).toThrow('No implementation available for apiRef{x}'); }).error, ).toEqual([ - expect.stringMatching( - /^Error: Uncaught \[Error: No implementation available for apiRef{x}\]/, - ), + expect.objectContaining({ + detail: new Error('No implementation available for apiRef{x}'), + type: 'unhandled exception', + }), expect.stringMatching( /^The above error occurred in the component/, ), @@ -173,9 +176,10 @@ describe('ApiProvider', () => { }).toThrow('No implementation available for apiRef{x}'); }).error, ).toEqual([ - expect.stringMatching( - /^Error: Uncaught \[Error: No implementation available for apiRef{x}\]/, - ), + expect.objectContaining({ + detail: new Error('No implementation available for apiRef{x}'), + type: 'unhandled exception', + }), expect.stringMatching( /^The above error occurred in the component/, ), diff --git a/packages/core-components/CHANGELOG.md b/packages/core-components/CHANGELOG.md index 64c5ddc502..66284b6bc6 100644 --- a/packages/core-components/CHANGELOG.md +++ b/packages/core-components/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/core-components +## 0.11.1 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- d3737da337: Export `HeaderActionMenu` and expose default `Table` icons via `Table.icons` +- 7d47def9c4: Removed dependency on `@types/jest`. +- b29c44d895: Adds code to generate ids for headers parsed through the MarkdownContent component. +- 37e8c5e128: The `RoutedTabs` component has been updated to be compatible with React Router v6 stable. +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- 13f23f6510: Allow custom images in the empty state component +- 023d14c52b: Fix overflow bug on MicDrop image for 404 page by moving the image and making it relative rather than absolute +- c8bb0ff8ce: Minor cleanup of the public API surface to reduce the number of warnings +- Updated dependencies + - @backstage/core-plugin-api@1.0.6 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + ## 0.11.1-next.3 ### Patch Changes diff --git a/packages/core-components/api-report.md b/packages/core-components/api-report.md index 3dc4e2848e..99d18b9b12 100644 --- a/packages/core-components/api-report.md +++ b/packages/core-components/api-report.md @@ -21,10 +21,12 @@ import { CSSProperties } from 'react'; import { ElementType } from 'react'; import { ErrorInfo } from 'react'; import { IconComponent } from '@backstage/core-plugin-api'; +import { Icons } from '@material-table/core'; import { IdentityApi } from '@backstage/core-plugin-api'; import { LinearProgressProps } from '@material-ui/core/LinearProgress'; import { LinkProps as LinkProps_2 } from '@material-ui/core/Link'; import { LinkProps as LinkProps_3 } from 'react-router-dom'; +import { ListItemTextProps } from '@material-ui/core/ListItemText'; import MaterialBreadcrumbs from '@material-ui/core/Breadcrumbs'; import { MaterialTableProps } from '@material-table/core'; import { NavLinkProps } from 'react-router-dom'; @@ -432,6 +434,23 @@ export function GroupIcon(props: IconComponentProps): JSX.Element; // @public export function Header(props: PropsWithChildren): JSX.Element; +// @public (undocumented) +export function HeaderActionMenu(props: HeaderActionMenuProps): JSX.Element; + +// @public (undocumented) +export type HeaderActionMenuItem = { + label?: ListItemTextProps['primary']; + secondaryLabel?: ListItemTextProps['secondary']; + icon?: ReactElement; + disabled?: boolean; + onClick?: (event: React_2.MouseEvent) => void; +}; + +// @public (undocumented) +export type HeaderActionMenuProps = { + actionItems: HeaderActionMenuItem[]; +}; + // @public (undocumented) export type HeaderClassKey = | 'header' @@ -1333,6 +1352,12 @@ export type TabIconClassKey = 'root'; // @public (undocumented) export function Table(props: TableProps): JSX.Element; +// @public (undocumented) +export namespace Table { + var // (undocumented) + icons: Readonly; +} + // Warning: (ae-missing-release-tag) "TableClassKey" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) diff --git a/packages/core-components/package.json b/packages/core-components/package.json index a32961eece..2c861c145a 100644 --- a/packages/core-components/package.json +++ b/packages/core-components/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/core-components", "description": "Core components used by Backstage plugins and apps", - "version": "0.11.1-next.3", + "version": "0.11.1", "publishConfig": { "access": "public", "main": "dist/index.esm.js", @@ -32,11 +32,11 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/config": "^1.0.2-next.0", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/theme": "^0.2.16", - "@backstage/version-bridge": "^1.0.1", + "@backstage/config": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/theme": "workspace:^", + "@backstage/version-bridge": "workspace:^", "@material-table/core": "^3.1.0", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -78,9 +78,9 @@ "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/react-hooks": "^8.0.0", diff --git a/packages/core-components/src/components/TabbedLayout/TabbedLayout.test.tsx b/packages/core-components/src/components/TabbedLayout/TabbedLayout.test.tsx index b700739a8b..e103fc2f46 100644 --- a/packages/core-components/src/components/TabbedLayout/TabbedLayout.test.tsx +++ b/packages/core-components/src/components/TabbedLayout/TabbedLayout.test.tsx @@ -47,9 +47,11 @@ describe('TabbedLayout', () => { }); expect(error).toEqual([ - expect.stringMatching( - /Child of TabbedLayout must be an TabbedLayout.Route/, - ), + expect.objectContaining({ + detail: new Error( + 'Child of TabbedLayout must be an TabbedLayout.Route', + ), + }), expect.stringMatching( /The above error occurred in the component/, ), diff --git a/packages/core-components/src/components/Table/Table.tsx b/packages/core-components/src/components/Table/Table.tsx index 65edb5b69b..49538b680a 100644 --- a/packages/core-components/src/components/Table/Table.tsx +++ b/packages/core-components/src/components/Table/Table.tsx @@ -292,6 +292,9 @@ export function TableToolbar(toolbarProps: { ); } +/** + * @public + */ export function Table(props: TableProps) { const { data, @@ -519,3 +522,5 @@ export function Table(props: TableProps) { ); } + +Table.icons = Object.freeze(tableIcons); diff --git a/packages/core-components/src/layout/ErrorBoundary/ErrorBoundary.test.tsx b/packages/core-components/src/layout/ErrorBoundary/ErrorBoundary.test.tsx index 361ad123bf..6a16224a02 100644 --- a/packages/core-components/src/layout/ErrorBoundary/ErrorBoundary.test.tsx +++ b/packages/core-components/src/layout/ErrorBoundary/ErrorBoundary.test.tsx @@ -67,7 +67,9 @@ describe('', () => { }); expect(error).toEqual([ - expect.stringMatching(/^Error: Uncaught \[Error: Bomb\]/), + expect.objectContaining({ + detail: new Error('Bomb'), + }), expect.stringMatching( /^The above error occurred in the component:/, ), diff --git a/packages/core-components/src/layout/ErrorPage/ErrorPage.tsx b/packages/core-components/src/layout/ErrorPage/ErrorPage.tsx index 928a3eb0d4..658c06de2a 100644 --- a/packages/core-components/src/layout/ErrorPage/ErrorPage.tsx +++ b/packages/core-components/src/layout/ErrorPage/ErrorPage.tsx @@ -70,7 +70,6 @@ export function ErrorPage(props: IErrorPageProps) { return ( - + ); } diff --git a/packages/core-components/src/layout/ErrorPage/MicDrop.tsx b/packages/core-components/src/layout/ErrorPage/MicDrop.tsx index efa101b23b..aacb44079a 100644 --- a/packages/core-components/src/layout/ErrorPage/MicDrop.tsx +++ b/packages/core-components/src/layout/ErrorPage/MicDrop.tsx @@ -22,12 +22,10 @@ const useStyles = makeStyles( theme => ({ micDrop: { maxWidth: '60%', - position: 'absolute', bottom: theme.spacing(2), right: theme.spacing(2), [theme.breakpoints.down('xs')]: { maxWidth: '96%', - position: 'relative', bottom: 'unset', right: 'unset', margin: `${theme.spacing(10)}px auto ${theme.spacing(4)}px`, diff --git a/packages/core-components/src/layout/HeaderActionMenu/HeaderActionMenu.test.tsx b/packages/core-components/src/layout/HeaderActionMenu/HeaderActionMenu.test.tsx index 3337571d4e..92ce241aa8 100644 --- a/packages/core-components/src/layout/HeaderActionMenu/HeaderActionMenu.test.tsx +++ b/packages/core-components/src/layout/HeaderActionMenu/HeaderActionMenu.test.tsx @@ -60,7 +60,7 @@ describe('', () => { ); }); - it('Test wrapper, and secondary label', async () => { + it('Secondary label', async () => { const onClickFunction = jest.fn(); const rendered = await renderInTestApp( ', () => { { label: 'Some label', secondaryLabel: 'Secondary label', - WrapperComponent: ({ children }) => ( - - ), + onClick: onClickFunction, }, ]} />, diff --git a/packages/core-components/src/layout/HeaderActionMenu/HeaderActionMenu.tsx b/packages/core-components/src/layout/HeaderActionMenu/HeaderActionMenu.tsx index d8dc398ce3..e164244ea7 100644 --- a/packages/core-components/src/layout/HeaderActionMenu/HeaderActionMenu.tsx +++ b/packages/core-components/src/layout/HeaderActionMenu/HeaderActionMenu.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import React, { Fragment, ReactElement, ComponentType } from 'react'; +import React, { Fragment, ReactElement } from 'react'; import IconButton from '@material-ui/core/IconButton'; import List from '@material-ui/core/List'; import ListItem from '@material-ui/core/ListItem'; @@ -23,15 +23,17 @@ import ListItemText, { ListItemTextProps, } from '@material-ui/core/ListItemText'; import Popover from '@material-ui/core/Popover'; -import { VerticalMenuIcon } from './VerticalMenuIcon'; +import MoreVert from '@material-ui/icons/MoreVert'; -type ActionItemProps = { +/** + * @public + */ +export type HeaderActionMenuItem = { label?: ListItemTextProps['primary']; secondaryLabel?: ListItemTextProps['secondary']; icon?: ReactElement; disabled?: boolean; - onClick?: (event: React.MouseEvent) => void; - WrapperComponent?: ComponentType; + onClick?: (event: React.MouseEvent) => void; }; const ActionItem = ({ @@ -40,10 +42,9 @@ const ActionItem = ({ icon, disabled = false, onClick, - WrapperComponent = React.Fragment, -}: ActionItemProps) => { +}: HeaderActionMenuItem) => { return ( - + {icon}} - + ); }; +/** + * @public + */ export type HeaderActionMenuProps = { - actionItems: ActionItemProps[]; + actionItems: HeaderActionMenuItem[]; }; +/** + * @public + */ export function HeaderActionMenu(props: HeaderActionMenuProps) { const { actionItems } = props; const [open, setOpen] = React.useState(false); @@ -84,7 +91,7 @@ export function HeaderActionMenu(props: HeaderActionMenuProps) { padding: 0, }} > - + { describe('tokenToExpiry', () => { - beforeEach(() => jest.useFakeTimers('modern')); + beforeEach(() => jest.useFakeTimers()); afterEach(() => jest.useRealTimers()); it('handles undefined', async () => { @@ -56,7 +56,7 @@ describe('ProxiedSignInIdentity', () => { }); describe('ProxiedSignInIdentity', () => { - beforeEach(() => jest.useFakeTimers('modern')); + beforeEach(() => jest.useFakeTimers()); afterEach(() => jest.useRealTimers()); const worker = setupServer(); diff --git a/packages/core-components/src/layout/index.ts b/packages/core-components/src/layout/index.ts index 9bb7fbaa26..4b594f0e94 100644 --- a/packages/core-components/src/layout/index.ts +++ b/packages/core-components/src/layout/index.ts @@ -20,6 +20,7 @@ export * from './ContentHeader'; export * from './ErrorBoundary'; export * from './ErrorPage'; export * from './Header'; +export * from './HeaderActionMenu'; export * from './HeaderLabel'; export * from './HeaderTabs'; export * from './HomepageTimer'; diff --git a/packages/core-plugin-api/CHANGELOG.md b/packages/core-plugin-api/CHANGELOG.md index 0889d0d6e9..9671062a50 100644 --- a/packages/core-plugin-api/CHANGELOG.md +++ b/packages/core-plugin-api/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/core-plugin-api +## 1.0.6 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 744fea158b: Added `getSystemIcons()` function to the `AppContext` available through `useApp` that will pull a list of all the icons that have been registered in the App. +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- ef9ab322de: Minor API signatures cleanup +- Updated dependencies + - @backstage/config@1.0.2 + ## 1.0.6-next.3 ### Patch Changes diff --git a/packages/core-plugin-api/package.json b/packages/core-plugin-api/package.json index 5d013f6e87..71372e26f1 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.0.6-next.3", + "version": "1.0.6", "publishConfig": { "access": "public", "main": "dist/index.esm.js", @@ -33,9 +33,9 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/config": "^1.0.2-next.0", - "@backstage/types": "^1.0.0", - "@backstage/version-bridge": "^1.0.1", + "@backstage/config": "workspace:^", + "@backstage/types": "workspace:^", + "@backstage/version-bridge": "workspace:^", "history": "^5.0.0", "prop-types": "^15.7.2", "zen-observable": "^0.8.15" @@ -46,9 +46,9 @@ "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/react-hooks": "^8.0.0", diff --git a/packages/core-plugin-api/src/extensions/extensions.test.tsx b/packages/core-plugin-api/src/extensions/extensions.test.tsx index 0601c01a17..3eca133608 100644 --- a/packages/core-plugin-api/src/extensions/extensions.test.tsx +++ b/packages/core-plugin-api/src/extensions/extensions.test.tsx @@ -117,7 +117,7 @@ describe('extensions', () => { render(); }); screen.getByText('Error in my-plugin'); - expect(errors[0]).toMatch('Test error'); + expect(errors[0]).toMatchObject({ detail: new Error('Test error') }); }); it('should wrap extended component with analytics context', async () => { diff --git a/packages/create-app/CHANGELOG.md b/packages/create-app/CHANGELOG.md index e131c59b6c..c3b9164858 100644 --- a/packages/create-app/CHANGELOG.md +++ b/packages/create-app/CHANGELOG.md @@ -1,5 +1,197 @@ # @backstage/create-app +## 0.4.31 + +### Patch Changes + +- 6ff94d60d5: Removed usage of the deprecated `diff` command in the root `package.json`. + + To make this change in an existing app, make the following change in the root `package.json`: + + ```diff + - "diff": "lerna run diff --", + ``` + +- c1f1a4c760: The Backstage packages and plugins have all been updated to support React Router v6 stable. The `create-app` template has not been migrated yet, but if you want to migrate your own app or plugins, check out the [migration guide](https://backstage.io/docs/tutorials/react-router-stable-migration). +- e83de28e36: Fix typo in the documentation +- 7d47def9c4: Removed dependency on `@types/jest`. +- 208d6780c9: The `packages/backend/Dockerfile` received a couple of updates, it now looks as follows: + + ```Dockerfile + FROM node:16-bullseye-slim + + # Install sqlite3 dependencies. You can skip this if you don't use sqlite3 in the image, + # in which case you should also move better-sqlite3 to "devDependencies" in package.json. + RUN apt-get update && \ + apt-get install -y --no-install-recommends libsqlite3-dev python3 build-essential && \ + rm -rf /var/lib/apt/lists/* && \ + yarn config set python /usr/bin/python3 + + # From here on we use the least-privileged `node` user to run the backend. + USER node + WORKDIR /app + + # This switches many Node.js dependencies to production mode. + ENV NODE_ENV production + + # Copy repo skeleton first, to avoid unnecessary docker cache invalidation. + # The skeleton contains the package.json of each package in the monorepo, + # and along with yarn.lock and the root package.json, that's enough to run yarn install. + COPY --chown=node:node yarn.lock package.json packages/backend/dist/skeleton.tar.gz ./ + RUN tar xzf skeleton.tar.gz && rm skeleton.tar.gz + + RUN yarn install --frozen-lockfile --production --network-timeout 300000 && rm -rf "$(yarn cache dir)" + + # Then copy the rest of the backend bundle, along with any other files we might want. + COPY --chown=node:node packages/backend/dist/bundle.tar.gz app-config*.yaml ./ + RUN tar xzf bundle.tar.gz && rm bundle.tar.gz + + CMD ["node", "packages/backend", "--config", "app-config.yaml", "--config", "app-config.production.yaml"] + ``` + + The two notable changes are that a `USER node` instruction has been added and the ordering of instructions has been changed accordingly. This means that the app will now be running using the least-privileged `node` user. In order for this to work we now need to make sure that all app files are owned by the `node` user, which we do by adding the `--chown=node:node` option to the `COPY` instructions. + + The second change is the addition of `ENV NODE_ENV production`, which ensured that all Node.js modules run in production mode. If you apply this change to an existing app, note that one of the more significant changes is that this switches the log formatting to use the default production format, JSON. Rather than your log lines looking like this: + + ```log + 2022-08-10T11:36:05.478Z catalog info Performing database migration type=plugin + ``` + + They will now look like this: + + ```log + {"level":"info","message":"Performing database migration","plugin":"catalog","service":"backstage","type":"plugin"} + ``` + + If you wish to keep the existing format, you can override this change by applying the following change to `packages/backend/src/index.ts`: + + ```diff + getRootLogger, + + setRootLogger, + + createRootLogger, + + coloredFormat, + useHotMemoize, + ... + ServerTokenManager, + } from '@backstage/backend-common'; + + ... + + async function main() { + + setRootLogger(createRootLogger({ format: coloredFormat })); + + + const config = await loadBackendConfig({ + ``` + +- 49416194e8: Adds `IdentityApi` configuration to `create-app` scaffolding templates. + + To migrate to the new `IdentityApi`, edit the `packages/backend/src/index.ts` adding the following import: + + ```typescript + import { DefaultIdentityClient } from '@backstage/plugin-auth-node'; + ``` + + Use the factory function to create an `IdentityApi` in the `makeCreateEnv` function and return it from the + function as follows: + + ```typescript + function makeCreateEnv(config: Config) { + ... + const identity = DefaultIdentityClient.create({ + discovery, + }); + ... + + return { + ..., + identity + } + } + ``` + + Backend plugins can be upgraded to work with this new `IdentityApi`. + + Add `identity` to the `RouterOptions` type. + + ```typescript + export interface RouterOptions { + ... + identity: IdentityApi; + } + ``` + + Then you can use the `IdentityApi` from the plugin. + + ```typescript + export async function createRouter( + options: RouterOptions, + ): Promise { + const { identity } = options; + + router.get('/user', async (req, res) => { + const user = await identity.getIdentity({ request: req }); + ... + ``` + +- 8d886dd33e: Added `yarn new` as one of the scripts installed by default, which calls `backstage-cli new`. This script replaces `create-plugin`, which you can now remove if you want to. It is kept in the `create-app` template for backwards compatibility. + + The `remove-plugin` command has been removed, as it has been removed from the Backstage CLI. + + To apply these changes to an existing app, make the following change to the root `package.json`: + + ```diff + - "remove-plugin": "backstage-cli remove-plugin" + + "new": "backstage-cli new --scope internal" + ``` + +- c3c90280be: The options part of `DatabaseManager.fromConfig` now accepts an optional logger + field. You may want to supply that logger in your backend initialization code to + ensure that you can get relevant logging data when things happen related to the + connection pool. + + In `packages/backend/src/index.ts`: + + ```diff + function makeCreateEnv(config: Config) { + const root = getRootLogger(); + ... + - const databaseManager = DatabaseManager.fromConfig(config); + + const databaseManager = DatabaseManager.fromConfig(config, { logger: root }); + ``` + +- a578558180: Updated the root `package.json` to use the new `backstage-cli repo clean` command. + + To apply this change to an existing project, make the following change to the root `package.json`: + + ```diff + - "clean": "backstage-cli clean && lerna run clean", + + "clean": "backstage-cli repo clean", + ``` + +- c0a08fd08c: Added `EntityLinksCard` to the system `EntityPage`. + + For an existing installation where you want to display the links card for entity pages of kind `system` you should make the following adjustment to `packages/app/src/components/catalog/EntityPage.tsx` + + ```diff + const systemPage = ( + ... + + + + + + + + + + - + + + + + ... + ); + ``` + +- Updated dependencies + - @backstage/cli-common@0.1.10 + ## 0.4.31-next.3 ### Patch Changes diff --git a/packages/create-app/package.json b/packages/create-app/package.json index d059446638..de1f495abe 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.4.31-next.3", + "version": "0.4.31", "publishConfig": { "access": "public" }, @@ -32,7 +32,7 @@ "start": "nodemon --" }, "dependencies": { - "@backstage/cli-common": "^0.1.10-next.0", + "@backstage/cli-common": "workspace:^", "chalk": "^4.0.0", "commander": "^9.1.0", "fs-extra": "10.1.0", @@ -42,7 +42,7 @@ "recursive-readdir": "^2.2.2" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", + "@backstage/cli": "workspace:^", "@types/fs-extra": "^9.0.1", "@types/inquirer": "^8.1.3", "@types/node": "^16.11.26", diff --git a/packages/create-app/src/createApp.test.ts b/packages/create-app/src/createApp.test.ts index d339460243..8e7b3bae7d 100644 --- a/packages/create-app/src/createApp.test.ts +++ b/packages/create-app/src/createApp.test.ts @@ -28,17 +28,6 @@ jest.mock('./lib/versions', () => ({ packageVersions: { root: '1.0.0' }, })); -beforeAll(() => { - mockFs({ - [`${__dirname}/package.json`]: '', // required by `findPaths(__dirname)` - 'templates/': mockFs.load(path.resolve(__dirname, '../templates/')), - }); -}); - -afterAll(() => { - mockFs.restore(); -}); - const promptMock = jest.spyOn(inquirer, 'prompt'); const checkPathExistsMock = jest.spyOn(tasks, 'checkPathExistsTask'); const templatingMock = jest.spyOn(tasks, 'templatingTask'); @@ -51,6 +40,17 @@ const moveAppMock = jest.spyOn(tasks, 'moveAppTask'); const buildAppMock = jest.spyOn(tasks, 'buildAppTask'); describe('command entrypoint', () => { + beforeAll(() => { + mockFs({ + [`${__dirname}/package.json`]: '', // required by `findPaths(__dirname)` + 'templates/': mockFs.load(path.resolve(__dirname, '../templates/')), + }); + }); + + afterAll(() => { + mockFs.restore(); + }); + beforeEach(() => { promptMock.mockResolvedValueOnce({ name: 'MyApp', diff --git a/packages/create-app/src/lib/tasks.test.ts b/packages/create-app/src/lib/tasks.test.ts index d2efe81b90..decc89fbd4 100644 --- a/packages/create-app/src/lib/tasks.test.ts +++ b/packages/create-app/src/lib/tasks.test.ts @@ -86,185 +86,191 @@ jest.mock('./versions', () => ({ }, })); -beforeEach(() => { - mockFs({ - 'projects/my-module.ts': '', - 'projects/dir/my-file.txt': '', - 'tmp/mockApp/.gitignore': '', - 'tmp/mockApp/package.json': '', - 'tmp/mockApp/packages/app/package.json': '', - // load templates into mock filesystem - 'templates/': mockFs.load(path.resolve(__dirname, '../../templates/')), - }); -}); - -afterEach(() => { - mockFs.restore(); -}); - -describe('checkAppExistsTask', () => { - it('should do nothing if the directory does not exist', async () => { - const dir = 'projects/'; - const name = 'MyNewApp'; - await expect(checkAppExistsTask(dir, name)).resolves.not.toThrow(); +describe('tasks', () => { + beforeEach(() => { + mockFs({ + 'projects/my-module.ts': '', + 'projects/dir/my-file.txt': '', + 'tmp/mockApp/.gitignore': '', + 'tmp/mockApp/package.json': '', + 'tmp/mockApp/packages/app/package.json': '', + // load templates into mock filesystem + 'templates/': mockFs.load(path.resolve(__dirname, '../../templates/')), + }); }); - it('should throw an error when a file of the same name exists', async () => { - const dir = 'projects/'; - const name = 'my-module.ts'; - await expect(checkAppExistsTask(dir, name)).rejects.toThrow( - 'already exists', - ); + afterEach(() => { + mockFs.restore(); }); - it('should throw an error when a directory of the same name exists', async () => { - const dir = 'projects/'; - const name = 'dir'; - await expect(checkAppExistsTask(dir, name)).rejects.toThrow( - 'already exists', - ); - }); -}); - -describe('checkPathExistsTask', () => { - it('should create a directory at the given path', async () => { - const appDir = 'projects/newProject'; - await expect(checkPathExistsTask(appDir)).resolves.not.toThrow(); - expect(fs.existsSync(appDir)).toBe(true); - }); - - it('should do nothing if a directory of the same name exists', async () => { - const appDir = 'projects/dir'; - await expect(checkPathExistsTask(appDir)).resolves.not.toThrow(); - expect(fs.existsSync(appDir)).toBe(true); - }); - - it('should fail if a file of the same name exists', async () => { - await expect(checkPathExistsTask('projects/my-module.ts')).rejects.toThrow( - 'already exists', - ); - }); -}); - -describe('createTemporaryAppFolderTask', () => { - it('should create a directory at a given path', async () => { - const tempDir = 'projects/tmpFolder'; - await expect(createTemporaryAppFolderTask(tempDir)).resolves.not.toThrow(); - expect(fs.existsSync(tempDir)).toBe(true); - }); - - it('should fail if a directory of the same name exists', async () => { - const tempDir = 'projects/dir'; - await expect(createTemporaryAppFolderTask(tempDir)).rejects.toThrow( - 'file already exists', - ); - }); - - it('should fail if a file of the same name exists', async () => { - const tempDir = 'projects/dir/my-file.txt'; - await expect(createTemporaryAppFolderTask(tempDir)).rejects.toThrow( - 'file already exists', - ); - }); -}); - -describe('buildAppTask', () => { - it('should change to `appDir` and run `yarn install` and `yarn tsc`', async () => { - const mockChdir = jest.spyOn(process, 'chdir'); - const mockExec = child_process.exec as unknown as jest.MockedFunction< - ( - command: string, - callback: (error: null, stdout: string, stderr: string) => void, - ) => void - >; - - // requires callback implementation to support `promisify` wrapper - // https://stackoverflow.com/a/60579617/10044859 - mockExec.mockImplementation((_command, callback) => { - callback(null, 'standard out', 'standard error'); + describe('checkAppExistsTask', () => { + it('should do nothing if the directory does not exist', async () => { + const dir = 'projects/'; + const name = 'MyNewApp'; + await expect(checkAppExistsTask(dir, name)).resolves.not.toThrow(); }); - const appDir = 'projects/dir'; - await expect(buildAppTask(appDir)).resolves.not.toThrow(); - expect(mockChdir).toHaveBeenCalledTimes(2); - expect(mockChdir).toHaveBeenNthCalledWith(1, appDir); - expect(mockChdir).toHaveBeenNthCalledWith(2, appDir); - expect(mockExec).toHaveBeenCalledTimes(2); - expect(mockExec).toHaveBeenNthCalledWith( - 1, - 'yarn install', - expect.any(Function), - ); - expect(mockExec).toHaveBeenNthCalledWith( - 2, - 'yarn tsc', - expect.any(Function), - ); - }); - - it('should fail if project directory does not exist', async () => { - const appDir = 'projects/missingProject'; - await expect(buildAppTask(appDir)).rejects.toThrow( - 'no such file or directory', - ); - }); -}); - -describe('moveAppTask', () => { - const tempDir = 'tmp/mockApp/'; - const id = 'myApp'; - - it('should move all files in the temp dir to the target dir', async () => { - const destination = 'projects/mockApp'; - await moveAppTask(tempDir, destination, id); - expect(fs.existsSync('projects/mockApp/.gitignore')).toBe(true); - expect(fs.existsSync('projects/mockApp/package.json')).toBe(true); - expect(fs.existsSync('projects/mockApp/packages/app/package.json')).toBe( - true, - ); - }); - - it('should fail to move files if destination already exists', async () => { - const destination = 'projects'; - await expect(moveAppTask(tempDir, destination, id)).rejects.toThrow( - 'dest already exists', - ); - }); - - it('should remove temporary files if move succeeded', async () => { - const destination = 'projects/mockApp'; - await moveAppTask(tempDir, destination, id); - expect(fs.existsSync('tmp/mockApp')).toBe(false); - }); - - it('should remove temporary files if move failed', async () => { - const destination = 'projects'; - await expect(moveAppTask(tempDir, destination, id)).rejects.toThrow(); - expect(fs.existsSync('tmp/mockApp')).toBe(false); - }); -}); - -describe('templatingTask', () => { - it('should generate a project populating context parameters', async () => { - const templateDir = 'templates/default-app'; - const destinationDir = 'templatedApp'; - const context = { - name: 'SuperCoolBackstageInstance', - dbTypeSqlite: true, - }; - await templatingTask(templateDir, destinationDir, context); - expect(fs.existsSync('templatedApp/package.json')).toBe(true); - expect(fs.existsSync('templatedApp/.dockerignore')).toBe(true); - await expect(fs.readJson('templatedApp/backstage.json')).resolves.toEqual({ - version: '1.2.3', + it('should throw an error when a file of the same name exists', async () => { + const dir = 'projects/'; + const name = 'my-module.ts'; + await expect(checkAppExistsTask(dir, name)).rejects.toThrow( + 'already exists', + ); + }); + + it('should throw an error when a directory of the same name exists', async () => { + const dir = 'projects/'; + const name = 'dir'; + await expect(checkAppExistsTask(dir, name)).rejects.toThrow( + 'already exists', + ); + }); + }); + + describe('checkPathExistsTask', () => { + it('should create a directory at the given path', async () => { + const appDir = 'projects/newProject'; + await expect(checkPathExistsTask(appDir)).resolves.not.toThrow(); + expect(fs.existsSync(appDir)).toBe(true); + }); + + it('should do nothing if a directory of the same name exists', async () => { + const appDir = 'projects/dir'; + await expect(checkPathExistsTask(appDir)).resolves.not.toThrow(); + expect(fs.existsSync(appDir)).toBe(true); + }); + + it('should fail if a file of the same name exists', async () => { + await expect( + checkPathExistsTask('projects/my-module.ts'), + ).rejects.toThrow('already exists'); + }); + }); + + describe('createTemporaryAppFolderTask', () => { + it('should create a directory at a given path', async () => { + const tempDir = 'projects/tmpFolder'; + await expect( + createTemporaryAppFolderTask(tempDir), + ).resolves.not.toThrow(); + expect(fs.existsSync(tempDir)).toBe(true); + }); + + it('should fail if a directory of the same name exists', async () => { + const tempDir = 'projects/dir'; + await expect(createTemporaryAppFolderTask(tempDir)).rejects.toThrow( + 'file already exists', + ); + }); + + it('should fail if a file of the same name exists', async () => { + const tempDir = 'projects/dir/my-file.txt'; + await expect(createTemporaryAppFolderTask(tempDir)).rejects.toThrow( + 'file already exists', + ); + }); + }); + + describe('buildAppTask', () => { + it('should change to `appDir` and run `yarn install` and `yarn tsc`', async () => { + const mockChdir = jest.spyOn(process, 'chdir'); + const mockExec = child_process.exec as unknown as jest.MockedFunction< + ( + command: string, + callback: (error: null, stdout: string, stderr: string) => void, + ) => void + >; + + // requires callback implementation to support `promisify` wrapper + // https://stackoverflow.com/a/60579617/10044859 + mockExec.mockImplementation((_command, callback) => { + callback(null, 'standard out', 'standard error'); + }); + + const appDir = 'projects/dir'; + await expect(buildAppTask(appDir)).resolves.not.toThrow(); + expect(mockChdir).toHaveBeenCalledTimes(2); + expect(mockChdir).toHaveBeenNthCalledWith(1, appDir); + expect(mockChdir).toHaveBeenNthCalledWith(2, appDir); + expect(mockExec).toHaveBeenCalledTimes(2); + expect(mockExec).toHaveBeenNthCalledWith( + 1, + 'yarn install', + expect.any(Function), + ); + expect(mockExec).toHaveBeenNthCalledWith( + 2, + 'yarn tsc', + expect.any(Function), + ); + }); + + it('should fail if project directory does not exist', async () => { + const appDir = 'projects/missingProject'; + await expect(buildAppTask(appDir)).rejects.toThrow( + 'no such file or directory', + ); + }); + }); + + describe('moveAppTask', () => { + const tempDir = 'tmp/mockApp/'; + const id = 'myApp'; + + it('should move all files in the temp dir to the target dir', async () => { + const destination = 'projects/mockApp'; + await moveAppTask(tempDir, destination, id); + expect(fs.existsSync('projects/mockApp/.gitignore')).toBe(true); + expect(fs.existsSync('projects/mockApp/package.json')).toBe(true); + expect(fs.existsSync('projects/mockApp/packages/app/package.json')).toBe( + true, + ); + }); + + it('should fail to move files if destination already exists', async () => { + const destination = 'projects'; + await expect(moveAppTask(tempDir, destination, id)).rejects.toThrow( + 'dest already exists', + ); + }); + + it('should remove temporary files if move succeeded', async () => { + const destination = 'projects/mockApp'; + await moveAppTask(tempDir, destination, id); + expect(fs.existsSync('tmp/mockApp')).toBe(false); + }); + + it('should remove temporary files if move failed', async () => { + const destination = 'projects'; + await expect(moveAppTask(tempDir, destination, id)).rejects.toThrow(); + expect(fs.existsSync('tmp/mockApp')).toBe(false); + }); + }); + + describe('templatingTask', () => { + it('should generate a project populating context parameters', async () => { + const templateDir = 'templates/default-app'; + const destinationDir = 'templatedApp'; + const context = { + name: 'SuperCoolBackstageInstance', + dbTypeSqlite: true, + }; + await templatingTask(templateDir, destinationDir, context); + expect(fs.existsSync('templatedApp/package.json')).toBe(true); + expect(fs.existsSync('templatedApp/.dockerignore')).toBe(true); + await expect(fs.readJson('templatedApp/backstage.json')).resolves.toEqual( + { + version: '1.2.3', + }, + ); + // catalog was populated with `context.name` + expect( + fs.readFileSync('templatedApp/catalog-info.yaml', 'utf-8'), + ).toContain('name: SuperCoolBackstageInstance'); + // backend dependencies include `sqlite3` from `context.SQLite` + expect( + fs.readFileSync('templatedApp/packages/backend/package.json', 'utf-8'), + ).toContain('sqlite3"'); }); - // catalog was populated with `context.name` - expect( - fs.readFileSync('templatedApp/catalog-info.yaml', 'utf-8'), - ).toContain('name: SuperCoolBackstageInstance'); - // backend dependencies include `sqlite3` from `context.SQLite` - expect( - fs.readFileSync('templatedApp/packages/backend/package.json', 'utf-8'), - ).toContain('sqlite3"'); }); }); diff --git a/packages/create-app/templates/default-app/package.json.hbs b/packages/create-app/templates/default-app/package.json.hbs index a4f8815822..dd4d937db0 100644 --- a/packages/create-app/templates/default-app/package.json.hbs +++ b/packages/create-app/templates/default-app/package.json.hbs @@ -14,8 +14,8 @@ "tsc": "tsc", "tsc:full": "tsc --skipLibCheck false --incremental false", "clean": "backstage-cli repo clean", - "test": "backstage-cli test", - "test:all": "lerna run test -- --coverage", + "test": "backstage-cli repo test", + "test:all": "backstage-cli repo test --coverage", "lint": "backstage-cli repo lint --since origin/master", "lint:all": "backstage-cli repo lint", "prettier:check": "prettier --check .", diff --git a/packages/dev-utils/CHANGELOG.md b/packages/dev-utils/CHANGELOG.md index e292fde14c..0f56fbb388 100644 --- a/packages/dev-utils/CHANGELOG.md +++ b/packages/dev-utils/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/dev-utils +## 1.0.6 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 329ed2b9c7: Fixed routing when using React Router v6 stable. +- 4c5e85ddf3: Removed the dependency and setup of `react-hot-loader`, since the `@backstage/cli` now uses `swc` with `React Refresh` instead. +- Updated dependencies + - @backstage/app-defaults@1.0.6 + - @backstage/core-app-api@1.1.0 + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/test-utils@1.2.0 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + - @backstage/integration-react@1.1.4 + ## 1.0.6-next.2 ### Patch Changes diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index dbbdce225a..4a43a0b8b3 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.6-next.2", + "version": "1.0.6", "publishConfig": { "access": "public", "main": "dist/index.esm.js", @@ -32,15 +32,15 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/app-defaults": "^1.0.6-next.2", - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/integration-react": "^1.1.4-next.2", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", - "@backstage/test-utils": "^1.2.0-next.3", - "@backstage/theme": "^0.2.16", + "@backstage/app-defaults": "workspace:^", + "@backstage/catalog-model": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/integration-react": "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", "@testing-library/jest-dom": "^5.10.1", @@ -57,7 +57,7 @@ "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", + "@backstage/cli": "workspace:^", "@types/node": "^16.0.0" }, "files": [ diff --git a/packages/e2e-test/package.json b/packages/e2e-test/package.json index 12f430cad2..372e2c0f05 100644 --- a/packages/e2e-test/package.json +++ b/packages/e2e-test/package.json @@ -27,9 +27,9 @@ }, "bin": "bin/e2e-test", "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/cli-common": "^0.1.10-next.0", - "@backstage/errors": "^1.1.1-next.0", + "@backstage/cli": "workspace:^", + "@backstage/cli-common": "workspace:^", + "@backstage/errors": "workspace:^", "@types/fs-extra": "^9.0.1", "@types/node": "^16.11.26", "@types/puppeteer": "^5.4.4", diff --git a/packages/errors/CHANGELOG.md b/packages/errors/CHANGELOG.md index cbb5292829..aad6d660c3 100644 --- a/packages/errors/CHANGELOG.md +++ b/packages/errors/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/errors +## 1.1.1 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. + ## 1.1.1-next.0 ### Patch Changes diff --git a/packages/errors/package.json b/packages/errors/package.json index ab315338bb..eb3627f1ba 100644 --- a/packages/errors/package.json +++ b/packages/errors/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/errors", "description": "Common utilities for error handling within Backstage", - "version": "1.1.1-next.0", + "version": "1.1.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,12 +32,12 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/types": "^1.0.0", + "@backstage/types": "workspace:^", "cross-fetch": "^3.1.5", "serialize-error": "^8.0.1" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3" + "@backstage/cli": "workspace:^" }, "files": [ "dist" diff --git a/packages/integration-react/CHANGELOG.md b/packages/integration-react/CHANGELOG.md index f09758bffe..29376adbab 100644 --- a/packages/integration-react/CHANGELOG.md +++ b/packages/integration-react/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/integration-react +## 1.1.4 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/integration@1.3.1 + - @backstage/config@1.0.2 + ## 1.1.4-next.2 ### Patch Changes diff --git a/packages/integration-react/package.json b/packages/integration-react/package.json index 80ea2f029b..3f23625aac 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.4-next.2", + "version": "1.1.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,11 +23,11 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/config": "^1.0.2-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/integration": "^1.3.1-next.2", - "@backstage/theme": "^0.2.16", + "@backstage/config": "workspace:^", + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/integration": "workspace:^", + "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -37,9 +37,9 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/packages/integration/CHANGELOG.md b/packages/integration/CHANGELOG.md index 0ac5e9e5bd..3aaeeb4d48 100644 --- a/packages/integration/CHANGELOG.md +++ b/packages/integration/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/integration +## 1.3.1 + +### Patch Changes + +- eadf56bbbf: Bump `git-url-parse` version to `^13.0.0` +- 7d47def9c4: Removed dependency on `@types/jest`. +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- 42918e085c: Fixed bug in the `bitbucketServer` integration where token did not take precedence over supplied username and password which is described in the documentation. +- f76f22c649: Improved caching around github app tokens. + Tokens are now cached for 50 minutes, not 10. + Calls to get app installations are also included in this cache. + If you have more than one github app configured, consider adding `allowedInstallationOwners` to your apps configuration to gain the most benefit from these performance changes. +- Updated dependencies + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + ## 1.3.1-next.2 ### Patch Changes diff --git a/packages/integration/package.json b/packages/integration/package.json index c68bd3176c..6c2e070467 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.3.1-next.2", + "version": "1.3.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,8 +32,8 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/config": "^1.0.2-next.0", - "@backstage/errors": "^1.1.1-next.0", + "@backstage/config": "workspace:^", + "@backstage/errors": "workspace:^", "@octokit/auth-app": "^4.0.0", "@octokit/rest": "^19.0.3", "cross-fetch": "^3.1.5", @@ -42,9 +42,9 @@ "luxon": "^3.0.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/config-loader": "^1.1.4-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/config-loader": "workspace:^", + "@backstage/test-utils": "workspace:^", "@types/luxon": "^3.0.0", "msw": "^0.47.0" }, diff --git a/packages/integration/src/helpers.test.ts b/packages/integration/src/helpers.test.ts index 06feb4104e..7468c83bc6 100644 --- a/packages/integration/src/helpers.test.ts +++ b/packages/integration/src/helpers.test.ts @@ -62,7 +62,7 @@ describe('isValidHost', () => { ['[::]', true], ['[::1]', true], ['[1:2:3:4:5:6:7:8]', true], - ['1.2.3.4.5.6.7.8', true], + ['1.2.3.4.5.6.7.8', false], ['https://example.com', false], ['foo:100000', false], ['FOO', false], diff --git a/packages/release-manifests/CHANGELOG.md b/packages/release-manifests/CHANGELOG.md index b0e104511f..177ea55a5a 100644 --- a/packages/release-manifests/CHANGELOG.md +++ b/packages/release-manifests/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/release-manifests +## 0.0.6 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. + ## 0.0.6-next.2 ### Patch Changes diff --git a/packages/release-manifests/package.json b/packages/release-manifests/package.json index 44c081581c..949cd2bcd5 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.6-next.2", + "version": "0.0.6", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { @@ -35,8 +35,8 @@ "cross-fetch": "^3.1.5" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/test-utils": "workspace:^", "@types/node": "^16.0.0", "msw": "^0.47.0" }, diff --git a/packages/techdocs-cli-embedded-app/CHANGELOG.md b/packages/techdocs-cli-embedded-app/CHANGELOG.md index ee1e3ea184..982eb6c0de 100644 --- a/packages/techdocs-cli-embedded-app/CHANGELOG.md +++ b/packages/techdocs-cli-embedded-app/CHANGELOG.md @@ -1,5 +1,23 @@ # techdocs-cli-embedded-app +## 0.2.74 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.19.0 + - @backstage/app-defaults@1.0.6 + - @backstage/core-app-api@1.1.0 + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/test-utils@1.2.0 + - @backstage/plugin-catalog@1.5.1 + - @backstage/plugin-techdocs-react@1.0.4 + - @backstage/plugin-techdocs@1.3.2 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/integration-react@1.1.4 + ## 0.2.74-next.2 ### Patch Changes diff --git a/packages/techdocs-cli-embedded-app/package.json b/packages/techdocs-cli-embedded-app/package.json index a8d0e0cf4c..060735636b 100644 --- a/packages/techdocs-cli-embedded-app/package.json +++ b/packages/techdocs-cli-embedded-app/package.json @@ -1,25 +1,25 @@ { "name": "techdocs-cli-embedded-app", - "version": "0.2.74-next.2", + "version": "0.2.74", "private": true, "backstage": { "role": "frontend" }, "bundled": true, "dependencies": { - "@backstage/app-defaults": "^1.0.6-next.2", - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/cli": "^0.19.0-next.3", - "@backstage/config": "^1.0.2-next.0", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/integration-react": "^1.1.4-next.2", - "@backstage/plugin-catalog": "^1.5.1-next.3", - "@backstage/plugin-techdocs": "^1.3.2-next.3", - "@backstage/plugin-techdocs-react": "^1.0.4-next.2", - "@backstage/test-utils": "^1.2.0-next.3", - "@backstage/theme": "^0.2.16", + "@backstage/app-defaults": "workspace:^", + "@backstage/catalog-model": "workspace:^", + "@backstage/cli": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/integration-react": "workspace:^", + "@backstage/plugin-catalog": "workspace:^", + "@backstage/plugin-techdocs": "workspace:^", + "@backstage/plugin-techdocs-react": "workspace:^", + "@backstage/test-utils": "workspace:^", + "@backstage/theme": "workspace:^", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "history": "^5.0.0", @@ -30,7 +30,7 @@ "react-use": "^17.2.4" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", + "@backstage/cli": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/packages/techdocs-cli/CHANGELOG.md b/packages/techdocs-cli/CHANGELOG.md index 56fdf6afd2..377e44625b 100644 --- a/packages/techdocs-cli/CHANGELOG.md +++ b/packages/techdocs-cli/CHANGELOG.md @@ -1,5 +1,17 @@ # @techdocs/cli +## 1.2.1 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/plugin-techdocs-node@1.4.0 + - @backstage/catalog-model@1.1.1 + - @backstage/cli-common@0.1.10 + - @backstage/config@1.0.2 + ## 1.2.1-next.2 ### Patch Changes diff --git a/packages/techdocs-cli/package.json b/packages/techdocs-cli/package.json index 2ec384eb34..2e74c28c62 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.2.1-next.2", + "version": "1.2.1", "publishConfig": { "access": "public" }, @@ -36,7 +36,7 @@ "techdocs-cli": "bin/techdocs-cli" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", + "@backstage/cli": "workspace:^", "@types/commander": "^2.12.2", "@types/fs-extra": "^9.0.6", "@types/http-proxy": "^1.17.4", @@ -60,11 +60,11 @@ "ext": "ts" }, "dependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/cli-common": "^0.1.10-next.0", - "@backstage/config": "^1.0.2-next.0", - "@backstage/plugin-techdocs-node": "^1.4.0-next.2", + "@backstage/backend-common": "workspace:^", + "@backstage/catalog-model": "workspace:^", + "@backstage/cli-common": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/plugin-techdocs-node": "workspace:^", "@types/dockerode": "^3.3.0", "commander": "^9.1.0", "dockerode": "^3.3.1", diff --git a/packages/test-utils/CHANGELOG.md b/packages/test-utils/CHANGELOG.md index b4101d9514..6258adff78 100644 --- a/packages/test-utils/CHANGELOG.md +++ b/packages/test-utils/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/test-utils +## 1.2.0 + +### Minor Changes + +- 817f3196f6: Elements rendered in a test app are no longer wrapped in a `Routes` and `Route` element, as this is not compatible with React Router v6 stable. + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- d9e39544be: Add missing peer dependencies +- Updated dependencies + - @backstage/core-app-api@1.1.0 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-permission-react@0.4.5 + - @backstage/config@1.0.2 + - @backstage/plugin-permission-common@0.6.4 + ## 1.2.0-next.3 ### Patch Changes diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index 4d45519fa1..4eba4e93fd 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.2.0-next.3", + "version": "1.2.0", "publishConfig": { "access": "public", "main": "dist/index.esm.js", @@ -32,13 +32,13 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/config": "^1.0.2-next.0", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/plugin-permission-common": "^0.6.4-next.2", - "@backstage/plugin-permission-react": "^0.4.5-next.2", - "@backstage/theme": "^0.2.16", - "@backstage/types": "^1.0.0", + "@backstage/config": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/plugin-permission-common": "workspace:^", + "@backstage/plugin-permission-react": "workspace:^", + "@backstage/theme": "workspace:^", + "@backstage/types": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.11.2", "@testing-library/jest-dom": "^5.10.1", @@ -55,7 +55,7 @@ "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", + "@backstage/cli": "workspace:^", "@types/node": "^16.11.26", "msw": "^0.47.0" }, diff --git a/packages/test-utils/src/testUtils/appWrappers.test.tsx b/packages/test-utils/src/testUtils/appWrappers.test.tsx index 1b0601d030..a116c8c781 100644 --- a/packages/test-utils/src/testUtils/appWrappers.test.tsx +++ b/packages/test-utils/src/testUtils/appWrappers.test.tsx @@ -92,9 +92,11 @@ describe('wrapInTestApp', () => { }); expect(error).toEqual([ - expect.stringMatching( - /^Error: Uncaught \[Error: MockErrorApi received unexpected error, Error: NOPE\]/, - ), + expect.objectContaining({ + detail: new Error( + 'MockErrorApi received unexpected error, Error: NOPE', + ), + }), expect.stringMatching(/^The above error occurred in the component:/), ]); }); diff --git a/packages/theme/package.json b/packages/theme/package.json index 4569c67eae..f311aa7c1f 100644 --- a/packages/theme/package.json +++ b/packages/theme/package.json @@ -35,7 +35,7 @@ "@material-ui/core": "^4.12.2" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.1" + "@backstage/cli": "workspace:^" }, "files": [ "dist" diff --git a/packages/types/package.json b/packages/types/package.json index 133b388ea9..b8ebeffce8 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -32,7 +32,7 @@ "clean": "backstage-cli package clean" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.1", + "@backstage/cli": "workspace:^", "@types/zen-observable": "^0.8.0", "zen-observable": "^0.8.15" }, diff --git a/packages/version-bridge/package.json b/packages/version-bridge/package.json index 52595c0cc9..3abfcd40f6 100644 --- a/packages/version-bridge/package.json +++ b/packages/version-bridge/package.json @@ -36,7 +36,7 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.1", + "@backstage/cli": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/react-hooks": "^8.0.0" diff --git a/plugins/adr-backend/CHANGELOG.md b/plugins/adr-backend/CHANGELOG.md index b92a33a8f0..f32be42f18 100644 --- a/plugins/adr-backend/CHANGELOG.md +++ b/plugins/adr-backend/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-adr-backend +## 0.2.1 + +### Patch Changes + +- b489de83b1: Continue processing subsequent entities when an error occurs in collator +- 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/integration@1.3.1 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + - @backstage/plugin-adr-common@0.2.1 + - @backstage/plugin-search-common@1.0.1 + ## 0.2.1-next.3 ### Patch Changes diff --git a/plugins/adr-backend/package.json b/plugins/adr-backend/package.json index 91ed8e002c..d8295c0e46 100644 --- a/plugins/adr-backend/package.json +++ b/plugins/adr-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-adr-backend", - "version": "0.2.1-next.3", + "version": "0.2.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -28,14 +28,14 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/catalog-client": "^1.1.0-next.2", - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/config": "^1.0.2-next.0", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/integration": "^1.3.1-next.2", - "@backstage/plugin-adr-common": "^0.2.1-next.1", - "@backstage/plugin-search-common": "^1.0.1-next.0", + "@backstage/backend-common": "workspace:^", + "@backstage/catalog-client": "workspace:^", + "@backstage/catalog-model": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/integration": "workspace:^", + "@backstage/plugin-adr-common": "workspace:^", + "@backstage/plugin-search-common": "workspace:^", "luxon": "^3.0.0", "marked": "^4.0.14", "node-fetch": "^2.6.5", @@ -43,7 +43,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", + "@backstage/cli": "workspace:^", "@types/marked": "^4.0.0", "@types/supertest": "^2.0.8", "msw": "^0.47.0", diff --git a/plugins/adr-common/CHANGELOG.md b/plugins/adr-common/CHANGELOG.md index 9269768185..9a68db3d74 100644 --- a/plugins/adr-common/CHANGELOG.md +++ b/plugins/adr-common/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-adr-common +## 0.2.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.3.1 + - @backstage/catalog-model@1.1.1 + - @backstage/plugin-search-common@1.0.1 + ## 0.2.1-next.1 ### Patch Changes diff --git a/plugins/adr-common/package.json b/plugins/adr-common/package.json index 02631c3e6c..02ae1d642d 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.1-next.1", + "version": "0.2.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -29,12 +29,12 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/integration": "^1.3.1-next.2", - "@backstage/plugin-search-common": "^1.0.1-next.0" + "@backstage/catalog-model": "workspace:^", + "@backstage/integration": "workspace:^", + "@backstage/plugin-search-common": "workspace:^" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3" + "@backstage/cli": "workspace:^" }, "files": [ "dist" diff --git a/plugins/adr/CHANGELOG.md b/plugins/adr/CHANGELOG.md index 3fc5634bd1..2fe9aacb31 100644 --- a/plugins/adr/CHANGELOG.md +++ b/plugins/adr/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-adr +## 0.2.1 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- eadf56bbbf: Bump `git-url-parse` version to `^13.0.0` +- 7d47def9c4: Removed dependency on `@types/jest`. +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- c8bb0ff8ce: Minor cleanup of the public API surface to reduce the number of warnings +- b489de83b1: Fix parsing of ADR location which includes a trailing slash +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/plugin-search-react@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/integration-react@1.1.4 + - @backstage/plugin-adr-common@0.2.1 + - @backstage/plugin-search-common@1.0.1 + ## 0.2.1-next.3 ### Patch Changes diff --git a/plugins/adr/package.json b/plugins/adr/package.json index 732cb4d67f..f64d901820 100644 --- a/plugins/adr/package.json +++ b/plugins/adr/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-adr", - "version": "0.2.1-next.3", + "version": "0.2.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,15 +22,15 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/integration-react": "^1.1.4-next.2", - "@backstage/plugin-adr-common": "^0.2.1-next.1", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", - "@backstage/plugin-search-common": "^1.0.1-next.0", - "@backstage/plugin-search-react": "^1.1.0-next.2", - "@backstage/theme": "^0.2.16", + "@backstage/catalog-model": "workspace:^", + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/integration-react": "workspace:^", + "@backstage/plugin-adr-common": "workspace:^", + "@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.57", @@ -45,10 +45,10 @@ "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/airbrake-backend/CHANGELOG.md b/plugins/airbrake-backend/CHANGELOG.md index 1868062e0b..2e249ba14a 100644 --- a/plugins/airbrake-backend/CHANGELOG.md +++ b/plugins/airbrake-backend/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-airbrake-backend +## 0.2.9 + +### Patch Changes + +- 148568b5c2: Switched to using node-fetch instead of cross-fetch as is standard for our backend packages +- 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 + ## 0.2.9-next.3 ### Patch Changes diff --git a/plugins/airbrake-backend/package.json b/plugins/airbrake-backend/package.json index 1a04e5185d..b79cdd80b1 100644 --- a/plugins/airbrake-backend/package.json +++ b/plugins/airbrake-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-airbrake-backend", - "version": "0.2.9-next.3", + "version": "0.2.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,8 +22,8 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/config": "^1.0.2-next.0", + "@backstage/backend-common": "workspace:^", + "@backstage/config": "workspace:^", "@types/express": "*", "express": "^4.17.1", "express-promise-router": "^4.1.0", @@ -32,7 +32,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", + "@backstage/cli": "workspace:^", "@types/http-proxy-middleware": "^0.19.3", "@types/supertest": "^2.0.8", "msw": "^0.47.0", diff --git a/plugins/airbrake/CHANGELOG.md b/plugins/airbrake/CHANGELOG.md index 8262a89cb0..2d03fb6ef2 100644 --- a/plugins/airbrake/CHANGELOG.md +++ b/plugins/airbrake/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-airbrake +## 0.3.9 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/dev-utils@1.0.6 + - @backstage/test-utils@1.2.0 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + ## 0.3.9-next.3 ### Patch Changes diff --git a/plugins/airbrake/package.json b/plugins/airbrake/package.json index c8ec322420..5dc54ea863 100644 --- a/plugins/airbrake/package.json +++ b/plugins/airbrake/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-airbrake", - "version": "0.3.9-next.3", + "version": "0.3.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,13 +22,13 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", - "@backstage/test-utils": "^1.2.0-next.3", - "@backstage/theme": "^0.2.16", + "@backstage/catalog-model": "workspace:^", + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@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.57", @@ -40,10 +40,10 @@ "react-router": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/app-defaults": "^1.0.6-next.2", - "@backstage/cli": "^0.19.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/app-defaults": "workspace:^", + "@backstage/cli": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/allure/CHANGELOG.md b/plugins/allure/CHANGELOG.md index 64e114dda7..60dcd97b14 100644 --- a/plugins/allure/CHANGELOG.md +++ b/plugins/allure/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-allure +## 0.1.25 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + ## 0.1.25-next.3 ### Patch Changes diff --git a/plugins/allure/package.json b/plugins/allure/package.json index 12400806a7..3bfe92c6ee 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.25-next.3", + "version": "0.1.25", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,11 +23,11 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", - "@backstage/theme": "^0.2.16", + "@backstage/catalog-model": "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.57", @@ -38,10 +38,10 @@ "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/analytics-module-ga/CHANGELOG.md b/plugins/analytics-module-ga/CHANGELOG.md index fb5051da23..622257c75a 100644 --- a/plugins/analytics-module-ga/CHANGELOG.md +++ b/plugins/analytics-module-ga/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-analytics-module-ga +## 0.1.20 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/config@1.0.2 + ## 0.1.20-next.2 ### Patch Changes diff --git a/plugins/analytics-module-ga/package.json b/plugins/analytics-module-ga/package.json index e9b5044d92..7e4ce38c20 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.20-next.2", + "version": "0.1.20", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,10 +22,10 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/config": "^1.0.2-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/theme": "^0.2.16", + "@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.57", @@ -36,10 +36,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/apache-airflow/CHANGELOG.md b/plugins/apache-airflow/CHANGELOG.md index 2396ca2b6f..66b3d3120b 100644 --- a/plugins/apache-airflow/CHANGELOG.md +++ b/plugins/apache-airflow/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-apache-airflow +## 0.2.2 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 2f52e74b49: Got rid of usages of the uppercase String type +- 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`. +- c8bb0ff8ce: Minor cleanup of the public API surface to reduce the number of warnings +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + ## 0.2.2-next.3 ### Patch Changes diff --git a/plugins/apache-airflow/package.json b/plugins/apache-airflow/package.json index f132c46a78..5555fd35fc 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.2-next.3", + "version": "0.2.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,8 +22,8 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -35,10 +35,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/api-docs-module-protoc-gen-doc/package.json b/plugins/api-docs-module-protoc-gen-doc/package.json index 04088e7566..072304d2cf 100644 --- a/plugins/api-docs-module-protoc-gen-doc/package.json +++ b/plugins/api-docs-module-protoc-gen-doc/package.json @@ -37,7 +37,7 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.1", + "@backstage/cli": "workspace:^", "@testing-library/jest-dom": "^5.16.4", "@types/react": "^16.13.1 || ^17.0.0" }, diff --git a/plugins/api-docs/CHANGELOG.md b/plugins/api-docs/CHANGELOG.md index db0ffbeada..339ad58f59 100644 --- a/plugins/api-docs/CHANGELOG.md +++ b/plugins/api-docs/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-api-docs +## 0.8.9 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- ef9ab322de: Minor API signatures cleanup +- c8bb0ff8ce: Minor cleanup of the public API surface to reduce the number of warnings +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/plugin-catalog@1.5.1 + - @backstage/catalog-model@1.1.1 + ## 0.8.9-next.3 ### Patch Changes diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index 8281a1522d..42cd8d5d74 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.8.9-next.3", + "version": "0.8.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,13 +32,13 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@asyncapi/react-component": "1.0.0-next.40", - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/plugin-catalog": "^1.5.1-next.3", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", - "@backstage/theme": "^0.2.16", + "@asyncapi/react-component": "1.0.0-next.42", + "@backstage/catalog-model": "workspace:^", + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/plugin-catalog": "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", @@ -56,10 +56,10 @@ "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/api-docs/src/setupTests.ts b/plugins/api-docs/src/setupTests.ts index 963c0f188b..a41fe2eeb4 100644 --- a/plugins/api-docs/src/setupTests.ts +++ b/plugins/api-docs/src/setupTests.ts @@ -15,3 +15,7 @@ */ import '@testing-library/jest-dom'; + +Object.defineProperty(global, 'TextDecoder', { + value: require('util').TextDecoder, +}); diff --git a/plugins/apollo-explorer/CHANGELOG.md b/plugins/apollo-explorer/CHANGELOG.md index 40c9fa0c57..f4dfdc2d35 100644 --- a/plugins/apollo-explorer/CHANGELOG.md +++ b/plugins/apollo-explorer/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-apollo-explorer +## 0.1.2 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- ef9ab322de: Minor API signatures cleanup +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + ## 0.1.2-next.2 ### Patch Changes diff --git a/plugins/apollo-explorer/package.json b/plugins/apollo-explorer/package.json index 39143c3133..770af99853 100644 --- a/plugins/apollo-explorer/package.json +++ b/plugins/apollo-explorer/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-apollo-explorer", - "version": "0.1.2-next.2", + "version": "0.1.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,9 +23,9 @@ }, "dependencies": { "@apollo/explorer": "^1.1.1", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/theme": "^0.2.16", + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/theme": "workspace:^", "@material-ui/core": "^4.9.13", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "^4.0.0-alpha.57", @@ -36,10 +36,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/app-backend/CHANGELOG.md b/plugins/app-backend/CHANGELOG.md index 02188afefc..a6cf9ef532 100644 --- a/plugins/app-backend/CHANGELOG.md +++ b/plugins/app-backend/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/plugin-app-backend +## 0.3.36 + +### 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`. +- 8872cc735d: Fixed a bug where the database option to skip migrations was ignored. +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/config-loader@1.1.4 + - @backstage/config@1.0.2 + ## 0.3.36-next.3 ### Patch Changes diff --git a/plugins/app-backend/package.json b/plugins/app-backend/package.json index c06c41e6dd..ffd40b89c0 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.36-next.3", + "version": "0.3.36", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,10 +32,10 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/config": "^1.0.2-next.0", - "@backstage/config-loader": "^1.1.4-next.2", - "@backstage/types": "^1.0.0", + "@backstage/backend-common": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/config-loader": "workspace:^", + "@backstage/types": "workspace:^", "@types/express": "^4.17.6", "express": "^4.17.1", "express-promise-router": "^4.1.0", @@ -49,9 +49,9 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/backend-test-utils": "^0.1.28-next.3", - "@backstage/cli": "^0.19.0-next.3", - "@backstage/types": "^1.0.0", + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", + "@backstage/types": "workspace:^", "@types/supertest": "^2.0.8", "mock-fs": "^5.1.0", "msw": "^0.47.0", diff --git a/plugins/auth-backend/CHANGELOG.md b/plugins/auth-backend/CHANGELOG.md index 7c5fff0dd0..189a4a235f 100644 --- a/plugins/auth-backend/CHANGELOG.md +++ b/plugins/auth-backend/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-auth-backend +## 0.16.0 + +### Minor Changes + +- 2fc41ebf07: Removed the previously deprecated class `AtlassianAuthProvider`. Please use `providers.atlassian.create(...)` instead. +- a291688bc5: Renamed the `RedirectInfo` type to `OAuthStartResponse` +- 8600855fbf: The auth0 integration is updated to use the `passport-auth0` library. The configuration under `auth.providers.auth0.\*` now supports an optional `audience` parameter; providing that allows you to connect to the correct API to get permissions, access tokens, and full profile information. + + [What is an Audience](https://community.auth0.com/t/what-is-the-audience/71414) + +### Patch Changes + +- 5b011fb2e6: Allow adding misc claims to JWT +- 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`. +- e1ebaeb332: Cloudflare Access Provider: Add JWT to CloudflareAccessResult +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/plugin-auth-node@0.2.5 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + ## 0.16.0-next.3 ### Minor Changes diff --git a/plugins/auth-backend/api-report.md b/plugins/auth-backend/api-report.md index d47abeee83..ea5b923baa 100644 --- a/plugins/auth-backend/api-report.md +++ b/plugins/auth-backend/api-report.md @@ -183,10 +183,12 @@ export type CookieConfigurer = (ctx: { providerId: string; baseUrl: string; callbackUrl: string; + appOrigin: string; }) => { domain: string; path: string; secure: boolean; + sameSite?: 'none' | 'lax' | 'strict'; }; // @public @@ -280,11 +282,10 @@ export class OAuthAdapter implements AuthProviderRouteHandlers { // @public (undocumented) export type OAuthAdapterOptions = { providerId: string; - secure: boolean; persistScopes?: boolean; - cookieDomain: string; - cookiePath: string; appOrigin: string; + baseUrl: string; + cookieConfigurer: CookieConfigurer; isOriginAllowed: (origin: string) => boolean; callbackUrl: string; }; @@ -706,7 +707,7 @@ export type TokenParams = { claims: { sub: string; ent?: string[]; - }; + } & Record; }; // @public (undocumented) diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index 4f820f4829..d3c4fc2724 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.16.0-next.3", + "version": "0.16.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,13 +32,13 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/catalog-client": "^1.1.0-next.2", - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/config": "^1.0.2-next.0", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/plugin-auth-node": "^0.2.5-next.3", - "@backstage/types": "^1.0.0", + "@backstage/backend-common": "workspace:^", + "@backstage/catalog-client": "workspace:^", + "@backstage/catalog-model": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/plugin-auth-node": "workspace:^", + "@backstage/types": "workspace:^", "@davidzemon/passport-okta-oauth": "^0.0.5", "@google-cloud/firestore": "^6.0.0", "@types/express": "^4.17.6", @@ -76,8 +76,8 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/backend-test-utils": "^0.1.28-next.3", - "@backstage/cli": "^0.19.0-next.3", + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", "@types/body-parser": "^1.19.0", "@types/cookie-parser": "^1.4.2", "@types/express-session": "^1.17.2", diff --git a/plugins/auth-backend/src/identity/FirestoreKeyStore.test.ts b/plugins/auth-backend/src/identity/FirestoreKeyStore.test.ts index d28cbfa11a..b04cf8a6b3 100644 --- a/plugins/auth-backend/src/identity/FirestoreKeyStore.test.ts +++ b/plugins/auth-backend/src/identity/FirestoreKeyStore.test.ts @@ -44,7 +44,7 @@ jest.mock('@google-cloud/firestore', () => ({ Firestore: jest.fn().mockImplementation(() => firestoreMock), })); -jest.useFakeTimers('legacy'); +jest.useFakeTimers({ legacyFakeTimers: true }); describe('FirestoreKeyStore', () => { const key = { diff --git a/plugins/auth-backend/src/identity/TokenFactory.test.ts b/plugins/auth-backend/src/identity/TokenFactory.test.ts index 9a163b3ff5..4f6df89210 100644 --- a/plugins/auth-backend/src/identity/TokenFactory.test.ts +++ b/plugins/auth-backend/src/identity/TokenFactory.test.ts @@ -48,7 +48,12 @@ describe('TokenFactory', () => { await expect(factory.listPublicKeys()).resolves.toEqual({ keys: [] }); const token = await factory.issueToken({ - claims: { sub: entityRef, ent: [entityRef] }, + claims: { + sub: entityRef, + ent: [entityRef], + 'x-fancy-claim': 'my special claim', + aud: 'this value will be overridden', + }, }); const { keys } = await factory.listPublicKeys(); @@ -60,6 +65,7 @@ describe('TokenFactory', () => { aud: 'backstage', sub: entityRef, ent: [entityRef], + 'x-fancy-claim': 'my special claim', iat: expect.any(Number), exp: expect.any(Number), }); diff --git a/plugins/auth-backend/src/identity/TokenFactory.ts b/plugins/auth-backend/src/identity/TokenFactory.ts index 44cfebfb71..f80b79b6bc 100644 --- a/plugins/auth-backend/src/identity/TokenFactory.ts +++ b/plugins/auth-backend/src/identity/TokenFactory.ts @@ -77,8 +77,7 @@ export class TokenFactory implements TokenIssuer { const key = await this.getKey(); const iss = this.issuer; - const sub = params.claims.sub; - const ent = params.claims.ent; + const { sub, ent, ...additionalClaims } = params.claims; const aud = 'backstage'; const iat = Math.floor(Date.now() / MS_IN_S); const exp = iat + this.keyDurationSeconds; @@ -98,7 +97,7 @@ export class TokenFactory implements TokenIssuer { throw new AuthenticationError('No algorithm was provided in the key'); } - return new SignJWT({ iss, sub, ent, aud, iat, exp }) + return new SignJWT({ ...additionalClaims, iss, sub, ent, aud, iat, exp }) .setProtectedHeader({ alg: key.alg, kid: key.kid }) .setIssuer(iss) .setAudience(aud) diff --git a/plugins/auth-backend/src/identity/types.ts b/plugins/auth-backend/src/identity/types.ts index 4765b50d7d..e325f74c81 100644 --- a/plugins/auth-backend/src/identity/types.ts +++ b/plugins/auth-backend/src/identity/types.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { JsonValue } from '@backstage/types'; + /** Represents any form of serializable JWK */ export interface AnyJWK extends Record { use: 'sig'; @@ -28,13 +30,20 @@ export interface AnyJWK extends Record { * @public */ export type TokenParams = { - /** The claims that will be embedded within the token */ + /** + * The claims that will be embedded within the token. At a minimum, this should include + * the subject claim, `sub`. It is common to also list entity ownership relations in the + * `ent` list. Additional claims may also be added at the developer's discretion except + * for the following list, which will be overwritten by the TokenIssuer: `iss`, `aud`, + * `iat`, and `exp`. The Backstage team also maintains the right add new claims in the future + * without listing the change as a "breaking change". + */ claims: { /** The token subject, i.e. User ID */ sub: string; /** A list of entity references that the user claims ownership through */ ent?: string[]; - }; + } & Record; }; /** diff --git a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.test.ts b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.test.ts index 9dcd76e92e..526b05d0ab 100644 --- a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.test.ts +++ b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.test.ts @@ -18,6 +18,7 @@ import express from 'express'; import { THOUSAND_DAYS_MS, TEN_MINUTES_MS, OAuthAdapter } from './OAuthAdapter'; import { encodeState } from './helpers'; import { OAuthHandlers, OAuthState } from './types'; +import { CookieConfigurer } from '../../providers/types'; const mockResponseData = { providerInfo: { @@ -36,6 +37,10 @@ const mockResponseData = { }; describe('OAuthAdapter', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + class MyAuthProvider implements OAuthHandlers { async start() { return { @@ -57,18 +62,24 @@ describe('OAuthAdapter', () => { } } const providerInstance = new MyAuthProvider(); + const mockCookieConfig: ReturnType = { + domain: 'domain.org', + path: '/auth/test-provider', + secure: false, + }; + const mockCookieConfigurer = jest.fn().mockReturnValue(mockCookieConfig); + const oAuthProviderOptions = { providerId: 'test-provider', - secure: false, appOrigin: 'http://localhost:3000', - cookieDomain: 'example.com', - cookiePath: '/auth/test-provider', + baseUrl: 'http://domain.org/auth', + cookieConfigurer: mockCookieConfigurer, tokenIssuer: { issueToken: async () => 'my-id-token', listPublicKeys: async () => ({ keys: [] }), }, isOriginAllowed: () => false, - callbackUrl: 'http://example.com:7007/auth/test-provider/frame/handler', + callbackUrl: 'http://domain.org/auth/test-provider/handler/frame', }; it('sets the correct headers in start', async () => { @@ -96,7 +107,14 @@ describe('OAuthAdapter', () => { expect(mockResponse.cookie).toHaveBeenCalledWith( `${oAuthProviderOptions.providerId}-nonce`, expect.any(String), - expect.objectContaining({ maxAge: TEN_MINUTES_MS }), + expect.objectContaining({ + httpOnly: true, + path: '/auth/test-provider/handler', + maxAge: TEN_MINUTES_MS, + domain: 'domain.org', + sameSite: 'lax', + secure: false, + }), ); // redirect checks expect(mockResponse.setHeader).toHaveBeenCalledTimes(2); @@ -129,13 +147,18 @@ describe('OAuthAdapter', () => { } as unknown as express.Response; await oauthProvider.frameHandler(mockRequest, mockResponse); + expect(mockCookieConfigurer).toHaveBeenCalledTimes(1); expect(mockResponse.cookie).toHaveBeenCalledTimes(1); expect(mockResponse.cookie).toHaveBeenCalledWith( expect.stringContaining('test-provider-refresh-token'), expect.stringContaining('token'), expect.objectContaining({ + httpOnly: true, path: '/auth/test-provider', maxAge: THOUSAND_DAYS_MS, + domain: 'domain.org', + secure: false, + sameSite: 'lax', }), ); }); @@ -207,8 +230,12 @@ describe('OAuthAdapter', () => { 'test-provider-granted-scope', 'user', expect.objectContaining({ + httpOnly: true, path: '/auth/test-provider', maxAge: THOUSAND_DAYS_MS, + domain: 'domain.org', + secure: false, + sameSite: 'lax', }), ); @@ -243,6 +270,7 @@ describe('OAuthAdapter', () => { const mockRequest = { header: () => 'XMLHttpRequest', + get: jest.fn(), } as unknown as express.Request; const mockResponse = { @@ -252,6 +280,7 @@ describe('OAuthAdapter', () => { } as unknown as express.Response; await oauthProvider.logout(mockRequest, mockResponse); + expect(mockRequest.get).toHaveBeenCalledTimes(1); expect(mockResponse.cookie).toHaveBeenCalledTimes(1); expect(mockResponse.cookie).toHaveBeenCalledWith( expect.stringContaining('test-provider-refresh-token'), @@ -295,7 +324,46 @@ describe('OAuthAdapter', () => { }); }); - it('sets the correct cookie configuration using a callbackUrl', async () => { + it('sets new access-token when old cookie exists', async () => { + const oauthProvider = new OAuthAdapter(providerInstance, { + ...oAuthProviderOptions, + isOriginAllowed: () => false, + }); + + const mockRequest = { + header: () => 'XMLHttpRequest', + cookies: { + 'test-provider-refresh-token': 'old-token', + }, + query: {}, + get: jest.fn(), + } as unknown as express.Request; + + const mockResponse = { + json: jest.fn().mockReturnThis(), + status: jest.fn().mockReturnThis(), + cookie: jest.fn().mockReturnThis(), + } as unknown as express.Response; + + await oauthProvider.refresh(mockRequest, mockResponse); + expect(mockRequest.get).toHaveBeenCalledTimes(1); + expect(mockCookieConfigurer).toHaveBeenCalledTimes(1); + expect(mockResponse.cookie).toHaveBeenCalledTimes(1); + expect(mockResponse.cookie).toHaveBeenCalledWith( + 'test-provider-refresh-token', + 'token', + expect.objectContaining({ + httpOnly: true, + path: '/auth/test-provider', + maxAge: THOUSAND_DAYS_MS, + domain: 'domain.org', + secure: false, + sameSite: 'lax', + }), + ); + }); + + it('sets the correct nonce cookie configuration', async () => { const config = { baseUrl: 'http://domain.org/auth', appUrl: 'http://domain.org', @@ -304,13 +372,13 @@ describe('OAuthAdapter', () => { const oauthProvider = OAuthAdapter.fromConfig(config, providerInstance, { ...oAuthProviderOptions, - callbackUrl: 'https://authdomain.org/auth/test-provider/handler/frame', }); const mockRequest = { query: { scope: 'user', env: 'development', + origin: 'http://domain.org', }, } as unknown as express.Request; @@ -322,15 +390,252 @@ describe('OAuthAdapter', () => { } as unknown as express.Response; await oauthProvider.start(mockRequest, mockResponse); - + expect(mockCookieConfigurer).not.toHaveBeenCalled(); expect(mockResponse.cookie).toHaveBeenCalledTimes(1); expect(mockResponse.cookie).toHaveBeenCalledWith( `${oAuthProviderOptions.providerId}-nonce`, expect.any(String), expect.objectContaining({ - domain: 'authdomain.org', + httpOnly: true, + domain: 'domain.org', + maxAge: TEN_MINUTES_MS, + path: '/auth/test-provider/handler', + secure: false, + sameSite: 'lax', + }), + ); + }); + + it('sets the correct nonce cookie configuration using origin from request', async () => { + const config = { + baseUrl: 'http://domain.org/auth', + appUrl: 'http://domain.org', + isOriginAllowed: () => false, + }; + + const oauthProvider = OAuthAdapter.fromConfig(config, providerInstance, { + ...oAuthProviderOptions, + callbackUrl: 'https://domain.org/auth/test-provider/handler/frame', + }); + + const mockRequest = { + query: { + scope: 'user', + env: 'development', + origin: 'http://other.domain', + }, + } as unknown as express.Request; + + const mockResponse = { + cookie: jest.fn().mockReturnThis(), + end: jest.fn().mockReturnThis(), + setHeader: jest.fn().mockReturnThis(), + statusCode: jest.fn().mockReturnThis(), + } as unknown as express.Response; + + await oauthProvider.start(mockRequest, mockResponse); + expect(mockCookieConfigurer).not.toHaveBeenCalled(); + expect(mockResponse.cookie).toHaveBeenCalledTimes(1); + expect(mockResponse.cookie).toHaveBeenCalledWith( + `${oAuthProviderOptions.providerId}-nonce`, + expect.any(String), + expect.objectContaining({ + httpOnly: true, + domain: 'domain.org', + maxAge: TEN_MINUTES_MS, path: '/auth/test-provider/handler', secure: true, + sameSite: 'none', + }), + ); + }); + + it('sets the correct cookie configuration using an secure callbackUrl', async () => { + const config = { + baseUrl: 'https://domain.org/auth', + appUrl: 'http://domain.org', + isOriginAllowed: () => false, + }; + + const oauthProvider = OAuthAdapter.fromConfig(config, providerInstance, { + ...oAuthProviderOptions, + callbackUrl: 'https://domain.org/auth/test-provider/handler/frame', + }); + + const state = { + nonce: 'nonce', + env: 'development', + }; + + const mockRequest = { + cookies: { + 'test-provider-nonce': 'nonce', + }, + query: { + state: encodeState(state), + }, + } as unknown as express.Request; + + const mockResponse = { + cookie: jest.fn().mockReturnThis(), + setHeader: jest.fn().mockReturnThis(), + end: jest.fn().mockReturnThis(), + } as unknown as express.Response; + + await oauthProvider.frameHandler(mockRequest, mockResponse); + expect(mockCookieConfigurer).not.toHaveBeenCalled(); + expect(mockResponse.cookie).toHaveBeenCalledTimes(1); + expect(mockResponse.cookie).toHaveBeenCalledWith( + expect.stringContaining('test-provider-refresh-token'), + expect.stringContaining('token'), + expect.objectContaining({ + httpOnly: true, + domain: 'domain.org', + path: '/auth/test-provider', + secure: true, + sameSite: 'lax', + }), + ); + }); + + it('sets the correct cookie configuration when on different domains and secure', async () => { + const config = { + baseUrl: 'https://domain.org/auth', + appUrl: 'http://domain.org', + isOriginAllowed: () => false, + }; + + const oauthProvider = OAuthAdapter.fromConfig(config, providerInstance, { + ...oAuthProviderOptions, + callbackUrl: 'https://authdomain.org/auth/test-provider/handler/frame', + }); + + const state = { + nonce: 'nonce', + env: 'development', + }; + + const mockRequest = { + cookies: { + 'test-provider-nonce': 'nonce', + }, + query: { + state: encodeState(state), + }, + } as unknown as express.Request; + + const mockResponse = { + cookie: jest.fn().mockReturnThis(), + setHeader: jest.fn().mockReturnThis(), + end: jest.fn().mockReturnThis(), + } as unknown as express.Response; + + await oauthProvider.frameHandler(mockRequest, mockResponse); + expect(mockCookieConfigurer).not.toHaveBeenCalled(); + expect(mockResponse.cookie).toHaveBeenCalledTimes(1); + expect(mockResponse.cookie).toHaveBeenCalledWith( + expect.stringContaining('test-provider-refresh-token'), + expect.stringContaining('token'), + expect.objectContaining({ + httpOnly: true, + domain: 'authdomain.org', + path: '/auth/test-provider', + secure: true, + sameSite: 'none', + }), + ); + }); + + it('sets the correct cookie configuration using origin from state', async () => { + const config = { + baseUrl: 'https://domain.org/auth', + appUrl: 'http://domain.org', + isOriginAllowed: () => true, + }; + + const oauthProvider = OAuthAdapter.fromConfig(config, providerInstance, { + ...oAuthProviderOptions, + callbackUrl: 'https://domain.org/auth/test-provider/handler/frame', + }); + + const state = { + nonce: 'nonce', + env: 'development', + origin: 'http://other.domain', + }; + + const mockRequest = { + cookies: { + 'test-provider-nonce': 'nonce', + }, + query: { + state: encodeState(state), + }, + } as unknown as express.Request; + + const mockResponse = { + cookie: jest.fn().mockReturnThis(), + setHeader: jest.fn().mockReturnThis(), + end: jest.fn().mockReturnThis(), + } as unknown as express.Response; + + await oauthProvider.frameHandler(mockRequest, mockResponse); + expect(mockCookieConfigurer).not.toHaveBeenCalled(); + expect(mockResponse.cookie).toHaveBeenCalledTimes(1); + expect(mockResponse.cookie).toHaveBeenCalledWith( + expect.stringContaining('test-provider-refresh-token'), + expect.stringContaining('token'), + expect.objectContaining({ + httpOnly: true, + domain: 'domain.org', + path: '/auth/test-provider', + secure: true, + sameSite: 'none', + }), + ); + }); + + it('sets the correct cookie configuration using origin from header', async () => { + const config = { + baseUrl: 'https://domain.org/auth', + appUrl: 'http://domain.org', + isOriginAllowed: () => false, + }; + + const oauthProvider = OAuthAdapter.fromConfig(config, providerInstance, { + ...oAuthProviderOptions, + callbackUrl: 'https://domain.org/auth/test-provider/handler/frame', + }); + + const mockRequest = { + header: () => 'XMLHttpRequest', + cookies: { + 'test-provider-refresh-token': 'old-token', + }, + query: {}, + get: jest.fn().mockReturnValue('http://other.domain'), + } as unknown as express.Request; + + const mockResponse = { + json: jest.fn().mockReturnThis(), + status: jest.fn().mockReturnThis(), + cookie: jest.fn().mockReturnThis(), + } as unknown as express.Response; + + await oauthProvider.refresh(mockRequest, mockResponse); + expect(mockRequest.get).toHaveBeenCalledTimes(1); + expect(mockCookieConfigurer).not.toHaveBeenCalled(); + expect(mockResponse.cookie).toHaveBeenCalledTimes(1); + expect(mockResponse.cookie).toHaveBeenCalledWith( + 'test-provider-refresh-token', + 'token', + expect.objectContaining({ + httpOnly: true, + path: '/auth/test-provider', + maxAge: THOUSAND_DAYS_MS, + domain: 'domain.org', + secure: true, + sameSite: 'none', }), ); }); diff --git a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts index 6caa9fed12..8f08cfbbd0 100644 --- a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts +++ b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts @@ -24,6 +24,7 @@ import { import { AuthProviderRouteHandlers, AuthProviderConfig, + CookieConfigurer, } from '../../providers/types'; import { AuthenticationError, @@ -47,11 +48,10 @@ export const TEN_MINUTES_MS = 600 * 1000; /** @public */ export type OAuthAdapterOptions = { providerId: string; - secure: boolean; persistScopes?: boolean; - cookieDomain: string; - cookiePath: string; appOrigin: string; + baseUrl: string; + cookieConfigurer: CookieConfigurer; isOriginAllowed: (origin: string) => boolean; callbackUrl: string; }; @@ -66,22 +66,17 @@ export class OAuthAdapter implements AuthProviderRouteHandlers { 'providerId' | 'persistScopes' | 'callbackUrl' >, ): OAuthAdapter { - const { origin: appOrigin } = new URL(config.appUrl); + const { appUrl, baseUrl, isOriginAllowed } = config; + const { origin: appOrigin } = new URL(appUrl); const cookieConfigurer = config.cookieConfigurer ?? defaultCookieConfigurer; - const cookieConfig = cookieConfigurer({ - providerId: options.providerId, - baseUrl: config.baseUrl, - callbackUrl: options.callbackUrl, - }); return new OAuthAdapter(handlers, { ...options, appOrigin, - cookieDomain: cookieConfig.domain, - cookiePath: cookieConfig.path, - secure: cookieConfig.secure, - isOriginAllowed: config.isOriginAllowed, + baseUrl, + cookieConfigurer, + isOriginAllowed, }); } @@ -94,9 +89,6 @@ export class OAuthAdapter implements AuthProviderRouteHandlers { this.baseCookieOptions = { httpOnly: true, sameSite: 'lax', - secure: this.options.secure, - path: this.options.cookiePath, - domain: this.options.cookieDomain, }; } @@ -110,9 +102,11 @@ export class OAuthAdapter implements AuthProviderRouteHandlers { throw new InputError('No env provided in request query parameters'); } + const cookieConfig = this.getCookieConfig(origin); + const nonce = crypto.randomBytes(16).toString('base64'); // set a nonce cookie before redirecting to oauth provider - this.setNonceCookie(res, nonce); + this.setNonceCookie(res, nonce, cookieConfig); const state: OAuthState = { nonce, env, origin }; @@ -158,16 +152,18 @@ export class OAuthAdapter implements AuthProviderRouteHandlers { const { response, refreshToken } = await this.handlers.handler(req); + const cookieConfig = this.getCookieConfig(appOrigin); + // Store the scope that we have been granted for this session. This is useful if // the provider does not return granted scopes on refresh or if they are normalized. if (this.options.persistScopes && state.scope) { - this.setGrantedScopeCookie(res, state.scope); + this.setGrantedScopeCookie(res, state.scope, cookieConfig); response.providerInfo.scope = state.scope; } if (refreshToken) { // set new refresh token - this.setRefreshTokenCookie(res, refreshToken); + this.setRefreshTokenCookie(res, refreshToken, cookieConfig); } const identity = await this.populateIdentity(response.backstageIdentity); @@ -195,7 +191,9 @@ export class OAuthAdapter implements AuthProviderRouteHandlers { } // remove refresh token cookie if it is set - this.removeRefreshTokenCookie(res); + const origin = req.get('origin'); + const cookieConfig = this.getCookieConfig(origin); + this.removeRefreshTokenCookie(res, cookieConfig); res.status(200).end(); } @@ -235,7 +233,9 @@ export class OAuthAdapter implements AuthProviderRouteHandlers { ); if (newRefreshToken && newRefreshToken !== refreshToken) { - this.setRefreshTokenCookie(res, newRefreshToken); + const origin = req.get('origin'); + const cookieConfig = this.getCookieConfig(origin); + this.setRefreshTokenCookie(res, newRefreshToken, cookieConfig); } res.status(200).json({ ...response, backstageIdentity }); @@ -261,18 +261,28 @@ export class OAuthAdapter implements AuthProviderRouteHandlers { return prepareBackstageIdentityResponse(identity); } - private setNonceCookie = (res: express.Response, nonce: string) => { + private setNonceCookie = ( + res: express.Response, + nonce: string, + cookieConfig: ReturnType, + ) => { res.cookie(`${this.options.providerId}-nonce`, nonce, { maxAge: TEN_MINUTES_MS, ...this.baseCookieOptions, - path: `${this.options.cookiePath}/handler`, + ...cookieConfig, + path: `${cookieConfig.path}/handler`, }); }; - private setGrantedScopeCookie = (res: express.Response, scope: string) => { + private setGrantedScopeCookie = ( + res: express.Response, + scope: string, + cookieConfig: ReturnType, + ) => { res.cookie(`${this.options.providerId}-granted-scope`, scope, { maxAge: THOUSAND_DAYS_MS, ...this.baseCookieOptions, + ...cookieConfig, }); }; @@ -283,17 +293,32 @@ export class OAuthAdapter implements AuthProviderRouteHandlers { private setRefreshTokenCookie = ( res: express.Response, refreshToken: string, + cookieConfig: ReturnType, ) => { res.cookie(`${this.options.providerId}-refresh-token`, refreshToken, { maxAge: THOUSAND_DAYS_MS, ...this.baseCookieOptions, + ...cookieConfig, }); }; - private removeRefreshTokenCookie = (res: express.Response) => { + private removeRefreshTokenCookie = ( + res: express.Response, + cookieConfig: ReturnType, + ) => { res.cookie(`${this.options.providerId}-refresh-token`, '', { maxAge: 0, ...this.baseCookieOptions, + ...cookieConfig, + }); + }; + + private getCookieConfig = (origin?: string) => { + return this.options.cookieConfigurer({ + providerId: this.options.providerId, + baseUrl: this.options.baseUrl, + callbackUrl: this.options.callbackUrl, + appOrigin: origin ?? this.options.appOrigin, }); }; } diff --git a/plugins/auth-backend/src/lib/oauth/helpers.test.ts b/plugins/auth-backend/src/lib/oauth/helpers.test.ts index b3052c93e1..58a3dcab05 100644 --- a/plugins/auth-backend/src/lib/oauth/helpers.test.ts +++ b/plugins/auth-backend/src/lib/oauth/helpers.test.ts @@ -117,6 +117,7 @@ describe('OAuthProvider Utils', () => { baseUrl: '', providerId: 'test-provider', callbackUrl: 'http://domain.org/auth', + appOrigin: 'http://domain.org', }), ).toMatchObject({ domain: 'domain.org', @@ -131,6 +132,7 @@ describe('OAuthProvider Utils', () => { baseUrl: '', providerId: 'test-provider', callbackUrl: 'http://domain.org/auth/test-provider/handler/frame', + appOrigin: 'http://domain.org', }), ).toMatchObject({ domain: 'domain.org', @@ -145,10 +147,67 @@ describe('OAuthProvider Utils', () => { baseUrl: '', providerId: 'test-provider', callbackUrl: 'https://domain.org/auth', + appOrigin: 'http://domain.org', }), ).toMatchObject({ secure: true, }); }); + + it('should set sameSite to lax for https on the same domain', () => { + expect( + defaultCookieConfigurer({ + baseUrl: '', + providerId: 'test-provider', + callbackUrl: 'https://domain.org/auth', + appOrigin: 'http://domain.org', + }), + ).toMatchObject({ + sameSite: 'lax', + secure: true, + }); + }); + + it('should set sameSite to lax for http on the same domain', () => { + expect( + defaultCookieConfigurer({ + baseUrl: '', + providerId: 'test-provider', + callbackUrl: 'http://domain.org/auth', + appOrigin: 'http://domain.org', + }), + ).toMatchObject({ + sameSite: 'lax', + secure: false, + }); + }); + + it('should set sameSite to lax if not secure and on different domains', () => { + expect( + defaultCookieConfigurer({ + baseUrl: '', + providerId: 'test-provider', + callbackUrl: 'http://authdomain.org/auth', + appOrigin: 'http://domain.org', + }), + ).toMatchObject({ + sameSite: 'lax', + secure: false, + }); + }); + + it('should set sameSite to none if secure and on different domains', () => { + expect( + defaultCookieConfigurer({ + baseUrl: '', + providerId: 'test-provider', + callbackUrl: 'https://authdomain.org/auth', + appOrigin: 'http://domain.org', + }), + ).toMatchObject({ + sameSite: 'none', + secure: true, + }); + }); }); }); diff --git a/plugins/auth-backend/src/lib/oauth/helpers.ts b/plugins/auth-backend/src/lib/oauth/helpers.ts index 63d5d62ef9..2b4e50b477 100644 --- a/plugins/auth-backend/src/lib/oauth/helpers.ts +++ b/plugins/auth-backend/src/lib/oauth/helpers.ts @@ -65,10 +65,20 @@ export const verifyNonce = (req: express.Request, providerId: string) => { export const defaultCookieConfigurer: CookieConfigurer = ({ callbackUrl, providerId, + appOrigin, }) => { const { hostname: domain, pathname, protocol } = new URL(callbackUrl); const secure = protocol === 'https:'; + // For situations where the auth-backend is running on a + // different domain than the app, we set the SameSite attribute + // to 'none' to allow third-party access to the cookie, but + // only if it's in a secure context (https). + let sameSite: ReturnType['sameSite'] = 'lax'; + if (new URL(appOrigin).hostname !== domain && secure) { + sameSite = 'none'; + } + // If the provider supports callbackUrls, the pathname will // contain the complete path to the frame handler so we need // to slice off the trailing part of the path. @@ -76,5 +86,5 @@ export const defaultCookieConfigurer: CookieConfigurer = ({ ? pathname.slice(0, -'/handler/frame'.length) : `${pathname}/${providerId}`; - return { domain, path, secure }; + return { domain, path, secure, sameSite }; }; diff --git a/plugins/auth-backend/src/providers/types.ts b/plugins/auth-backend/src/providers/types.ts index 574afade79..1459cff484 100644 --- a/plugins/auth-backend/src/providers/types.ts +++ b/plugins/auth-backend/src/providers/types.ts @@ -100,7 +100,14 @@ export type CookieConfigurer = (ctx: { baseUrl: string; /** The configured callback URL of the auth provider */ callbackUrl: string; -}) => { domain: string; path: string; secure: boolean }; + /** The origin URL of the app */ + appOrigin: string; +}) => { + domain: string; + path: string; + secure: boolean; + sameSite?: 'none' | 'lax' | 'strict'; +}; /** @public */ export type AuthProviderConfig = { diff --git a/plugins/auth-node/CHANGELOG.md b/plugins/auth-node/CHANGELOG.md index 13fb0bbcce..24ce679c1e 100644 --- a/plugins/auth-node/CHANGELOG.md +++ b/plugins/auth-node/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-auth-node +## 0.2.5 + +### Patch Changes + +- 9212439d15: Minor update to tests +- 2cbd533426: `IdentityClient` is now deprecated. Please migrate to `IdentityApi` and `DefaultIdentityClient` instead. The authenticate function on `DefaultIdentityClient` is also deprecated. Please use `getIdentity` instead. +- 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/errors@1.1.1 + ## 0.2.5-next.3 ### Patch Changes diff --git a/plugins/auth-node/package.json b/plugins/auth-node/package.json index 52115d6611..eac9d4e4d1 100644 --- a/plugins/auth-node/package.json +++ b/plugins/auth-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-node", - "version": "0.2.5-next.3", + "version": "0.2.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,9 +22,9 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/config": "^1.0.2-next.0", - "@backstage/errors": "^1.1.1-next.0", + "@backstage/backend-common": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/errors": "workspace:^", "@types/express": "*", "express": "^4.17.1", "jose": "^4.6.0", @@ -32,8 +32,8 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/backend-test-utils": "^0.1.28-next.3", - "@backstage/cli": "^0.19.0-next.3", + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", "lodash": "^4.17.21", "msw": "^0.47.0", "uuid": "^8.0.0" diff --git a/plugins/azure-devops-backend/CHANGELOG.md b/plugins/azure-devops-backend/CHANGELOG.md index d6145f3308..4f40ad3c6e 100644 --- a/plugins/azure-devops-backend/CHANGELOG.md +++ b/plugins/azure-devops-backend/CHANGELOG.md @@ -1,5 +1,55 @@ # @backstage/plugin-azure-devops-backend +## 0.3.15 + +### Patch Changes + +- 3f739be9d9: 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`. +- cb1cfc018b: `createRouter` now requires an additional reader: `UrlReader` argument + + ```diff + export default async function createPlugin( + env: PluginEnvironment, + ): Promise { + return createRouter({ + logger: env.logger, + config: env.config, + + reader: env.reader, + }); + } + ``` + + Remember to check if you have already provided these settings previously. + + #### [Azure DevOps] + + ```yaml + # app-config.yaml + azureDevOps: + host: dev.azure.com + token: my-token + organization: my-company + ``` + + #### [Azure Integrations] + + ```yaml + # app-config.yaml + integrations: + azure: + - host: dev.azure.com + token: ${AZURE_TOKEN} + ``` + +- ef9ab322de: Minor API signatures cleanup +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/plugin-azure-devops-common@0.3.0 + - @backstage/config@1.0.2 + ## 0.3.15-next.2 ### Patch Changes diff --git a/plugins/azure-devops-backend/package.json b/plugins/azure-devops-backend/package.json index 92bcf84c62..c77860abe5 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.3.15-next.2", + "version": "0.3.15", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,9 +22,9 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/config": "^1.0.2-next.0", - "@backstage/plugin-azure-devops-common": "^0.3.0-next.0", + "@backstage/backend-common": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/plugin-azure-devops-common": "workspace:^", "@types/express": "^4.17.6", "azure-devops-node-api": "^11.0.1", "express": "^4.17.1", @@ -35,7 +35,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", + "@backstage/cli": "workspace:^", "@types/supertest": "^2.0.8", "msw": "^0.47.0", "supertest": "^6.1.6" diff --git a/plugins/azure-devops-common/CHANGELOG.md b/plugins/azure-devops-common/CHANGELOG.md index 8f0c5b9f76..a96aae9f0a 100644 --- a/plugins/azure-devops-common/CHANGELOG.md +++ b/plugins/azure-devops-common/CHANGELOG.md @@ -1,5 +1,58 @@ # @backstage/plugin-azure-devops-common +## 0.3.0 + +### Minor Changes + +- 6c1c59b96e: Added README card `EntityAzureReadmeCard` for Azure Devops. + + To get the README component working you'll need to do the following two steps: + + 1. First we need to add the @backstage/plugin-azure-devops package to your frontend app: + + ```bash + # From your Backstage root directory + yarn add --cwd packages/app @backstage/plugin-azure-devops + ``` + + 2. Second we need to add the `EntityAzureReadmeCard` extension to the entity page in your app: + + ```tsx + // In packages/app/src/components/catalog/EntityPage.tsx + import { + EntityAzureReadmeCard, + isAzureDevOpsAvailable, + } from '@backstage/plugin-azure-devops'; + + // As it is a card, you can customize it the way you prefer + // For example in the Service section + + const overviewContent = ( + + + + + ... + + + + + + + + ); + ``` + + **Notes:** + + - 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% + +### Patch Changes + +- 3f739be9d9: Minor API signatures cleanup + ## 0.3.0-next.0 ### Minor Changes diff --git a/plugins/azure-devops-common/package.json b/plugins/azure-devops-common/package.json index 5633826d9e..cf0b33275f 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.0-next.0", + "version": "0.3.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,7 +31,7 @@ "clean": "backstage-cli package clean" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.1" + "@backstage/cli": "workspace:^" }, "files": [ "dist" diff --git a/plugins/azure-devops/CHANGELOG.md b/plugins/azure-devops/CHANGELOG.md index 13ea5bbaa5..6ca86dfefa 100644 --- a/plugins/azure-devops/CHANGELOG.md +++ b/plugins/azure-devops/CHANGELOG.md @@ -1,5 +1,70 @@ # @backstage/plugin-azure-devops +## 0.2.0 + +### Minor Changes + +- 6c1c59b96e: Added README card `EntityAzureReadmeCard` for Azure Devops. + + To get the README component working you'll need to do the following two steps: + + 1. First we need to add the @backstage/plugin-azure-devops package to your frontend app: + + ```bash + # From your Backstage root directory + yarn add --cwd packages/app @backstage/plugin-azure-devops + ``` + + 2. Second we need to add the `EntityAzureReadmeCard` extension to the entity page in your app: + + ```tsx + // In packages/app/src/components/catalog/EntityPage.tsx + import { + EntityAzureReadmeCard, + isAzureDevOpsAvailable, + } from '@backstage/plugin-azure-devops'; + + // As it is a card, you can customize it the way you prefer + // For example in the Service section + + const overviewContent = ( + + + + + ... + + + + + + + + ); + ``` + + **Notes:** + + - 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% + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 3f739be9d9: Minor API signatures cleanup +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/plugin-azure-devops-common@0.3.0 + - @backstage/catalog-model@1.1.1 + - @backstage/errors@1.1.1 + ## 0.2.0-next.3 ### Patch Changes diff --git a/plugins/azure-devops/package.json b/plugins/azure-devops/package.json index 0cdd048b1b..9785fdf2b3 100644 --- a/plugins/azure-devops/package.json +++ b/plugins/azure-devops/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-azure-devops", - "version": "0.2.0-next.3", + "version": "0.2.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -28,13 +28,13 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/plugin-azure-devops-common": "^0.3.0-next.0", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", - "@backstage/theme": "^0.2.16", + "@backstage/catalog-model": "workspace:^", + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@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.57", @@ -47,10 +47,10 @@ "react-router": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/azure-devops/src/utils/getDurationFromDates.test.ts b/plugins/azure-devops/src/utils/getDurationFromDates.test.ts index fac0e917d0..2a8ee6e04f 100644 --- a/plugins/azure-devops/src/utils/getDurationFromDates.test.ts +++ b/plugins/azure-devops/src/utils/getDurationFromDates.test.ts @@ -18,7 +18,7 @@ import { getDurationFromDates } from './getDurationFromDates'; describe('getDurationFromDates', () => { beforeAll(() => { - jest.useFakeTimers('modern'); + jest.useFakeTimers(); jest.setSystemTime(new Date('2021-10-15T09:45:25.0000000Z')); }); diff --git a/plugins/badges-backend/CHANGELOG.md b/plugins/badges-backend/CHANGELOG.md index c54c09a08b..8b842ca26a 100644 --- a/plugins/badges-backend/CHANGELOG.md +++ b/plugins/badges-backend/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-badges-backend +## 0.1.30 + +### Patch Changes + +- ef9ab322de: Minor API signatures cleanup +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + ## 0.1.30-next.1 ### Patch Changes diff --git a/plugins/badges-backend/package.json b/plugins/badges-backend/package.json index 0002695cc8..0eaf8a9d0a 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.1.30-next.1", + "version": "0.1.30", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,11 +33,11 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/catalog-client": "^1.1.0-next.2", - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/config": "^1.0.2-next.0", - "@backstage/errors": "^1.1.1-next.0", + "@backstage/backend-common": "workspace:^", + "@backstage/catalog-client": "workspace:^", + "@backstage/catalog-model": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/errors": "workspace:^", "@types/express": "^4.17.6", "badge-maker": "^3.3.0", "cors": "^2.8.5", @@ -47,7 +47,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", + "@backstage/cli": "workspace:^", "@types/supertest": "^2.0.8", "supertest": "^6.1.3" }, diff --git a/plugins/badges/CHANGELOG.md b/plugins/badges/CHANGELOG.md index 50137c221b..fff53440bc 100644 --- a/plugins/badges/CHANGELOG.md +++ b/plugins/badges/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-badges +## 0.2.33 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- ef9ab322de: Minor API signatures cleanup +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + - @backstage/errors@1.1.1 + ## 0.2.33-next.3 ### Patch Changes diff --git a/plugins/badges/package.json b/plugins/badges/package.json index 8748a05077..2e8081f3f6 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.33-next.3", + "version": "0.2.33", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -29,12 +29,12 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", - "@backstage/theme": "^0.2.16", + "@backstage/catalog-model": "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.57", @@ -45,10 +45,10 @@ "react-router": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/bazaar-backend/CHANGELOG.md b/plugins/bazaar-backend/CHANGELOG.md index 4494697278..805b1d2068 100644 --- a/plugins/bazaar-backend/CHANGELOG.md +++ b/plugins/bazaar-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-bazaar-backend +## 0.1.20 + +### Patch Changes + +- 8872cc735d: Fixed a bug where the database option to skip migrations was ignored. +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/config@1.0.2 + - @backstage/backend-test-utils@0.1.28 + ## 0.1.20-next.1 ### Patch Changes diff --git a/plugins/bazaar-backend/package.json b/plugins/bazaar-backend/package.json index c1242acd7e..5f11c694f8 100644 --- a/plugins/bazaar-backend/package.json +++ b/plugins/bazaar-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-bazaar-backend", - "version": "0.1.20-next.1", + "version": "0.1.20", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,9 +22,9 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/backend-test-utils": "^0.1.28-next.3", - "@backstage/config": "^1.0.2-next.0", + "@backstage/backend-common": "workspace:^", + "@backstage/backend-test-utils": "workspace:^", + "@backstage/config": "workspace:^", "@types/express": "^4.17.6", "express": "^4.17.1", "express-promise-router": "^4.1.0", @@ -33,7 +33,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3" + "@backstage/cli": "workspace:^" }, "files": [ "dist", diff --git a/plugins/bazaar/CHANGELOG.md b/plugins/bazaar/CHANGELOG.md index 8d93b89e0f..f936900cd8 100644 --- a/plugins/bazaar/CHANGELOG.md +++ b/plugins/bazaar/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-bazaar +## 0.1.24 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 1dd12349d1: Fixed broken routing by removing the wrapping `Router` from the `RoutedTabs` children. +- Updated dependencies + - @backstage/cli@0.19.0 + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/plugin-catalog@1.5.1 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + ## 0.1.24-next.2 ### Patch Changes diff --git a/plugins/bazaar/package.json b/plugins/bazaar/package.json index 21e2f3ce25..919f8a7df7 100644 --- a/plugins/bazaar/package.json +++ b/plugins/bazaar/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-bazaar", - "version": "0.1.24-next.2", + "version": "0.1.24", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,13 +22,13 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-client": "^1.1.0-next.2", - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/plugin-catalog": "^1.5.1-next.3", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", + "@backstage/catalog-client": "workspace:^", + "@backstage/catalog-model": "workspace:^", + "@backstage/cli": "workspace:^", + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/plugin-catalog": "workspace:^", + "@backstage/plugin-catalog-react": "workspace:^", "@date-io/luxon": "1.x", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -44,8 +44,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", + "@backstage/cli": "workspace:^", + "@backstage/dev-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "cross-fetch": "^3.1.5" }, diff --git a/plugins/bitbucket-cloud-common/CHANGELOG.md b/plugins/bitbucket-cloud-common/CHANGELOG.md index 759e3602f6..0990b34b42 100644 --- a/plugins/bitbucket-cloud-common/CHANGELOG.md +++ b/plugins/bitbucket-cloud-common/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-bitbucket-cloud-common +## 0.1.3 + +### Patch Changes + +- 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/integration@1.3.1 + ## 0.1.3-next.1 ### Patch Changes diff --git a/plugins/bitbucket-cloud-common/package.json b/plugins/bitbucket-cloud-common/package.json index e9bc4f02a4..1e8db8185f 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.1.3-next.1", + "version": "0.1.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -27,11 +27,11 @@ "update-models": "yarn refresh-schema && yarn generate-models && yarn reduce-models" }, "dependencies": { - "@backstage/integration": "^1.3.1-next.1", + "@backstage/integration": "workspace:^", "cross-fetch": "^3.1.5" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.2", + "@backstage/cli": "workspace:^", "@openapitools/openapi-generator-cli": "^2.4.26", "msw": "^0.47.0", "ts-morph": "^15.0.0" diff --git a/plugins/bitrise/CHANGELOG.md b/plugins/bitrise/CHANGELOG.md index 114ab5549e..55eb78d63e 100644 --- a/plugins/bitrise/CHANGELOG.md +++ b/plugins/bitrise/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-bitrise +## 0.1.36 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + ## 0.1.36-next.3 ### Patch Changes diff --git a/plugins/bitrise/package.json b/plugins/bitrise/package.json index b659cac03a..1a7e586e5c 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.36-next.3", + "version": "0.1.36", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,11 +23,11 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", - "@backstage/theme": "^0.2.16", + "@backstage/catalog-model": "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.57", @@ -42,10 +42,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/catalog-backend-module-aws/CHANGELOG.md b/plugins/catalog-backend-module-aws/CHANGELOG.md index 07b5446dcc..ea6f2810e7 100644 --- a/plugins/catalog-backend-module-aws/CHANGELOG.md +++ b/plugins/catalog-backend-module-aws/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-backend-module-aws +## 0.1.9 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/integration@1.3.1 + - @backstage/plugin-catalog-backend@1.4.0 + - @backstage/backend-tasks@0.3.5 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + ## 0.1.9-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-aws/package.json b/plugins/catalog-backend-module-aws/package.json index 33158ac182..c921aad767 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.1.9-next.2", + "version": "0.1.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,14 +32,14 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/backend-tasks": "^0.3.5-next.1", - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/config": "^1.0.2-next.0", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/integration": "^1.3.1-next.2", - "@backstage/plugin-catalog-backend": "^1.4.0-next.3", - "@backstage/types": "^1.0.0", + "@backstage/backend-common": "workspace:^", + "@backstage/backend-tasks": "workspace:^", + "@backstage/catalog-model": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/integration": "workspace:^", + "@backstage/plugin-catalog-backend": "workspace:^", + "@backstage/types": "workspace:^", "aws-sdk": "^2.840.0", "lodash": "^4.17.21", "p-limit": "^3.0.2", @@ -47,7 +47,7 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", + "@backstage/cli": "workspace:^", "@types/lodash": "^4.14.151", "aws-sdk-mock": "^5.2.1", "yaml": "^2.0.0" diff --git a/plugins/catalog-backend-module-azure/CHANGELOG.md b/plugins/catalog-backend-module-azure/CHANGELOG.md index 57d5315cf4..51d9752af9 100644 --- a/plugins/catalog-backend-module-azure/CHANGELOG.md +++ b/plugins/catalog-backend-module-azure/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-catalog-backend-module-azure +## 0.1.7 + +### Patch Changes + +- 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/integration@1.3.1 + - @backstage/plugin-catalog-backend@1.4.0 + - @backstage/backend-tasks@0.3.5 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + ## 0.1.7-next.3 ### Patch Changes diff --git a/plugins/catalog-backend-module-azure/package.json b/plugins/catalog-backend-module-azure/package.json index 3dd90d1bb3..afcfdf9f0f 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.7-next.3", + "version": "0.1.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,14 +32,14 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/backend-tasks": "^0.3.5-next.1", - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/config": "^1.0.2-next.0", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/integration": "^1.3.1-next.2", - "@backstage/plugin-catalog-backend": "^1.4.0-next.3", - "@backstage/types": "^1.0.0", + "@backstage/backend-common": "workspace:^", + "@backstage/backend-tasks": "workspace:^", + "@backstage/catalog-model": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/integration": "workspace:^", + "@backstage/plugin-catalog-backend": "workspace:^", + "@backstage/types": "workspace:^", "lodash": "^4.17.21", "msw": "^0.47.0", "node-fetch": "^2.6.7", @@ -47,8 +47,8 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/backend-test-utils": "^0.1.28-next.3", - "@backstage/cli": "^0.19.0-next.3", + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", "@types/lodash": "^4.14.151" }, "files": [ diff --git a/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md index cd50519279..453f6124ba 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-catalog-backend-module-bitbucket-cloud +## 0.1.3 + +### Patch Changes + +- 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/integration@1.3.1 + - @backstage/plugin-catalog-backend@1.4.0 + - @backstage/backend-tasks@0.3.5 + - @backstage/config@1.0.2 + - @backstage/plugin-bitbucket-cloud-common@0.1.3 + ## 0.1.3-next.3 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket-cloud/package.json b/plugins/catalog-backend-module-bitbucket-cloud/package.json index e8ddff85b0..4fdebd65bd 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.3-next.3", + "version": "0.1.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,18 +32,18 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/backend-tasks": "^0.3.5-next.1", - "@backstage/config": "^1.0.2-next.0", - "@backstage/integration": "^1.3.1-next.2", - "@backstage/plugin-bitbucket-cloud-common": "^0.1.3-next.1", - "@backstage/plugin-catalog-backend": "^1.4.0-next.3", + "@backstage/backend-tasks": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/integration": "workspace:^", + "@backstage/plugin-bitbucket-cloud-common": "workspace:^", + "@backstage/plugin-catalog-backend": "workspace:^", "uuid": "^8.0.0", "winston": "^3.2.1" }, "devDependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/backend-test-utils": "^0.1.28-next.3", - "@backstage/cli": "^0.19.0-next.3", + "@backstage/backend-common": "workspace:^", + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", "msw": "^0.47.0" }, "files": [ diff --git a/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md index ae82dc8ad7..5ec5a515bb 100644 --- a/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-catalog-backend-module-bitbucket-server +## 0.1.1 + +### Patch Changes + +- 148568b5c2: Switched to using node-fetch instead of cross-fetch as is standard for our backend packages +- 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/integration@1.3.1 + - @backstage/plugin-catalog-backend@1.4.0 + - @backstage/backend-tasks@0.3.5 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + ## 0.1.1-next.3 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket-server/package.json b/plugins/catalog-backend-module-bitbucket-server/package.json index 4064732eca..d4e27a8ec6 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.1-next.3", + "version": "0.1.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,21 +31,21 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/backend-tasks": "^0.3.5-next.1", - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/config": "^1.0.2-next.0", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/integration": "^1.3.1-next.2", - "@backstage/plugin-catalog-backend": "^1.4.0-next.3", + "@backstage/backend-common": "workspace:^", + "@backstage/backend-tasks": "workspace:^", + "@backstage/catalog-model": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/integration": "workspace:^", + "@backstage/plugin-catalog-backend": "workspace:^", "@types/node-fetch": "^2.5.12", "node-fetch": "^2.6.7", "uuid": "^8.0.0", "winston": "^3.2.1" }, "devDependencies": { - "@backstage/backend-test-utils": "^0.1.28-next.3", - "@backstage/cli": "^0.19.0-next.3", + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", "msw": "^0.47.0" }, "files": [ diff --git a/plugins/catalog-backend-module-bitbucket/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket/CHANGELOG.md index 7533ebaa47..9af08254eb 100644 --- a/plugins/catalog-backend-module-bitbucket/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-catalog-backend-module-bitbucket +## 0.2.3 + +### Patch Changes + +- 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/integration@1.3.1 + - @backstage/plugin-catalog-backend@1.4.0 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + - @backstage/plugin-bitbucket-cloud-common@0.1.3 + ## 0.2.3-next.3 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket/package.json b/plugins/catalog-backend-module-bitbucket/package.json index 7d27598d1f..171493dfc2 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.3-next.3", + "version": "0.2.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,22 +32,22 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/config": "^1.0.2-next.0", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/integration": "^1.3.1-next.2", - "@backstage/plugin-bitbucket-cloud-common": "^0.1.3-next.1", - "@backstage/plugin-catalog-backend": "^1.4.0-next.3", - "@backstage/types": "^1.0.0", + "@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-backend": "workspace:^", + "@backstage/types": "workspace:^", "lodash": "^4.17.21", "msw": "^0.47.0", "node-fetch": "^2.6.7", "winston": "^3.2.1" }, "devDependencies": { - "@backstage/backend-test-utils": "^0.1.28-next.3", - "@backstage/cli": "^0.19.0-next.3", + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", "@types/lodash": "^4.14.151" }, "files": [ diff --git a/plugins/catalog-backend-module-gerrit/CHANGELOG.md b/plugins/catalog-backend-module-gerrit/CHANGELOG.md index d90cbfbe10..2dc4229172 100644 --- a/plugins/catalog-backend-module-gerrit/CHANGELOG.md +++ b/plugins/catalog-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-catalog-backend-module-gerrit +## 0.1.4 + +### Patch Changes + +- 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/integration@1.3.1 + - @backstage/plugin-catalog-backend@1.4.0 + - @backstage/backend-tasks@0.3.5 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + ## 0.1.4-next.3 ### Patch Changes diff --git a/plugins/catalog-backend-module-gerrit/package.json b/plugins/catalog-backend-module-gerrit/package.json index 53d54afc06..6a115ea481 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.4-next.3", + "version": "0.1.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -28,13 +28,13 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/backend-tasks": "^0.3.5-next.1", - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/config": "^1.0.2-next.0", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/integration": "^1.3.1-next.2", - "@backstage/plugin-catalog-backend": "^1.4.0-next.3", + "@backstage/backend-common": "workspace:^", + "@backstage/backend-tasks": "workspace:^", + "@backstage/catalog-model": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/integration": "workspace:^", + "@backstage/plugin-catalog-backend": "workspace:^", "fs-extra": "10.1.0", "msw": "^0.47.0", "node-fetch": "^2.6.7", @@ -42,8 +42,8 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/backend-test-utils": "^0.1.28-next.3", - "@backstage/cli": "^0.19.0-next.3", + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", "@types/fs-extra": "^9.0.1" }, "files": [ diff --git a/plugins/catalog-backend-module-github/CHANGELOG.md b/plugins/catalog-backend-module-github/CHANGELOG.md index a1a11f1519..fa49109016 100644 --- a/plugins/catalog-backend-module-github/CHANGELOG.md +++ b/plugins/catalog-backend-module-github/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-catalog-backend-module-github +## 0.1.7 + +### Patch Changes + +- 3c4a388537: New experimental alpha exports for use with the upcoming backend system. +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- 3a62594a11: Add support for including (or excluding) Github repositories by topic +- 287a64bf97: Added the ability to configure the host for the `GitHubEntityProvider` to use against GitHub Enterprise +- 91e2abbd46: Remove the duplicated `scheduleFn` initialization in `GitHubEntityProvider`. +- Updated dependencies + - @backstage/backend-plugin-api@0.1.2 + - @backstage/backend-common@0.15.1 + - @backstage/plugin-catalog-node@1.1.0 + - @backstage/integration@1.3.1 + - @backstage/plugin-catalog-backend@1.4.0 + - @backstage/backend-tasks@0.3.5 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + ## 0.1.7-next.3 ### Patch Changes diff --git a/plugins/catalog-backend-module-github/package.json b/plugins/catalog-backend-module-github/package.json index c27d3d4c60..278f108a7b 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.1.7-next.3", + "version": "0.1.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,16 +33,16 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/backend-plugin-api": "^0.1.2-next.2", - "@backstage/backend-tasks": "^0.3.5-next.1", - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/config": "^1.0.2-next.0", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/integration": "^1.3.1-next.2", - "@backstage/plugin-catalog-backend": "^1.4.0-next.3", - "@backstage/plugin-catalog-node": "^1.1.0-next.2", - "@backstage/types": "^1.0.0", + "@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-backend": "workspace:^", + "@backstage/plugin-catalog-node": "workspace:^", + "@backstage/types": "workspace:^", "@octokit/graphql": "^5.0.0", "lodash": "^4.17.21", "msw": "^0.47.0", @@ -51,8 +51,8 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/backend-test-utils": "^0.1.28-next.3", - "@backstage/cli": "^0.19.0-next.3", + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", "@types/lodash": "^4.14.151" }, "files": [ diff --git a/plugins/catalog-backend-module-github/src/providers/GitHubEntityProvider.ts b/plugins/catalog-backend-module-github/src/providers/GitHubEntityProvider.ts index cf9b2cdd0a..3909b5a3c2 100644 --- a/plugins/catalog-backend-module-github/src/providers/GitHubEntityProvider.ts +++ b/plugins/catalog-backend-module-github/src/providers/GitHubEntityProvider.ts @@ -98,7 +98,6 @@ export class GitHubEntityProvider implements EntityProvider { this.scheduleFn = this.createScheduleFn(schedule); this.githubCredentialsProvider = SingleInstanceGithubCredentialsProvider.create(integration.config); - this.scheduleFn = this.createScheduleFn(schedule); } /** {@inheritdoc @backstage/plugin-catalog-backend#EntityProvider.getProviderName} */ diff --git a/plugins/catalog-backend-module-gitlab/CHANGELOG.md b/plugins/catalog-backend-module-gitlab/CHANGELOG.md index ba2016b713..d6b3cfb3d7 100644 --- a/plugins/catalog-backend-module-gitlab/CHANGELOG.md +++ b/plugins/catalog-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-catalog-backend-module-gitlab +## 0.1.7 + +### Patch Changes + +- 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/integration@1.3.1 + - @backstage/plugin-catalog-backend@1.4.0 + - @backstage/backend-tasks@0.3.5 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + ## 0.1.7-next.3 ### Patch Changes diff --git a/plugins/catalog-backend-module-gitlab/package.json b/plugins/catalog-backend-module-gitlab/package.json index 56d6fd73e8..457be11480 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.1.7-next.3", + "version": "0.1.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,14 +32,14 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/backend-tasks": "^0.3.5-next.1", - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/config": "^1.0.2-next.0", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/integration": "^1.3.1-next.2", - "@backstage/plugin-catalog-backend": "^1.4.0-next.3", - "@backstage/types": "^1.0.0", + "@backstage/backend-common": "workspace:^", + "@backstage/backend-tasks": "workspace:^", + "@backstage/catalog-model": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/integration": "workspace:^", + "@backstage/plugin-catalog-backend": "workspace:^", + "@backstage/types": "workspace:^", "lodash": "^4.17.21", "msw": "^0.47.0", "node-fetch": "^2.6.7", @@ -47,8 +47,8 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/backend-test-utils": "^0.1.28-next.3", - "@backstage/cli": "^0.19.0-next.3", + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", "@types/lodash": "^4.14.151", "@types/uuid": "^8.0.0" }, diff --git a/plugins/catalog-backend-module-gitlab/src/GitLabDiscoveryProcessor.test.ts b/plugins/catalog-backend-module-gitlab/src/GitLabDiscoveryProcessor.test.ts index d0f2eb383d..385ce59bfb 100644 --- a/plugins/catalog-backend-module-gitlab/src/GitLabDiscoveryProcessor.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/GitLabDiscoveryProcessor.test.ts @@ -153,7 +153,7 @@ describe('GitlabDiscoveryProcessor', () => { setupRequestMockHandlers(server); beforeAll(() => { - jest.useFakeTimers('modern'); + jest.useFakeTimers(); jest.setSystemTime(new Date(SERVER_TIME)); }); diff --git a/plugins/catalog-backend-module-ldap/CHANGELOG.md b/plugins/catalog-backend-module-ldap/CHANGELOG.md index 6429576b05..7e21490644 100644 --- a/plugins/catalog-backend-module-ldap/CHANGELOG.md +++ b/plugins/catalog-backend-module-ldap/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-backend-module-ldap +## 0.5.3 + +### Patch Changes + +- 7fa54c3c77: Added ae-dir LDAP vendor to correctly extract DN. +- c54fcea9af: Now the `searchStream` method in LDAP client awaits the callbacks +- Updated dependencies + - @backstage/plugin-catalog-backend@1.4.0 + - @backstage/backend-tasks@0.3.5 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + ## 0.5.3-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-ldap/package.json b/plugins/catalog-backend-module-ldap/package.json index 4d9de73a77..ea00832f98 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.3-next.2", + "version": "0.5.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,12 +32,12 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/backend-tasks": "^0.3.5-next.1", - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/config": "^1.0.2-next.0", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/plugin-catalog-backend": "^1.4.0-next.3", - "@backstage/types": "^1.0.0", + "@backstage/backend-tasks": "workspace:^", + "@backstage/catalog-model": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/plugin-catalog-backend": "workspace:^", + "@backstage/types": "workspace:^", "@types/ldapjs": "^2.2.0", "ldapjs": "^2.2.0", "lodash": "^4.17.21", @@ -45,7 +45,7 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", + "@backstage/cli": "workspace:^", "@types/lodash": "^4.14.151" }, "files": [ diff --git a/plugins/catalog-backend-module-msgraph/CHANGELOG.md b/plugins/catalog-backend-module-msgraph/CHANGELOG.md index 25ac8c2716..aa601f1c3f 100644 --- a/plugins/catalog-backend-module-msgraph/CHANGELOG.md +++ b/plugins/catalog-backend-module-msgraph/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-catalog-backend-module-msgraph +## 0.4.2 + +### Patch Changes + +- c1d32d2b76: Fixed a bug in the `MicrosoftGraphEntityProvider` that ignored the `userExpand` and `groupExpand` configuration parameters +- d80aab31ae: Added $select attribute to user query +- a246d5a9b8: Read `queryMode` from the `microsoftGraphOrg` config +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- 4c82b955fc: Fix typo +- Updated dependencies + - @backstage/plugin-catalog-backend@1.4.0 + - @backstage/backend-tasks@0.3.5 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + ## 0.4.2-next.3 ### Patch Changes diff --git a/plugins/catalog-backend-module-msgraph/config.d.ts b/plugins/catalog-backend-module-msgraph/config.d.ts index df41b581f9..9fe1cb81c9 100644 --- a/plugins/catalog-backend-module-msgraph/config.d.ts +++ b/plugins/catalog-backend-module-msgraph/config.d.ts @@ -144,6 +144,15 @@ export interface Config { */ clientSecret?: string; + /** + * By default, the Microsoft Graph API only provides the basic feature set + * for querying. Certain features are limited to advanced query capabilities + * (see https://docs.microsoft.com/en-us/graph/aad-advanced-queries) + * and need to be enabled. + * + * Some features like `$expand` are not available for advanced queries, though. + */ + queryMode?: string; user?: { /** * The "expand" argument to apply to users. @@ -230,6 +239,15 @@ export interface Config { */ clientSecret: string; + /** + * By default, the Microsoft Graph API only provides the basic feature set + * for querying. Certain features are limited to advanced query capabilities + * (see https://docs.microsoft.com/en-us/graph/aad-advanced-queries) + * and need to be enabled. + * + * Some features like `$expand` are not available for advanced queries, though. + */ + queryMode?: string; user?: { /** * The filter to apply to extract users. diff --git a/plugins/catalog-backend-module-msgraph/package.json b/plugins/catalog-backend-module-msgraph/package.json index 93270570fb..5a5b90832e 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.4.2-next.3", + "version": "0.4.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,10 +33,10 @@ }, "dependencies": { "@azure/identity": "^2.1.0", - "@backstage/backend-tasks": "^0.3.5-next.1", - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/config": "^1.0.2-next.0", - "@backstage/plugin-catalog-backend": "^1.4.0-next.3", + "@backstage/backend-tasks": "workspace:^", + "@backstage/catalog-model": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/plugin-catalog-backend": "workspace:^", "@microsoft/microsoft-graph-types": "^2.6.0", "@types/node-fetch": "^2.5.12", "lodash": "^4.17.21", @@ -47,9 +47,9 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/backend-test-utils": "^0.1.28-next.3", - "@backstage/cli": "^0.19.0-next.3", + "@backstage/backend-common": "workspace:^", + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", "@types/lodash": "^4.14.151", "msw": "^0.47.0" }, diff --git a/plugins/catalog-backend-module-msgraph/src/microsoftGraph/config.test.ts b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/config.test.ts index 8e2866df65..3331e3609d 100644 --- a/plugins/catalog-backend-module-msgraph/src/microsoftGraph/config.test.ts +++ b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/config.test.ts @@ -162,6 +162,7 @@ describe('readProviderConfigs', () => { clientId: 'clientId', clientSecret: 'clientSecret', authority: 'https://login.example.com/', + queryMode: 'advanced', user: { expand: 'manager', filter: 'accountEnabled eq true', @@ -185,6 +186,7 @@ describe('readProviderConfigs', () => { clientId: 'clientId', clientSecret: 'clientSecret', authority: 'https://login.example.com/', + queryMode: 'advanced', userExpand: 'manager', userFilter: 'accountEnabled eq true', groupExpand: 'member', diff --git a/plugins/catalog-backend-module-msgraph/src/microsoftGraph/config.ts b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/config.ts index 2429b67c89..b8565e0d72 100644 --- a/plugins/catalog-backend-module-msgraph/src/microsoftGraph/config.ts +++ b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/config.ts @@ -261,6 +261,15 @@ export function readProviderConfig( const groupSearch = config.getOptionalString('group.search'); const groupSelect = config.getOptionalStringArray('group.select'); + const queryMode = config.getOptionalString('queryMode'); + if ( + queryMode !== undefined && + queryMode !== 'basic' && + queryMode !== 'advanced' + ) { + throw new Error(`queryMode must be one of: basic, advanced`); + } + const userGroupMemberFilter = config.getOptionalString( 'userGroupMember.filter', ); @@ -300,6 +309,7 @@ export function readProviderConfig( groupFilter, groupSearch, groupSelect, + queryMode, userGroupMemberFilter, userGroupMemberSearch, }; diff --git a/plugins/catalog-backend-module-openapi/CHANGELOG.md b/plugins/catalog-backend-module-openapi/CHANGELOG.md index f9a1ad9ed9..81f356168e 100644 --- a/plugins/catalog-backend-module-openapi/CHANGELOG.md +++ b/plugins/catalog-backend-module-openapi/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-catalog-backend-module-openapi +## 0.1.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/plugin-catalog-node@1.1.0 + - @backstage/integration@1.3.1 + - @backstage/plugin-catalog-backend@1.4.0 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + ## 0.1.2-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-openapi/package.json b/plugins/catalog-backend-module-openapi/package.json index 420a9d547e..f3081f575b 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.2-next.2", + "version": "0.1.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,19 +33,19 @@ }, "dependencies": { "@apidevtools/swagger-parser": "^10.1.0", - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/config": "^1.0.2-next.0", - "@backstage/integration": "^1.3.1-next.2", - "@backstage/plugin-catalog-backend": "^1.4.0-next.3", - "@backstage/plugin-catalog-node": "^1.1.0-next.2", - "@backstage/types": "^1.0.0", + "@backstage/backend-common": "workspace:^", + "@backstage/catalog-model": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/integration": "workspace:^", + "@backstage/plugin-catalog-backend": "workspace:^", + "@backstage/plugin-catalog-node": "workspace:^", + "@backstage/types": "workspace:^", "winston": "^3.2.1", "yaml": "^2.1.1" }, "devDependencies": { - "@backstage/backend-test-utils": "^0.1.28-next.3", - "@backstage/cli": "^0.19.0-next.3", + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", "openapi-types": "^12.0.0" }, "files": [ diff --git a/plugins/catalog-backend/CHANGELOG.md b/plugins/catalog-backend/CHANGELOG.md index 07d434b7b2..d702df4af0 100644 --- a/plugins/catalog-backend/CHANGELOG.md +++ b/plugins/catalog-backend/CHANGELOG.md @@ -1,5 +1,40 @@ # @backstage/plugin-catalog-backend +## 1.4.0 + +### Minor Changes + +- dd395335bc: Allow unknown typed location from being registered via the location service by configuration settings +- 651c9d6800: The search index now does retain fields that have a very long value, but in the form of just a null. This makes it possible to at least filter for their existence. +- 6e63bc43f2: Added the `refresh` function to the Connection of the entity providers. + +### Patch Changes + +- eadf56bbbf: Bump `git-url-parse` version to `^13.0.0` +- 07dda0b746: Add optional value to `hasAnnotation` permission rule +- 243533ecdc: Added support to mysql on some raw queries +- ce77e78c93: Fixes a bug to be able to utilize refresh keys after the entity is loaded from cache +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- 679f7c5e95: Include entity ref into error message when catalog policies fail +- 06e2b077a1: Limit the length of error messages that get written to the database and logs - to prevent performance issues +- 62788b2ee8: The experimental `CatalogProcessingExtensionPoint` now accepts multiple providers and processors at once. +- Updated dependencies + - @backstage/backend-plugin-api@0.1.2 + - @backstage/backend-common@0.15.1 + - @backstage/plugin-permission-node@0.6.5 + - @backstage/plugin-catalog-node@1.1.0 + - @backstage/integration@1.3.1 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + - @backstage/plugin-permission-common@0.6.4 + - @backstage/plugin-scaffolder-common@1.2.0 + - @backstage/plugin-catalog-common@1.0.6 + - @backstage/plugin-search-common@1.0.1 + ## 1.4.0-next.3 ### Minor Changes diff --git a/plugins/catalog-backend/api-report.md b/plugins/catalog-backend/api-report.md index a92ebb9624..f18d396114 100644 --- a/plugins/catalog-backend/api-report.md +++ b/plugins/catalog-backend/api-report.md @@ -177,7 +177,7 @@ export const catalogConditions: Conditions<{ Entity, EntitiesSearchFilter, 'catalog-entity', - [annotation: string] + [annotation: string, value?: string | undefined] >; hasLabel: PermissionRule< Entity, @@ -448,7 +448,7 @@ export const permissionRules: { Entity, EntitiesSearchFilter, 'catalog-entity', - [annotation: string] + [annotation: string, value?: string | undefined] >; hasLabel: PermissionRule< Entity, diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index 0b9d363b3a..f834b0e2e8 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.4.0-next.3", + "version": "1.4.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,20 +33,20 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/backend-plugin-api": "^0.1.2-next.2", - "@backstage/catalog-client": "^1.1.0-next.2", - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/config": "^1.0.2-next.0", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/integration": "^1.3.1-next.2", - "@backstage/plugin-catalog-common": "^1.0.6-next.0", - "@backstage/plugin-catalog-node": "^1.1.0-next.2", - "@backstage/plugin-permission-common": "^0.6.4-next.2", - "@backstage/plugin-permission-node": "^0.6.5-next.3", - "@backstage/plugin-scaffolder-common": "^1.2.0-next.1", - "@backstage/plugin-search-common": "^1.0.1-next.0", - "@backstage/types": "^1.0.0", + "@backstage/backend-common": "workspace:^", + "@backstage/backend-plugin-api": "workspace:^", + "@backstage/catalog-client": "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/plugin-permission-common": "workspace:^", + "@backstage/plugin-permission-node": "workspace:^", + "@backstage/plugin-scaffolder-common": "workspace:^", + "@backstage/plugin-search-common": "workspace:^", + "@backstage/types": "workspace:^", "@types/express": "^4.17.6", "codeowners-utils": "^1.0.2", "core-js": "^3.6.5", @@ -69,10 +69,10 @@ "zod": "^3.11.6" }, "devDependencies": { - "@backstage/backend-test-utils": "^0.1.28-next.3", - "@backstage/cli": "^0.19.0-next.3", - "@backstage/plugin-permission-common": "^0.6.4-next.2", - "@backstage/plugin-search-backend-node": "1.0.2-next.2", + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", + "@backstage/plugin-permission-common": "workspace:^", + "@backstage/plugin-search-backend-node": "workspace:^", "@types/core-js": "^2.5.4", "@types/git-url-parse": "^9.0.0", "@types/lodash": "^4.14.151", diff --git a/plugins/catalog-backend/src/modules/core/PlaceholderProcessor.test.ts b/plugins/catalog-backend/src/modules/core/PlaceholderProcessor.test.ts index 8fd8114760..105ab03d90 100644 --- a/plugins/catalog-backend/src/modules/core/PlaceholderProcessor.test.ts +++ b/plugins/catalog-backend/src/modules/core/PlaceholderProcessor.test.ts @@ -387,6 +387,39 @@ describe('PlaceholderProcessor', () => { key: 'url:http://example.com/path-to-file.json', }); }); + + it('accepts arbitrary object as value', async () => { + const processor = new PlaceholderProcessor({ + resolvers: { + merge: async ({ value }) => { + if (value instanceof Object) { + return { merged: 'value', ...value }; + } + return value; + }, + }, + reader, + integrations, + }); + + const result = await processor.preProcessEntity( + { + apiVersion: 'a', + kind: 'k', + metadata: { name: 'n' }, + spec: { a: { $merge: { passed: 'value' } } }, + }, + { type: 'fake', target: 'http://example.com' }, + () => {}, + ); + + expect(result).toMatchObject({ + apiVersion: 'a', + kind: 'k', + metadata: { name: 'n' }, + spec: { a: { passed: 'value', merged: 'value' } }, + }); + }); }); describe('yamlPlaceholderResolver', () => { diff --git a/plugins/catalog-backend/src/modules/core/PlaceholderProcessor.ts b/plugins/catalog-backend/src/modules/core/PlaceholderProcessor.ts index 39c9dc59ec..5e49c67915 100644 --- a/plugins/catalog-backend/src/modules/core/PlaceholderProcessor.ts +++ b/plugins/catalog-backend/src/modules/core/PlaceholderProcessor.ts @@ -111,12 +111,11 @@ export class PlaceholderProcessor implements CatalogProcessor { const resolverValue = data[keys[0]]; const resolver = this.options.resolvers[resolverKey]; - if (!resolver || typeof resolverValue !== 'string') { - // If there was no such placeholder resolver or if the value was not a - // string, we err on the side of safety and assume that this is - // something that's best left alone. For example, if the input contains - // JSONSchema, there may be "$ref": "#/definitions/node" nodes in the - // document. + if (!resolver) { + // If there was no such placeholder resolver, we err on the side of safety + // and assume that this is something that's best left alone. For example, if + // the input contains JSONSchema, there may be "$ref": "#/definitions/node" + // nodes in the document. return [data, false]; } diff --git a/plugins/catalog-backend/src/permissions/rules/hasAnnotation.test.ts b/plugins/catalog-backend/src/permissions/rules/hasAnnotation.test.ts index 1596270907..609114be3d 100644 --- a/plugins/catalog-backend/src/permissions/rules/hasAnnotation.test.ts +++ b/plugins/catalog-backend/src/permissions/rules/hasAnnotation.test.ts @@ -49,6 +49,19 @@ describe('hasAnnotation permission rule', () => { 'backstage.io/test-annotation', ), ).toEqual(false); + expect( + hasAnnotation.apply( + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'test-component', + }, + }, + 'backstage.io/test-annotation', + 'some value', + ), + ).toEqual(false); }); it('returns true when specified annotation is present', () => { @@ -69,6 +82,46 @@ describe('hasAnnotation permission rule', () => { ), ).toEqual(true); }); + + it('returns false when specified annotation has different than expected value', () => { + expect( + hasAnnotation.apply( + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'test-component', + annotations: { + 'other-annotation': 'foo', + 'backstage.io/test-annotation': 'bar', + }, + }, + }, + 'backstage.io/test-annotation', + 'baz', + ), + ).toEqual(false); + }); + + it('returns true when specified annotation has expected value', () => { + expect( + hasAnnotation.apply( + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'test-component', + annotations: { + 'other-annotation': 'foo', + 'backstage.io/test-annotation': 'bar', + }, + }, + }, + 'backstage.io/test-annotation', + 'bar', + ), + ).toEqual(true); + }); }); describe('toQuery', () => { @@ -78,4 +131,13 @@ describe('hasAnnotation permission rule', () => { }); }); }); + + it('returns an appropriate catalog-backend filter with values', () => { + expect( + hasAnnotation.toQuery('backstage.io/test-annotation', 'foo'), + ).toEqual({ + key: 'metadata.annotations.backstage.io/test-annotation', + values: ['foo'], + }); + }); }); diff --git a/plugins/catalog-backend/src/permissions/rules/hasAnnotation.ts b/plugins/catalog-backend/src/permissions/rules/hasAnnotation.ts index 68ca65418d..22dbd307a6 100644 --- a/plugins/catalog-backend/src/permissions/rules/hasAnnotation.ts +++ b/plugins/catalog-backend/src/permissions/rules/hasAnnotation.ts @@ -22,6 +22,8 @@ import { createCatalogPermissionRule } from './util'; * A catalog {@link @backstage/plugin-permission-node#PermissionRule} which * filters for the presence of an annotation on a given entity. * + * If a value is given, it filters for the annotation value, too. + * * @alpha */ export const hasAnnotation = createCatalogPermissionRule({ @@ -29,9 +31,18 @@ export const hasAnnotation = createCatalogPermissionRule({ description: 'Allow entities which are annotated with the specified annotation', resourceType: RESOURCE_TYPE_CATALOG_ENTITY, - apply: (resource: Entity, annotation: string) => - !!resource.metadata.annotations?.hasOwnProperty(annotation), - toQuery: (annotation: string) => ({ - key: `metadata.annotations.${annotation}`, - }), + apply: (resource: Entity, annotation: string, value?: string) => + !!resource.metadata.annotations?.hasOwnProperty(annotation) && + (value === undefined + ? true + : resource.metadata.annotations?.[annotation] === value), + toQuery: (annotation: string, value?: string) => + value === undefined + ? { + key: `metadata.annotations.${annotation}`, + } + : { + key: `metadata.annotations.${annotation}`, + values: [value], + }, }); diff --git a/plugins/catalog-common/CHANGELOG.md b/plugins/catalog-common/CHANGELOG.md index 45d1e9bbec..57600eb6a5 100644 --- a/plugins/catalog-common/CHANGELOG.md +++ b/plugins/catalog-common/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-catalog-common +## 1.0.6 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.6.4 + - @backstage/plugin-search-common@1.0.1 + ## 1.0.6-next.0 ### Patch Changes diff --git a/plugins/catalog-common/package.json b/plugins/catalog-common/package.json index 32a34ec1c0..357636341a 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.6-next.0", + "version": "1.0.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,11 +33,11 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/plugin-permission-common": "^0.6.4-next.0", - "@backstage/plugin-search-common": "^1.0.1-next.0" + "@backstage/plugin-permission-common": "workspace:^", + "@backstage/plugin-search-common": "workspace:^" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.1" + "@backstage/cli": "workspace:^" }, "files": [ "dist", diff --git a/plugins/catalog-customized/CHANGELOG.md b/plugins/catalog-customized/CHANGELOG.md index d8c95242db..409c007eea 100644 --- a/plugins/catalog-customized/CHANGELOG.md +++ b/plugins/catalog-customized/CHANGELOG.md @@ -1,5 +1,13 @@ # @internal/plugin-catalog-customized +## 0.0.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/plugin-catalog@1.5.1 + ## 0.0.2-next.0 ### Patch Changes diff --git a/plugins/catalog-customized/package.json b/plugins/catalog-customized/package.json index deed4a5885..a8ffbd7494 100644 --- a/plugins/catalog-customized/package.json +++ b/plugins/catalog-customized/package.json @@ -1,7 +1,7 @@ { "name": "@internal/plugin-catalog-customized", "description": "The internal Backstage Customizable plugin for browsing the Backstage catalog", - "version": "0.0.2-next.0", + "version": "0.0.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,8 +33,8 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/plugin-catalog": "^1.5.1-next.0", - "@backstage/plugin-catalog-react": "^1.1.4-next.0" + "@backstage/plugin-catalog": "workspace:^", + "@backstage/plugin-catalog-react": "workspace:^" }, "devDependencies": { "@types/react": "^16.13.1 || ^17.0.0" diff --git a/plugins/catalog-graph/CHANGELOG.md b/plugins/catalog-graph/CHANGELOG.md index 5fbaa9ecca..09a41b65c5 100644 --- a/plugins/catalog-graph/CHANGELOG.md +++ b/plugins/catalog-graph/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-graph +## 0.2.21 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + ## 0.2.21-next.2 ### Patch Changes diff --git a/plugins/catalog-graph/package.json b/plugins/catalog-graph/package.json index 995ed3eebe..88a45c4bde 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.21-next.2", + "version": "0.2.21", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,12 +22,12 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-client": "^1.1.0-next.2", - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", - "@backstage/theme": "^0.2.16", + "@backstage/catalog-client": "workspace:^", + "@backstage/catalog-model": "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.57", @@ -43,12 +43,12 @@ "react-router": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/plugin-catalog": "^1.5.1-next.3", - "@backstage/test-utils": "^1.2.0-next.3", - "@backstage/types": "^1.0.0", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/plugin-catalog": "workspace:^", + "@backstage/test-utils": "workspace:^", + "@backstage/types": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/react-hooks": "^8.0.0", diff --git a/plugins/catalog-graphql/CHANGELOG.md b/plugins/catalog-graphql/CHANGELOG.md index 28eafef43b..f2280d2f0a 100644 --- a/plugins/catalog-graphql/CHANGELOG.md +++ b/plugins/catalog-graphql/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-catalog-graphql +## 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 diff --git a/plugins/catalog-graphql/package.json b/plugins/catalog-graphql/package.json index b8c65b2784..7ad5fb68be 100644 --- a/plugins/catalog-graphql/package.json +++ b/plugins/catalog-graphql/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-graphql", "description": "An experimental Backstage catalog GraphQL module", - "version": "0.3.13-next.3", + "version": "0.3.13", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,9 +34,9 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/config": "^1.0.2-next.0", - "@backstage/types": "^1.0.0", + "@backstage/catalog-model": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/types": "workspace:^", "apollo-server": "^3.0.0", "graphql": "^16.0.0", "graphql-modules": "^2.0.0", @@ -46,8 +46,8 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/test-utils": "workspace:^", "@graphql-codegen/cli": "^2.3.1", "@graphql-codegen/graphql-modules-preset": "^2.3.2", "@graphql-codegen/typescript": "^2.4.2", diff --git a/plugins/catalog-import/CHANGELOG.md b/plugins/catalog-import/CHANGELOG.md index 35633dca6a..a1c4d9145f 100644 --- a/plugins/catalog-import/CHANGELOG.md +++ b/plugins/catalog-import/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/plugin-catalog-import +## 0.8.12 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- eadf56bbbf: Bump `git-url-parse` version to `^13.0.0` +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/integration@1.3.1 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + - @backstage/integration-react@1.1.4 + ## 0.8.12-next.3 ### Patch Changes diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json index 895973f1ca..7ec45fc6ed 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.8.12-next.3", + "version": "0.8.12", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,15 +32,15 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-client": "^1.1.0-next.2", - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/config": "^1.0.2-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/integration": "^1.3.1-next.2", - "@backstage/integration-react": "^1.1.4-next.2", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", + "@backstage/catalog-client": "workspace:^", + "@backstage/catalog-model": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/integration": "workspace:^", + "@backstage/integration-react": "workspace:^", + "@backstage/plugin-catalog-react": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -58,10 +58,10 @@ "react-router": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/react-hooks": "^8.0.0", diff --git a/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/PreparePullRequestForm.test.tsx b/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/PreparePullRequestForm.test.tsx index b439366728..3acb7390a9 100644 --- a/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/PreparePullRequestForm.test.tsx +++ b/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/PreparePullRequestForm.test.tsx @@ -87,7 +87,6 @@ describe('', () => { {formState.errors.main && ( diff --git a/plugins/catalog-node/CHANGELOG.md b/plugins/catalog-node/CHANGELOG.md index 0c88527b97..f4c1782da2 100644 --- a/plugins/catalog-node/CHANGELOG.md +++ b/plugins/catalog-node/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-catalog-node +## 1.1.0 + +### Minor Changes + +- 9743bc788c: Added refresh function to the `EntityProviderConnection` to be able to schedule refreshes from entity providers. + +### Patch Changes + +- 7d7d947352: Adds experimental `catalogServiceRef` for obtaining a `CatalogClient` in the new backend system. +- 409ed984e8: Updated usage of experimental backend service APIs. +- 62788b2ee8: The experimental `CatalogProcessingExtensionPoint` now accepts multiple providers and processors at once. +- Updated dependencies + - @backstage/backend-plugin-api@0.1.2 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/errors@1.1.1 + ## 1.1.0-next.2 ### Minor Changes diff --git a/plugins/catalog-node/package.json b/plugins/catalog-node/package.json index 2ef9a738fc..4bd1f5259b 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.1.0-next.2", + "version": "1.1.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -24,16 +24,16 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/backend-plugin-api": "^0.1.2-next.2", - "@backstage/catalog-client": "^1.1.0-next.2", - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/errors": "1.1.1-next.0", - "@backstage/types": "^1.0.0" + "@backstage/backend-plugin-api": "workspace:^", + "@backstage/catalog-client": "workspace:^", + "@backstage/catalog-model": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/types": "workspace:^" }, "devDependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/backend-test-utils": "^0.1.28-next.3", - "@backstage/cli": "^0.19.0-next.3" + "@backstage/backend-common": "workspace:^", + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^" }, "files": [ "dist", diff --git a/plugins/catalog-react/CHANGELOG.md b/plugins/catalog-react/CHANGELOG.md index a0e7bfcae5..00710c2f45 100644 --- a/plugins/catalog-react/CHANGELOG.md +++ b/plugins/catalog-react/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/plugin-catalog-react +## 1.1.4 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- f6033d1121: humanizeEntityRef function can now be forced to include default namespace +- c86741a052: Support showing counts in option labels of the `EntityTagPicker`. You can enable this by adding the `showCounts` property +- 7d47def9c4: Removed dependency on `@types/jest`. +- a6d551fad9: Properly handle free-text entity filtering in the case of empty tag arrays +- ef9ab322de: Minor API signatures cleanup +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-permission-react@0.4.5 + - @backstage/integration@1.3.1 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/errors@1.1.1 + - @backstage/plugin-permission-common@0.6.4 + - @backstage/plugin-catalog-common@1.0.6 + ## 1.1.4-next.2 ### Patch Changes diff --git a/plugins/catalog-react/package.json b/plugins/catalog-react/package.json index 962c859c62..759aa6e4a9 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.1.4-next.2", + "version": "1.1.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,18 +33,18 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/catalog-client": "^1.1.0-next.2", - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/integration": "^1.3.1-next.2", - "@backstage/plugin-catalog-common": "^1.0.6-next.0", - "@backstage/plugin-permission-common": "^0.6.4-next.2", - "@backstage/plugin-permission-react": "^0.4.5-next.2", - "@backstage/theme": "^0.2.16", - "@backstage/types": "^1.0.0", - "@backstage/version-bridge": "^1.0.1", + "@backstage/catalog-client": "workspace:^", + "@backstage/catalog-model": "workspace:^", + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/integration": "workspace:^", + "@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", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -62,11 +62,11 @@ "react-router": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/plugin-catalog-common": "^1.0.6-next.0", - "@backstage/plugin-scaffolder-common": "^1.2.0-next.1", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/plugin-catalog-common": "workspace:^", + "@backstage/plugin-scaffolder-common": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/react-hooks": "^8.0.0", diff --git a/plugins/catalog/CHANGELOG.md b/plugins/catalog/CHANGELOG.md index 51507389cf..57a1c60174 100644 --- a/plugins/catalog/CHANGELOG.md +++ b/plugins/catalog/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/plugin-catalog +## 1.5.1 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- d669d89206: Minor API signatures cleanup +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/plugin-search-react@1.1.0 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/errors@1.1.1 + - @backstage/integration-react@1.1.4 + - @backstage/plugin-catalog-common@1.0.6 + - @backstage/plugin-search-common@1.0.1 + ## 1.5.1-next.3 ### Patch Changes diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index 2610c9db93..99361b6a3d 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.5.1-next.3", + "version": "1.5.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,18 +32,18 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-client": "^1.1.0-next.2", - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/integration-react": "^1.1.4-next.2", - "@backstage/plugin-catalog-common": "^1.0.6-next.0", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", - "@backstage/plugin-search-common": "^1.0.1-next.0", - "@backstage/plugin-search-react": "^1.1.0-next.2", - "@backstage/theme": "^0.2.16", - "@backstage/types": "^1.0.0", + "@backstage/catalog-client": "workspace:^", + "@backstage/catalog-model": "workspace:^", + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/integration-react": "workspace:^", + "@backstage/plugin-catalog-common": "workspace:^", + "@backstage/plugin-catalog-react": "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.57", @@ -59,11 +59,11 @@ "react-router": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/plugin-permission-react": "^0.4.5-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/plugin-permission-react": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/cicd-statistics-module-gitlab/CHANGELOG.md b/plugins/cicd-statistics-module-gitlab/CHANGELOG.md index 32ababf2d9..01dd968ad6 100644 --- a/plugins/cicd-statistics-module-gitlab/CHANGELOG.md +++ b/plugins/cicd-statistics-module-gitlab/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-cicd-statistics-module-gitlab +## 0.1.5 + +### Patch Changes + +- 71b7464a7c: Fixing typo in the Readme file: `'@backstage plugin-cicd-statistics-module-gitlab';` -> `'@backstage/plugin-cicd-statistics-module-gitlab';` +- a98f5d4c21: add the ability to add CICD default options to createGitlabApi constructor +- Updated dependencies + - @backstage/core-plugin-api@1.0.6 + - @backstage/catalog-model@1.1.1 + - @backstage/plugin-cicd-statistics@0.1.11 + ## 0.1.5-next.1 ### Patch Changes diff --git a/plugins/cicd-statistics-module-gitlab/README.md b/plugins/cicd-statistics-module-gitlab/README.md index 0b11f6950a..67da1c2291 100644 --- a/plugins/cicd-statistics-module-gitlab/README.md +++ b/plugins/cicd-statistics-module-gitlab/README.md @@ -7,13 +7,14 @@ This is an extension module to the `cicd-statistics` plugin, providing a `CicdSt 1. Install the `cicd-statistics` and `cicd-statistics-module-gitlab` plugins in the `app` package. 2. Configure your ApiFactory: + - You can optionally pass in a second argument to `CicdStatisticsApiGitlab` of type [CicdDefaults](https://github.com/backstage/backstage/blob/2881c53cb383bf127c150f837f37fe535d8cf97b/plugins/cicd-statistics/src/apis/types.ts#L179) to alter the default CICD UI configuration ```tsx // packages/app/src/apis.ts import { gitlabAuthApiRef } from '@backstage/core-plugin-api'; import { cicdStatisticsApiRef } from '@backstage/plugin-cicd-statistics'; -import { CicdStatisticsApiGitlab } from '@backstage plugin-cicd-statistics-module-gitlab'; +import { CicdStatisticsApiGitlab } from '@backstage/plugin-cicd-statistics-module-gitlab'; export const apis: AnyApiFactory[] = [ createApiFactory({ diff --git a/plugins/cicd-statistics-module-gitlab/api-report.md b/plugins/cicd-statistics-module-gitlab/api-report.md index 5e07255f54..a0364afa31 100644 --- a/plugins/cicd-statistics-module-gitlab/api-report.md +++ b/plugins/cicd-statistics-module-gitlab/api-report.md @@ -4,6 +4,7 @@ ```ts import { CicdConfiguration } from '@backstage/plugin-cicd-statistics'; +import { CicdDefaults } from '@backstage/plugin-cicd-statistics'; import { CicdState } from '@backstage/plugin-cicd-statistics'; import { CicdStatisticsApi } from '@backstage/plugin-cicd-statistics'; import { Entity } from '@backstage/catalog-model'; @@ -13,7 +14,7 @@ import { OAuthApi } from '@backstage/core-plugin-api'; // @public export class CicdStatisticsApiGitlab implements CicdStatisticsApi { - constructor(gitLabAuthApi: OAuthApi); + constructor(gitLabAuthApi: OAuthApi, cicdDefaults?: Partial); // (undocumented) createGitlabApi(entity: Entity, scopes: string[]): Promise; // (undocumented) diff --git a/plugins/cicd-statistics-module-gitlab/package.json b/plugins/cicd-statistics-module-gitlab/package.json index ee8eaed465..a8c4ef7dec 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.5-next.1", + "version": "0.1.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -28,16 +28,16 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/plugin-cicd-statistics": "^0.1.11-next.2", + "@backstage/catalog-model": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/plugin-cicd-statistics": "workspace:^", "@gitbeaker/browser": "^35.6.0", "@gitbeaker/core": "^35.6.0", "luxon": "^3.0.0", "p-limit": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3" + "@backstage/cli": "workspace:^" }, "files": [ "dist" diff --git a/plugins/cicd-statistics-module-gitlab/src/api/gitlab.ts b/plugins/cicd-statistics-module-gitlab/src/api/gitlab.ts index 7439d1800c..5e4384fe88 100644 --- a/plugins/cicd-statistics-module-gitlab/src/api/gitlab.ts +++ b/plugins/cicd-statistics-module-gitlab/src/api/gitlab.ts @@ -18,6 +18,7 @@ import { CicdStatisticsApi, CicdState, CicdConfiguration, + CicdDefaults, Build, FetchBuildsOptions, Stage, @@ -47,9 +48,14 @@ export type GitlabClient = { */ export class CicdStatisticsApiGitlab implements CicdStatisticsApi { readonly #gitLabAuthApi: OAuthApi; + readonly #cicdDefaults: Partial; - constructor(gitLabAuthApi: OAuthApi) { + constructor( + gitLabAuthApi: OAuthApi, + cicdDefaults: Partial = {}, + ) { this.#gitLabAuthApi = gitLabAuthApi; + this.#cicdDefaults = cicdDefaults; } public async createGitlabApi( @@ -154,6 +160,7 @@ export class CicdStatisticsApiGitlab implements CicdStatisticsApi { 'expired', 'unknown', ] as const, + defaults: this.#cicdDefaults, }; } } diff --git a/plugins/cicd-statistics/CHANGELOG.md b/plugins/cicd-statistics/CHANGELOG.md index ac1cd23660..6bda1cf68d 100644 --- a/plugins/cicd-statistics/CHANGELOG.md +++ b/plugins/cicd-statistics/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-cicd-statistics +## 0.1.11 + +### Patch Changes + +- d669d89206: Minor API signatures cleanup +- Updated dependencies + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + ## 0.1.11-next.2 ### Patch Changes diff --git a/plugins/cicd-statistics/package.json b/plugins/cicd-statistics/package.json index 6394baaf94..b4c1e7bb15 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.11-next.2", + "version": "0.1.11", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,14 +32,14 @@ "start": "backstage-cli package start" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", + "@backstage/cli": "workspace:^", "@types/luxon": "^3.0.0", "@types/react": "^16.13.1 || ^17.0.0" }, "dependencies": { - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", + "@backstage/catalog-model": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/plugin-catalog-react": "workspace:^", "@date-io/luxon": "^1.3.13", "@material-ui/core": "^4.9.13", "@material-ui/icons": "^4.11.2", diff --git a/plugins/circleci/CHANGELOG.md b/plugins/circleci/CHANGELOG.md index 44ccf89c42..f020e67b0f 100644 --- a/plugins/circleci/CHANGELOG.md +++ b/plugins/circleci/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-circleci +## 0.3.9 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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`. +- ef9ab322de: Minor API signatures cleanup +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + ## 0.3.9-next.3 ### Patch Changes diff --git a/plugins/circleci/package.json b/plugins/circleci/package.json index 229ff9fb11..7363bd98f0 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.9-next.3", + "version": "0.3.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,11 +33,11 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", - "@backstage/theme": "^0.2.16", + "@backstage/catalog-model": "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.57", @@ -53,10 +53,10 @@ "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/cloudbuild/CHANGELOG.md b/plugins/cloudbuild/CHANGELOG.md index 35a8a675e0..5c01b5be4b 100644 --- a/plugins/cloudbuild/CHANGELOG.md +++ b/plugins/cloudbuild/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/plugin-cloudbuild +## 0.3.9 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 3f739be9d9: Minor API signatures cleanup +- 763fb81e82: Internal refactor to use more type safe code when dealing with route parameters. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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`. +- ef9ab322de: Minor API signatures cleanup +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + ## 0.3.9-next.3 ### Patch Changes diff --git a/plugins/cloudbuild/package.json b/plugins/cloudbuild/package.json index 6215547041..3b20b28c3d 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.9-next.3", + "version": "0.3.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,11 +33,11 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", - "@backstage/theme": "^0.2.16", + "@backstage/catalog-model": "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.57", @@ -51,10 +51,10 @@ "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/code-climate/CHANGELOG.md b/plugins/code-climate/CHANGELOG.md index 3d45e5c3a2..418421aafe 100644 --- a/plugins/code-climate/CHANGELOG.md +++ b/plugins/code-climate/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-code-climate +## 0.1.9 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + ## 0.1.9-next.3 ### Patch Changes diff --git a/plugins/code-climate/package.json b/plugins/code-climate/package.json index 464142f680..1863e3e080 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.9-next.3", + "version": "0.1.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,11 +22,11 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", - "@backstage/theme": "^0.2.16", + "@backstage/catalog-model": "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.57", @@ -39,9 +39,9 @@ "react-router": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/code-coverage-backend/CHANGELOG.md b/plugins/code-coverage-backend/CHANGELOG.md index 2d440fd31b..9001fbeab0 100644 --- a/plugins/code-coverage-backend/CHANGELOG.md +++ b/plugins/code-coverage-backend/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-code-coverage-backend +## 0.2.2 + +### Patch Changes + +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- 8872cc735d: Fixed a bug where the database option to skip migrations was ignored. +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/integration@1.3.1 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + ## 0.2.2-next.2 ### Patch Changes diff --git a/plugins/code-coverage-backend/package.json b/plugins/code-coverage-backend/package.json index bbc5714fb8..3cf9b2f087 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.2-next.2", + "version": "0.2.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,12 +23,12 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/catalog-client": "^1.1.0-next.2", - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/config": "^1.0.2-next.0", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/integration": "^1.3.1-next.2", + "@backstage/backend-common": "workspace:^", + "@backstage/catalog-client": "workspace:^", + "@backstage/catalog-model": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/integration": "workspace:^", "@types/express": "^4.17.6", "express": "^4.17.1", "express-promise-router": "^4.1.0", @@ -39,7 +39,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", + "@backstage/cli": "workspace:^", "@types/express-xml-bodyparser": "^0.3.2", "@types/supertest": "^2.0.8", "msw": "^0.47.0", diff --git a/plugins/code-coverage/CHANGELOG.md b/plugins/code-coverage/CHANGELOG.md index 9e120afd38..b8e384fbd7 100644 --- a/plugins/code-coverage/CHANGELOG.md +++ b/plugins/code-coverage/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-code-coverage +## 0.2.2 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + ## 0.2.2-next.3 ### Patch Changes diff --git a/plugins/code-coverage/package.json b/plugins/code-coverage/package.json index c3f992a428..ab4e071ccc 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.2-next.3", + "version": "0.2.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,13 +23,13 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/config": "^1.0.2-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", - "@backstage/theme": "^0.2.16", + "@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.57", @@ -45,10 +45,10 @@ "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/codescene/CHANGELOG.md b/plugins/codescene/CHANGELOG.md index aa43d5edd3..b5d70d9d17 100644 --- a/plugins/codescene/CHANGELOG.md +++ b/plugins/codescene/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-codescene +## 0.1.4 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + ## 0.1.4-next.3 ### Patch Changes diff --git a/plugins/codescene/package.json b/plugins/codescene/package.json index bc709a215c..884b751347 100644 --- a/plugins/codescene/package.json +++ b/plugins/codescene/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-codescene", - "version": "0.1.4-next.3", + "version": "0.1.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,11 +22,11 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/config": "^1.0.2-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/theme": "^0.2.16", + "@backstage/config": "workspace:^", + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/theme": "workspace:^", "@material-ui/core": "^4.9.10", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "^4.0.0-alpha.57", @@ -38,10 +38,10 @@ "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/config-schema/CHANGELOG.md b/plugins/config-schema/CHANGELOG.md index 3e7483e879..88d12a9da1 100644 --- a/plugins/config-schema/CHANGELOG.md +++ b/plugins/config-schema/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-config-schema +## 0.1.32 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + ## 0.1.32-next.3 ### Patch Changes diff --git a/plugins/config-schema/package.json b/plugins/config-schema/package.json index 7f650fb4bc..cf2cb6cf90 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.32-next.3", + "version": "0.1.32", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,12 +23,12 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/config": "^1.0.2-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/theme": "^0.2.16", - "@backstage/types": "^1.0.0", + "@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", "@material-ui/lab": "4.0.0-alpha.57", @@ -40,10 +40,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/cost-insights-common/package.json b/plugins/cost-insights-common/package.json index ff458b0a5c..d675e0a548 100644 --- a/plugins/cost-insights-common/package.json +++ b/plugins/cost-insights-common/package.json @@ -32,7 +32,7 @@ "clean": "backstage-cli package clean" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.1" + "@backstage/cli": "workspace:^" }, "files": [ "dist" diff --git a/plugins/cost-insights/CHANGELOG.md b/plugins/cost-insights/CHANGELOG.md index fec45acdd1..1bb7d5aa75 100644 --- a/plugins/cost-insights/CHANGELOG.md +++ b/plugins/cost-insights/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-cost-insights +## 0.11.31 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 9318bf15d4: The `CostInsightsHeader`component now uses group names if available +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + ## 0.11.31-next.3 ### Patch Changes diff --git a/plugins/cost-insights/package.json b/plugins/cost-insights/package.json index 8034195d62..fc128f405f 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.11.31-next.3", + "version": "0.11.31", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,12 +32,12 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/config": "^1.0.2-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/plugin-cost-insights-common": "^0.1.1", - "@backstage/theme": "^0.2.16", + "@backstage/catalog-model": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/plugin-cost-insights-common": "workspace:^", + "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -59,10 +59,10 @@ "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/dynatrace/CHANGELOG.md b/plugins/dynatrace/CHANGELOG.md index 33e547a2bf..ae367016e3 100644 --- a/plugins/dynatrace/CHANGELOG.md +++ b/plugins/dynatrace/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-dynatrace +## 0.2.0 + +### Minor Changes + +- e44c0b3811: New features: + + - Some visual improvements to the table that displays Problems + - Added support for viewing recent Synthetics results using + - Added some additional linking to the configured Dynatrace instance + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 148568b5c2: Switched to using node-fetch instead of cross-fetch as is standard for our backend packages +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/catalog-model@1.1.1 + ## 0.2.0-next.3 ### Patch Changes diff --git a/plugins/dynatrace/package.json b/plugins/dynatrace/package.json index 3df69ca25f..d8b3cb06a8 100644 --- a/plugins/dynatrace/package.json +++ b/plugins/dynatrace/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-dynatrace", - "version": "0.2.0-next.3", + "version": "0.2.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,24 +22,24 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/theme": "^0.2.16", + "@backstage/catalog-model": "workspace:^", + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/theme": "workspace:^", "@material-ui/core": "^4.9.13", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", "react-use": "^17.2.4" }, "peerDependencies": { - "@backstage/plugin-catalog-react": "^1.1.4-next.0", + "@backstage/plugin-catalog-react": "workspace:^", "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/example-todo-list-backend/CHANGELOG.md b/plugins/example-todo-list-backend/CHANGELOG.md index f3bdba1397..5bc46323d8 100644 --- a/plugins/example-todo-list-backend/CHANGELOG.md +++ b/plugins/example-todo-list-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @internal/plugin-todo-list-backend +## 1.0.5 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/plugin-auth-node@0.2.5 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + ## 1.0.5-next.1 ### Patch Changes diff --git a/plugins/example-todo-list-backend/package.json b/plugins/example-todo-list-backend/package.json index 5623c22f58..295aad4021 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.5-next.1", + "version": "1.0.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,10 +23,10 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/config": "^1.0.2-next.0", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/plugin-auth-node": "^0.2.5-next.3", + "@backstage/backend-common": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/plugin-auth-node": "workspace:^", "@types/express": "^4.17.6", "express": "^4.17.1", "express-promise-router": "^4.1.0", @@ -35,7 +35,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", + "@backstage/cli": "workspace:^", "@types/supertest": "^2.0.8", "@types/uuid": "^8.0.0", "msw": "^0.47.0", diff --git a/plugins/example-todo-list-common/CHANGELOG.md b/plugins/example-todo-list-common/CHANGELOG.md index ed40a99c3e..3754f768ab 100644 --- a/plugins/example-todo-list-common/CHANGELOG.md +++ b/plugins/example-todo-list-common/CHANGELOG.md @@ -1,5 +1,12 @@ # @internal/plugin-todo-list-common +## 1.0.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.6.4 + ## 1.0.4-next.0 ### Patch Changes diff --git a/plugins/example-todo-list-common/package.json b/plugins/example-todo-list-common/package.json index 564d56e784..32dfe96ef4 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.4-next.0", + "version": "1.0.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,13 +23,13 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/plugin-permission-common": "^0.6.4-next.0" + "@backstage/plugin-permission-common": "workspace:^" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.1", - "@backstage/core-app-api": "^1.1.0-next.1", - "@backstage/dev-utils": "^1.0.6-next.1", - "@backstage/test-utils": "^1.2.0-next.1", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", "msw": "^0.47.0" diff --git a/plugins/example-todo-list/CHANGELOG.md b/plugins/example-todo-list/CHANGELOG.md index b096ccfa4e..be969303aa 100644 --- a/plugins/example-todo-list/CHANGELOG.md +++ b/plugins/example-todo-list/CHANGELOG.md @@ -1,5 +1,13 @@ # @internal/plugin-todo-list +## 1.0.5 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + ## 1.0.5-next.0 ### Patch Changes diff --git a/plugins/example-todo-list/package.json b/plugins/example-todo-list/package.json index 07cf546d1d..9b66c0c0a9 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.5-next.0", + "version": "1.0.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,9 +23,9 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.11.1-next.1", - "@backstage/core-plugin-api": "^1.0.6-next.1", - "@backstage/theme": "^0.2.16", + "@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.57", @@ -35,10 +35,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.1", - "@backstage/core-app-api": "^1.1.0-next.1", - "@backstage/dev-utils": "^1.0.6-next.1", - "@backstage/test-utils": "^1.2.0-next.1", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/explore-react/CHANGELOG.md b/plugins/explore-react/CHANGELOG.md index 0a1d2c795d..e35dae9e32 100644 --- a/plugins/explore-react/CHANGELOG.md +++ b/plugins/explore-react/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-explore-react +## 0.0.21 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-plugin-api@1.0.6 + ## 0.0.21-next.3 ### Patch Changes diff --git a/plugins/explore-react/package.json b/plugins/explore-react/package.json index 1e715965a8..66ac17f785 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.21-next.3", + "version": "0.0.21", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,12 +32,12 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/core-plugin-api": "^1.0.6-next.3" + "@backstage/core-plugin-api": "workspace:^" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/explore/CHANGELOG.md b/plugins/explore/CHANGELOG.md index c558be8b63..3e803d2d6b 100644 --- a/plugins/explore/CHANGELOG.md +++ b/plugins/explore/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-explore +## 0.3.40 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 3f739be9d9: Minor API signatures cleanup +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + - @backstage/plugin-explore-react@0.0.21 + ## 0.3.40-next.3 ### Patch Changes diff --git a/plugins/explore/package.json b/plugins/explore/package.json index c0a5453c02..b9b9257a3a 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.3.40-next.3", + "version": "0.3.40", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,12 +32,12 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", - "@backstage/plugin-explore-react": "^0.0.21-next.3", - "@backstage/theme": "^0.2.16", + "@backstage/catalog-model": "workspace:^", + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/plugin-catalog-react": "workspace:^", + "@backstage/plugin-explore-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", @@ -51,10 +51,10 @@ "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/firehydrant/CHANGELOG.md b/plugins/firehydrant/CHANGELOG.md index 1e55a1fdfa..eae65d3c36 100644 --- a/plugins/firehydrant/CHANGELOG.md +++ b/plugins/firehydrant/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-firehydrant +## 0.1.26 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + ## 0.1.26-next.3 ### Patch Changes diff --git a/plugins/firehydrant/package.json b/plugins/firehydrant/package.json index bc10c957c6..37aa7b259b 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.1.26-next.3", + "version": "0.1.26", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,10 +23,10 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", - "@backstage/theme": "^0.2.16", + "@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.57", @@ -37,10 +37,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/fossa/CHANGELOG.md b/plugins/fossa/CHANGELOG.md index 05ec48b992..3126dbc0e1 100644 --- a/plugins/fossa/CHANGELOG.md +++ b/plugins/fossa/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-fossa +## 0.2.41 + +### Patch Changes + +- 3f739be9d9: Minor API signatures cleanup +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + - @backstage/errors@1.1.1 + ## 0.2.41-next.2 ### Patch Changes diff --git a/plugins/fossa/package.json b/plugins/fossa/package.json index c96353f3d6..bf249c1b9d 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.41-next.2", + "version": "0.2.41", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,12 +33,12 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", - "@backstage/theme": "^0.2.16", + "@backstage/catalog-model": "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.57", @@ -51,10 +51,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/gcalendar/CHANGELOG.md b/plugins/gcalendar/CHANGELOG.md index f87f087880..2be25841e7 100644 --- a/plugins/gcalendar/CHANGELOG.md +++ b/plugins/gcalendar/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-gcalendar +## 0.3.5 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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`. +- a69ac5b63a: Upgrade `react-query:3` to `@tanstack/react-query:4` +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/errors@1.1.1 + ## 0.3.5-next.3 ### Patch Changes diff --git a/plugins/gcalendar/package.json b/plugins/gcalendar/package.json index fbcc9b0c33..9ef566e95c 100644 --- a/plugins/gcalendar/package.json +++ b/plugins/gcalendar/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-gcalendar", - "version": "0.3.5-next.3", + "version": "0.3.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,10 +22,10 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/theme": "^0.2.16", + "@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.57", @@ -43,10 +43,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/gcp-projects/CHANGELOG.md b/plugins/gcp-projects/CHANGELOG.md index cbd55e8414..d4e54838c4 100644 --- a/plugins/gcp-projects/CHANGELOG.md +++ b/plugins/gcp-projects/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-gcp-projects +## 0.3.28 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + ## 0.3.28-next.3 ### Patch Changes diff --git a/plugins/gcp-projects/package.json b/plugins/gcp-projects/package.json index 601d491184..d2926de41b 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.28-next.3", + "version": "0.3.28", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,9 +33,9 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/theme": "^0.2.16", + "@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.57", @@ -46,10 +46,10 @@ "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/git-release-manager/CHANGELOG.md b/plugins/git-release-manager/CHANGELOG.md index 1dc0bd72bd..0c7f930e60 100644 --- a/plugins/git-release-manager/CHANGELOG.md +++ b/plugins/git-release-manager/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-git-release-manager +## 0.3.22 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 3f739be9d9: Minor API signatures cleanup +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/integration@1.3.1 + ## 0.3.22-next.3 ### Patch Changes diff --git a/plugins/git-release-manager/package.json b/plugins/git-release-manager/package.json index fb56a6d0e1..89061cc510 100644 --- a/plugins/git-release-manager/package.json +++ b/plugins/git-release-manager/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-git-release-manager", "description": "A Backstage plugin that helps you manage releases in git", - "version": "0.3.22-next.3", + "version": "0.3.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,10 +23,10 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/integration": "^1.3.1-next.2", - "@backstage/theme": "^0.2.16", + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/integration": "workspace:^", + "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -42,10 +42,10 @@ "react-router": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/react-hooks": "^8.0.0", diff --git a/plugins/git-release-manager/src/api/GitReleaseClient.test.ts b/plugins/git-release-manager/src/api/GitReleaseClient.test.ts index 418da485a2..2b1877d487 100644 --- a/plugins/git-release-manager/src/api/GitReleaseClient.test.ts +++ b/plugins/git-release-manager/src/api/GitReleaseClient.test.ts @@ -52,7 +52,7 @@ describe('GitReleaseClient', () => { "getRepository": [Function], "getTag": [Function], "getUser": [Function], - "githubAuthApi": Object { + "githubAuthApi": { "getAccessToken": [MockFunction], }, "host": "github.com", diff --git a/plugins/git-release-manager/src/api/serviceApiRef.test.ts b/plugins/git-release-manager/src/api/serviceApiRef.test.ts index b27738671d..0ac1c89265 100644 --- a/plugins/git-release-manager/src/api/serviceApiRef.test.ts +++ b/plugins/git-release-manager/src/api/serviceApiRef.test.ts @@ -22,7 +22,7 @@ describe('gitReleaseManagerApiRef', () => { expect(result).toMatchInlineSnapshot(` ApiRefImpl { - "config": Object { + "config": { "id": "plugin.git-release-manager.service", }, } diff --git a/plugins/git-release-manager/src/constants/constants.test.ts b/plugins/git-release-manager/src/constants/constants.test.ts index fb475bd577..49b5f90c7f 100644 --- a/plugins/git-release-manager/src/constants/constants.test.ts +++ b/plugins/git-release-manager/src/constants/constants.test.ts @@ -19,19 +19,19 @@ import * as constants from './constants'; describe('constants', () => { it('should match snapshot', () => { expect(constants).toMatchInlineSnapshot(` - Object { - "DISABLE_CACHE": Object { - "headers": Object { + { + "DISABLE_CACHE": { + "headers": { "If-None-Match": "", }, }, - "SEMVER_PARTS": Object { + "SEMVER_PARTS": { "major": "major", "minor": "minor", "patch": "patch", }, "TAG_OBJECT_MESSAGE": "Tag generated by your friendly neighborhood Backstage Release Manager", - "VERSIONING_STRATEGIES": Object { + "VERSIONING_STRATEGIES": { "calver": "calver", "semver": "semver", }, diff --git a/plugins/git-release-manager/src/features/CreateReleaseCandidate/hooks/useCreateReleaseCandidate.test.tsx b/plugins/git-release-manager/src/features/CreateReleaseCandidate/hooks/useCreateReleaseCandidate.test.tsx index 3128fde9c8..25a987df2a 100644 --- a/plugins/git-release-manager/src/features/CreateReleaseCandidate/hooks/useCreateReleaseCandidate.test.tsx +++ b/plugins/git-release-manager/src/features/CreateReleaseCandidate/hooks/useCreateReleaseCandidate.test.tsx @@ -72,37 +72,37 @@ describe('useCreateReleaseCandidate', () => { expect(result.current.responseSteps).toHaveLength(7); expect(result.current).toMatchInlineSnapshot(` - Object { + { "progress": 100, - "responseSteps": Array [ - Object { + "responseSteps": [ + { "link": "https://latestCommit.html_url", - "message": "Fetched latest commit from \\"mock_defaultBranch\\"", - "secondaryMessage": "with message \\"latestCommit.commit.message\\"", + "message": "Fetched latest commit from "mock_defaultBranch"", + "secondaryMessage": "with message "latestCommit.commit.message"", }, - Object { + { "message": "Created Release Branch", - "secondaryMessage": "with ref \\"mock_createRef_ref\\"", + "secondaryMessage": "with ref "mock_createRef_ref"", }, - Object { + { "message": "Created Tag Object", - "secondaryMessage": "with sha \\"mock_tag_object_sha\\"", + "secondaryMessage": "with sha "mock_tag_object_sha"", }, - Object { + { "message": "Cut Tag Reference", - "secondaryMessage": "with ref \\"mock_createRef_ref\\"", + "secondaryMessage": "with ref "mock_createRef_ref"", }, - Object { + { "link": "https://mock_compareCommits_html_url", "message": "Fetched commit comparison", "secondaryMessage": "rc/2020.01.01_1...rc/2020.01.01_1", }, - Object { + { "link": "https://mock_createRelease_html_url", - "message": "Created Release Candidate \\"mock_createRelease_name\\"", - "secondaryMessage": "with tag \\"rc-2020.01.01_1\\"", + "message": "Created Release Candidate "mock_createRelease_name"", + "secondaryMessage": "with tag "rc-2020.01.01_1"", }, - Object { + { "icon": "success", "message": "Success callback successfully called 🚀", }, diff --git a/plugins/git-release-manager/src/features/Patch/hooks/usePatch.test.ts b/plugins/git-release-manager/src/features/Patch/hooks/usePatch.test.ts index f3b94c2476..0bd7f27cdb 100644 --- a/plugins/git-release-manager/src/features/Patch/hooks/usePatch.test.ts +++ b/plugins/git-release-manager/src/features/Patch/hooks/usePatch.test.ts @@ -75,91 +75,91 @@ describe('patch', () => { expect(result.error).toEqual(undefined); expect(result.current.responseSteps).toHaveLength(19); expect(result.current).toMatchInlineSnapshot(` - Object { + { "progress": 100, - "responseSteps": Array [ - Object { + "responseSteps": [ + { "message": , }, - Object { + { "message": , }, - Object { + { "message": , }, - Object { + { "message": , }, - Object { + { "message": , }, - Object { + { "message": , }, - Object { + { "message": , }, - Object { + { "message": , }, - Object { + { "message": , }, - Object { + { "link": "https://mock_branch_links_html", - "message": "Fetched release branch \\"rc/1.2.3\\"", + "message": "Fetched release branch "rc/1.2.3"", }, - Object { + { "message": "Created temporary commit", - "secondaryMessage": "with message \\"mock_commit_message\\"", + "secondaryMessage": "with message "mock_commit_message"", }, - Object { - "message": "Forced branch \\"rc/2020.01.01_1\\" to temporary commit \\"mock_commit_sha\\"", + { + "message": "Forced branch "rc/2020.01.01_1" to temporary commit "mock_commit_sha"", }, - Object { + { "link": "https://mock_merge_html_url", - "message": "Merged temporary commit into \\"rc/2020.01.01_1\\"", - "secondaryMessage": "with message \\"mock_merge_commit_message\\"", + "message": "Merged temporary commit into "rc/2020.01.01_1"", + "secondaryMessage": "with message "mock_merge_commit_message"", }, - Object { - "message": "Cherry-picked patch commit to \\"mock_branch_commit_sha\\"", - "secondaryMessage": "with message \\"mock_commit_message\\"", + { + "message": "Cherry-picked patch commit to "mock_branch_commit_sha"", + "secondaryMessage": "with message "mock_commit_message"", }, - Object { - "message": "Updated reference \\"mock_update_ref_ref\\"", + { + "message": "Updated reference "mock_update_ref_ref"", }, - Object { + { "message": "Created new tag object", - "secondaryMessage": "with name \\"mock_tag_object_tag\\"", + "secondaryMessage": "with name "mock_tag_object_tag"", }, - Object { - "message": "Created new reference \\"mock_createRef_ref\\"", - "secondaryMessage": "for tag object \\"mock_tag_object_tag\\"", + { + "message": "Created new reference "mock_createRef_ref"", + "secondaryMessage": "for tag object "mock_tag_object_tag"", }, - Object { + { "link": "https://mock_update_release_html_url", - "message": "Updated release \\"mock_update_release_name\\"", + "message": "Updated release "mock_update_release_name"", "secondaryMessage": "with tag mock_update_release_tag_name", }, - Object { + { "icon": "success", "message": "Success callback successfully called 🚀", }, diff --git a/plugins/git-release-manager/src/features/PromoteRc/hooks/usePromoteRc.test.ts b/plugins/git-release-manager/src/features/PromoteRc/hooks/usePromoteRc.test.ts index ff1c58b5be..f4e0fcb081 100644 --- a/plugins/git-release-manager/src/features/PromoteRc/hooks/usePromoteRc.test.ts +++ b/plugins/git-release-manager/src/features/PromoteRc/hooks/usePromoteRc.test.ts @@ -72,27 +72,27 @@ describe('usePromoteRc', () => { expect(result.current.responseSteps).toHaveLength(5); expect(result.current).toMatchInlineSnapshot(` - Object { + { "progress": 100, - "responseSteps": Array [ - Object { + "responseSteps": [ + { "message": "Fetched most recent commit from release branch", - "secondaryMessage": "with sha \\"latestCommit.sha\\"", + "secondaryMessage": "with sha "latestCommit.sha"", }, - Object { + { "message": "Created Tag Object", - "secondaryMessage": "with sha \\"mock_tag_object_sha\\"", + "secondaryMessage": "with sha "mock_tag_object_sha"", }, - Object { + { "message": "Create Tag Reference", - "secondaryMessage": "with ref \\"mock_createRef_ref\\"", + "secondaryMessage": "with ref "mock_createRef_ref"", }, - Object { + { "link": "https://mock_update_release_html_url", - "message": "Promoted \\"mock_update_release_name\\"", - "secondaryMessage": "from \\"rc-2020.01.01_1\\" to \\"mock_update_release_tag_name\\"", + "message": "Promoted "mock_update_release_name"", + "secondaryMessage": "from "rc-2020.01.01_1" to "mock_update_release_tag_name"", }, - Object { + { "icon": "success", "message": "Success callback successfully called 🚀", }, diff --git a/plugins/git-release-manager/src/features/RepoDetailsForm/Owner.test.tsx b/plugins/git-release-manager/src/features/RepoDetailsForm/Owner.test.tsx index e8798f3ce0..d73f6bf2aa 100644 --- a/plugins/git-release-manager/src/features/RepoDetailsForm/Owner.test.tsx +++ b/plugins/git-release-manager/src/features/RepoDetailsForm/Owner.test.tsx @@ -71,7 +71,7 @@ describe('Owner', () => { await waitFor(() => screen.getAllByTestId(TEST_IDS.form.owner.empty)); expect(getAllByTestId(TEST_IDS.form.owner.empty)).toMatchInlineSnapshot(` - Array [ + [

{ await waitFor(() => screen.getAllByTestId(TEST_IDS.form.repo.empty)); expect(getAllByTestId(TEST_IDS.form.repo.empty)).toMatchInlineSnapshot(` - Array [ + [

{ fireEvent.click(radio2); expect(mockNavigate.mock.calls).toMatchInlineSnapshot(` - Array [ - Array [ + [ + [ "?versioningStrategy=calver&owner=mock_owner&repo=mock_repo", - Object { + { "replace": true, }, ], diff --git a/plugins/git-release-manager/src/features/Stats/Info/helpers/getReleaseCommitPairs.test.tsx b/plugins/git-release-manager/src/features/Stats/Info/helpers/getReleaseCommitPairs.test.tsx index 5b800a4df5..4e946d965c 100644 --- a/plugins/git-release-manager/src/features/Stats/Info/helpers/getReleaseCommitPairs.test.tsx +++ b/plugins/git-release-manager/src/features/Stats/Info/helpers/getReleaseCommitPairs.test.tsx @@ -96,29 +96,29 @@ describe('getReleaseCommitPairs', () => { }); expect(result).toMatchInlineSnapshot(` - Object { - "releaseCommitPairs": Array [ - Object { + { + "releaseCommitPairs": [ + { "baseVersion": "2.0", - "endCommit": Object { + "endCommit": { "tagName": "version-2.0.0", "tagSha": "sha-2.0.0", "tagType": "tag", }, - "startCommit": Object { + "startCommit": { "tagName": "rc-2.0.0", "tagSha": "sha-2.0.0", "tagType": "tag", }, }, - Object { + { "baseVersion": "3.0", - "endCommit": Object { + "endCommit": { "tagName": "version-3.0.1", "tagSha": "sha-3.0.1", "tagType": "tag", }, - "startCommit": Object { + "startCommit": { "tagName": "rc-3.0.0", "tagSha": "sha-3.0.0", "tagType": "tag", diff --git a/plugins/git-release-manager/src/features/Stats/helpers/getMappedReleases.test.tsx b/plugins/git-release-manager/src/features/Stats/helpers/getMappedReleases.test.tsx index b0467b1260..1989cd9c09 100644 --- a/plugins/git-release-manager/src/features/Stats/helpers/getMappedReleases.test.tsx +++ b/plugins/git-release-manager/src/features/Stats/helpers/getMappedReleases.test.tsx @@ -33,27 +33,27 @@ describe('getMappedReleases', () => { }); expect(result).toMatchInlineSnapshot(` - Object { - "mappedReleases": Object { - "releases": Object { - "1.0": Object { + { + "mappedReleases": { + "releases": { + "1.0": { "baseVersion": "1.0", - "candidates": Array [], + "candidates": [], "createdAt": "2021-01-01T10:11:12Z", "htmlUrl": "html_url", - "versions": Array [], + "versions": [], }, - "1.1": Object { + "1.1": { "baseVersion": "1.1", - "candidates": Array [], + "candidates": [], "createdAt": "2021-01-01T10:11:12Z", "htmlUrl": "html_url", - "versions": Array [], + "versions": [], }, }, - "unmappableTags": Array [], - "unmatchedReleases": Array [], - "unmatchedTags": Array [], + "unmappableTags": [], + "unmatchedReleases": [], + "unmatchedTags": [], }, } `); diff --git a/plugins/git-release-manager/src/features/Stats/helpers/getReleaseStats.test.tsx b/plugins/git-release-manager/src/features/Stats/helpers/getReleaseStats.test.tsx index f46d0978b8..f446bca1c3 100644 --- a/plugins/git-release-manager/src/features/Stats/helpers/getReleaseStats.test.tsx +++ b/plugins/git-release-manager/src/features/Stats/helpers/getReleaseStats.test.tsx @@ -60,23 +60,23 @@ describe('getReleaseStats', () => { }); expect(result).toMatchInlineSnapshot(` - Object { - "releaseStats": Object { - "releases": Object { - "1.0": Object { + { + "releaseStats": { + "releases": { + "1.0": { "baseVersion": "1.0", - "candidates": Array [ - Object { + "candidates": [ + { "tagName": "rc-1.0.0", "tagSha": "sha", "tagType": "tag", }, - Object { + { "tagName": "rc-1.0.1", "tagSha": "sha", "tagType": "tag", }, - Object { + { "tagName": "rc-1.0.2", "tagSha": "sha", "tagType": "tag", @@ -84,18 +84,18 @@ describe('getReleaseStats', () => { ], "createdAt": "2021-01-01T10:11:12Z", "htmlUrl": "html_url", - "versions": Array [ - Object { + "versions": [ + { "tagName": "version-1.0.2", "tagSha": "sha", "tagType": "tag", }, ], }, - "1.1": Object { + "1.1": { "baseVersion": "1.1", - "candidates": Array [ - Object { + "candidates": [ + { "tagName": "rc-1.1.1", "tagSha": "sha", "tagType": "tag", @@ -103,14 +103,14 @@ describe('getReleaseStats', () => { ], "createdAt": "2021-01-01T10:11:12Z", "htmlUrl": "html_url", - "versions": Array [], + "versions": [], }, }, - "unmappableTags": Array [ + "unmappableTags": [ "rc-123.123.123", ], - "unmatchedReleases": Array [], - "unmatchedTags": Array [ + "unmatchedReleases": [], + "unmatchedTags": [ "rc-1/2/3", ], }, diff --git a/plugins/git-release-manager/src/features/Stats/helpers/getSummary.test.tsx b/plugins/git-release-manager/src/features/Stats/helpers/getSummary.test.tsx index d36eb85128..ee873800af 100644 --- a/plugins/git-release-manager/src/features/Stats/helpers/getSummary.test.tsx +++ b/plugins/git-release-manager/src/features/Stats/helpers/getSummary.test.tsx @@ -22,8 +22,8 @@ describe('getSummary', () => { const result = getSummary({ releaseStats: mockReleaseStats }); expect(result).toMatchInlineSnapshot(` - Object { - "summary": Object { + { + "summary": { "totalCandidatePatches": 3, "totalReleases": 2, "totalVersionPatches": 1, diff --git a/plugins/git-release-manager/src/features/Stats/helpers/getTagDates.test.ts b/plugins/git-release-manager/src/features/Stats/helpers/getTagDates.test.ts index ba17bc0be6..7900942c82 100644 --- a/plugins/git-release-manager/src/features/Stats/helpers/getTagDates.test.ts +++ b/plugins/git-release-manager/src/features/Stats/helpers/getTagDates.test.ts @@ -43,7 +43,7 @@ describe('getTagDates', () => { }); expect(result).toMatchInlineSnapshot(` - Object { + { "endDate": undefined, "startDate": "TAG-START", } @@ -65,7 +65,7 @@ describe('getTagDates', () => { }); expect(result).toMatchInlineSnapshot(` - Object { + { "endDate": undefined, "startDate": "COMMIT_START", } @@ -91,7 +91,7 @@ describe('getTagDates', () => { }); expect(result).toMatchInlineSnapshot(` - Object { + { "endDate": "TAG-END", "startDate": "TAG-START", } @@ -117,7 +117,7 @@ describe('getTagDates', () => { }); expect(result).toMatchInlineSnapshot(` - Object { + { "endDate": "COMMIT_END", "startDate": "COMMIT_START", } @@ -160,7 +160,7 @@ describe('getTagDates', () => { [{ owner, ref: 'OBJECT_SHA_START', repo }], ]); expect(result).toMatchInlineSnapshot(` - Object { + { "endDate": "COMMIT_START", "startDate": "COMMIT_END", } @@ -203,7 +203,7 @@ describe('getTagDates', () => { [{ owner, ref: 'OBJECT_SHA_END', repo }], ]); expect(result).toMatchInlineSnapshot(` - Object { + { "endDate": "COMMIT_END", "startDate": "COMMIT_START", } diff --git a/plugins/git-release-manager/src/helpers/createResponseStepError.test.ts b/plugins/git-release-manager/src/helpers/createResponseStepError.test.ts index b010a0e21f..fd21b7ea52 100644 --- a/plugins/git-release-manager/src/helpers/createResponseStepError.test.ts +++ b/plugins/git-release-manager/src/helpers/createResponseStepError.test.ts @@ -21,7 +21,7 @@ describe('createResponseStepError', () => { const result = createResponseStepError(new Error('banana')); expect(result).toMatchInlineSnapshot(` - Object { + { "icon": "failure", "message": "Something went wrong ❌", "secondaryMessage": "Error message: banana", diff --git a/plugins/git-release-manager/src/helpers/getBumpedTag.test.ts b/plugins/git-release-manager/src/helpers/getBumpedTag.test.ts index 32a296bbd2..84c2b5de04 100644 --- a/plugins/git-release-manager/src/helpers/getBumpedTag.test.ts +++ b/plugins/git-release-manager/src/helpers/getBumpedTag.test.ts @@ -30,10 +30,10 @@ describe('getBumpedTag', () => { }); expect(result).toMatchInlineSnapshot(` - Object { + { "bumpedTag": "rc-2020.01.01_2", "error": undefined, - "tagParts": Object { + "tagParts": { "calver": "2020.01.01", "patch": 2, "prefix": "rc", @@ -50,10 +50,10 @@ describe('getBumpedTag', () => { }); expect(result).toMatchInlineSnapshot(` - Object { + { "bumpedTag": "rc-2020.01.01_2", "error": undefined, - "tagParts": Object { + "tagParts": { "calver": "2020.01.01", "patch": 2, "prefix": "rc", @@ -72,10 +72,10 @@ describe('getBumpedTag', () => { }); expect(result).toMatchInlineSnapshot(` - Object { + { "bumpedTag": "rc-1.2.4", "error": undefined, - "tagParts": Object { + "tagParts": { "major": 1, "minor": 2, "patch": 4, @@ -93,10 +93,10 @@ describe('getBumpedTag', () => { }); expect(result).toMatchInlineSnapshot(` - Object { + { "bumpedTag": "rc-1.3.0", "error": undefined, - "tagParts": Object { + "tagParts": { "major": 1, "minor": 3, "patch": 0, @@ -114,10 +114,10 @@ describe('getBumpedTag', () => { }); expect(result).toMatchInlineSnapshot(` - Object { + { "bumpedTag": "rc-2.0.0", "error": undefined, - "tagParts": Object { + "tagParts": { "major": 2, "minor": 0, "patch": 0, @@ -137,9 +137,9 @@ describe('getBumpedTag', () => { }); expect(result).toMatchInlineSnapshot(` - Object { - "error": Object { - "subtitle": "Expected calver matching \\"/(rc|version)-([0-9]{4}\\\\.[0-9]{2}\\\\.[0-9]{2})_([0-9]+)/\\", found \\"😬\\"", + { + "error": { + "subtitle": "Expected calver matching "/(rc|version)-([0-9]{4}\\.[0-9]{2}\\.[0-9]{2})_([0-9]+)/", found "😬"", "title": "Invalid tag", }, } diff --git a/plugins/git-release-manager/src/helpers/getReleaseCandidateGitInfo.test.ts b/plugins/git-release-manager/src/helpers/getReleaseCandidateGitInfo.test.ts index 20130c450c..693e9971db 100644 --- a/plugins/git-release-manager/src/helpers/getReleaseCandidateGitInfo.test.ts +++ b/plugins/git-release-manager/src/helpers/getReleaseCandidateGitInfo.test.ts @@ -43,7 +43,7 @@ describe('getReleaseCandidateGitInfo', () => { injectedDate: '2021.01.28', }), ).toMatchInlineSnapshot(` - Object { + { "rcBranch": "rc/2021.01.28", "rcReleaseTag": "rc-2021.01.28_0", "releaseName": "Version 2021.01.28", @@ -61,7 +61,7 @@ describe('getReleaseCandidateGitInfo', () => { semverBumpLevel: 'minor', }), ).toMatchInlineSnapshot(` - Object { + { "rcBranch": "rc/1.3.0", "rcReleaseTag": "rc-1.3.0", "releaseName": "Version 1.3.0", @@ -77,7 +77,7 @@ describe('getReleaseCandidateGitInfo', () => { semverBumpLevel: 'minor', }), ).toMatchInlineSnapshot(` - Object { + { "rcBranch": "rc/0.0.1", "rcReleaseTag": "rc-0.0.1", "releaseName": "Version 0.0.1", diff --git a/plugins/git-release-manager/src/helpers/tagParts/getCalverTagParts.test.ts b/plugins/git-release-manager/src/helpers/tagParts/getCalverTagParts.test.ts index 1d46c0abdd..7a12fab45b 100644 --- a/plugins/git-release-manager/src/helpers/tagParts/getCalverTagParts.test.ts +++ b/plugins/git-release-manager/src/helpers/tagParts/getCalverTagParts.test.ts @@ -26,28 +26,28 @@ describe('getCalverTagParts', () => { const result = getCalverTagParts(mockReleaseCandidateCalver.tagName); expect(result).toMatchInlineSnapshot(` - Object { - "tagParts": Object { - "calver": "2020.01.01", - "patch": 1, - "prefix": "rc", - }, - } - `); + { + "tagParts": { + "calver": "2020.01.01", + "patch": 1, + "prefix": "rc", + }, + } + `); }); it('should return tagParts for Version tag', () => { const result = getCalverTagParts(mockReleaseVersionCalver.tagName); expect(result).toMatchInlineSnapshot(` - Object { - "tagParts": Object { - "calver": "2020.01.01", - "patch": 1, - "prefix": "version", - }, - } - `); + { + "tagParts": { + "calver": "2020.01.01", + "patch": 1, + "prefix": "version", + }, + } + `); }); }); @@ -56,9 +56,9 @@ describe('getCalverTagParts', () => { const result = getCalverTagParts('invalid-2020.01.01_1'); expect(result).toMatchInlineSnapshot(` - Object { - "error": Object { - "subtitle": "Expected calver matching \\"/(rc|version)-([0-9]{4}\\\\.[0-9]{2}\\\\.[0-9]{2})_([0-9]+)/\\", found \\"invalid-2020.01.01_1\\"", + { + "error": { + "subtitle": "Expected calver matching "/(rc|version)-([0-9]{4}\\.[0-9]{2}\\.[0-9]{2})_([0-9]+)/", found "invalid-2020.01.01_1"", "title": "Invalid tag", }, } @@ -69,9 +69,9 @@ describe('getCalverTagParts', () => { const result = getCalverTagParts('rc-2020.1.01_1'); expect(result).toMatchInlineSnapshot(` - Object { - "error": Object { - "subtitle": "Expected calver matching \\"/(rc|version)-([0-9]{4}\\\\.[0-9]{2}\\\\.[0-9]{2})_([0-9]+)/\\", found \\"rc-2020.1.01_1\\"", + { + "error": { + "subtitle": "Expected calver matching "/(rc|version)-([0-9]{4}\\.[0-9]{2}\\.[0-9]{2})_([0-9]+)/", found "rc-2020.1.01_1"", "title": "Invalid tag", }, } @@ -82,9 +82,9 @@ describe('getCalverTagParts', () => { const result = getCalverTagParts('rc-2020.01_1'); expect(result).toMatchInlineSnapshot(` - Object { - "error": Object { - "subtitle": "Expected calver matching \\"/(rc|version)-([0-9]{4}\\\\.[0-9]{2}\\\\.[0-9]{2})_([0-9]+)/\\", found \\"rc-2020.01_1\\"", + { + "error": { + "subtitle": "Expected calver matching "/(rc|version)-([0-9]{4}\\.[0-9]{2}\\.[0-9]{2})_([0-9]+)/", found "rc-2020.01_1"", "title": "Invalid tag", }, } @@ -95,9 +95,9 @@ describe('getCalverTagParts', () => { const result = getCalverTagParts('rc-2020.01.01_a'); expect(result).toMatchInlineSnapshot(` - Object { - "error": Object { - "subtitle": "Expected calver matching \\"/(rc|version)-([0-9]{4}\\\\.[0-9]{2}\\\\.[0-9]{2})_([0-9]+)/\\", found \\"rc-2020.01.01_a\\"", + { + "error": { + "subtitle": "Expected calver matching "/(rc|version)-([0-9]{4}\\.[0-9]{2}\\.[0-9]{2})_([0-9]+)/", found "rc-2020.01.01_a"", "title": "Invalid tag", }, } diff --git a/plugins/git-release-manager/src/helpers/tagParts/getSemverTagParts.test.ts b/plugins/git-release-manager/src/helpers/tagParts/getSemverTagParts.test.ts index c637325843..7edb013dfd 100644 --- a/plugins/git-release-manager/src/helpers/tagParts/getSemverTagParts.test.ts +++ b/plugins/git-release-manager/src/helpers/tagParts/getSemverTagParts.test.ts @@ -28,15 +28,15 @@ describe('getSemverTagParts', () => { ); expect(semverTagParts).toMatchInlineSnapshot(` - Object { - "tagParts": Object { - "major": 1, - "minor": 2, - "patch": 3, - "prefix": "rc", - }, - } - `); + { + "tagParts": { + "major": 1, + "minor": 2, + "patch": 3, + "prefix": "rc", + }, + } + `); }); it('should return tagParts for Version tag', () => { @@ -45,15 +45,15 @@ describe('getSemverTagParts', () => { ); expect(semverTagParts).toMatchInlineSnapshot(` - Object { - "tagParts": Object { - "major": 1, - "minor": 2, - "patch": 3, - "prefix": "version", - }, - } - `); + { + "tagParts": { + "major": 1, + "minor": 2, + "patch": 3, + "prefix": "version", + }, + } + `); }); }); @@ -62,9 +62,9 @@ describe('getSemverTagParts', () => { const semverTagParts = getSemverTagParts('invalid-1.2.3'); expect(semverTagParts).toMatchInlineSnapshot(` - Object { - "error": Object { - "subtitle": "Expected semver matching \\"/(rc|version)-([0-9]+)\\\\.([0-9]+)\\\\.([0-9]+)/\\", found \\"invalid-1.2.3\\"", + { + "error": { + "subtitle": "Expected semver matching "/(rc|version)-([0-9]+)\\.([0-9]+)\\.([0-9]+)/", found "invalid-1.2.3"", "title": "Invalid tag", }, } @@ -75,9 +75,9 @@ describe('getSemverTagParts', () => { const semverTagParts = getSemverTagParts('rc-1.2'); expect(semverTagParts).toMatchInlineSnapshot(` - Object { - "error": Object { - "subtitle": "Expected semver matching \\"/(rc|version)-([0-9]+)\\\\.([0-9]+)\\\\.([0-9]+)/\\", found \\"rc-1.2\\"", + { + "error": { + "subtitle": "Expected semver matching "/(rc|version)-([0-9]+)\\.([0-9]+)\\.([0-9]+)/", found "rc-1.2"", "title": "Invalid tag", }, } @@ -88,9 +88,9 @@ describe('getSemverTagParts', () => { const semverTagParts = getSemverTagParts('rc-1337.01.01_1'); expect(semverTagParts).toMatchInlineSnapshot(` - Object { - "error": Object { - "subtitle": "Expected semver matching \\"/(rc|version)-([0-9]+)\\\\.([0-9]+)\\\\.([0-9]+)/\\", found calver \\"rc-1337.01.01_1\\"", + { + "error": { + "subtitle": "Expected semver matching "/(rc|version)-([0-9]+)\\.([0-9]+)\\.([0-9]+)/", found calver "rc-1337.01.01_1"", "title": "Invalid tag", }, } diff --git a/plugins/git-release-manager/src/helpers/tagParts/validateTagParts.test.ts b/plugins/git-release-manager/src/helpers/tagParts/validateTagParts.test.ts index 50cbd6cf9e..64f60ec4d6 100644 --- a/plugins/git-release-manager/src/helpers/tagParts/validateTagParts.test.ts +++ b/plugins/git-release-manager/src/helpers/tagParts/validateTagParts.test.ts @@ -31,7 +31,7 @@ describe('validateTagName', () => { }); expect(result).toMatchInlineSnapshot(` - Object { + { "tagNameError": undefined, } `); @@ -43,10 +43,10 @@ describe('validateTagName', () => { }); expect(result).toMatchInlineSnapshot(` - Object { - "tagNameError": null, - } - `); + { + "tagNameError": null, + } + `); }); }); @@ -58,9 +58,9 @@ describe('validateTagName', () => { }); expect(result).toMatchInlineSnapshot(` - Object { - "tagNameError": Object { - "subtitle": "Expected semver matching \\"/(rc|version)-([0-9]+)\\\\.([0-9]+)\\\\.([0-9]+)/\\", found calver \\"rc-2020.01.01_1\\"", + { + "tagNameError": { + "subtitle": "Expected semver matching "/(rc|version)-([0-9]+)\\.([0-9]+)\\.([0-9]+)/", found calver "rc-2020.01.01_1"", "title": "Invalid tag", }, } @@ -74,9 +74,9 @@ describe('validateTagName', () => { }); expect(result).toMatchInlineSnapshot(` - Object { - "tagNameError": Object { - "subtitle": "Expected calver matching \\"/(rc|version)-([0-9]{4}\\\\.[0-9]{2}\\\\.[0-9]{2})_([0-9]+)/\\", found \\"rc-1.2.3\\"", + { + "tagNameError": { + "subtitle": "Expected calver matching "/(rc|version)-([0-9]{4}\\.[0-9]{2}\\.[0-9]{2})_([0-9]+)/", found "rc-1.2.3"", "title": "Invalid tag", }, } @@ -92,9 +92,9 @@ describe('validateTagName', () => { }); expect(result).toMatchInlineSnapshot(` - Object { - "tagNameError": Object { - "subtitle": "Expected semver matching \\"/(rc|version)-([0-9]+)\\\\.([0-9]+)\\\\.([0-9]+)/\\", found \\"this-is-so-invalid\\"", + { + "tagNameError": { + "subtitle": "Expected semver matching "/(rc|version)-([0-9]+)\\.([0-9]+)\\.([0-9]+)/", found "this-is-so-invalid"", "title": "Invalid tag", }, } @@ -108,9 +108,9 @@ describe('validateTagName', () => { }); expect(result).toMatchInlineSnapshot(` - Object { - "tagNameError": Object { - "subtitle": "Expected calver matching \\"/(rc|version)-([0-9]{4}\\\\.[0-9]{2}\\\\.[0-9]{2})_([0-9]+)/\\", found \\"this-is-so-invalid\\"", + { + "tagNameError": { + "subtitle": "Expected calver matching "/(rc|version)-([0-9]{4}\\.[0-9]{2}\\.[0-9]{2})_([0-9]+)/", found "this-is-so-invalid"", "title": "Invalid tag", }, } diff --git a/plugins/git-release-manager/src/hooks/useGetGitBatchInfo.test.ts b/plugins/git-release-manager/src/hooks/useGetGitBatchInfo.test.ts index fb1a8b6919..8e89add810 100644 --- a/plugins/git-release-manager/src/hooks/useGetGitBatchInfo.test.ts +++ b/plugins/git-release-manager/src/hooks/useGetGitBatchInfo.test.ts @@ -35,31 +35,31 @@ describe('useGetHubBatchInfo', () => { }); expect(result.current.gitBatchInfo).toMatchInlineSnapshot(` - Object { + { "loading": false, - "value": Object { - "latestRelease": Object { + "value": { + "latestRelease": { "htmlUrl": "https://mock_release_html_url", "id": 1, "prerelease": false, "tagName": "rc-2020.01.01_1", "targetCommitish": "rc/2020.01.01_1", }, - "releaseBranch": Object { - "commit": Object { - "commit": Object { - "tree": Object { + "releaseBranch": { + "commit": { + "commit": { + "tree": { "sha": "mock_branch_commit_commit_tree_sha", }, }, "sha": "mock_branch_commit_sha", }, - "links": Object { + "links": { "html": "https://mock_branch_links_html", }, "name": "rc/1.2.3", }, - "repository": Object { + "repository": { "defaultBranch": "mock_defaultBranch", "name": "mock_repo", "pushPermissions": true, @@ -86,12 +86,12 @@ describe('useGetHubBatchInfo', () => { }); expect(result.current.gitBatchInfo).toMatchInlineSnapshot(` - Object { + { "loading": false, - "value": Object { + "value": { "latestRelease": null, "releaseBranch": null, - "repository": Object { + "repository": { "defaultBranch": "mock_defaultBranch", "name": "mock_repo", "pushPermissions": true, diff --git a/plugins/git-release-manager/src/hooks/useQueryHandler.test.tsx b/plugins/git-release-manager/src/hooks/useQueryHandler.test.tsx index 7d06c5d829..020b068188 100644 --- a/plugins/git-release-manager/src/hooks/useQueryHandler.test.tsx +++ b/plugins/git-release-manager/src/hooks/useQueryHandler.test.tsx @@ -50,14 +50,14 @@ describe('useQueryHandler', () => { const result = getByTestId(TEST_ID).innerHTML; expect(result).toMatchInlineSnapshot(` - "{ - \\"parsedQuery\\": { - \\"versioningStrategy\\": \\"semver\\", - \\"owner\\": \\"mock_owner\\", - \\"repo\\": \\"mock_repo\\" - }, - \\"queryParams\\": \\"versioningStrategy=semver&owner=mock_owner&repo=updated_mock_repo\\" - }" - `); + "{ + "parsedQuery": { + "versioningStrategy": "semver", + "owner": "mock_owner", + "repo": "mock_repo" + }, + "queryParams": "versioningStrategy=semver&owner=mock_owner&repo=updated_mock_repo" + }" + `); }); }); diff --git a/plugins/git-release-manager/src/hooks/useResponseSteps.test.ts b/plugins/git-release-manager/src/hooks/useResponseSteps.test.ts index 5daa8b47ad..450fc87b97 100644 --- a/plugins/git-release-manager/src/hooks/useResponseSteps.test.ts +++ b/plugins/git-release-manager/src/hooks/useResponseSteps.test.ts @@ -23,11 +23,11 @@ describe('useResponseSteps', () => { const { result } = renderHook(() => useResponseSteps()); expect(result.current).toMatchInlineSnapshot(` - Object { + { "abortIfError": [Function], "addStepToResponseSteps": [Function], "asyncCatcher": [Function], - "responseSteps": Array [], + "responseSteps": [], } `); }); @@ -36,7 +36,7 @@ describe('useResponseSteps', () => { it('should add responseSteps to state', async () => { const { result } = renderHook(() => useResponseSteps()); - expect(result.current.responseSteps).toMatchInlineSnapshot(`Array []`); + expect(result.current.responseSteps).toMatchInlineSnapshot(`[]`); act(() => { result.current.addStepToResponseSteps({ @@ -45,12 +45,12 @@ describe('useResponseSteps', () => { }); expect(result.current.responseSteps).toMatchInlineSnapshot(` - Array [ - Object { - "message": "totally added a messaage ✌🏼", - }, - ] - `); + [ + { + "message": "totally added a messaage ✌🏼", + }, + ] + `); }); }); @@ -58,7 +58,7 @@ describe('useResponseSteps', () => { it('should catch Errors and add as failure step, then throw', async () => { const { result } = renderHook(() => useResponseSteps()); - expect(result.current.responseSteps).toMatchInlineSnapshot(`Array []`); + expect(result.current.responseSteps).toMatchInlineSnapshot(`[]`); await act(async () => { await new Promise((_, reject) => reject(new Error(':('))) @@ -69,8 +69,8 @@ describe('useResponseSteps', () => { }); expect(result.current.responseSteps).toMatchInlineSnapshot(` - Array [ - Object { + [ + { "icon": "failure", "message": Something went wrong @@ -91,7 +91,7 @@ describe('useResponseSteps', () => { it('should catch unknown Errors and add as failure step, then throw', async () => { const { result } = renderHook(() => useResponseSteps()); - expect(result.current.responseSteps).toMatchInlineSnapshot(`Array []`); + expect(result.current.responseSteps).toMatchInlineSnapshot(`[]`); await act(async () => { await new Promise((_, reject) => reject()) @@ -102,8 +102,8 @@ describe('useResponseSteps', () => { }); expect(result.current.responseSteps).toMatchInlineSnapshot(` - Array [ - Object { + [ + { "icon": "failure", "message": Something went wrong @@ -126,13 +126,13 @@ describe('useResponseSteps', () => { it('should do nothing if not Error', async () => { const { result } = renderHook(() => useResponseSteps()); - expect(result.current.responseSteps).toMatchInlineSnapshot(`Array []`); + expect(result.current.responseSteps).toMatchInlineSnapshot(`[]`); act(() => { result.current.abortIfError(undefined); }); - expect(result.current.responseSteps).toMatchInlineSnapshot(`Array []`); + expect(result.current.responseSteps).toMatchInlineSnapshot(`[]`); }); }); }); diff --git a/plugins/git-release-manager/src/plugin.test.ts b/plugins/git-release-manager/src/plugin.test.ts index db60617c24..b293ea05eb 100644 --- a/plugins/git-release-manager/src/plugin.test.ts +++ b/plugins/git-release-manager/src/plugin.test.ts @@ -19,7 +19,7 @@ import * as plugin from './plugin'; describe('git-release-manager', () => { it('should export plugin & friends', () => { expect(Object.keys(plugin)).toMatchInlineSnapshot(` - Array [ + [ "gitReleaseManagerApiRef", "constants", "helpers", diff --git a/plugins/github-actions/CHANGELOG.md b/plugins/github-actions/CHANGELOG.md index b261cef2ba..4a0ca4dce0 100644 --- a/plugins/github-actions/CHANGELOG.md +++ b/plugins/github-actions/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/plugin-github-actions +## 0.5.9 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 1bdb0bf24b: Modify RecentWorkflowRunsCard use constructed route instead of hardcoded route. +- 3f739be9d9: Minor API signatures cleanup +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/integration@1.3.1 + - @backstage/catalog-model@1.1.1 + ## 0.5.9-next.3 ### Patch Changes diff --git a/plugins/github-actions/package.json b/plugins/github-actions/package.json index 7866ded70e..596e844c11 100644 --- a/plugins/github-actions/package.json +++ b/plugins/github-actions/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-github-actions", "description": "A Backstage plugin that integrates towards GitHub Actions", - "version": "0.5.9-next.3", + "version": "0.5.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,12 +34,12 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/integration": "^1.3.1-next.2", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", - "@backstage/theme": "^0.2.16", + "@backstage/catalog-model": "workspace:^", + "@backstage/core-components": "workspace:^", + "@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.57", @@ -53,10 +53,10 @@ "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/github-actions/src/components/Cards/RecentWorkflowRunsCard.test.tsx b/plugins/github-actions/src/components/Cards/RecentWorkflowRunsCard.test.tsx index 7a20501072..5e0a5f3e15 100644 --- a/plugins/github-actions/src/components/Cards/RecentWorkflowRunsCard.test.tsx +++ b/plugins/github-actions/src/components/Cards/RecentWorkflowRunsCard.test.tsx @@ -15,21 +15,19 @@ */ import { EntityProvider } from '@backstage/plugin-catalog-react'; -import { lightTheme } from '@backstage/theme'; -import { ThemeProvider } from '@material-ui/core'; -import { render } from '@testing-library/react'; import React from 'react'; -import { MemoryRouter } from 'react-router'; import { useWorkflowRuns } from '../useWorkflowRuns'; import { RecentWorkflowRunsCard } from './RecentWorkflowRunsCard'; import { ConfigReader } from '@backstage/core-app-api'; import { - errorApiRef, - configApiRef, ConfigApi, + configApiRef, + errorApiRef, } from '@backstage/core-plugin-api'; -import { TestApiProvider } from '@backstage/test-utils'; +import { TestApiProvider, wrapInTestApp } from '@backstage/test-utils'; +import { rootRouteRef } from '../../routes'; +import { render } from '@testing-library/react'; jest.mock('../useWorkflowRuns', () => ({ useWorkflowRuns: jest.fn(), @@ -76,24 +74,27 @@ describe('', () => { const renderSubject = (props: any = {}) => render( - - - - - - - - - , + wrapInTestApp( + + + + + , + { + mountedRoutes: { + '/ci-cd': rootRouteRef, + }, + }, + ), ); it('renders a table with a row for each workflow', async () => { - const subject = renderSubject(); + const subject = await renderSubject(); workflowRuns.forEach(run => { expect(subject.getByText(run.message)).toBeInTheDocument(); @@ -101,7 +102,7 @@ describe('', () => { }); it('renders a workflow row correctly', async () => { - const subject = renderSubject(); + const subject = await renderSubject(); const [run] = workflowRuns; expect(subject.getByText(run.message).closest('a')).toHaveAttribute( 'href', diff --git a/plugins/github-actions/src/components/Cards/RecentWorkflowRunsCard.tsx b/plugins/github-actions/src/components/Cards/RecentWorkflowRunsCard.tsx index fcd0f194a3..931b5b676e 100644 --- a/plugins/github-actions/src/components/Cards/RecentWorkflowRunsCard.tsx +++ b/plugins/github-actions/src/components/Cards/RecentWorkflowRunsCard.tsx @@ -16,19 +16,25 @@ import { readGitHubIntegrationConfigs } from '@backstage/integration'; import { useEntity } from '@backstage/plugin-catalog-react'; import React, { useEffect } from 'react'; -import { generatePath, Link as RouterLink } from 'react-router-dom'; +import { Link as RouterLink } from 'react-router-dom'; import { GITHUB_ACTIONS_ANNOTATION } from '../getProjectNameFromEntity'; import { useWorkflowRuns, WorkflowRun } from '../useWorkflowRuns'; import { WorkflowRunStatus } from '../WorkflowRunStatus'; import { Typography } from '@material-ui/core'; -import { configApiRef, errorApiRef, useApi } from '@backstage/core-plugin-api'; +import { + configApiRef, + errorApiRef, + useApi, + useRouteRef, +} from '@backstage/core-plugin-api'; import { InfoCard, InfoCardVariants, Link, Table, } from '@backstage/core-components'; +import { buildRouteRef } from '../../routes'; const firstLine = (message: string): string => message.split('\n')[0]; @@ -69,7 +75,7 @@ export const RecentWorkflowRunsCard = (props: { }, [error, errorApi]); const githubHost = hostname || 'github.com'; - + const routeLink = useRouteRef(buildRouteRef); return ( ( - + {firstLine(data.message ?? '')} ), diff --git a/plugins/github-deployments/CHANGELOG.md b/plugins/github-deployments/CHANGELOG.md index 655d640357..244a610d0c 100644 --- a/plugins/github-deployments/CHANGELOG.md +++ b/plugins/github-deployments/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-github-deployments +## 0.1.40 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/integration@1.3.1 + - @backstage/catalog-model@1.1.1 + - @backstage/errors@1.1.1 + - @backstage/integration-react@1.1.4 + ## 0.1.40-next.3 ### Patch Changes diff --git a/plugins/github-deployments/package.json b/plugins/github-deployments/package.json index 8e32c3c0ff..a0f94015dd 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.40-next.3", + "version": "0.1.40", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,14 +23,14 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/integration": "^1.3.1-next.2", - "@backstage/integration-react": "^1.1.4-next.2", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", - "@backstage/theme": "^0.2.16", + "@backstage/catalog-model": "workspace:^", + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/errors": "workspace:^", + "@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.57", @@ -42,10 +42,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/github-issues/CHANGELOG.md b/plugins/github-issues/CHANGELOG.md index 758146689a..8519b5cc08 100644 --- a/plugins/github-issues/CHANGELOG.md +++ b/plugins/github-issues/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-github-issues +## 0.1.1 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/integration@1.3.1 + - @backstage/catalog-model@1.1.1 + - @backstage/errors@1.1.1 + ## 0.1.1-next.2 ### Patch Changes diff --git a/plugins/github-issues/package.json b/plugins/github-issues/package.json index b98197505c..c393e4db8a 100644 --- a/plugins/github-issues/package.json +++ b/plugins/github-issues/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-github-issues", - "version": "0.1.1-next.2", + "version": "0.1.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,13 +22,13 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/integration": "^1.3.1-next.2", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", - "@backstage/theme": "^0.2.15", + "@backstage/catalog-model": "workspace:^", + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@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", @@ -40,10 +40,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@spotify/prettier-config": "^14.0.0", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", diff --git a/plugins/github-pull-requests-board/CHANGELOG.md b/plugins/github-pull-requests-board/CHANGELOG.md index 37d3fdc257..061fca1187 100644 --- a/plugins/github-pull-requests-board/CHANGELOG.md +++ b/plugins/github-pull-requests-board/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-github-pull-requests-board +## 0.1.3 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 2665ee4ed4: Clarified GitHub app permissions required by plugin +- 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`. +- 723113296b: Add optional `pullRequestLimit` prop to `EntityTeamPullRequestsCard` and `EntityTeamPullRequestsContent` to limit the number of PRs shown per repository. Excluding this prop will default the number of pull requests shown to 10 per repository (the existing functionality). +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/integration@1.3.1 + - @backstage/catalog-model@1.1.1 + ## 0.1.3-next.3 ### Patch Changes diff --git a/plugins/github-pull-requests-board/package.json b/plugins/github-pull-requests-board/package.json index d667acb5a3..62826918a9 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.3-next.3", + "version": "0.1.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,12 +34,12 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/integration": "^1.3.1-next.2", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", - "@backstage/theme": "^0.2.16", + "@backstage/catalog-model": "workspace:^", + "@backstage/core-components": "workspace:^", + "@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.57", @@ -48,9 +48,9 @@ "react-use": "^17.2.4" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/gitops-profiles/CHANGELOG.md b/plugins/gitops-profiles/CHANGELOG.md index 93975d7184..0845dcf919 100644 --- a/plugins/gitops-profiles/CHANGELOG.md +++ b/plugins/gitops-profiles/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-gitops-profiles +## 0.3.27 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + ## 0.3.27-next.3 ### Patch Changes diff --git a/plugins/gitops-profiles/package.json b/plugins/gitops-profiles/package.json index 6e54ed98e9..9c2114a91f 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.27-next.3", + "version": "0.3.27", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,9 +33,9 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/theme": "^0.2.16", + "@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.57", @@ -46,10 +46,10 @@ "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/gocd/CHANGELOG.md b/plugins/gocd/CHANGELOG.md index 3673cc4163..aa676a8c77 100644 --- a/plugins/gocd/CHANGELOG.md +++ b/plugins/gocd/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-gocd +## 0.1.15 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + - @backstage/errors@1.1.1 + ## 0.1.15-next.2 ### Patch Changes diff --git a/plugins/gocd/package.json b/plugins/gocd/package.json index 0ab50a90e5..6ed5489b61 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.15-next.2", + "version": "0.1.15", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -29,12 +29,12 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", - "@backstage/theme": "^0.2.16", + "@backstage/catalog-model": "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.57", @@ -47,10 +47,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/graphiql/CHANGELOG.md b/plugins/graphiql/CHANGELOG.md index a9f2f743ec..fbd18a82db 100644 --- a/plugins/graphiql/CHANGELOG.md +++ b/plugins/graphiql/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-graphiql +## 0.2.41 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + ## 0.2.41-next.3 ### Patch Changes diff --git a/plugins/graphiql/package.json b/plugins/graphiql/package.json index d6a16708b9..2ad33b0f9a 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.2.41-next.3", + "version": "0.2.41", "publishConfig": { "access": "public", "main": "dist/index.esm.js", @@ -32,9 +32,9 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/theme": "^0.2.16", + "@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.57", @@ -48,10 +48,10 @@ "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/graphql-backend/CHANGELOG.md b/plugins/graphql-backend/CHANGELOG.md index c94a7619b5..d25668d794 100644 --- a/plugins/graphql-backend/CHANGELOG.md +++ b/plugins/graphql-backend/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-graphql-backend +## 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 diff --git a/plugins/graphql-backend/package.json b/plugins/graphql-backend/package.json index 96fe0c1fe8..8575323fe6 100644 --- a/plugins/graphql-backend/package.json +++ b/plugins/graphql-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-graphql-backend", "description": "An experimental Backstage backend plugin for GraphQL", - "version": "0.1.26-next.3", + "version": "0.1.26", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,9 +33,9 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/config": "^1.0.2-next.0", - "@backstage/plugin-catalog-graphql": "^0.3.13-next.3", + "@backstage/backend-common": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/plugin-catalog-graphql": "workspace:^", "@graphql-tools/schema": "^9.0.0", "@types/express": "^4.17.6", "apollo-server": "^3.0.0", @@ -50,7 +50,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", + "@backstage/cli": "workspace:^", "@types/supertest": "^2.0.8", "msw": "^0.47.0", "supertest": "^6.1.3" diff --git a/plugins/home/CHANGELOG.md b/plugins/home/CHANGELOG.md index 55da92f23f..bbeec680e2 100644 --- a/plugins/home/CHANGELOG.md +++ b/plugins/home/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-home +## 0.4.25 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/plugin-stack-overflow@0.1.5 + ## 0.4.25-next.3 ### Patch Changes diff --git a/plugins/home/package.json b/plugins/home/package.json index df285bad43..bfa3d388c3 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.4.25-next.3", + "version": "0.4.25", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,13 +33,13 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/config": "^1.0.2-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", - "@backstage/plugin-stack-overflow": "^0.1.5-next.3", - "@backstage/theme": "^0.2.16", + "@backstage/catalog-model": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/plugin-catalog-react": "workspace:^", + "@backstage/plugin-stack-overflow": "workspace:^", + "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -52,10 +52,10 @@ "react-router": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/ilert/CHANGELOG.md b/plugins/ilert/CHANGELOG.md index bfb3ada100..9c228fdf99 100644 --- a/plugins/ilert/CHANGELOG.md +++ b/plugins/ilert/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-ilert +## 0.1.35 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + - @backstage/errors@1.1.1 + ## 0.1.35-next.3 ### Patch Changes diff --git a/plugins/ilert/package.json b/plugins/ilert/package.json index 7aa79fb143..391a9e495d 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.1.35-next.3", + "version": "0.1.35", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,12 +23,12 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", - "@backstage/theme": "^0.2.16", + "@backstage/catalog-model": "workspace:^", + "@backstage/core-components": "workspace:^", + "@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", @@ -42,10 +42,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/jenkins-backend/CHANGELOG.md b/plugins/jenkins-backend/CHANGELOG.md index 9aa3e20d79..693c0d2988 100644 --- a/plugins/jenkins-backend/CHANGELOG.md +++ b/plugins/jenkins-backend/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-jenkins-backend +## 0.1.26 + +### Patch Changes + +- 618c06f838: Add example on how to pass through permissions +- a966ed8385: Unwrap error message when getting projects +- 47952621dc: Extend configuration so that extra headers can be sent to jenkins instance +- d669d89206: Minor API signatures cleanup +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- 69ec1cf39f: Updated dependency `jenkins` to `^1.0.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- e55d855a6b: Jenkins plugin works again +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/plugin-auth-node@0.2.5 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + - @backstage/plugin-permission-common@0.6.4 + - @backstage/plugin-jenkins-common@0.1.8 + ## 0.1.26-next.3 ### Patch Changes diff --git a/plugins/jenkins-backend/README.md b/plugins/jenkins-backend/README.md index 6d767c502e..133b9f42e2 100644 --- a/plugins/jenkins-backend/README.md +++ b/plugins/jenkins-backend/README.md @@ -43,6 +43,7 @@ export default async function createPlugin( config: env.config, catalog, }), + permissions: env.permissions, }); } ``` diff --git a/plugins/jenkins-backend/package.json b/plugins/jenkins-backend/package.json index 55f856003e..7c2203a866 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.1.26-next.3", + "version": "0.1.26", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -24,14 +24,14 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/catalog-client": "^1.1.0-next.2", - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/config": "^1.0.2-next.0", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/plugin-auth-node": "^0.2.5-next.3", - "@backstage/plugin-jenkins-common": "^0.1.8-next.0", - "@backstage/plugin-permission-common": "^0.6.4-next.2", + "@backstage/backend-common": "workspace:^", + "@backstage/catalog-client": "workspace:^", + "@backstage/catalog-model": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/plugin-auth-node": "workspace:^", + "@backstage/plugin-jenkins-common": "workspace:^", + "@backstage/plugin-permission-common": "workspace:^", "@types/express": "^4.17.6", "express": "^4.17.1", "express-promise-router": "^4.1.0", @@ -41,7 +41,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", + "@backstage/cli": "workspace:^", "@types/jenkins": "^0.23.1", "@types/supertest": "^2.0.8", "msw": "^0.47.0", diff --git a/plugins/jenkins-backend/src/service/jenkinsApi.ts b/plugins/jenkins-backend/src/service/jenkinsApi.ts index ae2fa0f7b5..b9eee42f64 100644 --- a/plugins/jenkins-backend/src/service/jenkinsApi.ts +++ b/plugins/jenkins-backend/src/service/jenkinsApi.ts @@ -15,7 +15,7 @@ */ import type { JenkinsInfo } from './jenkinsInfoProvider'; -import jenkins from 'jenkins'; +import Jenkins from 'jenkins'; import type { BackstageBuild, BackstageProject, @@ -100,7 +100,7 @@ export class JenkinsApiImpl { // Filter only be the information we need, instead of loading all fields. // Limit to only show the latest build for each job and only load 50 jobs // at all. - // Whitespaces are only included for readablity here and stripped out + // Whitespaces are only included for readability here and stripped out // before sending to Jenkins tree: JenkinsApiImpl.jobsTreeSpec.replace(/\s/g, ''), }); @@ -177,12 +177,12 @@ export class JenkinsApiImpl { private static async getClient(jenkinsInfo: JenkinsInfo) { // The typings for the jenkins library are out of date so just cast to any - return jenkins({ + return new (Jenkins as any)({ baseUrl: jenkinsInfo.baseUrl, headers: jenkinsInfo.headers, promisify: true, crumbIssuer: jenkinsInfo.crumbIssuer, - }) as any; + }); } private augmentProject(project: JenkinsProject): BackstageProject { diff --git a/plugins/jenkins-backend/src/service/router.ts b/plugins/jenkins-backend/src/service/router.ts index bc0e978396..df4c3b5a11 100644 --- a/plugins/jenkins-backend/src/service/router.ts +++ b/plugins/jenkins-backend/src/service/router.ts @@ -27,6 +27,7 @@ import { } from '@backstage/plugin-permission-common'; import { getBearerTokenFromAuthorizationHeader } from '@backstage/plugin-auth-node'; import { stringifyEntityRef } from '@backstage/catalog-model'; +import { stringifyError } from '@backstage/errors'; /** @public */ export interface RouterOptions { @@ -90,11 +91,25 @@ export async function createRouter( }, backstageToken: token, }); - const projects = await jenkinsApi.getProjects(jenkinsInfo, branches); - response.json({ - projects: projects, - }); + try { + const projects = await jenkinsApi.getProjects(jenkinsInfo, branches); + + response.json({ + projects: projects, + }); + } catch (err) { + // Promise.any, used in the getProjects call returns an Aggregate error message with a useless error message 'AggregateError: All promises were rejected' + // extract useful information ourselves + if (err.errors) { + throw new Error( + `Unable to fetch projects, for ${ + jenkinsInfo.jobFullName + }: ${stringifyError(err.errors)}`, + ); + } + throw err; + } }, ); diff --git a/plugins/jenkins-common/CHANGELOG.md b/plugins/jenkins-common/CHANGELOG.md index 1eedf680d5..a1d29726fd 100644 --- a/plugins/jenkins-common/CHANGELOG.md +++ b/plugins/jenkins-common/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-jenkins-common +## 0.1.8 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.6.4 + - @backstage/plugin-catalog-common@1.0.6 + ## 0.1.8-next.0 ### Patch Changes diff --git a/plugins/jenkins-common/package.json b/plugins/jenkins-common/package.json index 2e2d670ab9..fd752b9d84 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.8-next.0", + "version": "0.1.8", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,11 +22,11 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/plugin-catalog-common": "^1.0.6-next.0", - "@backstage/plugin-permission-common": "^0.6.4-next.0" + "@backstage/plugin-catalog-common": "workspace:^", + "@backstage/plugin-permission-common": "workspace:^" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.1" + "@backstage/cli": "workspace:^" }, "files": [ "dist" diff --git a/plugins/jenkins/CHANGELOG.md b/plugins/jenkins/CHANGELOG.md index c6cc5ed432..ff4612ba8f 100644 --- a/plugins/jenkins/CHANGELOG.md +++ b/plugins/jenkins/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-jenkins +## 0.7.8 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 3f739be9d9: Minor API signatures cleanup +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + - @backstage/errors@1.1.1 + - @backstage/plugin-jenkins-common@0.1.8 + ## 0.7.8-next.3 ### Patch Changes diff --git a/plugins/jenkins/package.json b/plugins/jenkins/package.json index f415770809..18b4507b48 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.7.8-next.3", + "version": "0.7.8", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,13 +33,13 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", - "@backstage/plugin-jenkins-common": "^0.1.8-next.0", - "@backstage/theme": "^0.2.16", + "@backstage/catalog-model": "workspace:^", + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@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.57", @@ -52,10 +52,10 @@ "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/kafka-backend/CHANGELOG.md b/plugins/kafka-backend/CHANGELOG.md index 6bd87b05b7..8294bcd1aa 100644 --- a/plugins/kafka-backend/CHANGELOG.md +++ b/plugins/kafka-backend/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-kafka-backend +## 0.2.29 + +### Patch Changes + +- f6be17460d: Minor API signatures cleanup +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + ## 0.2.29-next.1 ### Patch Changes diff --git a/plugins/kafka-backend/package.json b/plugins/kafka-backend/package.json index 0d65283a53..5c56582454 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.2.29-next.1", + "version": "0.2.29", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,10 +34,10 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/config": "^1.0.2-next.0", - "@backstage/errors": "^1.1.1-next.0", + "@backstage/backend-common": "workspace:^", + "@backstage/catalog-model": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/errors": "workspace:^", "@types/express": "^4.17.6", "express": "^4.17.1", "express-promise-router": "^4.1.0", @@ -46,7 +46,7 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", + "@backstage/cli": "workspace:^", "@types/jest-when": "^3.5.0", "@types/lodash": "^4.14.151", "jest-when": "^3.1.0", diff --git a/plugins/kafka/CHANGELOG.md b/plugins/kafka/CHANGELOG.md index 3a9e86b62e..ca3383b39e 100644 --- a/plugins/kafka/CHANGELOG.md +++ b/plugins/kafka/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-kafka +## 0.3.9 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- f6be17460d: Minor API signatures cleanup +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + ## 0.3.9-next.3 ### Patch Changes diff --git a/plugins/kafka/package.json b/plugins/kafka/package.json index 291f1dcea6..228b2d6bc9 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.9-next.3", + "version": "0.3.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -24,12 +24,12 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/config": "^1.0.2-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", - "@backstage/theme": "^0.2.16", + "@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.57", @@ -40,10 +40,10 @@ "react-router": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/react-hooks": "^8.0.0", diff --git a/plugins/kubernetes-backend/CHANGELOG.md b/plugins/kubernetes-backend/CHANGELOG.md index 626003f241..135bb3cd6e 100644 --- a/plugins/kubernetes-backend/CHANGELOG.md +++ b/plugins/kubernetes-backend/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-kubernetes-backend +## 0.7.2 + +### Patch Changes + +- 8902c2e39d: chore: Exporting KubernetesClientProvider and everything in kubernetes-auth-translator as requested in issue #10457 +- a57d29d572: Adds skipMetricsLookup to the kubernetes-backend schema +- 0768d6dece: add new kubernetes backend endpoints to kubernetes backend client +- 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 + - @backstage/plugin-auth-node@0.2.5 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + - @backstage/plugin-kubernetes-common@0.4.2 + ## 0.7.2-next.3 ### Patch Changes diff --git a/plugins/kubernetes-backend/api-report.md b/plugins/kubernetes-backend/api-report.md index f97a0fd032..4219387819 100644 --- a/plugins/kubernetes-backend/api-report.md +++ b/plugins/kubernetes-backend/api-report.md @@ -8,6 +8,7 @@ import { Config } from '@backstage/config'; import { CoreV1Api } from '@kubernetes/client-node'; import { Credentials } from 'aws-sdk'; import { CustomObjectsApi } from '@kubernetes/client-node'; +import type { CustomResourceMatcher } from '@backstage/plugin-kubernetes-common'; import { Duration } from 'luxon'; import { Entity } from '@backstage/catalog-model'; import express from 'express'; @@ -101,9 +102,6 @@ export interface CustomResource extends ObjectToFetch { objectType: 'customresources'; } -// @alpha (undocumented) -export type CustomResourceMatcher = Omit; - // @alpha (undocumented) export interface CustomResourcesByEntity extends KubernetesObjectsByEntity { // (undocumented) diff --git a/plugins/kubernetes-backend/package.json b/plugins/kubernetes-backend/package.json index f40492e1b7..9adb3d4c22 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.7.2-next.3", + "version": "0.7.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,13 +35,13 @@ }, "dependencies": { "@azure/identity": "^2.0.4", - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/catalog-client": "^1.1.0-next.2", - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/config": "^1.0.2-next.0", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/plugin-auth-node": "^0.2.5-next.3", - "@backstage/plugin-kubernetes-common": "^0.4.2-next.1", + "@backstage/backend-common": "workspace:^", + "@backstage/catalog-client": "workspace:^", + "@backstage/catalog-model": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/plugin-auth-node": "workspace:^", + "@backstage/plugin-kubernetes-common": "workspace:^", "@google-cloud/container": "^4.0.0", "@kubernetes/client-node": "^0.17.0", "@types/express": "^4.17.6", @@ -62,7 +62,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", + "@backstage/cli": "workspace:^", "@types/aws4": "^1.5.1", "aws-sdk-mock": "^5.2.1", "supertest": "^6.1.3" diff --git a/plugins/kubernetes-backend/schema.d.ts b/plugins/kubernetes-backend/schema.d.ts index fed243ef17..59fa7a5d97 100644 --- a/plugins/kubernetes-backend/schema.d.ts +++ b/plugins/kubernetes-backend/schema.d.ts @@ -40,6 +40,8 @@ export interface Config { region?: string; /** @visibility frontend */ skipTLSVerify?: boolean; + /** @visibility frontend */ + skipMetricsLookup?: boolean; } | { /** @visibility frontend */ @@ -62,6 +64,8 @@ export interface Config { oidcTokenProvider?: string; /** @visibility frontend */ skipTLSVerify?: boolean; + /** @visibility frontend */ + skipMetricsLookup?: boolean; }>; } >; diff --git a/plugins/kubernetes-backend/src/kubernetes-auth-translator/AzureIdentityKubernetesAuthTranslator.test.ts b/plugins/kubernetes-backend/src/kubernetes-auth-translator/AzureIdentityKubernetesAuthTranslator.test.ts index a28f825434..704551eb9f 100644 --- a/plugins/kubernetes-backend/src/kubernetes-auth-translator/AzureIdentityKubernetesAuthTranslator.test.ts +++ b/plugins/kubernetes-backend/src/kubernetes-auth-translator/AzureIdentityKubernetesAuthTranslator.test.ts @@ -46,6 +46,10 @@ describe('AzureIdentityKubernetesAuthTranslator tests', () => { url: 'mycluster.privatelink.westeurope.azmk8s.io', }; + afterEach(() => { + jest.useRealTimers(); + }); + it('should decorate cluster with Azure token', async () => { const authTranslator = new AzureIdentityKubernetesAuthTranslator( logger, @@ -70,6 +74,8 @@ describe('AzureIdentityKubernetesAuthTranslator tests', () => { }); it('should issue new token 15 minutes befory expiry', async () => { + jest.useFakeTimers(); + const authTranslator = new AzureIdentityKubernetesAuthTranslator( logger, new StaticTokenCredential(16 * 60 * 1000), // token expires in 16min @@ -78,13 +84,15 @@ describe('AzureIdentityKubernetesAuthTranslator tests', () => { const response = await authTranslator.decorateClusterDetailsWithAuth(cd); expect(response.serviceAccountToken).toEqual('MY_TOKEN_1'); - jest.useFakeTimers().setSystemTime(Date.now() + 2 * 60 * 1000); // advance time by 2mins + jest.setSystemTime(Date.now() + 2 * 60 * 1000); // advance time by 2mins const response2 = await authTranslator.decorateClusterDetailsWithAuth(cd); expect(response2.serviceAccountToken).toEqual('MY_TOKEN_2'); }); it('should re-use existing token if there is afailure', async () => { + jest.useFakeTimers(); + const authTranslator = new AzureIdentityKubernetesAuthTranslator( logger, new StaticTokenCredential(16 * 60 * 1000), // new tokens expires in 16min @@ -93,12 +101,12 @@ describe('AzureIdentityKubernetesAuthTranslator tests', () => { const response = await authTranslator.decorateClusterDetailsWithAuth(cd); expect(response.serviceAccountToken).toEqual('MY_TOKEN_1'); - jest.useFakeTimers().setSystemTime(Date.now() + 2 * 60 * 1000); // advance time by 2min + jest.setSystemTime(Date.now() + 2 * 60 * 1000); // advance time by 2min const response2 = await authTranslator.decorateClusterDetailsWithAuth(cd); expect(response2.serviceAccountToken).toEqual('MY_TOKEN_2'); - jest.useFakeTimers().setSystemTime(Date.now() + 2 * 60 * 1000); // advance time by 2min + jest.setSystemTime(Date.now() + 2 * 60 * 1000); // advance time by 2min const response3 = await authTranslator.decorateClusterDetailsWithAuth(cd); expect(response3.serviceAccountToken).toEqual('MY_TOKEN_2'); @@ -108,6 +116,8 @@ describe('AzureIdentityKubernetesAuthTranslator tests', () => { }); it('should throw if existing token expired and failed to fetch a new one', async () => { + jest.useFakeTimers(); + const authTranslator = new AzureIdentityKubernetesAuthTranslator( logger, new StaticTokenCredential(16 * 60 * 1000), // new tokens expires in 16min @@ -116,12 +126,12 @@ describe('AzureIdentityKubernetesAuthTranslator tests', () => { const response = await authTranslator.decorateClusterDetailsWithAuth(cd); expect(response.serviceAccountToken).toEqual('MY_TOKEN_1'); - jest.useFakeTimers().setSystemTime(Date.now() + 2 * 60 * 1000); // advance time by 2min + jest.setSystemTime(Date.now() + 2 * 60 * 1000); // advance time by 2min const response2 = await authTranslator.decorateClusterDetailsWithAuth(cd); expect(response2.serviceAccountToken).toEqual('MY_TOKEN_2'); - jest.useFakeTimers().setSystemTime(Date.now() + 17 * 60 * 1000); // advance time by 17min + jest.setSystemTime(Date.now() + 17 * 60 * 1000); // advance time by 17min await expect( authTranslator.decorateClusterDetailsWithAuth(cd), diff --git a/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.ts b/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.ts index 7fcc9836a3..23163d1004 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.ts @@ -25,7 +25,6 @@ import { FetchResponseWrapper, ObjectToFetch, CustomResource, - CustomResourceMatcher, CustomResourcesByEntity, KubernetesObjectsByEntity, } from '../types/types'; @@ -40,6 +39,7 @@ import { ObjectsByEntityResponse, PodFetchResponse, KubernetesRequestAuth, + CustomResourceMatcher, } from '@backstage/plugin-kubernetes-common'; import { ContainerStatus, diff --git a/plugins/kubernetes-backend/src/types/types.ts b/plugins/kubernetes-backend/src/types/types.ts index 33fde70b24..5ddfe7367d 100644 --- a/plugins/kubernetes-backend/src/types/types.ts +++ b/plugins/kubernetes-backend/src/types/types.ts @@ -18,6 +18,7 @@ import { Entity } from '@backstage/catalog-model'; import { Logger } from 'winston'; import type { JsonObject } from '@backstage/types'; import type { + CustomResourceMatcher, FetchResponse, KubernetesFetchError, KubernetesRequestAuth, @@ -86,12 +87,6 @@ export interface CustomResource extends ObjectToFetch { objectType: 'customresources'; } -/** - * - * @alpha - */ -export type CustomResourceMatcher = Omit; - /** * * @alpha diff --git a/plugins/kubernetes-common/CHANGELOG.md b/plugins/kubernetes-common/CHANGELOG.md index 08ba0764dc..dd5e74b384 100644 --- a/plugins/kubernetes-common/CHANGELOG.md +++ b/plugins/kubernetes-common/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-kubernetes-common +## 0.4.2 + +### Patch Changes + +- 0768d6dece: add new kubernetes backend endpoints to kubernetes backend client +- d669d89206: Minor API signatures cleanup +- Updated dependencies + - @backstage/catalog-model@1.1.1 + ## 0.4.2-next.1 ### Patch Changes diff --git a/plugins/kubernetes-common/api-report.md b/plugins/kubernetes-common/api-report.md index ef36d5ce28..85015662c6 100644 --- a/plugins/kubernetes-common/api-report.md +++ b/plugins/kubernetes-common/api-report.md @@ -89,6 +89,16 @@ export interface CronJobsFetchResponse { type: 'cronjobs'; } +// @public (undocumented) +export interface CustomObjectsByEntityRequest { + // (undocumented) + auth: KubernetesRequestAuth; + // (undocumented) + customResources: CustomResourceMatcher[]; + // (undocumented) + entity: Entity; +} + // @public (undocumented) export interface CustomResourceFetchResponse { // (undocumented) @@ -97,6 +107,16 @@ export interface CustomResourceFetchResponse { type: 'customresources'; } +// @public (undocumented) +export interface CustomResourceMatcher { + // (undocumented) + apiVersion: string; + // (undocumented) + group: string; + // (undocumented) + plural: string; +} + // @public (undocumented) export interface DaemonSetsFetchResponse { // (undocumented) @@ -233,4 +253,12 @@ export interface StatefulSetsFetchResponse { // (undocumented) type: 'statefulsets'; } + +// @public (undocumented) +export interface WorkloadsByEntityRequest { + // (undocumented) + auth: KubernetesRequestAuth; + // (undocumented) + entity: Entity; +} ``` diff --git a/plugins/kubernetes-common/package.json b/plugins/kubernetes-common/package.json index 3095ac68d4..5baa12800d 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.4.2-next.1", + "version": "0.4.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -38,11 +38,11 @@ "url": "https://github.com/backstage/backstage/issues" }, "dependencies": { - "@backstage/catalog-model": "^1.1.1-next.0", + "@backstage/catalog-model": "workspace:^", "@kubernetes/client-node": "^0.17.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3" + "@backstage/cli": "workspace:^" }, "jest": { "roots": [ diff --git a/plugins/kubernetes-common/src/types.ts b/plugins/kubernetes-common/src/types.ts index 830c32c32c..149caadb15 100644 --- a/plugins/kubernetes-common/src/types.ts +++ b/plugins/kubernetes-common/src/types.ts @@ -39,6 +39,26 @@ export interface KubernetesRequestAuth { }; } +/** @public */ +export interface CustomResourceMatcher { + group: string; + apiVersion: string; + plural: string; +} + +/** @public */ +export interface WorkloadsByEntityRequest { + auth: KubernetesRequestAuth; + entity: Entity; +} + +/** @public */ +export interface CustomObjectsByEntityRequest { + auth: KubernetesRequestAuth; + customResources: CustomResourceMatcher[]; + entity: Entity; +} + /** @public */ export interface KubernetesRequestBody { auth?: KubernetesRequestAuth; diff --git a/plugins/kubernetes/CHANGELOG.md b/plugins/kubernetes/CHANGELOG.md index 264e550c5c..b5909b8c01 100644 --- a/plugins/kubernetes/CHANGELOG.md +++ b/plugins/kubernetes/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-kubernetes +## 0.7.2 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 0768d6dece: add new kubernetes backend endpoints to kubernetes backend client +- 19a27929fb: Reset error state on success +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- ef9ab322de: Minor API signatures cleanup +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/plugin-kubernetes-common@0.4.2 + ## 0.7.2-next.3 ### Patch Changes diff --git a/plugins/kubernetes/api-report.md b/plugins/kubernetes/api-report.md index 81ce386200..b7ec80aee3 100644 --- a/plugins/kubernetes/api-report.md +++ b/plugins/kubernetes/api-report.md @@ -10,6 +10,7 @@ import { BackstagePlugin } from '@backstage/core-plugin-api'; import { ClientPodStatus } from '@backstage/plugin-kubernetes-common'; import { ClusterAttributes } from '@backstage/plugin-kubernetes-common'; import { ClusterObjects } from '@backstage/plugin-kubernetes-common'; +import { CustomObjectsByEntityRequest } from '@backstage/plugin-kubernetes-common'; import { DiscoveryApi } from '@backstage/core-plugin-api'; import { Entity } from '@backstage/catalog-model'; import { IdentityApi } from '@backstage/core-plugin-api'; @@ -31,6 +32,7 @@ import { V1Pod } from '@kubernetes/client-node'; import { V1ReplicaSet } from '@kubernetes/client-node'; import { V1Service } from '@kubernetes/client-node'; import { V1StatefulSet } from '@kubernetes/client-node'; +import { WorkloadsByEntityRequest } from '@backstage/plugin-kubernetes-common'; // Warning: (ae-forgotten-export) The symbol "ClusterProps" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "Cluster" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -245,9 +247,17 @@ export interface KubernetesApi { }[] >; // (undocumented) + getCustomObjectsByEntity( + request: CustomObjectsByEntityRequest, + ): Promise; + // (undocumented) getObjectsByEntity( requestBody: KubernetesRequestBody, ): Promise; + // (undocumented) + getWorkloadsByEntity( + request: WorkloadsByEntityRequest, + ): Promise; } // Warning: (ae-missing-release-tag) "kubernetesApiRef" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -304,9 +314,17 @@ export class KubernetesBackendClient implements KubernetesApi { }[] >; // (undocumented) + getCustomObjectsByEntity( + request: CustomObjectsByEntityRequest, + ): Promise; + // (undocumented) getObjectsByEntity( requestBody: KubernetesRequestBody, ): Promise; + // (undocumented) + getWorkloadsByEntity( + request: WorkloadsByEntityRequest, + ): Promise; } // Warning: (ae-forgotten-export) The symbol "KubernetesContentProps" needs to be exported by the entry point index.d.ts diff --git a/plugins/kubernetes/dev/index.tsx b/plugins/kubernetes/dev/index.tsx index 068f26b7f5..05fcdefc8a 100644 --- a/plugins/kubernetes/dev/index.tsx +++ b/plugins/kubernetes/dev/index.tsx @@ -24,8 +24,10 @@ import { KubernetesApi, } from '../src'; import { + CustomObjectsByEntityRequest, FetchResponse, ObjectsByEntityResponse, + WorkloadsByEntityRequest, } from '@backstage/plugin-kubernetes-common'; import fixture1 from '../src/__fixtures__/1-deployments.json'; import fixture2 from '../src/__fixtures__/2-deployments.json'; @@ -59,6 +61,16 @@ class MockKubernetesClient implements KubernetesApi { ({ type: type.toLocaleLowerCase('en-US'), resources } as FetchResponse), ); } + async getWorkloadsByEntity( + _request: WorkloadsByEntityRequest, + ): Promise { + throw new Error('Method not implemented.'); + } + async getCustomObjectsByEntity( + _request: CustomObjectsByEntityRequest, + ): Promise { + throw new Error('Method not implemented.'); + } async getObjectsByEntity(): Promise { return { diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index 27b91b7c79..a6c3171529 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.7.2-next.3", + "version": "0.7.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,13 +33,13 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/config": "^1.0.2-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", - "@backstage/plugin-kubernetes-common": "^0.4.2-next.1", - "@backstage/theme": "^0.2.16", + "@backstage/catalog-model": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/plugin-catalog-react": "workspace:^", + "@backstage/plugin-kubernetes-common": "workspace:^", + "@backstage/theme": "workspace:^", "@kubernetes/client-node": "^0.17.0", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -56,10 +56,10 @@ "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/react-hooks": "^8.0.0", diff --git a/plugins/kubernetes/src/api/KubernetesBackendClient.ts b/plugins/kubernetes/src/api/KubernetesBackendClient.ts index 209f5f950d..bffc966333 100644 --- a/plugins/kubernetes/src/api/KubernetesBackendClient.ts +++ b/plugins/kubernetes/src/api/KubernetesBackendClient.ts @@ -18,8 +18,11 @@ import { KubernetesApi } from './types'; import { KubernetesRequestBody, ObjectsByEntityResponse, + WorkloadsByEntityRequest, + CustomObjectsByEntityRequest, } from '@backstage/plugin-kubernetes-common'; import { DiscoveryApi, IdentityApi } from '@backstage/core-plugin-api'; +import { stringifyEntityRef } from '@backstage/catalog-model'; export class KubernetesBackendClient implements KubernetesApi { private readonly discoveryApi: DiscoveryApi; @@ -51,10 +54,7 @@ export class KubernetesBackendClient implements KubernetesApi { return await response.json(); } - private async postRequired( - path: string, - requestBody: KubernetesRequestBody, - ): Promise { + private async postRequired(path: string, requestBody: any): Promise { const url = `${await this.discoveryApi.getBaseUrl('kubernetes')}${path}`; const { token: idToken } = await this.identityApi.getCredentials(); const response = await fetch(url, { @@ -78,6 +78,25 @@ export class KubernetesBackendClient implements KubernetesApi { ); } + async getWorkloadsByEntity( + request: WorkloadsByEntityRequest, + ): Promise { + return await this.postRequired('/resources/workloads/query', { + auth: request.auth, + entityRef: stringifyEntityRef(request.entity), + }); + } + + async getCustomObjectsByEntity( + request: CustomObjectsByEntityRequest, + ): Promise { + return await this.postRequired(`/resources/custom/query`, { + entityRef: stringifyEntityRef(request.entity), + auth: request.auth, + customResources: request.customResources, + }); + } + async getClusters(): Promise<{ name: string; authProvider: string }[]> { const { token: idToken } = await this.identityApi.getCredentials(); const url = `${await this.discoveryApi.getBaseUrl('kubernetes')}/clusters`; diff --git a/plugins/kubernetes/src/api/types.ts b/plugins/kubernetes/src/api/types.ts index 7c5943a6eb..0005a8d069 100644 --- a/plugins/kubernetes/src/api/types.ts +++ b/plugins/kubernetes/src/api/types.ts @@ -17,6 +17,8 @@ import { KubernetesRequestBody, ObjectsByEntityResponse, + WorkloadsByEntityRequest, + CustomObjectsByEntityRequest, } from '@backstage/plugin-kubernetes-common'; import { createApiRef } from '@backstage/core-plugin-api'; @@ -35,4 +37,10 @@ export interface KubernetesApi { oidcTokenProvider?: string | undefined; }[] >; + getWorkloadsByEntity( + request: WorkloadsByEntityRequest, + ): Promise; + getCustomObjectsByEntity( + request: CustomObjectsByEntityRequest, + ): Promise; } diff --git a/plugins/lighthouse/CHANGELOG.md b/plugins/lighthouse/CHANGELOG.md index 7cb872e30f..7980f276d6 100644 --- a/plugins/lighthouse/CHANGELOG.md +++ b/plugins/lighthouse/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-lighthouse +## 0.3.9 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- f6be17460d: Minor API signatures cleanup +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + ## 0.3.9-next.3 ### Patch Changes diff --git a/plugins/lighthouse/package.json b/plugins/lighthouse/package.json index cfe7be9b16..78ae3237cb 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.3.9-next.3", + "version": "0.3.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,12 +33,12 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/config": "^1.0.2-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", - "@backstage/theme": "^0.2.16", + "@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.57", @@ -49,10 +49,10 @@ "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/react-hooks": "^8.0.0", diff --git a/plugins/newrelic-dashboard/CHANGELOG.md b/plugins/newrelic-dashboard/CHANGELOG.md index 8668e588fa..bd9d5cd4ca 100644 --- a/plugins/newrelic-dashboard/CHANGELOG.md +++ b/plugins/newrelic-dashboard/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-newrelic-dashboard +## 0.2.2 + +### Patch Changes + +- 3f739be9d9: Minor API signatures cleanup +- d669d89206: Minor API signatures cleanup +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + - @backstage/errors@1.1.1 + ## 0.2.2-next.2 ### Patch Changes diff --git a/plugins/newrelic-dashboard/package.json b/plugins/newrelic-dashboard/package.json index d08ce75ef3..986ebd44ab 100644 --- a/plugins/newrelic-dashboard/package.json +++ b/plugins/newrelic-dashboard/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-newrelic-dashboard", - "version": "0.2.2-next.2", + "version": "0.2.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,19 +22,19 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", + "@backstage/catalog-model": "workspace:^", + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/plugin-catalog-react": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", "react-use": "^17.2.4" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", + "@backstage/cli": "workspace:^", + "@backstage/dev-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@types/react": "^16.13.1 || ^17.0.0", "cross-fetch": "^3.1.5" diff --git a/plugins/newrelic/CHANGELOG.md b/plugins/newrelic/CHANGELOG.md index 3748b744de..66adaffc65 100644 --- a/plugins/newrelic/CHANGELOG.md +++ b/plugins/newrelic/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-newrelic +## 0.3.27 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + ## 0.3.27-next.3 ### Patch Changes diff --git a/plugins/newrelic/package.json b/plugins/newrelic/package.json index 978b0abddd..c76f73c41a 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.27-next.3", + "version": "0.3.27", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,9 +33,9 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/theme": "^0.2.16", + "@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.57", @@ -45,10 +45,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/org/CHANGELOG.md b/plugins/org/CHANGELOG.md index 568bba4890..7e535db9e5 100644 --- a/plugins/org/CHANGELOG.md +++ b/plugins/org/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-org +## 0.5.9 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- ab6650ede9: Added an edit button to the `UserProfileCard` that is enabled when the `backstage.io/edit-url` is present, this matches how the `GroupProfileCard` works +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + ## 0.5.9-next.3 ### Patch Changes diff --git a/plugins/org/package.json b/plugins/org/package.json index f62d938486..9fb4b45a32 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.5.9-next.3", + "version": "0.5.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -28,11 +28,11 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", - "@backstage/theme": "^0.2.16", + "@backstage/catalog-model": "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.57", @@ -47,11 +47,11 @@ "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/catalog-client": "^1.1.0-next.2", - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/catalog-client": "workspace:^", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/pagerduty/CHANGELOG.md b/plugins/pagerduty/CHANGELOG.md index 98485e3836..b4fdd60fae 100644 --- a/plugins/pagerduty/CHANGELOG.md +++ b/plugins/pagerduty/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-pagerduty +## 0.5.2 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 3f739be9d9: Minor API signatures cleanup +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + - @backstage/errors@1.1.1 + ## 0.5.2-next.3 ### Patch Changes diff --git a/plugins/pagerduty/package.json b/plugins/pagerduty/package.json index dda460bbb6..4909465deb 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.5.2-next.3", + "version": "0.5.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,12 +33,12 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", - "@backstage/theme": "^0.2.16", + "@backstage/catalog-model": "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.57", @@ -52,10 +52,10 @@ "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/periskop-backend/CHANGELOG.md b/plugins/periskop-backend/CHANGELOG.md index adf1520cf9..d23f635d8d 100644 --- a/plugins/periskop-backend/CHANGELOG.md +++ b/plugins/periskop-backend/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-periskop-backend +## 0.1.7 + +### Patch Changes + +- 148568b5c2: Switched to using node-fetch instead of cross-fetch as is standard for our backend packages +- 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 + ## 0.1.7-next.3 ### Patch Changes diff --git a/plugins/periskop-backend/package.json b/plugins/periskop-backend/package.json index c49d71028e..4704370394 100644 --- a/plugins/periskop-backend/package.json +++ b/plugins/periskop-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-periskop-backend", - "version": "0.1.7-next.3", + "version": "0.1.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,8 +23,8 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/config": "^1.0.2-next.0", + "@backstage/backend-common": "workspace:^", + "@backstage/config": "workspace:^", "@types/express": "*", "express": "^4.17.1", "express-promise-router": "^4.1.0", @@ -33,7 +33,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", + "@backstage/cli": "workspace:^", "@types/supertest": "^2.0.8", "msw": "^0.47.0", "supertest": "^6.1.6" diff --git a/plugins/periskop/CHANGELOG.md b/plugins/periskop/CHANGELOG.md index 7b5cccc8d4..b4258a2d73 100644 --- a/plugins/periskop/CHANGELOG.md +++ b/plugins/periskop/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-periskop +## 0.1.7 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + - @backstage/errors@1.1.1 + ## 0.1.7-next.2 ### Patch Changes diff --git a/plugins/periskop/package.json b/plugins/periskop/package.json index b4494bc934..94ec1fdc21 100644 --- a/plugins/periskop/package.json +++ b/plugins/periskop/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-periskop", - "version": "0.1.7-next.2", + "version": "0.1.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,12 +23,12 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", - "@backstage/theme": "^0.2.16", + "@backstage/catalog-model": "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.57", @@ -40,10 +40,10 @@ "react-dom": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/permission-backend/CHANGELOG.md b/plugins/permission-backend/CHANGELOG.md index 615104ee9b..9dad2e00fb 100644 --- a/plugins/permission-backend/CHANGELOG.md +++ b/plugins/permission-backend/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-permission-backend +## 0.5.11 + +### Patch Changes + +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- 2cbd533426: Uptake the `IdentityApi` change to use `getIdentity` instead of `authenticate` for retrieving the logged in users identity. +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/plugin-auth-node@0.2.5 + - @backstage/plugin-permission-node@0.6.5 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + - @backstage/plugin-permission-common@0.6.4 + ## 0.5.11-next.2 ### Patch Changes diff --git a/plugins/permission-backend/package.json b/plugins/permission-backend/package.json index 42dd4fcd1c..234e633482 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.11-next.2", + "version": "0.5.11", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,12 +22,12 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/config": "^1.0.2-next.0", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/plugin-auth-node": "^0.2.5-next.3", - "@backstage/plugin-permission-common": "^0.6.4-next.2", - "@backstage/plugin-permission-node": "^0.6.5-next.3", + "@backstage/backend-common": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/plugin-auth-node": "workspace:^", + "@backstage/plugin-permission-common": "workspace:^", + "@backstage/plugin-permission-node": "workspace:^", "@types/express": "*", "dataloader": "^2.0.0", "express": "^4.17.1", @@ -39,7 +39,7 @@ "zod": "^3.11.6" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", + "@backstage/cli": "workspace:^", "@types/lodash": "^4.14.151", "@types/supertest": "^2.0.8", "msw": "^0.47.0", diff --git a/plugins/permission-common/CHANGELOG.md b/plugins/permission-common/CHANGELOG.md index 0a64a7faf8..b906ac0038 100644 --- a/plugins/permission-common/CHANGELOG.md +++ b/plugins/permission-common/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-permission-common +## 0.6.4 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/config@1.0.2 + - @backstage/errors@1.1.1 + ## 0.6.4-next.2 ### Patch Changes diff --git a/plugins/permission-common/package.json b/plugins/permission-common/package.json index 5a6d98aba5..e83131387a 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.6.4-next.2", + "version": "0.6.4", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { @@ -41,14 +41,14 @@ "url": "https://github.com/backstage/backstage/issues" }, "dependencies": { - "@backstage/config": "^1.0.2-next.0", - "@backstage/errors": "^1.1.1-next.0", + "@backstage/config": "workspace:^", + "@backstage/errors": "workspace:^", "cross-fetch": "^3.1.5", "uuid": "^8.0.0", "zod": "^3.11.6" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", + "@backstage/cli": "workspace:^", "msw": "^0.47.0" } } diff --git a/plugins/permission-node/CHANGELOG.md b/plugins/permission-node/CHANGELOG.md index 6ac474d76d..0543ac4e43 100644 --- a/plugins/permission-node/CHANGELOG.md +++ b/plugins/permission-node/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-permission-node +## 0.6.5 + +### Patch Changes + +- 9212439d15: Minor update to tests +- 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/plugin-auth-node@0.2.5 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + - @backstage/plugin-permission-common@0.6.4 + ## 0.6.5-next.3 ### Patch Changes diff --git a/plugins/permission-node/package.json b/plugins/permission-node/package.json index 6cb3f771d5..354aced054 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.6.5-next.3", + "version": "0.6.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,19 +33,19 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/config": "^1.0.2-next.0", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/plugin-auth-node": "^0.2.5-next.3", - "@backstage/plugin-permission-common": "^0.6.4-next.2", + "@backstage/backend-common": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/plugin-auth-node": "workspace:^", + "@backstage/plugin-permission-common": "workspace:^", "@types/express": "^4.17.6", "express": "^4.17.1", "express-promise-router": "^4.1.0", "zod": "^3.11.6" }, "devDependencies": { - "@backstage/backend-test-utils": "^0.1.28-next.3", - "@backstage/cli": "^0.19.0-next.3", + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", "@types/supertest": "^2.0.8", "msw": "^0.47.0", "supertest": "^6.1.3" diff --git a/plugins/permission-react/CHANGELOG.md b/plugins/permission-react/CHANGELOG.md index 8cc4c02424..c69fe65e0a 100644 --- a/plugins/permission-react/CHANGELOG.md +++ b/plugins/permission-react/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-permission-react +## 0.4.5 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 817f3196f6: **DEPRECATION**: The `PermissionedRoute` component has been deprecated in favor of the new `RequirePermission` component. This is because the usage pattern of `PermissionedRoute` is not compatible with React Router v6 stable. + + Embed the type from `react-router` instead of exporting it directly. + +- Updated dependencies + - @backstage/core-plugin-api@1.0.6 + - @backstage/config@1.0.2 + - @backstage/plugin-permission-common@0.6.4 + ## 0.4.5-next.2 ### Patch Changes diff --git a/plugins/permission-react/package.json b/plugins/permission-react/package.json index 82c5140f86..faaca8829f 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.5-next.2", + "version": "0.4.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,9 +31,9 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/config": "^1.0.2-next.0", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/plugin-permission-common": "^0.6.4-next.2", + "@backstage/config": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/plugin-permission-common": "workspace:^", "cross-fetch": "^3.1.5", "react-use": "^17.2.4", "swr": "^1.1.2" @@ -44,8 +44,8 @@ "react-router": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3" }, diff --git a/plugins/playlist-backend/.eslintrc.js b/plugins/playlist-backend/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/playlist-backend/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/playlist-backend/CHANGELOG.md b/plugins/playlist-backend/CHANGELOG.md new file mode 100644 index 0000000000..ca4ab28ba7 --- /dev/null +++ b/plugins/playlist-backend/CHANGELOG.md @@ -0,0 +1,21 @@ +# @backstage/plugin-playlist-backend + +## 0.1.0 + +### Minor Changes + +- d3737da337: Implement playlist plugin, check out the `README.md` for more details! + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/plugin-auth-node@0.2.5 + - @backstage/plugin-permission-node@0.6.5 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + - @backstage/plugin-permission-common@0.6.4 + - @backstage/backend-test-utils@0.1.28 + - @backstage/plugin-playlist-common@0.1.0 diff --git a/plugins/playlist-backend/README.md b/plugins/playlist-backend/README.md new file mode 100644 index 0000000000..14a39ca741 --- /dev/null +++ b/plugins/playlist-backend/README.md @@ -0,0 +1,88 @@ +# Playlist Backend + +Welcome to the playlist backend plugin! + +# Installation + +## Install the package + +```bash +# From your Backstage root directory +yarn add --cwd packages/backend @backstage/plugin-playlist-backend +``` + +## Adding the plugin to your `packages/backend` + +You'll need to add the plugin to the router in your `backend` package. You can do this by creating a file called `packages/backend/src/plugins/playlist.ts` + +```tsx +import { IdentityClient } from '@backstage/plugin-auth-node'; +import { createRouter } from '@backstage/plugin-playlist-backend'; +import { Router } from 'express'; +import { PluginEnvironment } from '../types'; + +export default async function createPlugin( + env: PluginEnvironment, +): Promise { + return await createRouter({ + database: env.database, + discovery: env.discovery, + identity: env.identity, + logger: env.logger, + permissions: env.permissions, + }); +} +``` + +With the `playlist.ts` router setup in place, add the router to `packages/backend/src/index.ts`: + +```diff ++import playlist from './plugins/playlist'; + +async function main() { + ... + const createEnv = makeCreateEnv(config); + + const catalogEnv = useHotMemoize(module, () => createEnv('catalog')); ++ const playlistEnv = useHotMemoize(module, () => createEnv('playlist')); + + const apiRouter = Router(); ++ apiRouter.use('/playlist', await playlist(playlistEnv)); + ... + apiRouter.use(notFoundHandler()); + +``` + +## Setting up plugin permissions + +You configure permissions for specific playlist actions by importing the supported set of permissions from the [playlist-common](../playlist-common/README.md) package along with the custom rules/conditions provided here to incorporate into your [permission policy](https://backstage.io/docs/permissions/writing-a-policy). + +This package also exports a `DefaultPlaylistPermissionPolicy` which contains a recommended default permissions policy you can apply as a "sub-policy" in your app: + +```diff +# packages/backend/src/plugins/permission.ts + ++import { DefaultPlaylistPermissionPolicy, isPlaylistPermission } from '@backstage/plugin-playlist-backend'; +... +class BackstagePermissionPolicy implements PermissionPolicy { ++ private playlistPermissionPolicy = new DefaultPlaylistPermissionPolicy(); + + async handle( + request: PolicyQuery, + user?: BackstageIdentityResponse, + ): Promise { ++ if (isPlaylistPermission(request.permission)) { ++ return this.playlistPermissionPolicy.handle(request, user); ++ } + ... + } +} + +export default async function createPlugin(env: PluginEnvironment): Promise { + return await createRouter({ + config: env.config, + logger: env.logger, + discovery: env.discovery, + policy: new BackstagePermissionPolicy(), + ... +``` diff --git a/plugins/playlist-backend/api-report.md b/plugins/playlist-backend/api-report.md new file mode 100644 index 0000000000..c7109efbfb --- /dev/null +++ b/plugins/playlist-backend/api-report.md @@ -0,0 +1,96 @@ +## API Report File for "@backstage/plugin-playlist-backend" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { BackstageIdentityResponse } from '@backstage/plugin-auth-node'; +import { ConditionalPolicyDecision } from '@backstage/plugin-permission-common'; +import { Conditions } from '@backstage/plugin-permission-node'; +import express from 'express'; +import { IdentityApi } from '@backstage/plugin-auth-node'; +import { Logger } from 'winston'; +import { Permission } from '@backstage/plugin-permission-common'; +import { PermissionCondition } from '@backstage/plugin-permission-common'; +import { PermissionCriteria } from '@backstage/plugin-permission-common'; +import { PermissionEvaluator } from '@backstage/plugin-permission-common'; +import { PermissionPolicy } from '@backstage/plugin-permission-node'; +import { PermissionRule } from '@backstage/plugin-permission-node'; +import { PlaylistMetadata } from '@backstage/plugin-playlist-common'; +import { PluginDatabaseManager } from '@backstage/backend-common'; +import { PluginEndpointDiscovery } from '@backstage/backend-common'; +import { PolicyDecision } from '@backstage/plugin-permission-common'; +import { PolicyQuery } from '@backstage/plugin-permission-node'; +import { ResourcePermission } from '@backstage/plugin-permission-common'; + +// @public (undocumented) +export const createPlaylistConditionalDecision: ( + permission: ResourcePermission<'playlist-list'>, + conditions: PermissionCriteria< + PermissionCondition<'playlist-list', unknown[]> + >, +) => ConditionalPolicyDecision; + +// @public (undocumented) +export function createRouter(options: RouterOptions): Promise; + +// @public +export class DefaultPlaylistPermissionPolicy implements PermissionPolicy { + // (undocumented) + handle( + request: PolicyQuery, + user?: BackstageIdentityResponse, + ): Promise; +} + +// @public (undocumented) +export const isPlaylistPermission: (permission: Permission) => boolean; + +// @public (undocumented) +export type ListPlaylistsFilter = + | { + allOf: ListPlaylistsFilter[]; + } + | { + anyOf: ListPlaylistsFilter[]; + } + | { + not: ListPlaylistsFilter; + } + | ListPlaylistsMatchFilter; + +// @public (undocumented) +export type ListPlaylistsMatchFilter = { + key: string; + values: any[]; +}; + +// @public (undocumented) +export const playlistConditions: Conditions<{ + isOwner: PermissionRule< + PlaylistMetadata, + ListPlaylistsFilter, + 'playlist-list', + [userOwnershipRefs: string[]] + >; + isPublic: PermissionRule< + PlaylistMetadata, + ListPlaylistsFilter, + 'playlist-list', + [] + >; +}>; + +// @public (undocumented) +export interface RouterOptions { + // (undocumented) + database: PluginDatabaseManager; + // (undocumented) + discovery: PluginEndpointDiscovery; + // (undocumented) + identity: IdentityApi; + // (undocumented) + logger: Logger; + // (undocumented) + permissions: PermissionEvaluator; +} +``` diff --git a/plugins/playlist-backend/migrations/20220701011329_init.js b/plugins/playlist-backend/migrations/20220701011329_init.js new file mode 100644 index 0000000000..be08363dec --- /dev/null +++ b/plugins/playlist-backend/migrations/20220701011329_init.js @@ -0,0 +1,64 @@ +/* + * 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. + */ + +exports.up = async function up(knex) { + await knex.schema.createTable('playlists', table => { + table.comment('Playlists table'); + table.uuid('id').primary().comment('Automatically generated unique ID'); + table.text('name').notNullable().comment('The name of the playlist'); + table.text('description').comment('The description of the playlist'); + table.string('owner').notNullable().comment('The owner entity ref'); + table + .boolean('public') + .defaultTo(false) + .notNullable() + .comment('Whether the playlist is public'); + }); + + await knex.schema.createTable('entities', table => { + table.comment('The table of playlist entities'); + table + .uuid('playlist_id') + .notNullable() + .references('playlists.id') + .onDelete('CASCADE') + .comment('The id of the playlist this entity belongs to'); + table.string('entity_ref').notNullable().comment('A entity ref'); + table.unique(['playlist_id', 'entity_ref'], { + indexName: 'playlist_entity_composite_index', + }); + }); + + await knex.schema.createTable('followers', table => { + table.comment('The table of playlist followers'); + table + .uuid('playlist_id') + .notNullable() + .references('playlists.id') + .onDelete('CASCADE') + .comment('The id of the playlist being followed'); + table.string('user_ref').notNullable().comment('A user entity ref'); + table.unique(['playlist_id', 'user_ref'], { + indexName: 'playlist_follower_composite_index', + }); + }); +}; + +exports.down = async function down(knex) { + await knex.schema.dropTable('playlists'); + await knex.schema.dropTable('entities'); + await knex.schema.dropTable('followers'); +}; diff --git a/plugins/playlist-backend/package.json b/plugins/playlist-backend/package.json new file mode 100644 index 0000000000..ae472da767 --- /dev/null +++ b/plugins/playlist-backend/package.json @@ -0,0 +1,54 @@ +{ + "name": "@backstage/plugin-playlist-backend", + "version": "0.1.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" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/backend-common": "workspace:^", + "@backstage/backend-test-utils": "workspace:^", + "@backstage/catalog-client": "workspace:^", + "@backstage/catalog-model": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/plugin-auth-node": "workspace:^", + "@backstage/plugin-permission-common": "workspace:^", + "@backstage/plugin-permission-node": "workspace:^", + "@backstage/plugin-playlist-common": "workspace:^", + "@types/express": "*", + "express": "^4.17.1", + "express-promise-router": "^4.1.0", + "knex": "^2.0.0", + "node-fetch": "^2.6.7", + "uuid": "^8.2.0", + "winston": "^3.2.1", + "yn": "^4.0.0" + }, + "devDependencies": { + "@backstage/cli": "workspace:^", + "@types/supertest": "^2.0.8", + "msw": "^0.47.0", + "supertest": "^6.1.3" + }, + "files": [ + "dist", + "migrations/**/*.{js,d.ts}" + ] +} diff --git a/plugins/playlist-backend/src/index.ts b/plugins/playlist-backend/src/index.ts new file mode 100644 index 0000000000..eeccd8913f --- /dev/null +++ b/plugins/playlist-backend/src/index.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. + */ + +/** + * Playlist backend plugin + * + * @packageDocumentation + */ +export * from './service'; +export { + createPlaylistConditionalDecision, + DefaultPlaylistPermissionPolicy, + isPlaylistPermission, + playlistConditions, +} from './permissions'; diff --git a/plugins/playlist-backend/src/permissions/DefaultPlaylistPermissionPolicy.test.ts b/plugins/playlist-backend/src/permissions/DefaultPlaylistPermissionPolicy.test.ts new file mode 100644 index 0000000000..179b0d7f9b --- /dev/null +++ b/plugins/playlist-backend/src/permissions/DefaultPlaylistPermissionPolicy.test.ts @@ -0,0 +1,135 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { BackstageIdentityResponse } from '@backstage/plugin-auth-node'; +import { + AuthorizeResult, + createPermission, +} from '@backstage/plugin-permission-common'; +import { + permissions, + PLAYLIST_LIST_RESOURCE_TYPE, +} from '@backstage/plugin-playlist-common'; + +import { playlistConditions } from './conditions'; +import { DefaultPlaylistPermissionPolicy } from './DefaultPlaylistPermissionPolicy'; + +describe('DefaultPlaylistPermissionPolicy', () => { + const policy = new DefaultPlaylistPermissionPolicy(); + const mockUser: BackstageIdentityResponse = { + token: 'token', + identity: { + type: 'user', + ownershipEntityRefs: ['user:default/me', 'group:default/owner'], + userEntityRef: 'user:default/me', + }, + }; + + it('should deny non-playlist permissions', async () => { + const mockPermission = createPermission({ + name: 'test.permission', + attributes: { action: 'read' }, + }); + + expect(await policy.handle({ permission: mockPermission })).toEqual({ + result: AuthorizeResult.DENY, + }); + }); + + it('should allow create permissions', async () => { + expect( + await policy.handle({ permission: permissions.playlistListCreate }), + ).toEqual({ result: AuthorizeResult.ALLOW }); + }); + + it('should return a conditional decision for read permissions', async () => { + expect( + await policy.handle( + { permission: permissions.playlistListRead }, + mockUser, + ), + ).toEqual({ + result: AuthorizeResult.CONDITIONAL, + pluginId: 'playlist', + resourceType: PLAYLIST_LIST_RESOURCE_TYPE, + conditions: { + anyOf: [ + playlistConditions.isOwner([ + 'user:default/me', + 'group:default/owner', + ]), + playlistConditions.isPublic(), + ], + }, + }); + }); + + it('should return a conditional decision for followers update permissions', async () => { + expect( + await policy.handle( + { permission: permissions.playlistFollowersUpdate }, + mockUser, + ), + ).toEqual({ + result: AuthorizeResult.CONDITIONAL, + pluginId: 'playlist', + resourceType: PLAYLIST_LIST_RESOURCE_TYPE, + conditions: { + anyOf: [ + playlistConditions.isOwner([ + 'user:default/me', + 'group:default/owner', + ]), + playlistConditions.isPublic(), + ], + }, + }); + }); + + it('should return a conditional decision for update permissions', async () => { + expect( + await policy.handle( + { permission: permissions.playlistListUpdate }, + mockUser, + ), + ).toEqual({ + result: AuthorizeResult.CONDITIONAL, + pluginId: 'playlist', + resourceType: PLAYLIST_LIST_RESOURCE_TYPE, + conditions: playlistConditions.isOwner([ + 'user:default/me', + 'group:default/owner', + ]), + }); + }); + + it('should return a conditional decision for delete permissions', async () => { + expect( + await policy.handle( + { permission: permissions.playlistListDelete }, + mockUser, + ), + ).toEqual({ + result: AuthorizeResult.CONDITIONAL, + pluginId: 'playlist', + resourceType: PLAYLIST_LIST_RESOURCE_TYPE, + conditions: playlistConditions.isOwner([ + 'user:default/me', + 'group:default/owner', + ]), + }); + }); +}); diff --git a/plugins/playlist-backend/src/permissions/DefaultPlaylistPermissionPolicy.ts b/plugins/playlist-backend/src/permissions/DefaultPlaylistPermissionPolicy.ts new file mode 100644 index 0000000000..86d103e789 --- /dev/null +++ b/plugins/playlist-backend/src/permissions/DefaultPlaylistPermissionPolicy.ts @@ -0,0 +1,90 @@ +/* + * 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 { BackstageIdentityResponse } from '@backstage/plugin-auth-node'; +import { + AuthorizeResult, + isPermission, + Permission, + PolicyDecision, +} from '@backstage/plugin-permission-common'; +import { + PermissionPolicy, + PolicyQuery, +} from '@backstage/plugin-permission-node'; +import { permissions } from '@backstage/plugin-playlist-common'; + +import { + createPlaylistConditionalDecision, + playlistConditions, +} from './conditions'; + +/** + * @public + */ +export const isPlaylistPermission = (permission: Permission) => + Object.values(permissions).some(playlistPermission => + isPermission(permission, playlistPermission), + ); + +/** + * Default policy for the Playlist plugin. This should be applied as a "sub-policy" + * of your master permission policy for Playlist permission requests only. + * + * @public + */ +export class DefaultPlaylistPermissionPolicy implements PermissionPolicy { + async handle( + request: PolicyQuery, + user?: BackstageIdentityResponse, + ): Promise { + // Reject permissions we don't know how to evaluate in case this policy was incorrectly applied + if (!isPlaylistPermission(request.permission)) { + return { result: AuthorizeResult.DENY }; + } + + // Anyone should be allowed to create a new playlist + if (isPermission(request.permission, permissions.playlistListCreate)) { + return { result: AuthorizeResult.ALLOW }; + } + + // Reading and following/unfollowing playlists is allowed if it is public or owned + if ( + isPermission(request.permission, permissions.playlistListRead) || + isPermission(request.permission, permissions.playlistFollowersUpdate) + ) { + return createPlaylistConditionalDecision(request.permission, { + anyOf: [ + playlistConditions.isOwner(user?.identity.ownershipEntityRefs ?? []), + playlistConditions.isPublic(), + ], + }); + } + + // Updating or deleting playlists is only allowed for owners + if ( + isPermission(request.permission, permissions.playlistListUpdate) || + isPermission(request.permission, permissions.playlistListDelete) + ) { + return createPlaylistConditionalDecision( + request.permission, + playlistConditions.isOwner(user?.identity.ownershipEntityRefs ?? []), + ); + } + + return { result: AuthorizeResult.ALLOW }; + } +} diff --git a/plugins/playlist-backend/src/permissions/conditions.ts b/plugins/playlist-backend/src/permissions/conditions.ts new file mode 100644 index 0000000000..8162c1046f --- /dev/null +++ b/plugins/playlist-backend/src/permissions/conditions.ts @@ -0,0 +1,44 @@ +/* + * 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 { PLAYLIST_LIST_RESOURCE_TYPE } from '@backstage/plugin-playlist-common'; +import { + ConditionTransformer, + createConditionExports, + createConditionTransformer, +} from '@backstage/plugin-permission-node'; + +import { ListPlaylistsFilter } from '../service'; +import { rules } from './rules'; + +const { conditions, createConditionalDecision } = createConditionExports({ + pluginId: 'playlist', + resourceType: PLAYLIST_LIST_RESOURCE_TYPE, + rules, +}); + +/** + * @public + */ +export const playlistConditions = conditions; + +/** + * @public + */ +export const createPlaylistConditionalDecision = createConditionalDecision; + +export const transformConditions: ConditionTransformer = + createConditionTransformer(Object.values(rules)); diff --git a/plugins/playlist-backend/src/permissions/index.ts b/plugins/playlist-backend/src/permissions/index.ts new file mode 100644 index 0000000000..a6bb633a1e --- /dev/null +++ b/plugins/playlist-backend/src/permissions/index.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. + */ + +export * from './conditions'; +export * from './rules'; +export * from './DefaultPlaylistPermissionPolicy'; diff --git a/plugins/playlist-backend/src/permissions/rules.ts b/plugins/playlist-backend/src/permissions/rules.ts new file mode 100644 index 0000000000..cbf81bee65 --- /dev/null +++ b/plugins/playlist-backend/src/permissions/rules.ts @@ -0,0 +1,54 @@ +/* + * 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 { makeCreatePermissionRule } from '@backstage/plugin-permission-node'; +import { + PLAYLIST_LIST_RESOURCE_TYPE, + PlaylistMetadata, +} from '@backstage/plugin-playlist-common'; + +import { ListPlaylistsFilter } from '../service'; + +const createPlaylistPermissionRule = makeCreatePermissionRule< + PlaylistMetadata, + ListPlaylistsFilter, + typeof PLAYLIST_LIST_RESOURCE_TYPE +>(); + +const isOwner = createPlaylistPermissionRule({ + name: 'IS_OWNER', + description: 'Should allow only if the playlist belongs to the user', + resourceType: PLAYLIST_LIST_RESOURCE_TYPE, + apply: (list: PlaylistMetadata, userOwnershipRefs: string[]) => + userOwnershipRefs.includes(list.owner), + toQuery: (userOwnershipRefs: string[]) => ({ + key: 'owner', + values: userOwnershipRefs, + }), +}); + +const isPublic = createPlaylistPermissionRule({ + name: 'IS_PUBLIC', + description: 'Should allow only if the playlist is public', + resourceType: PLAYLIST_LIST_RESOURCE_TYPE, + apply: (list: PlaylistMetadata) => list.public, + toQuery: () => ({ key: 'public', values: [true] }), +}); + +/** + * @public + */ +export const rules = { isOwner, isPublic }; diff --git a/plugins/playlist-backend/src/run.ts b/plugins/playlist-backend/src/run.ts new file mode 100644 index 0000000000..d945aa13f0 --- /dev/null +++ b/plugins/playlist-backend/src/run.ts @@ -0,0 +1,33 @@ +/* + * 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 { getRootLogger } from '@backstage/backend-common'; +import yn from 'yn'; +import { startStandaloneServer } from './service/standaloneServer'; + +const port = process.env.PLUGIN_PORT ? Number(process.env.PLUGIN_PORT) : 7007; +const enableCors = yn(process.env.PLUGIN_CORS, { default: false }); +const logger = getRootLogger(); + +startStandaloneServer({ port, enableCors, logger }).catch(err => { + logger.error(err); + process.exit(1); +}); + +process.on('SIGINT', () => { + logger.info('CTRL+C pressed; exiting.'); + process.exit(0); +}); diff --git a/plugins/playlist-backend/src/service/DatabaseHandler.test.ts b/plugins/playlist-backend/src/service/DatabaseHandler.test.ts new file mode 100644 index 0000000000..5d6b4aa0ca --- /dev/null +++ b/plugins/playlist-backend/src/service/DatabaseHandler.test.ts @@ -0,0 +1,349 @@ +/* + * 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 { DatabaseHandler } from './DatabaseHandler'; +import { TestDatabaseId, TestDatabases } from '@backstage/backend-test-utils'; +import { BackstageUserIdentity } from '@backstage/plugin-auth-node'; +import { Knex } from 'knex'; +import { v4 as uuid } from 'uuid'; + +describe('DatabaseHandler', () => { + const databases = TestDatabases.create(); + + async function createDatabaseHandler(databaseId: TestDatabaseId) { + const knex = await databases.init(databaseId); + return { + knex, + dbHandler: await DatabaseHandler.create({ database: knex }), + }; + } + + describe.each(databases.eachSupportedId())( + '%p', + databaseId => { + let knex: Knex; + let dbHandler: DatabaseHandler; + const playlist1Id = uuid(); + const playlist2Id = uuid(); + const playlist3Id = uuid(); + const user: BackstageUserIdentity = { + type: 'user', + userEntityRef: 'user:default/foo', + ownershipEntityRefs: ['user:default/foo', 'group:default/foo-group'], + }; + + beforeEach(async () => { + ({ knex, dbHandler } = await createDatabaseHandler(databaseId)); + await knex('playlists').insert([ + { + id: playlist1Id, + name: 'test', + description: 'test description', + owner: 'user:default/foo', + public: true, + }, + { + id: playlist2Id, + name: 'test 2', + description: 'test description 2', + owner: 'group:default/foo-group', + public: false, + }, + { + id: playlist3Id, + name: 'test 3', + description: 'test description 3', + owner: 'user:default/bar', + public: false, + }, + ]); + + await knex('entities').insert([ + { + playlist_id: playlist1Id, + entity_ref: 'component:default/ent0', + }, + { + playlist_id: playlist1Id, + entity_ref: 'component:default/ent1', + }, + { + playlist_id: playlist1Id, + entity_ref: 'component:default/ent2', + }, + { + playlist_id: playlist2Id, + entity_ref: 'component:default/ent1', + }, + ]); + + await knex('followers').insert([ + { + playlist_id: playlist2Id, + user_ref: 'user:default/some-user', + }, + { + playlist_id: playlist2Id, + user_ref: 'user:default/bar', + }, + { + playlist_id: playlist2Id, + user_ref: 'user:default/foo', + }, + { + playlist_id: playlist3Id, + user_ref: 'user:default/foo', + }, + ]); + }, 30000); + + it('listPlaylists', async () => { + const allPlaylists = [ + { + id: playlist1Id, + name: 'test', + description: 'test description', + owner: 'user:default/foo', + public: true, + entities: 3, + followers: 0, + isFollowing: false, + }, + { + id: playlist2Id, + name: 'test 2', + description: 'test description 2', + owner: 'group:default/foo-group', + public: false, + entities: 1, + followers: 3, + isFollowing: true, + }, + { + id: playlist3Id, + name: 'test 3', + description: 'test description 3', + owner: 'user:default/bar', + public: false, + entities: 0, + followers: 1, + isFollowing: true, + }, + ]; + + const playlists = await dbHandler.listPlaylists(user); + expect(playlists.length).toEqual(3); + expect(playlists).toEqual(expect.arrayContaining(allPlaylists)); + + const followedPlaylists = await dbHandler.listPlaylists(user, { + key: 'public', + values: [true], + }); + expect(followedPlaylists).toEqual([allPlaylists[0]]); + + const ownedPlaylists = await dbHandler.listPlaylists(user, { + key: 'owner', + values: user.ownershipEntityRefs, + }); + expect(ownedPlaylists.length).toEqual(2); + expect(ownedPlaylists).toEqual( + expect.arrayContaining([allPlaylists[0], allPlaylists[1]]), + ); + }); + + it('createPlaylist', async () => { + const newList = { + name: 'new list', + description: 'new description', + owner: 'user:default/new', + public: true, + }; + + const newPlaylistId = await dbHandler.createPlaylist(newList); + + const newPlaylist = await knex('playlists').where('id', newPlaylistId); + expect( + newPlaylist.map(list => ({ ...list, public: Boolean(list.public) })), + ).toEqual([ + { + ...newList, + id: newPlaylistId, + }, + ]); + }); + + it('getPlaylist', async () => { + const playlist = await dbHandler.getPlaylist(playlist1Id, user); + expect(playlist).toEqual({ + id: playlist1Id, + name: 'test', + description: 'test description', + owner: 'user:default/foo', + public: true, + entities: 3, + followers: 0, + isFollowing: false, + }); + }); + + it('updatePlaylist', async () => { + const update = { + id: playlist1Id, + name: 'test rename', + description: 'test new description', + owner: 'user:default/new-foo', + public: false, + }; + await dbHandler.updatePlaylist(update); + + const updatedPlaylist = await knex('playlists').where( + 'id', + playlist1Id, + ); + expect( + updatedPlaylist.map(list => ({ + ...list, + public: Boolean(list.public), + })), + ).toEqual([update]); + }); + + it('deletePlaylist', async () => { + await dbHandler.deletePlaylist(playlist1Id); + const deleted = await knex('playlists').where('id', playlist1Id); + expect(deleted.length).toEqual(0); + }); + + it('addPlaylistEntities', async () => { + await dbHandler.addPlaylistEntities(playlist1Id, [ + 'component:default/ent1', + 'component:default/ent3', + 'component:default/ent4', + ]); + + const entities = await knex('entities').where( + 'playlist_id', + playlist1Id, + ); + expect(entities.length).toEqual(5); + expect(entities).toEqual( + expect.arrayContaining([ + { + playlist_id: playlist1Id, + entity_ref: 'component:default/ent0', + }, + { + playlist_id: playlist1Id, + entity_ref: 'component:default/ent1', + }, + { + playlist_id: playlist1Id, + entity_ref: 'component:default/ent2', + }, + { + playlist_id: playlist1Id, + entity_ref: 'component:default/ent3', + }, + { + playlist_id: playlist1Id, + entity_ref: 'component:default/ent4', + }, + ]), + ); + }); + + it('getPlaylistEntities', async () => { + const entities = await dbHandler.getPlaylistEntities(playlist1Id); + expect(entities.length).toEqual(3); + expect(entities).toEqual( + expect.arrayContaining([ + 'component:default/ent0', + 'component:default/ent1', + 'component:default/ent2', + ]), + ); + }); + + it('removePlaylistEntities', async () => { + await dbHandler.removePlaylistEntities(playlist1Id, [ + 'component:default/ent1', + 'component:default/ent2', + ]); + + const entities = await knex('entities').where( + 'playlist_id', + playlist1Id, + ); + expect(entities).toEqual([ + { + playlist_id: playlist1Id, + entity_ref: 'component:default/ent0', + }, + ]); + }); + + it('followPlaylist', async () => { + await dbHandler.followPlaylist(playlist1Id, user); + + const playlist1Followers = await knex('followers').where( + 'playlist_id', + playlist1Id, + ); + expect(playlist1Followers).toEqual([ + { + playlist_id: playlist1Id, + user_ref: 'user:default/foo', + }, + ]); + + await dbHandler.followPlaylist(playlist3Id, user); + + const playlist3Followers = await knex('followers').where( + 'playlist_id', + playlist3Id, + ); + expect(playlist3Followers).toEqual([ + { + playlist_id: playlist3Id, + user_ref: 'user:default/foo', + }, + ]); + }); + + it('unfollowPlaylist', async () => { + await dbHandler.unfollowPlaylist(playlist2Id, user); + + const followers = await knex('followers').where( + 'playlist_id', + playlist2Id, + ); + expect(followers).toEqual( + expect.arrayContaining([ + { + playlist_id: playlist2Id, + user_ref: 'user:default/some-user', + }, + { + playlist_id: playlist2Id, + user_ref: 'user:default/bar', + }, + ]), + ); + }); + }, + 60000, + ); +}); diff --git a/plugins/playlist-backend/src/service/DatabaseHandler.ts b/plugins/playlist-backend/src/service/DatabaseHandler.ts new file mode 100644 index 0000000000..6118f22ff9 --- /dev/null +++ b/plugins/playlist-backend/src/service/DatabaseHandler.ts @@ -0,0 +1,278 @@ +/* + * 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 { resolvePackagePath } from '@backstage/backend-common'; +import { BackstageUserIdentity } from '@backstage/plugin-auth-node'; +import { Playlist, PlaylistMetadata } from '@backstage/plugin-playlist-common'; +import { Knex } from 'knex'; +import { v4 as uuid } from 'uuid'; + +import { + ListPlaylistsFilter, + ListPlaylistsMatchFilter, +} from './ListPlaylistsFilter'; + +const migrationsDir = resolvePackagePath( + '@backstage/plugin-playlist-backend', + 'migrations', +); + +function isMatchFilter( + filter: ListPlaylistsMatchFilter | ListPlaylistsFilter, +): filter is ListPlaylistsMatchFilter { + return filter.hasOwnProperty('key'); +} + +function isOrFilter( + filter: { anyOf: ListPlaylistsFilter[] } | ListPlaylistsFilter, +): filter is { anyOf: ListPlaylistsFilter[] } { + return filter.hasOwnProperty('anyOf'); +} + +function isNegationFilter( + filter: { not: ListPlaylistsFilter } | ListPlaylistsFilter, +): filter is { not: ListPlaylistsFilter } { + return filter.hasOwnProperty('not'); +} + +function parseFilter( + filter: ListPlaylistsFilter, + query: Knex.QueryBuilder, + db: Knex, + negate: boolean = false, +): Knex.QueryBuilder { + if (isMatchFilter(filter)) { + return query.andWhere(function filterFunction() { + if (filter.values.length === 1) { + this.where(filter.key, negate ? '!=' : '=', filter.values[0]); + } else { + this.andWhere(filter.key, negate ? 'not in' : 'in', filter.values); + } + }); + } + + if (isNegationFilter(filter)) { + return parseFilter(filter.not, query, db, !negate); + } + + return query[negate ? 'andWhereNot' : 'andWhere'](function filterFunction() { + if (isOrFilter(filter)) { + for (const subFilter of filter.anyOf ?? []) { + this.orWhere(subQuery => parseFilter(subFilter, subQuery, db)); + } + } else { + for (const subFilter of filter.allOf ?? []) { + this.andWhere(subQuery => parseFilter(subFilter, subQuery, db)); + } + } + }); +} + +type Options = { + database: Knex; +}; + +/** + * @public + */ +export class DatabaseHandler { + static async create(options: Options): Promise { + const { database } = options; + + await database.migrate.latest({ + directory: migrationsDir, + }); + + return new DatabaseHandler(options); + } + + private readonly database: Knex; + + private constructor(options: Options) { + this.database = options.database; + } + + private playlistColumns = ['id', 'name', 'description', 'owner', 'public']; + + async listPlaylists( + user: BackstageUserIdentity, + filter?: ListPlaylistsFilter, + ): Promise { + let playlistQuery = this.database>( + 'playlists', + ) + .select( + ...this.playlistColumns, + this.database.raw('COALESCE(entities, 0) AS entities'), + this.database.raw('COALESCE(followers, 0) AS followers'), + ) + .leftOuterJoin( + this.database('entities') + .as('e') + .select('playlist_id') + .count('entity_ref', { as: 'entities' }) + .groupBy('playlist_id'), + 'playlists.id', + 'e.playlist_id', + ) + .leftOuterJoin( + this.database('followers') + .as('f') + .select('playlist_id') + .count('user_ref', { as: 'followers' }) + .groupBy('playlist_id'), + 'playlists.id', + 'f.playlist_id', + ); + + if (filter) { + playlistQuery = parseFilter(filter, playlistQuery, this.database); + } + + const playlists = await playlistQuery; + + const followedPlaylists = ( + await this.database('followers') + .select('playlist_id') + .where('user_ref', user.userEntityRef) + ).map(follows => follows.playlist_id); + + return playlists.map(list => ({ + ...list, + entities: Number(list.entities), + followers: Number(list.followers), + public: Boolean(list.public), + isFollowing: followedPlaylists.includes(list.id), + })); + } + + async createPlaylist( + playlist: Omit, + ): Promise { + const id = uuid(); + const newPlaylist = await this.database('playlists').insert( + { + ...playlist, + id, + }, + ['id'], + ); + + // MySQL does not support returning from inserts so return generated uuid if undefined + return newPlaylist[0].id ?? id; + } + + async getPlaylist( + id: string, + user?: BackstageUserIdentity, + ): Promise { + const playlist = await this.database>( + 'playlists', + ) + .select( + ...this.playlistColumns, + this.database.raw('COALESCE(entities, 0) AS entities'), + this.database.raw('COALESCE(followers, 0) AS followers'), + ) + .where('id', id) + .leftOuterJoin( + this.database('entities') + .as('e') + .select('playlist_id') + .count('entity_ref', { as: 'entities' }) + .groupBy('playlist_id'), + 'playlists.id', + 'e.playlist_id', + ) + .leftOuterJoin( + this.database('followers') + .as('f') + .select('playlist_id') + .count('user_ref', { as: 'followers' }) + .groupBy('playlist_id'), + 'playlists.id', + 'f.playlist_id', + ); + + if (!playlist.length) { + return undefined; + } + + const followedPlaylists = user + ? ( + await this.database('followers') + .select('playlist_id') + .where('user_ref', user.userEntityRef) + ).map(follows => follows.playlist_id) + : []; + + return { + ...playlist[0], + entities: Number(playlist[0].entities), + followers: Number(playlist[0].followers), + public: Boolean(playlist[0].public), + isFollowing: followedPlaylists.includes(playlist[0].id), + }; + } + + async updatePlaylist(playlist: PlaylistMetadata) { + await this.database('playlists').where('id', playlist.id).update(playlist); + } + + async deletePlaylist(id: string) { + await this.database('playlists').where('id', id).del(); + } + + async addPlaylistEntities(playlistId: string, entityRefs: string[]) { + await this.database('entities') + .insert( + entityRefs.map(ref => ({ playlist_id: playlistId, entity_ref: ref })), + ) + .onConflict(['playlist_id', 'entity_ref']) + .ignore(); + } + + async getPlaylistEntities(playlistId: string): Promise { + return ( + await this.database('entities') + .select('entity_ref') + .where('playlist_id', playlistId) + ).map(entity => entity.entity_ref); + } + + async removePlaylistEntities(playlistId: string, entityRefs: string[]) { + await this.database('entities') + .where(builder => + entityRefs.forEach(ref => + builder.orWhere({ playlist_id: playlistId, entity_ref: ref }), + ), + ) + .del(); + } + + async followPlaylist(playlistId: string, user: BackstageUserIdentity) { + await this.database('followers') + .insert({ playlist_id: playlistId, user_ref: user.userEntityRef }) + .onConflict(['playlist_id', 'user_ref']) + .ignore(); + } + + async unfollowPlaylist(playlistId: string, user: BackstageUserIdentity) { + await this.database('followers') + .where({ playlist_id: playlistId, user_ref: user.userEntityRef }) + .del(); + } +} diff --git a/plugins/playlist-backend/src/service/ListPlaylistsFilter.test.ts b/plugins/playlist-backend/src/service/ListPlaylistsFilter.test.ts new file mode 100644 index 0000000000..64405fa6d0 --- /dev/null +++ b/plugins/playlist-backend/src/service/ListPlaylistsFilter.test.ts @@ -0,0 +1,95 @@ +/* + * 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 { + parseListPlaylistsFilterParams, + parseListPlaylistsFilterString, +} from './ListPlaylistsFilter'; + +describe('parseListPlaylistsFilterParams', () => { + it('translates empty query to empty list', () => { + const result = parseListPlaylistsFilterParams({}); + expect(result).toEqual(undefined); + }); + + it('supports single-string format', () => { + const result = parseListPlaylistsFilterParams({ filter: 'a=1' })!; + expect(result).toEqual({ + anyOf: [{ allOf: [{ key: 'a', values: ['1'] }] }], + }); + }); + + it('supports array-of-strings format', () => { + const result = parseListPlaylistsFilterParams({ + filter: ['a=1', 'b=2'], + }); + expect(result).toEqual({ + anyOf: [ + { allOf: [{ key: 'a', values: ['1'] }] }, + { allOf: [{ key: 'b', values: ['2'] }] }, + ], + }); + }); + + it('merges values within each filter', () => { + const result = parseListPlaylistsFilterParams({ + filter: ['a=1', 'b=2,b=3,c=4'], + }); + expect(result).toEqual({ + anyOf: [ + { allOf: [{ key: 'a', values: ['1'] }] }, + { + allOf: [ + { key: 'b', values: ['2', '3'] }, + { key: 'c', values: ['4'] }, + ], + }, + ], + }); + }); + + it('throws for non-strings', () => { + expect(() => parseListPlaylistsFilterParams({ filter: [3] })).toThrow( + 'Invalid filter', + ); + }); +}); + +describe('parseListPlaylistsFilterString', () => { + it('works for the happy path', () => { + expect(parseListPlaylistsFilterString('')).toBeUndefined(); + expect(parseListPlaylistsFilterString('a=1,b=2,a=3')).toEqual([ + { key: 'a', values: ['1', '3'] }, + { key: 'b', values: ['2'] }, + ]); + }); + + it('trims values', () => { + expect(parseListPlaylistsFilterString(' a = 1 , b = 2 , a = 3 ')).toEqual([ + { key: 'a', values: ['1', '3'] }, + { key: 'b', values: ['2'] }, + ]); + }); + + it('rejects malformed strings', () => { + expect(() => parseListPlaylistsFilterString('x=2,=a')).toThrow( + "Invalid filter, '=a' is not a valid statement (expected a string of the form a=b)", + ); + expect(() => parseListPlaylistsFilterString('x=2,a=')).toThrow( + "Invalid filter, 'a=' is not a valid statement (expected a string of the form a=b)", + ); + }); +}); diff --git a/plugins/playlist-backend/src/service/ListPlaylistsFilter.ts b/plugins/playlist-backend/src/service/ListPlaylistsFilter.ts new file mode 100644 index 0000000000..a746286136 --- /dev/null +++ b/plugins/playlist-backend/src/service/ListPlaylistsFilter.ts @@ -0,0 +1,100 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { InputError } from '@backstage/errors'; + +// TODO(kuangp): this filter shape was basically plagiarized from catalog-backend, +// it should probably be abstracted into a common plugin module to allow others to reuse the same pattern + +/** + * @public + */ +export type ListPlaylistsMatchFilter = { + key: string; + values: any[]; +}; + +/** + * @public + */ +export type ListPlaylistsFilter = + | { allOf: ListPlaylistsFilter[] } + | { anyOf: ListPlaylistsFilter[] } + | { not: ListPlaylistsFilter } + | ListPlaylistsMatchFilter; + +export function parseListPlaylistsFilterParams( + params: Record, +): ListPlaylistsFilter | undefined { + if (!params.filter) { + return undefined; + } + + // Each filter string is on the form a=b,c=d + const filterStrings = [params.filter].flat(); + if (filterStrings.some(p => typeof p !== 'string')) { + throw new InputError('Invalid filter'); + } + + // Outer array: "any of the inner ones" + // Inner arrays: "all of these must match" + const filters = (filterStrings as string[]) + .map(parseListPlaylistsFilterString) + .filter(Boolean); + if (!filters.length) { + return undefined; + } + + return { anyOf: filters.map(f => ({ allOf: f! })) }; +} + +export function parseListPlaylistsFilterString( + filterString: string, +): ListPlaylistsMatchFilter[] | undefined { + const statements = filterString + .split(',') + .map(s => s.trim()) + .filter(Boolean); + + if (!statements.length) { + return undefined; + } + + const filtersByKey = new Map(); + + for (const statement of statements) { + const equalsIndex = statement.indexOf('='); + + const key = + equalsIndex === -1 ? statement : statement.substr(0, equalsIndex).trim(); + const value = + equalsIndex === -1 ? undefined : statement.substr(equalsIndex + 1).trim(); + + if (!key || !value) { + throw new InputError( + `Invalid filter, '${statement}' is not a valid statement (expected a string of the form a=b)`, + ); + } + + const f = filtersByKey.has(key) + ? filtersByKey.get(key) + : filtersByKey.set(key, { key, values: [] }).get(key); + + f!.values.push(value); + } + + return [...filtersByKey.values()]; +} diff --git a/plugins/playlist-backend/src/service/index.ts b/plugins/playlist-backend/src/service/index.ts new file mode 100644 index 0000000000..3a1499f495 --- /dev/null +++ b/plugins/playlist-backend/src/service/index.ts @@ -0,0 +1,21 @@ +/* + * 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 * from './router'; +export type { + ListPlaylistsFilter, + ListPlaylistsMatchFilter, +} from './ListPlaylistsFilter'; diff --git a/plugins/playlist-backend/src/service/router.test.ts b/plugins/playlist-backend/src/service/router.test.ts new file mode 100644 index 0000000000..3f90a8b8af --- /dev/null +++ b/plugins/playlist-backend/src/service/router.test.ts @@ -0,0 +1,570 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + DatabaseManager, + getVoidLogger, + PluginEndpointDiscovery, +} from '@backstage/backend-common'; +import { ConfigReader } from '@backstage/config'; +import { IdentityApi } from '@backstage/plugin-auth-node'; +import { AuthorizeResult } from '@backstage/plugin-permission-common'; +import { permissions } from '@backstage/plugin-playlist-common'; +import express from 'express'; +import request from 'supertest'; + +import { createRouter } from './router'; + +const sampleEntities = [ + { + kind: 'system', + metadata: { + namespace: 'default', + name: 'test-ent-system', + title: 'Test Ent', + description: 'test ent description', + }, + }, + { + kind: 'component', + metadata: { + namespace: 'default', + name: 'test-ent', + title: 'Test Ent 2', + description: 'test ent description 2', + }, + spec: { + type: 'library', + }, + }, +]; +const mockGetEntties = jest + .fn() + .mockImplementation(async () => ({ items: sampleEntities })); +jest.mock('@backstage/catalog-client', () => ({ + CatalogClient: jest + .fn() + .mockImplementation(() => ({ getEntities: mockGetEntties })), +})); + +jest.mock('@backstage/plugin-auth-node', () => ({ + getBearerTokenFromAuthorizationHeader: () => 'token', +})); + +const mockConditionFilter = { key: 'test', values: ['test-val'] }; +jest.mock('../permissions', () => ({ + ...jest.requireActual('../permissions'), + transformConditions: () => mockConditionFilter, +})); + +const mockPlaylist = { + id: 'playlist-id', + name: 'test-playlist', + owner: 'group:default/owner', + public: true, + entities: 2, + followers: 4, + isFollowing: false, +}; + +const mockEntities = [ + 'component:default/test-ent', + 'system:default/test-ent-system', +]; + +const mockDbHandler = { + listPlaylists: jest.fn().mockImplementation(async () => [mockPlaylist]), + createPlaylist: jest.fn().mockImplementation(async () => 'playlist-id'), + getPlaylist: jest.fn().mockImplementation(async () => mockPlaylist), + updatePlaylist: jest.fn().mockImplementation(async () => {}), + deletePlaylist: jest.fn().mockImplementation(async () => {}), + addPlaylistEntities: jest.fn().mockImplementation(async () => {}), + getPlaylistEntities: jest.fn().mockImplementation(async () => mockEntities), + removePlaylistEntities: jest.fn().mockImplementation(async () => {}), + followPlaylist: jest.fn().mockImplementation(async () => {}), + unfollowPlaylist: jest.fn().mockImplementation(async () => {}), +}; + +jest.mock('./DatabaseHandler', () => ({ + DatabaseHandler: { create: async () => mockDbHandler }, +})); + +describe('createRouter', () => { + let app: express.Express; + + const createDatabase = () => + DatabaseManager.fromConfig( + new ConfigReader({ + backend: { + database: { + client: 'better-sqlite3', + connection: ':memory:', + }, + }, + }), + ).forPlugin('playlist'); + + const mockedAuthorize = jest + .fn() + .mockImplementation(async () => [{ result: AuthorizeResult.ALLOW }]); + const mockedAuthorizeConditional = jest + .fn() + .mockImplementation(async () => [{ result: AuthorizeResult.ALLOW }]); + const mockPermissionEvaluator = { + authorize: mockedAuthorize, + authorizeConditional: mockedAuthorizeConditional, + }; + + const mockUser = { + type: 'user', + ownershipEntityRefs: ['user:default/me', 'group:default/owner'], + userEntityRef: 'user:default/me', + }; + const mockIdentityClient = { + getIdentity: jest + .fn() + .mockImplementation(async () => ({ identity: mockUser })), + } as unknown as IdentityApi; + + const discovery: jest.Mocked = { + getBaseUrl: jest.fn(), + getExternalBaseUrl: jest.fn(), + }; + + beforeEach(async () => { + const router = await createRouter({ + database: createDatabase(), + discovery, + identity: mockIdentityClient, + logger: getVoidLogger(), + permissions: mockPermissionEvaluator, + }); + + app = express().use(router); + jest.clearAllMocks(); + }); + + describe('GET /', () => { + const mockRequestFilter = { + anyOf: [ + { allOf: [{ key: 'mock', values: ['test'] }] }, + { allOf: [{ key: 'foo', values: ['bar'] }] }, + ], + }; + + it('should respond correctly if unauthorized', async () => { + mockedAuthorizeConditional.mockImplementationOnce(async () => [ + { result: AuthorizeResult.DENY }, + ]); + const response = await request(app).get('/').send(); + + expect(mockedAuthorizeConditional).toHaveBeenCalledWith( + [{ permission: permissions.playlistListRead }], + { token: 'token' }, + ); + expect(mockDbHandler.listPlaylists).not.toHaveBeenCalled(); + expect(response.status).toEqual(403); + }); + + it('should get playlists correctly', async () => { + let response = await request(app).get('/').send(); + expect(mockDbHandler.listPlaylists).toHaveBeenLastCalledWith( + mockUser, + undefined, + ); + expect(response.status).toEqual(200); + expect(response.body).toEqual([mockPlaylist]); + + mockedAuthorizeConditional.mockImplementationOnce(async () => [ + { result: AuthorizeResult.CONDITIONAL }, + ]); + response = await request(app).get('/').send(); + expect(mockDbHandler.listPlaylists).toHaveBeenLastCalledWith( + mockUser, + mockConditionFilter, + ); + expect(response.status).toEqual(200); + expect(response.body).toEqual([mockPlaylist]); + }); + + it('should get filtered playlists correctly', async () => { + let response = await request(app) + .get('/?filter=mock=test&filter=foo=bar') + .send(); + expect(mockDbHandler.listPlaylists).toHaveBeenLastCalledWith( + mockUser, + mockRequestFilter, + ); + expect(response.status).toEqual(200); + expect(response.body).toEqual([mockPlaylist]); + + mockedAuthorizeConditional.mockImplementationOnce(async () => [ + { result: AuthorizeResult.CONDITIONAL }, + ]); + response = await request(app) + .get('/?filter=mock=test&filter=foo=bar') + .send(); + expect(mockDbHandler.listPlaylists).toHaveBeenLastCalledWith(mockUser, { + allOf: [mockRequestFilter, mockConditionFilter], + }); + expect(response.status).toEqual(200); + expect(response.body).toEqual([mockPlaylist]); + }); + + it('should get editable playlists correctly', async () => { + let response = await request(app).get('/?editable=true').send(); + expect(mockedAuthorizeConditional).toHaveBeenCalledWith( + [{ permission: permissions.playlistListUpdate }], + { token: 'token' }, + ); + expect(mockDbHandler.listPlaylists).toHaveBeenLastCalledWith( + mockUser, + undefined, + ); + expect(response.status).toEqual(200); + expect(response.body).toEqual([mockPlaylist]); + + response = await request(app) + .get('/?editable=true&filter=mock=test&filter=foo=bar') + .send(); + expect(mockDbHandler.listPlaylists).toHaveBeenLastCalledWith( + mockUser, + mockRequestFilter, + ); + expect(response.status).toEqual(200); + expect(response.body).toEqual([mockPlaylist]); + + mockedAuthorizeConditional.mockImplementation(async () => [ + { result: AuthorizeResult.CONDITIONAL }, + ]); + response = await request(app).get('/?editable=true').send(); + expect(mockDbHandler.listPlaylists).toHaveBeenLastCalledWith(mockUser, { + allOf: [mockConditionFilter, mockConditionFilter], + }); + expect(response.status).toEqual(200); + expect(response.body).toEqual([mockPlaylist]); + + mockedAuthorizeConditional.mockImplementation(async () => [ + { result: AuthorizeResult.CONDITIONAL }, + ]); + response = await request(app) + .get('/?editable=true&filter=mock=test&filter=foo=bar') + .send(); + expect(mockDbHandler.listPlaylists).toHaveBeenLastCalledWith(mockUser, { + allOf: [ + { allOf: [mockRequestFilter, mockConditionFilter] }, + mockConditionFilter, + ], + }); + expect(response.status).toEqual(200); + expect(response.body).toEqual([mockPlaylist]); + }); + }); + + describe('POST /', () => { + const body = { name: 'new-playlist' }; + + it('should respond correctly if unauthorized', async () => { + mockedAuthorize.mockImplementationOnce(async () => [ + { result: AuthorizeResult.DENY }, + ]); + const response = await request(app).post('/').send(body); + + expect(mockedAuthorize).toHaveBeenCalledWith( + [{ permission: permissions.playlistListCreate }], + { token: 'token' }, + ); + expect(mockDbHandler.createPlaylist).not.toHaveBeenCalled(); + expect(response.status).toEqual(403); + }); + + it('should create a playlist correctly', async () => { + const response = await request(app).post('/').send(body); + expect(mockDbHandler.createPlaylist).toHaveBeenCalledWith(body); + expect(response.status).toEqual(201); + expect(response.body).toEqual('playlist-id'); + }); + }); + + describe('GET /:playlistId', () => { + it('should respond correctly if unauthorized', async () => { + mockedAuthorize.mockImplementationOnce(async () => [ + { result: AuthorizeResult.DENY }, + ]); + const response = await request(app).get('/playlist-id').send(); + + expect(mockedAuthorize).toHaveBeenCalledWith( + [ + { + permission: permissions.playlistListRead, + resourceRef: 'playlist-id', + }, + ], + { token: 'token' }, + ); + expect(mockDbHandler.getPlaylist).not.toHaveBeenCalled(); + expect(response.status).toEqual(403); + }); + + it('should get a playlist correctly', async () => { + const response = await request(app).get('/playlist-id').send(); + expect(mockDbHandler.getPlaylist).toHaveBeenCalledWith( + 'playlist-id', + mockUser, + ); + expect(response.status).toEqual(200); + expect(response.body).toEqual(mockPlaylist); + }); + }); + + describe('PUT /:playlistId', () => { + it('should respond correctly if unauthorized', async () => { + mockedAuthorize.mockImplementationOnce(async () => [ + { result: AuthorizeResult.DENY }, + ]); + const response = await request(app) + .put('/playlist-id') + .send(mockPlaylist); + + expect(mockedAuthorize).toHaveBeenCalledWith( + [ + { + permission: permissions.playlistListUpdate, + resourceRef: 'playlist-id', + }, + ], + { token: 'token' }, + ); + expect(mockDbHandler.updatePlaylist).not.toHaveBeenCalled(); + expect(response.status).toEqual(403); + }); + + it('should update a playlist correctly', async () => { + const response = await request(app) + .put('/playlist-id') + .send(mockPlaylist); + expect(mockDbHandler.updatePlaylist).toHaveBeenCalledWith(mockPlaylist); + expect(response.status).toEqual(200); + }); + }); + + describe('DELETE /:playlistId', () => { + it('should respond correctly if unauthorized', async () => { + mockedAuthorize.mockImplementationOnce(async () => [ + { result: AuthorizeResult.DENY }, + ]); + const response = await request(app).delete('/playlist-id').send(); + + expect(mockedAuthorize).toHaveBeenCalledWith( + [ + { + permission: permissions.playlistListDelete, + resourceRef: 'playlist-id', + }, + ], + { token: 'token' }, + ); + expect(mockDbHandler.deletePlaylist).not.toHaveBeenCalled(); + expect(response.status).toEqual(403); + }); + + it('should delete a playlist correctly', async () => { + const response = await request(app).delete('/playlist-id').send(); + expect(mockDbHandler.deletePlaylist).toHaveBeenCalledWith('playlist-id'); + expect(response.status).toEqual(200); + }); + }); + + describe('POST /:playlistId/entities', () => { + it('should respond correctly if unauthorized', async () => { + mockedAuthorize.mockImplementationOnce(async () => [ + { result: AuthorizeResult.DENY }, + ]); + const response = await request(app) + .post('/playlist-id/entities') + .send(['component:default/test-ent']); + + expect(mockedAuthorize).toHaveBeenCalledWith( + [ + { + permission: permissions.playlistListUpdate, + resourceRef: 'playlist-id', + }, + ], + { token: 'token' }, + ); + expect(mockDbHandler.addPlaylistEntities).not.toHaveBeenCalled(); + expect(response.status).toEqual(403); + }); + + it('should add entities to a playlist correctly', async () => { + const response = await request(app) + .post('/playlist-id/entities') + .send(mockEntities); + expect(mockDbHandler.addPlaylistEntities).toHaveBeenCalledWith( + 'playlist-id', + mockEntities, + ); + expect(response.status).toEqual(200); + }); + }); + + describe('GET /:playlistId/entities', () => { + it('should respond correctly if unauthorized', async () => { + mockedAuthorize.mockImplementationOnce(async () => [ + { result: AuthorizeResult.DENY }, + ]); + const response = await request(app).get('/playlist-id/entities').send(); + + expect(mockedAuthorize).toHaveBeenCalledWith( + [ + { + permission: permissions.playlistListRead, + resourceRef: 'playlist-id', + }, + ], + { token: 'token' }, + ); + expect(mockDbHandler.getPlaylistEntities).not.toHaveBeenCalled(); + expect(mockGetEntties).not.toHaveBeenCalled(); + expect(response.status).toEqual(403); + }); + + it('should get entities from a playlist correctly', async () => { + const response = await request(app).get('/playlist-id/entities').send(); + expect(mockDbHandler.getPlaylistEntities).toHaveBeenCalledWith( + 'playlist-id', + ); + expect(mockGetEntties).toHaveBeenCalledWith( + { + filter: [ + { + kind: 'component', + 'metadata.namespace': 'default', + 'metadata.name': 'test-ent', + }, + { + kind: 'system', + 'metadata.namespace': 'default', + 'metadata.name': 'test-ent-system', + }, + ], + }, + { token: 'token' }, + ); + expect(response.status).toEqual(200); + expect(response.body).toEqual(sampleEntities); + }); + }); + + describe('DELETE /:playlistId/entities', () => { + it('should respond correctly if unauthorized', async () => { + mockedAuthorize.mockImplementationOnce(async () => [ + { result: AuthorizeResult.DENY }, + ]); + const response = await request(app) + .delete('/playlist-id/entities') + .send(mockEntities); + + expect(mockedAuthorize).toHaveBeenCalledWith( + [ + { + permission: permissions.playlistListUpdate, + resourceRef: 'playlist-id', + }, + ], + { token: 'token' }, + ); + expect(mockDbHandler.removePlaylistEntities).not.toHaveBeenCalled(); + expect(response.status).toEqual(403); + }); + + it('should delete entities from a playlist correctly', async () => { + const response = await request(app) + .delete('/playlist-id/entities') + .send(mockEntities); + expect(mockDbHandler.removePlaylistEntities).toHaveBeenCalledWith( + 'playlist-id', + mockEntities, + ); + expect(response.status).toEqual(200); + }); + }); + + describe('POST /:playlistId/followers', () => { + it('should respond correctly if unauthorized', async () => { + mockedAuthorize.mockImplementationOnce(async () => [ + { result: AuthorizeResult.DENY }, + ]); + const response = await request(app).post('/playlist-id/followers').send(); + + expect(mockedAuthorize).toHaveBeenCalledWith( + [ + { + permission: permissions.playlistFollowersUpdate, + resourceRef: 'playlist-id', + }, + ], + { token: 'token' }, + ); + expect(mockDbHandler.followPlaylist).not.toHaveBeenCalled(); + expect(response.status).toEqual(403); + }); + + it('should follow a playlist correctly', async () => { + const response = await request(app).post('/playlist-id/followers').send(); + expect(mockDbHandler.followPlaylist).toHaveBeenCalledWith( + 'playlist-id', + mockUser, + ); + expect(response.status).toEqual(200); + }); + }); + + describe('DELETE /:playlistId/followers', () => { + it('should respond correctly if unauthorized', async () => { + mockedAuthorize.mockImplementationOnce(async () => [ + { result: AuthorizeResult.DENY }, + ]); + const response = await request(app) + .delete('/playlist-id/followers') + .send(); + + expect(mockedAuthorize).toHaveBeenCalledWith( + [ + { + permission: permissions.playlistFollowersUpdate, + resourceRef: 'playlist-id', + }, + ], + { token: 'token' }, + ); + expect(mockDbHandler.unfollowPlaylist).not.toHaveBeenCalled(); + expect(response.status).toEqual(403); + }); + + it('should unfollow a playlist correctly', async () => { + const response = await request(app) + .delete('/playlist-id/followers') + .send(); + expect(mockDbHandler.unfollowPlaylist).toHaveBeenCalledWith( + 'playlist-id', + mockUser, + ); + expect(response.status).toEqual(200); + }); + }); +}); diff --git a/plugins/playlist-backend/src/service/router.ts b/plugins/playlist-backend/src/service/router.ts new file mode 100644 index 0000000000..bf0b789b7a --- /dev/null +++ b/plugins/playlist-backend/src/service/router.ts @@ -0,0 +1,273 @@ +/* + * 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 { + errorHandler, + PluginDatabaseManager, + PluginEndpointDiscovery, +} from '@backstage/backend-common'; +import { CatalogClient } from '@backstage/catalog-client'; +import { parseEntityRef } from '@backstage/catalog-model'; +import { NotAllowedError } from '@backstage/errors'; +import { + getBearerTokenFromAuthorizationHeader, + IdentityApi, +} from '@backstage/plugin-auth-node'; +import { + AuthorizePermissionRequest, + AuthorizeResult, + PermissionEvaluator, + QueryPermissionRequest, +} from '@backstage/plugin-permission-common'; +import { createPermissionIntegrationRouter } from '@backstage/plugin-permission-node'; +import { + PLAYLIST_LIST_RESOURCE_TYPE, + permissions, +} from '@backstage/plugin-playlist-common'; +import express from 'express'; +import Router from 'express-promise-router'; +import { Logger } from 'winston'; + +import { rules, transformConditions } from '../permissions'; +import { DatabaseHandler } from './DatabaseHandler'; +import { parseListPlaylistsFilterParams } from './ListPlaylistsFilter'; + +/** + * @public + */ +export interface RouterOptions { + database: PluginDatabaseManager; + discovery: PluginEndpointDiscovery; + identity: IdentityApi; + logger: Logger; + permissions: PermissionEvaluator; +} + +/** + * @public + */ +export async function createRouter( + options: RouterOptions, +): Promise { + const { + database, + discovery, + identity, + logger, + permissions: permissionEvaluator, + } = options; + + logger.info('Initializing Playlist backend'); + + const catalogClient = new CatalogClient({ discoveryApi: discovery }); + const db = await database.getClient(); + const dbHandler = await DatabaseHandler.create({ database: db }); + + const evaluateRequestPermission = async ( + request: express.Request, + permission: AuthorizePermissionRequest | QueryPermissionRequest, + conditional: boolean = false, + ) => { + const token = getBearerTokenFromAuthorizationHeader( + request.header('authorization'), + ); + + const user = await identity.getIdentity({ request }); + if (!user) { + throw new NotAllowedError('Unauthorized'); + } + + const decision = conditional + ? ( + await permissionEvaluator.authorizeConditional( + [permission as QueryPermissionRequest], + { token }, + ) + )[0] + : ( + await permissionEvaluator.authorize( + [permission as AuthorizePermissionRequest], + { token }, + ) + )[0]; + + if (decision.result === AuthorizeResult.DENY) { + throw new NotAllowedError('Unauthorized'); + } + + return { decision, user: user.identity }; + }; + + const permissionIntegrationRouter = createPermissionIntegrationRouter({ + getResources: resourceRefs => + Promise.all(resourceRefs.map(ref => dbHandler.getPlaylist(ref))), + resourceType: PLAYLIST_LIST_RESOURCE_TYPE, + rules: Object.values(rules), + }); + + const router = Router(); + router.use(express.json()); + router.use(permissionIntegrationRouter); + + router.get('/', async (req, res) => { + const { decision, user } = await evaluateRequestPermission( + req, + { permission: permissions.playlistListRead }, + true, + ); + + let filter = parseListPlaylistsFilterParams(req.query); + if (decision.result === AuthorizeResult.CONDITIONAL) { + const conditionsFilter = transformConditions(decision.conditions); + filter = filter + ? { allOf: [filter, conditionsFilter] } + : conditionsFilter; + } + + if (req.query.editable) { + const { decision: updatePermissionDecision } = + await evaluateRequestPermission( + req, + { permission: permissions.playlistListUpdate }, + true, + ); + + if (updatePermissionDecision.result === AuthorizeResult.CONDITIONAL) { + const updateConditionsFilter = transformConditions( + updatePermissionDecision.conditions, + ); + filter = filter + ? { allOf: [filter, updateConditionsFilter] } + : updateConditionsFilter; + } + } + + const playlists = await dbHandler.listPlaylists(user, filter); + res.json(playlists); + }); + + router.post('/', async (req, res) => { + await evaluateRequestPermission(req, { + permission: permissions.playlistListCreate, + }); + const playlistId = await dbHandler.createPlaylist(req.body); + res.status(201).json(playlistId); + }); + + router.get('/:playlistId', async (req, res) => { + const { user } = await evaluateRequestPermission(req, { + permission: permissions.playlistListRead, + resourceRef: req.params.playlistId, + }); + const playlist = await dbHandler.getPlaylist(req.params.playlistId, user); + res.json(playlist); + }); + + router.put('/:playlistId', async (req, res) => { + await evaluateRequestPermission(req, { + permission: permissions.playlistListUpdate, + resourceRef: req.params.playlistId, + }); + await dbHandler.updatePlaylist({ ...req.body, id: req.params.playlistId }); + res.status(200).end(); + }); + + router.delete('/:playlistId', async (req, res) => { + await evaluateRequestPermission(req, { + permission: permissions.playlistListDelete, + resourceRef: req.params.playlistId, + }); + await dbHandler.deletePlaylist(req.params.playlistId); + res.status(200).end(); + }); + + router.post('/:playlistId/entities', async (req, res) => { + await evaluateRequestPermission(req, { + permission: permissions.playlistListUpdate, + resourceRef: req.params.playlistId, + }); + await dbHandler.addPlaylistEntities(req.params.playlistId, req.body); + res.status(200).end(); + }); + + router.get('/:playlistId/entities', async (req, res) => { + await evaluateRequestPermission(req, { + permission: permissions.playlistListRead, + resourceRef: req.params.playlistId, + }); + + const entityRefs = await dbHandler.getPlaylistEntities( + req.params.playlistId, + ); + if (!entityRefs.length) { + res.json([]); + return; + } + + const filter = entityRefs.map(ref => { + const compoundRef = parseEntityRef(ref); + return { + kind: compoundRef.kind, + 'metadata.namespace': compoundRef.namespace, + 'metadata.name': compoundRef.name, + }; + }); + + const token = getBearerTokenFromAuthorizationHeader( + req.header('authorization'), + ); + + // TODO(kuanpg): entities in this playlist that no longer exist in the catalog will be + // excluded from this response, we need a way to clean up these orphaned refs potentially + // via catalog events (https://github.com/backstage/backstage/issues/8219) + // + // Note: This will also enforce catalog permissions and will only return entities for which the current user has access to + const entities = (await catalogClient.getEntities({ filter }, { token })) + .items; + + res.json(entities); + }); + + router.delete('/:playlistId/entities', async (req, res) => { + await evaluateRequestPermission(req, { + permission: permissions.playlistListUpdate, + resourceRef: req.params.playlistId, + }); + await dbHandler.removePlaylistEntities(req.params.playlistId, req.body); + res.status(200).end(); + }); + + router.post('/:playlistId/followers', async (req, res) => { + const { user } = await evaluateRequestPermission(req, { + permission: permissions.playlistFollowersUpdate, + resourceRef: req.params.playlistId, + }); + await dbHandler.followPlaylist(req.params.playlistId, user); + res.status(200).end(); + }); + + router.delete('/:playlistId/followers', async (req, res) => { + const { user } = await evaluateRequestPermission(req, { + permission: permissions.playlistFollowersUpdate, + resourceRef: req.params.playlistId, + }); + await dbHandler.unfollowPlaylist(req.params.playlistId, user); + res.status(200).end(); + }); + + router.use(errorHandler()); + return router; +} diff --git a/plugins/playlist-backend/src/service/standaloneServer.ts b/plugins/playlist-backend/src/service/standaloneServer.ts new file mode 100644 index 0000000000..3b6acfd09b --- /dev/null +++ b/plugins/playlist-backend/src/service/standaloneServer.ts @@ -0,0 +1,91 @@ +/* + * 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 { + createServiceBuilder, + DatabaseManager, + loadBackendConfig, + ServerTokenManager, + SingleHostDiscovery, + useHotMemoize, +} from '@backstage/backend-common'; +import { ConfigReader } from '@backstage/config'; +import { DefaultIdentityClient } from '@backstage/plugin-auth-node'; +import { ServerPermissionClient } from '@backstage/plugin-permission-node'; +import { Server } from 'http'; +import { Logger } from 'winston'; +import { createRouter } from './router'; + +export interface ServerOptions { + port: number; + enableCors: boolean; + logger: Logger; +} + +export async function startStandaloneServer( + options: ServerOptions, +): Promise { + const logger = options.logger.child({ service: 'playlist-backend' }); + const config = await loadBackendConfig({ logger, argv: process.argv }); + const discovery = SingleHostDiscovery.fromConfig(config); + + const database = useHotMemoize(module, () => { + const manager = DatabaseManager.fromConfig( + new ConfigReader({ + backend: { + database: { client: 'better-sqlite3', connection: ':memory:' }, + }, + }), + ); + return manager.forPlugin('playlist'); + }); + + const identity = DefaultIdentityClient.create({ + discovery, + issuer: await discovery.getExternalBaseUrl('auth'), + }); + + const tokenManager = ServerTokenManager.fromConfig(config, { + logger, + }); + const permissions = ServerPermissionClient.fromConfig(config, { + discovery, + tokenManager, + }); + + logger.debug('Starting application server...'); + const router = await createRouter({ + database, + discovery, + identity, + logger, + permissions, + }); + + let service = createServiceBuilder(module) + .setPort(options.port) + .addRouter('/playlist', router); + if (options.enableCors) { + service = service.enableCors({ origin: 'http://localhost:3000' }); + } + + return await service.start().catch(err => { + logger.error(err); + process.exit(1); + }); +} + +module.hot?.accept(); diff --git a/plugins/playlist-backend/src/setupTests.ts b/plugins/playlist-backend/src/setupTests.ts new file mode 100644 index 0000000000..813cdeaae3 --- /dev/null +++ b/plugins/playlist-backend/src/setupTests.ts @@ -0,0 +1,17 @@ +/* + * 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 {}; diff --git a/plugins/playlist-common/.eslintrc.js b/plugins/playlist-common/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/playlist-common/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/playlist-common/CHANGELOG.md b/plugins/playlist-common/CHANGELOG.md new file mode 100644 index 0000000000..1c7ae8af12 --- /dev/null +++ b/plugins/playlist-common/CHANGELOG.md @@ -0,0 +1,12 @@ +# @backstage/plugin-playlist-common + +## 0.1.0 + +### Minor Changes + +- d3737da337: Implement playlist plugin, check out the `README.md` for more details! + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.6.4 diff --git a/plugins/playlist-common/README.md b/plugins/playlist-common/README.md new file mode 100644 index 0000000000..72f502386c --- /dev/null +++ b/plugins/playlist-common/README.md @@ -0,0 +1,3 @@ +# Playlist Common + +Common functionalities, types, and permissions for the playlist plugin. diff --git a/plugins/playlist-common/api-report.md b/plugins/playlist-common/api-report.md new file mode 100644 index 0000000000..e97cb3dc64 --- /dev/null +++ b/plugins/playlist-common/api-report.md @@ -0,0 +1,36 @@ +## API Report File for "@backstage/plugin-playlist-common" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { BasicPermission } from '@backstage/plugin-permission-common'; +import { ResourcePermission } from '@backstage/plugin-permission-common'; + +// @public (undocumented) +export const permissions: { + playlistListCreate: BasicPermission; + playlistListRead: ResourcePermission<'playlist-list'>; + playlistListUpdate: ResourcePermission<'playlist-list'>; + playlistListDelete: ResourcePermission<'playlist-list'>; + playlistFollowersUpdate: ResourcePermission<'playlist-list'>; +}; + +// @public (undocumented) +export type Playlist = PlaylistMetadata & { + entities: number; + followers: number; + isFollowing: boolean; +}; + +// @public (undocumented) +export const PLAYLIST_LIST_RESOURCE_TYPE = 'playlist-list'; + +// @public (undocumented) +export type PlaylistMetadata = { + id: string; + name: string; + description?: string; + owner: string; + public: boolean; +}; +``` diff --git a/plugins/playlist-common/package.json b/plugins/playlist-common/package.json new file mode 100644 index 0000000000..87dbc7d9f5 --- /dev/null +++ b/plugins/playlist-common/package.json @@ -0,0 +1,34 @@ +{ + "name": "@backstage/plugin-playlist-common", + "description": "Common functionalities for the playlist plugin", + "version": "0.1.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "main": "dist/index.cjs.js", + "module": "dist/index.esm.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "common-library" + }, + "scripts": { + "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/plugin-permission-common": "workspace:^" + }, + "devDependencies": { + "@backstage/cli": "workspace:^" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/playlist-common/src/index.ts b/plugins/playlist-common/src/index.ts new file mode 100644 index 0000000000..92cf1eb461 --- /dev/null +++ b/plugins/playlist-common/src/index.ts @@ -0,0 +1,24 @@ +/* + * 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. + */ + +/** + * Common functionalities for the playlist plugin. + * + * @packageDocumentation + */ + +export * from './types'; +export * from './permissions'; diff --git a/plugins/playlist-common/src/permissions.ts b/plugins/playlist-common/src/permissions.ts new file mode 100644 index 0000000000..89d526127e --- /dev/null +++ b/plugins/playlist-common/src/permissions.ts @@ -0,0 +1,62 @@ +/* + * 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 { createPermission } from '@backstage/plugin-permission-common'; + +/** + * @public + */ +export const PLAYLIST_LIST_RESOURCE_TYPE = 'playlist-list'; + +const playlistListCreate = createPermission({ + name: 'playlist.list.create', + attributes: { action: 'create' }, +}); + +const playlistListRead = createPermission({ + name: 'playlist.list.read', + attributes: { action: 'read' }, + resourceType: PLAYLIST_LIST_RESOURCE_TYPE, +}); + +const playlistListUpdate = createPermission({ + name: 'playlist.list.update', + attributes: { action: 'update' }, + resourceType: PLAYLIST_LIST_RESOURCE_TYPE, +}); + +const playlistListDelete = createPermission({ + name: 'playlist.list.delete', + attributes: { action: 'delete' }, + resourceType: PLAYLIST_LIST_RESOURCE_TYPE, +}); + +const playlistFollowersUpdate = createPermission({ + name: 'playlist.followers.update', + attributes: { action: 'update' }, + resourceType: PLAYLIST_LIST_RESOURCE_TYPE, +}); + +/** + * @public + */ +export const permissions = { + playlistListCreate, + playlistListRead, + playlistListUpdate, + playlistListDelete, + playlistFollowersUpdate, +}; diff --git a/plugins/playlist-common/src/setupTests.ts b/plugins/playlist-common/src/setupTests.ts new file mode 100644 index 0000000000..8b9b6bd586 --- /dev/null +++ b/plugins/playlist-common/src/setupTests.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 {}; diff --git a/plugins/playlist-common/src/types.ts b/plugins/playlist-common/src/types.ts new file mode 100644 index 0000000000..667cd35ece --- /dev/null +++ b/plugins/playlist-common/src/types.ts @@ -0,0 +1,35 @@ +/* + * 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. + */ + +/** + * @public + */ +export type PlaylistMetadata = { + id: string; + name: string; + description?: string; + owner: string; + public: boolean; +}; + +/** + * @public + */ +export type Playlist = PlaylistMetadata & { + entities: number; + followers: number; + isFollowing: boolean; +}; diff --git a/plugins/playlist/.eslintrc.js b/plugins/playlist/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/playlist/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/playlist/CHANGELOG.md b/plugins/playlist/CHANGELOG.md new file mode 100644 index 0000000000..f4be6fc149 --- /dev/null +++ b/plugins/playlist/CHANGELOG.md @@ -0,0 +1,21 @@ +# @backstage/plugin-playlist + +## 0.1.0 + +### Minor Changes + +- d3737da337: Implement playlist plugin, check out the `README.md` for more details! + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/plugin-permission-react@0.4.5 + - @backstage/plugin-search-react@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/errors@1.1.1 + - @backstage/plugin-permission-common@0.6.4 + - @backstage/plugin-playlist-common@0.1.0 + - @backstage/plugin-catalog-common@1.0.6 diff --git a/plugins/playlist/README.md b/plugins/playlist/README.md new file mode 100644 index 0000000000..7c814d302b --- /dev/null +++ b/plugins/playlist/README.md @@ -0,0 +1,128 @@ +# Playlist Plugin + +Welcome to the playlist plugin! + +This plugin allows you to create, share, and follow custom collections of entities available in the Backstage catalog. + +## Setup + +Install this plugin: + +```bash +# From your Backstage root directory +yarn --cwd packages/app add @backstage/plugin-playlist +``` + +### Add the plugin to your `packages/app` + +Add the root page that the playlist plugin provides to your app. You can +choose any path for the route, but we recommend the following: + +```diff +// packages/app/src/App.tsx ++import { PlaylistIndexPage } from '@backstage/plugin-playlist'; + + + + } /> + }> + {entityPage} + ++ } /> + ... + +``` + +You may also want to add a link to the playlist page to your application sidebar: + +```diff +// packages/app/src/components/Root/Root.tsx ++import PlaylistPlayIcon from '@material-ui/icons/PlaylistPlay'; + +export const Root = ({ children }: PropsWithChildren<{}>) => ( + + ++ + ... + +``` + +### Entity Pages + +You can also make the following changes to add the playlist context menu to your `EntityPage.tsx` +to be able to add entities to playlists directly from your entity pages: + +First we need to add the following imports: + +```ts +import { EntityPlaylistDialog } from '@backstage/plugin-playlist'; +import PlaylistAddIcon from '@material-ui/icons/PlaylistAdd'; +``` + +Next we'll update the React import that looks like this: + +```ts +import React from 'react'; +``` + +To look like this: + +```ts +import React, { ReactNode, useMemo, useState } from 'react'; +``` + +Then we have to add this chunk of code after all the imports but before any of the other code: + +```ts +const EntityLayoutWrapper = (props: { children?: ReactNode }) => { + const [playlistDialogOpen, setPlaylistDialogOpen] = useState(false); + + const extraMenuItems = useMemo(() => { + return [ + { + title: 'Add to playlist', + Icon: PlaylistAddIcon, + onClick: () => setPlaylistDialogOpen(true), + }, + ]; + }, []); + + return ( + <> + + {props.children} + + setPlaylistDialogOpen(false)} + /> + + ); +}; +``` + +The last step is to wrap all the entity pages in the `EntityLayoutWrapper` like this: + +```diff +const defaultEntityPage = ( ++ + + {overviewContent} + + + + + + + + + ++ +); +``` + +Note: the above only shows an example for the `defaultEntityPage` for a full example of this you can look at [this EntityPage](../../packages/app/src/components/catalog/EntityPage.tsx) + +## Links + +- [playlist-backend](../playlist-backend) provides the backend API for this frontend. diff --git a/plugins/playlist/api-report.md b/plugins/playlist/api-report.md new file mode 100644 index 0000000000..7a732a4a53 --- /dev/null +++ b/plugins/playlist/api-report.md @@ -0,0 +1,106 @@ +## API Report File for "@backstage/plugin-playlist" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +/// + +import { ApiRef } from '@backstage/core-plugin-api'; +import { BackstagePlugin } 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'; +import { Playlist } from '@backstage/plugin-playlist-common'; +import { PlaylistMetadata } from '@backstage/plugin-playlist-common'; +import { RouteRef } from '@backstage/core-plugin-api'; + +// @public (undocumented) +export const EntityPlaylistDialog: ( + props: EntityPlaylistDialogProps, +) => JSX.Element; + +// @public (undocumented) +export type EntityPlaylistDialogProps = { + open: boolean; + onClose: () => void; +}; + +// @public (undocumented) +export interface GetAllPlaylistsRequest { + // (undocumented) + editable?: boolean; + filter?: + | Record[] + | Record; +} + +// @public (undocumented) +export interface PlaylistApi { + // (undocumented) + addPlaylistEntities(playlistId: string, entityRefs: string[]): Promise; + // (undocumented) + createPlaylist(playlist: Omit): Promise; + // (undocumented) + deletePlaylist(playlistId: string): Promise; + // (undocumented) + followPlaylist(playlistId: string): Promise; + // (undocumented) + getAllPlaylists(req: GetAllPlaylistsRequest): Promise; + // (undocumented) + getPlaylist(playlistId: string): Promise; + // (undocumented) + getPlaylistEntities(playlistId: string): Promise; + // (undocumented) + removePlaylistEntities( + playlistId: string, + entityRefs: string[], + ): Promise; + // (undocumented) + unfollowPlaylist(playlistId: string): Promise; + // (undocumented) + updatePlaylist(playlist: PlaylistMetadata): Promise; +} + +// @public (undocumented) +export const playlistApiRef: ApiRef; + +// @public (undocumented) +export class PlaylistClient implements PlaylistApi { + constructor(options: { discoveryApi: DiscoveryApi; fetchApi: FetchApi }); + // (undocumented) + addPlaylistEntities(playlistId: string, entityRefs: string[]): Promise; + // (undocumented) + createPlaylist(playlist: Omit): Promise; + // (undocumented) + deletePlaylist(playlistId: string): Promise; + // (undocumented) + followPlaylist(playlistId: string): Promise; + // (undocumented) + getAllPlaylists(req?: GetAllPlaylistsRequest): Promise; + // (undocumented) + getPlaylist(playlistId: string): Promise; + // (undocumented) + getPlaylistEntities(playlistId: string): Promise; + // (undocumented) + removePlaylistEntities( + playlistId: string, + entityRefs: string[], + ): Promise; + // (undocumented) + unfollowPlaylist(playlistId: string): Promise; + // (undocumented) + updatePlaylist(playlist: PlaylistMetadata): Promise; +} + +// @public (undocumented) +export const PlaylistIndexPage: () => JSX.Element; + +// @public (undocumented) +export const playlistPlugin: BackstagePlugin< + { + root: RouteRef; + }, + {}, + {} +>; +``` diff --git a/plugins/playlist/dev/index.tsx b/plugins/playlist/dev/index.tsx new file mode 100644 index 0000000000..c9c626ab38 --- /dev/null +++ b/plugins/playlist/dev/index.tsx @@ -0,0 +1,27 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; +import { createDevApp } from '@backstage/dev-utils'; +import { playlistPlugin, PlaylistIndexPage } from '../src/plugin'; + +createDevApp() + .registerPlugin(playlistPlugin) + .addPage({ + element: , + title: 'Root Page', + path: '/playlist', + }) + .render(); diff --git a/plugins/playlist/package.json b/plugins/playlist/package.json new file mode 100644 index 0000000000..7da8d4ba08 --- /dev/null +++ b/plugins/playlist/package.json @@ -0,0 +1,66 @@ +{ + "name": "@backstage/plugin-playlist", + "version": "0.1.0", + "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": "frontend-plugin" + }, + "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/catalog-model": "workspace:^", + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/plugin-catalog-common": "workspace:^", + "@backstage/plugin-catalog-react": "workspace:^", + "@backstage/plugin-permission-common": "workspace:^", + "@backstage/plugin-permission-react": "workspace:^", + "@backstage/plugin-playlist-common": "workspace:^", + "@backstage/plugin-search-react": "workspace:^", + "@backstage/theme": "workspace:^", + "@material-ui/core": "^4.9.13", + "@material-ui/icons": "^4.9.1", + "@material-ui/lab": "^4.0.0-alpha.57", + "lodash": "^4.17.21", + "qs": "^6.9.4", + "react-hook-form": "^7.13.0", + "react-use": "^17.2.4" + }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0", + "react-router": "6.0.0-beta.0 || ^6.3.0", + "react-router-dom": "6.0.0-beta.0 || ^6.3.0" + }, + "devDependencies": { + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", + "@testing-library/jest-dom": "^5.10.1", + "@testing-library/react": "^12.1.3", + "@testing-library/react-hooks": "^8.0.0", + "@testing-library/user-event": "^14.0.0", + "@types/node": "*", + "cross-fetch": "^3.1.5", + "msw": "^0.47.0", + "swr": "^1.1.2" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/playlist/src/api/PlaylistApi.ts b/plugins/playlist/src/api/PlaylistApi.ts new file mode 100644 index 0000000000..9a9da1badb --- /dev/null +++ b/plugins/playlist/src/api/PlaylistApi.ts @@ -0,0 +1,76 @@ +/* + * 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 { Entity } from '@backstage/catalog-model'; +import { createApiRef } from '@backstage/core-plugin-api'; +import { Playlist, PlaylistMetadata } from '@backstage/plugin-playlist-common'; + +/** + * @public + */ +export const playlistApiRef = createApiRef({ + id: 'plugin.playlist.service', +}); + +/** + * @public + */ +export interface GetAllPlaylistsRequest { + /** + * If multiple filter sets are given as an array, then there is effectively an + * OR between each filter set. + * + * Within one filter set, there is effectively an AND between the various + * keys. + * + * Within one key, if there are more than one value, then there is effectively + * an OR between them. + */ + filter?: + | Record[] + | Record; + + // If true, will filter results that satisfies the playlist.list.update permission + editable?: boolean; +} + +/** + * @public + */ +export interface PlaylistApi { + getAllPlaylists(req: GetAllPlaylistsRequest): Promise; + + createPlaylist(playlist: Omit): Promise; + + getPlaylist(playlistId: string): Promise; + + updatePlaylist(playlist: PlaylistMetadata): Promise; + + deletePlaylist(playlistId: string): Promise; + + addPlaylistEntities(playlistId: string, entityRefs: string[]): Promise; + + getPlaylistEntities(playlistId: string): Promise; + + removePlaylistEntities( + playlistId: string, + entityRefs: string[], + ): Promise; + + followPlaylist(playlistId: string): Promise; + + unfollowPlaylist(playlistId: string): Promise; +} diff --git a/plugins/playlist/src/api/PlaylistClient.test.ts b/plugins/playlist/src/api/PlaylistClient.test.ts new file mode 100644 index 0000000000..20d4a0bcc8 --- /dev/null +++ b/plugins/playlist/src/api/PlaylistClient.test.ts @@ -0,0 +1,294 @@ +/* + * 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 { MockFetchApi, setupRequestMockHandlers } from '@backstage/test-utils'; +import { rest } from 'msw'; +import { setupServer } from 'msw/node'; + +import { PlaylistClient } from './PlaylistClient'; + +const server = setupServer(); + +describe('PlaylistClient', () => { + setupRequestMockHandlers(server); + const mockBaseUrl = 'http://backstage/api/playlist'; + const discoveryApi = { getBaseUrl: async () => mockBaseUrl }; + const fetchApi = new MockFetchApi(); + + let client: PlaylistClient; + beforeEach(() => { + client = new PlaylistClient({ discoveryApi, fetchApi }); + }); + + describe('getAllPlaylists', () => { + const expectedResp = [ + { + id: 'id', + name: 'name', + description: 'description', + owner: 'owner', + public: true, + entities: 1, + followers: 2, + isFollowing: true, + }, + ]; + + it('should fetch playlists from correct endpoint', async () => { + server.use( + rest.get(`${mockBaseUrl}/`, (_, res, ctx) => + res(ctx.json(expectedResp)), + ), + ); + const response = await client.getAllPlaylists(); + expect(response).toEqual(expectedResp); + }); + + it('should fetch editable playlists correctly', async () => { + expect.assertions(2); + + server.use( + rest.get(`${mockBaseUrl}/`, (req, res, ctx) => { + expect(req.url.search).toBe('?editable=true'); + return res(ctx.json(expectedResp)); + }), + ); + + const response = await client.getAllPlaylists({ editable: true }); + expect(response).toEqual(expectedResp); + }); + + it('builds multiple search filters properly', async () => { + expect.assertions(2); + + server.use( + rest.get(`${mockBaseUrl}/`, (req, res, ctx) => { + expect(req.url.search).toBe( + '?filter=a=1,b=2,b=3,%C3%B6=%3D&filter=a=2&editable=true', + ); + return res(ctx.json(expectedResp)); + }), + ); + + const response = await client.getAllPlaylists({ + editable: true, + filter: [ + { + a: '1', + b: ['2', '3'], + ö: '=', + }, + { + a: '2', + }, + ], + }); + + expect(response).toEqual(expectedResp); + }); + + it('builds single search filter properly', async () => { + expect.assertions(2); + + server.use( + rest.get(`${mockBaseUrl}/`, (req, res, ctx) => { + expect(req.url.search).toBe('?filter=a=1,b=2,b=3,%C3%B6=%3D'); + return res(ctx.json(expectedResp)); + }), + ); + + const response = await client.getAllPlaylists({ + filter: { + a: '1', + b: ['2', '3'], + ö: '=', + }, + }); + + expect(response).toEqual(expectedResp); + }); + }); + + it('createPlaylist', async () => { + expect.assertions(2); + + const newPlaylist = { + name: 'name', + description: 'description', + owner: 'owner', + public: true, + }; + + server.use( + rest.post(`${mockBaseUrl}/`, (req, res, ctx) => { + expect(req.body).toEqual(newPlaylist); + return res(ctx.json('123')); + }), + ); + + const response = await client.createPlaylist(newPlaylist); + + expect(response).toEqual('123'); + }); + + it('getPlaylist', async () => { + const playlist = { + id: '123', + name: 'name', + description: 'description', + owner: 'owner', + public: true, + entities: 1, + followers: 2, + isFollowing: true, + }; + + server.use( + rest.get(`${mockBaseUrl}/123`, (_, res, ctx) => res(ctx.json(playlist))), + ); + + const response = await client.getPlaylist('123'); + expect(response).toEqual(playlist); + }); + + it('updatePlaylist', async () => { + expect.assertions(1); + + const playlist = { + id: 'id', + name: 'name', + description: 'description', + owner: 'owner', + public: true, + }; + + server.use( + rest.put(`${mockBaseUrl}/id`, (req, res) => { + expect(req.body).toEqual(playlist); + return res(); + }), + ); + + await client.updatePlaylist(playlist); + }); + + it('deletePlaylist', async () => { + expect.assertions(1); + + server.use( + rest.delete(`${mockBaseUrl}/id`, (_, res) => { + // eslint requires at least 1 assertion so this is here is verify this handler is called + expect(true).toBe(true); + return res(); + }), + ); + + await client.deletePlaylist('id'); + }); + + it('addPlaylistEntities', async () => { + expect.assertions(1); + + const entities = ['component:default/ent1', 'component:default/ent2']; + + server.use( + rest.post(`${mockBaseUrl}/id/entities`, (req, res) => { + expect(req.body).toEqual(entities); + return res(); + }), + ); + + await client.addPlaylistEntities('id', entities); + }); + + it('getPlaylistEntities', async () => { + const entities = [ + { + kind: 'system', + metadata: { + namespace: 'default', + name: 'test-ent', + title: 'Test Ent', + description: 'test ent description', + }, + }, + { + kind: 'component', + metadata: { + namespace: 'foo', + name: 'test-ent2', + title: 'Test Ent 2', + description: 'test ent description 2', + }, + spec: { + type: 'library', + }, + }, + ]; + + server.use( + rest.get(`${mockBaseUrl}/id/entities`, (_, res, ctx) => + res(ctx.json(entities)), + ), + ); + + const response = await client.getPlaylistEntities('id'); + expect(response).toEqual(entities); + }); + + it('removePlaylistEntities', async () => { + expect.assertions(1); + + const entities = ['component:default/ent1', 'component:default/ent2']; + + server.use( + rest.delete(`${mockBaseUrl}/id/entities`, (req, res) => { + expect(req.body).toEqual(entities); + return res(); + }), + ); + + await client.removePlaylistEntities('id', entities); + }); + + it('followPlaylist', async () => { + expect.assertions(1); + + server.use( + rest.post(`${mockBaseUrl}/id/followers`, (_, res) => { + // eslint requires at least 1 assertion so this is here is verify this handler is called + expect(true).toBe(true); + return res(); + }), + ); + + await client.followPlaylist('id'); + }); + + it('unfollowPlaylist', async () => { + expect.assertions(1); + + server.use( + rest.delete(`${mockBaseUrl}/id/followers`, (_, res) => { + // eslint requires at least 1 assertion so this is here is verify this handler is called + expect(true).toBe(true); + return res(); + }), + ); + + await client.unfollowPlaylist('id'); + }); +}); diff --git a/plugins/playlist/src/api/PlaylistClient.ts b/plugins/playlist/src/api/PlaylistClient.ts new file mode 100644 index 0000000000..425b185de8 --- /dev/null +++ b/plugins/playlist/src/api/PlaylistClient.ts @@ -0,0 +1,199 @@ +/* + * 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 { Entity } from '@backstage/catalog-model'; +import { DiscoveryApi, FetchApi } from '@backstage/core-plugin-api'; +import { ResponseError } from '@backstage/errors'; +import { Playlist, PlaylistMetadata } from '@backstage/plugin-playlist-common'; + +import { GetAllPlaylistsRequest, PlaylistApi } from './PlaylistApi'; + +/** + * @public + */ +export class PlaylistClient implements PlaylistApi { + private readonly discoveryApi: DiscoveryApi; + private readonly fetchApi: FetchApi; + + constructor(options: { discoveryApi: DiscoveryApi; fetchApi: FetchApi }) { + this.discoveryApi = options.discoveryApi; + this.fetchApi = options.fetchApi; + } + + async getAllPlaylists(req: GetAllPlaylistsRequest = {}): Promise { + const { filter = [], editable } = req; + const params: string[] = []; + + // the "outer array" defined by `filter` occurrences corresponds to "anyOf" filters + // the "inner array" defined within a `filter` param corresponds to "allOf" filters + for (const filterItem of [filter].flat()) { + const filterParts: string[] = []; + for (const [key, value] of Object.entries(filterItem)) { + for (const v of [value].flat()) { + if (typeof v === 'string') { + filterParts.push( + `${encodeURIComponent(key)}=${encodeURIComponent(v)}`, + ); + } + } + } + + if (filterParts.length) { + params.push(`filter=${filterParts.join(',')}`); + } + } + + if (editable) { + params.push('editable=true'); + } + + const query = params.length ? `?${params.join('&')}` : ''; + const baseUrl = await this.discoveryApi.getBaseUrl('playlist'); + const resp = await this.fetchApi.fetch(`${baseUrl}/${query}`, { + method: 'GET', + }); + + if (!resp.ok) { + throw await ResponseError.fromResponse(resp); + } + + return await resp.json(); + } + + async createPlaylist( + playlist: Omit, + ): Promise { + const baseUrl = await this.discoveryApi.getBaseUrl('playlist'); + const resp = await this.fetchApi.fetch(`${baseUrl}/`, { + headers: { 'Content-Type': 'application/json' }, + method: 'POST', + body: JSON.stringify(playlist), + }); + + if (!resp.ok) { + throw await ResponseError.fromResponse(resp); + } + + return await resp.json(); + } + + async getPlaylist(playlistId: string): Promise { + const baseUrl = await this.discoveryApi.getBaseUrl('playlist'); + const resp = await this.fetchApi.fetch(`${baseUrl}/${playlistId}`, { + method: 'GET', + }); + + if (!resp.ok) { + throw await ResponseError.fromResponse(resp); + } + + return await resp.json(); + } + + async updatePlaylist(playlist: PlaylistMetadata) { + const baseUrl = await this.discoveryApi.getBaseUrl('playlist'); + const resp = await this.fetchApi.fetch(`${baseUrl}/${playlist.id}`, { + headers: { 'Content-Type': 'application/json' }, + method: 'PUT', + body: JSON.stringify(playlist), + }); + + if (!resp.ok) { + throw await ResponseError.fromResponse(resp); + } + } + + async deletePlaylist(playlistId: string) { + const baseUrl = await this.discoveryApi.getBaseUrl('playlist'); + const resp = await this.fetchApi.fetch(`${baseUrl}/${playlistId}`, { + method: 'DELETE', + }); + + if (!resp.ok) { + throw await ResponseError.fromResponse(resp); + } + } + + async addPlaylistEntities(playlistId: string, entityRefs: string[]) { + const baseUrl = await this.discoveryApi.getBaseUrl('playlist'); + const resp = await this.fetchApi.fetch( + `${baseUrl}/${playlistId}/entities`, + { + headers: { 'Content-Type': 'application/json' }, + method: 'POST', + body: JSON.stringify(entityRefs), + }, + ); + + if (!resp.ok) { + throw await ResponseError.fromResponse(resp); + } + } + + async getPlaylistEntities(playlistId: string): Promise { + const baseUrl = await this.discoveryApi.getBaseUrl('playlist'); + const resp = await this.fetchApi.fetch( + `${baseUrl}/${playlistId}/entities`, + { method: 'GET' }, + ); + + if (!resp.ok) { + throw await ResponseError.fromResponse(resp); + } + + return await resp.json(); + } + + async removePlaylistEntities(playlistId: string, entityRefs: string[]) { + const baseUrl = await this.discoveryApi.getBaseUrl('playlist'); + const resp = await this.fetchApi.fetch( + `${baseUrl}/${playlistId}/entities`, + { + headers: { 'Content-Type': 'application/json' }, + method: 'DELETE', + body: JSON.stringify(entityRefs), + }, + ); + + if (!resp.ok) { + throw await ResponseError.fromResponse(resp); + } + } + + async followPlaylist(playlistId: string) { + const baseUrl = await this.discoveryApi.getBaseUrl('playlist'); + const resp = await this.fetchApi.fetch( + `${baseUrl}/${playlistId}/followers`, + { method: 'POST' }, + ); + + if (!resp.ok) { + throw await ResponseError.fromResponse(resp); + } + } + + async unfollowPlaylist(playlistId: string) { + const baseUrl = await this.discoveryApi.getBaseUrl('playlist'); + const resp = await this.fetchApi.fetch( + `${baseUrl}/${playlistId}/followers`, + { method: 'DELETE' }, + ); + + if (!resp.ok) { + throw await ResponseError.fromResponse(resp); + } + } +} diff --git a/plugins/playlist/src/api/index.ts b/plugins/playlist/src/api/index.ts new file mode 100644 index 0000000000..b53cbd99ef --- /dev/null +++ b/plugins/playlist/src/api/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 * from './PlaylistClient'; +export * from './PlaylistApi'; diff --git a/plugins/playlist/src/components/CreatePlaylistButton/CreatePlaylistButton.test.tsx b/plugins/playlist/src/components/CreatePlaylistButton/CreatePlaylistButton.test.tsx new file mode 100644 index 0000000000..e00f7dc582 --- /dev/null +++ b/plugins/playlist/src/components/CreatePlaylistButton/CreatePlaylistButton.test.tsx @@ -0,0 +1,142 @@ +/* + * 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 { ErrorApi, errorApiRef } from '@backstage/core-plugin-api'; +import { AuthorizeResult } from '@backstage/plugin-permission-common'; +import { + PermissionApi, + permissionApiRef, +} from '@backstage/plugin-permission-react'; +import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; +import { Button } from '@material-ui/core'; +import { fireEvent, waitFor } from '@testing-library/react'; +import { act } from '@testing-library/react-hooks'; +import React from 'react'; +import { SWRConfig } from 'swr'; + +import { PlaylistApi, playlistApiRef } from '../../api'; +import { rootRouteRef } from '../../routes'; +import { CreatePlaylistButton } from './CreatePlaylistButton'; + +jest.mock('../PlaylistEditDialog', () => ({ + PlaylistEditDialog: ({ onSave, open }: { onSave: Function; open: boolean }) => + open ? ( + + )} + setOpenDialog(false)} + onSave={savePlaylist} + /> + + ); +}; diff --git a/plugins/playlist/src/components/CreatePlaylistButton/index.ts b/plugins/playlist/src/components/CreatePlaylistButton/index.ts new file mode 100644 index 0000000000..ac28bbc509 --- /dev/null +++ b/plugins/playlist/src/components/CreatePlaylistButton/index.ts @@ -0,0 +1,17 @@ +/* + * 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 * from './CreatePlaylistButton'; diff --git a/plugins/playlist/src/components/EntityPlaylistDialog/EntityPlaylistDialog.test.tsx b/plugins/playlist/src/components/EntityPlaylistDialog/EntityPlaylistDialog.test.tsx new file mode 100644 index 0000000000..9c61105ef9 --- /dev/null +++ b/plugins/playlist/src/components/EntityPlaylistDialog/EntityPlaylistDialog.test.tsx @@ -0,0 +1,200 @@ +/* + * 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 { Entity } from '@backstage/catalog-model'; +import { AlertApi, alertApiRef } from '@backstage/core-plugin-api'; +import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; +import { EntityProvider } from '@backstage/plugin-catalog-react'; +import { AuthorizeResult } from '@backstage/plugin-permission-common'; +import { + PermissionApi, + permissionApiRef, +} from '@backstage/plugin-permission-react'; +import { Button } from '@material-ui/core'; +import { fireEvent, getByRole, waitFor } from '@testing-library/react'; +import { act } from '@testing-library/react-hooks'; +import React from 'react'; +import { SWRConfig } from 'swr'; + +import { PlaylistApi, playlistApiRef } from '../../api'; +import { rootRouteRef } from '../../routes'; +import { EntityPlaylistDialog } from './EntityPlaylistDialog'; + +const navigateMock = jest.fn(); +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useNavigate: () => navigateMock, +})); + +jest.mock('../PlaylistEditDialog', () => ({ + PlaylistEditDialog: ({ onSave, open }: { onSave: Function; open: boolean }) => + open ? ( + + + + setOpenEditDialog(false)} + onSave={createNewPlaylist} + /> + + ); +}; diff --git a/plugins/playlist/src/components/EntityPlaylistDialog/index.ts b/plugins/playlist/src/components/EntityPlaylistDialog/index.ts new file mode 100644 index 0000000000..77d7e73ae0 --- /dev/null +++ b/plugins/playlist/src/components/EntityPlaylistDialog/index.ts @@ -0,0 +1,17 @@ +/* + * 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 * from './EntityPlaylistDialog'; diff --git a/plugins/playlist/src/components/PersonalListPicker/PersonalListPicker.test.tsx b/plugins/playlist/src/components/PersonalListPicker/PersonalListPicker.test.tsx new file mode 100644 index 0000000000..9255ee1bdb --- /dev/null +++ b/plugins/playlist/src/components/PersonalListPicker/PersonalListPicker.test.tsx @@ -0,0 +1,286 @@ +/* + * 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 { ApiProvider } from '@backstage/core-app-api'; +import { + ConfigApi, + configApiRef, + IdentityApi, + identityApiRef, + storageApiRef, +} from '@backstage/core-plugin-api'; +import { Playlist } from '@backstage/plugin-playlist-common'; +import { MockStorageApi, TestApiRegistry } from '@backstage/test-utils'; +import { fireEvent, render, waitFor } from '@testing-library/react'; +import React from 'react'; + +import { MockPlaylistListProvider } from '../../testUtils'; +import { PlaylistOwnerFilter } from '../PlaylistOwnerPicker'; +import { PersonalListPicker } from './PersonalListPicker'; + +const mockConfigApi = { + getOptionalString: () => 'Test Company', +} as Partial; + +const mockIdentityApi = { + getBackstageIdentity: async () => ({ + ownershipEntityRefs: ['user:default/owner', 'group:default/some-owner'], + }), +} as Partial; + +const apis = TestApiRegistry.from( + [configApiRef, mockConfigApi], + [identityApiRef, mockIdentityApi], + [storageApiRef, MockStorageApi.create()], +); + +const backendPlaylists: Playlist[] = [ + { + id: 'id1', + name: 'playlist-1', + owner: 'group:default/some-owner', + public: true, + entities: 1, + followers: 2, + isFollowing: false, + }, + { + id: 'id2', + name: 'playlist-2', + owner: 'group:default/another-owner', + public: true, + entities: 2, + followers: 1, + isFollowing: true, + }, + { + id: 'id3', + name: 'playlist-3', + owner: 'group:default/another-owner', + public: true, + entities: 2, + followers: 1, + isFollowing: true, + }, + { + id: 'id4', + name: 'playlist-4', + owner: 'user:default/owner', + public: true, + entities: 2, + followers: 1, + isFollowing: true, + }, +]; + +describe('', () => { + const updateFilters = jest.fn() as any; + + beforeEach(() => { + updateFilters.mockClear(); + }); + + it('renders filter groups', async () => { + const { queryByText } = render( + + + + + , + ); + + await waitFor(() => { + expect(queryByText('Personal')).toBeInTheDocument(); + expect(queryByText('Test Company')).toBeInTheDocument(); + }); + }); + + it('renders filters', async () => { + const { getAllByRole } = render( + + + + + , + ); + + await waitFor(() => { + expect( + getAllByRole('menuitem').map(({ textContent }) => textContent), + ).toEqual(['Owned 2', 'Following 3', 'All 4']); + }); + }); + + it('respects other frontend filters in counts', async () => { + const { getAllByRole } = render( + + + + + , + ); + + await waitFor(() => { + expect( + getAllByRole('menuitem').map(({ textContent }) => textContent), + ).toEqual(['Owned -', 'Following 2', 'All 2']); + }); + }); + + it('respects the query parameter filter value', async () => { + const queryParameters = { personal: 'owned' }; + render( + + + + + , + ); + + await waitFor(() => { + expect(updateFilters.mock.lastCall[0].personal.value).toBe('owned'); + }); + }); + + it('updates personal filter when a menuitem is selected', async () => { + const { getByText } = render( + + + + + , + ); + + fireEvent.click(getByText('Following')); + + await waitFor(() => { + expect(updateFilters.mock.lastCall[0].personal.value).toBe('following'); + }); + }); + + it('responds to external queryParameters changes', async () => { + const rendered = render( + + + + + , + ); + + await waitFor(() => { + expect(updateFilters.mock.lastCall[0].personal.value).toBe('all'); + }); + + rendered.rerender( + + + + + , + ); + + await waitFor(() => { + expect(updateFilters.mock.lastCall[0].personal.value).toBe('owned'); + }); + }); + + describe.each(['owned', 'following'])( + 'filter resetting for %s playlists', + type => { + const picker = (props: { loading: boolean; mockData: any }) => ( + + ({ + ...p, + ...props.mockData, + })), + queryParameters: { personal: type }, + updateFilters, + loading: props.loading, + }} + > + + + + ); + + describe(`when there are no ${type} playlists`, () => { + const mockData = + type === 'owned' + ? { owner: 'group:default/no-owner' } + : { isFollowing: false }; + + it('does not reset the filter while playlists are loading', async () => { + render(picker({ loading: true, mockData })); + await waitFor(() => { + expect(updateFilters.mock.lastCall[0].personal.value).not.toBe( + 'all', + ); + }); + }); + + it('resets the filter to "all" when playlists are loaded', async () => { + render(picker({ loading: false, mockData })); + await waitFor(() => { + expect(updateFilters.mock.lastCall[0].personal.value).toBe('all'); + }); + }); + }); + + describe(`when there are some ${type} playlists present`, () => { + const mockData = {}; + + it('does not reset the filter while playlists are loading', async () => { + render(picker({ loading: true, mockData })); + await waitFor(() => { + expect(updateFilters.mock.lastCall[0].personal.value).not.toBe( + 'all', + ); + }); + }); + + it('does not reset the filter when playlists are loaded', async () => { + render(picker({ loading: false, mockData })); + await waitFor(() => { + expect(updateFilters.mock.lastCall[0].personal.value).toBe(type); + }); + }); + }); + }, + ); +}); diff --git a/plugins/playlist/src/components/PersonalListPicker/PersonalListPicker.tsx b/plugins/playlist/src/components/PersonalListPicker/PersonalListPicker.tsx new file mode 100644 index 0000000000..1172f2f6fa --- /dev/null +++ b/plugins/playlist/src/components/PersonalListPicker/PersonalListPicker.tsx @@ -0,0 +1,293 @@ +/* + * 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 { + configApiRef, + IconComponent, + identityApiRef, + useApi, +} from '@backstage/core-plugin-api'; +import { Playlist } from '@backstage/plugin-playlist-common'; +import { + Card, + List, + ListItemIcon, + ListItemSecondaryAction, + ListItemText, + makeStyles, + MenuItem, + Theme, + Typography, +} from '@material-ui/core'; +import PlaylistPlayIcon from '@material-ui/icons/PlaylistPlay'; +import SettingsIcon from '@material-ui/icons/Settings'; +import { compact } from 'lodash'; +import React, { Fragment, useEffect, useMemo, useState } from 'react'; +import useAsync from 'react-use/lib/useAsync'; + +import { usePlaylistList } from '../../hooks'; +import { PlaylistFilter } from '../../types'; + +export const enum PersonalListFilterValue { + owned = 'owned', + following = 'following', + all = 'all', +} + +export class PersonalListFilter implements PlaylistFilter { + constructor( + readonly value: PersonalListFilterValue, + readonly isOwnedPlaylist: (playlist: Playlist) => boolean, + ) {} + + filterPlaylist(playlist: Playlist): boolean { + switch (this.value) { + case PersonalListFilterValue.owned: + return this.isOwnedPlaylist(playlist); + case PersonalListFilterValue.following: + return playlist.isFollowing; + default: + return true; + } + } + + toQueryValue(): string { + return this.value; + } +} + +const useStyles = makeStyles(theme => ({ + root: { + backgroundColor: 'rgba(0, 0, 0, .11)', + boxShadow: 'none', + margin: theme.spacing(1, 0, 1, 0), + }, + title: { + margin: theme.spacing(1, 0, 0, 1), + textTransform: 'uppercase', + fontSize: 12, + fontWeight: 'bold', + }, + listIcon: { + minWidth: 30, + color: theme.palette.text.primary, + }, + menuItem: { + minHeight: theme.spacing(6), + }, + groupWrapper: { + margin: theme.spacing(1, 1, 2, 1), + }, +})); + +type ButtonGroup = { + name: string; + items: { + id: PersonalListFilterValue; + label: string; + icon?: IconComponent; + }[]; +}; + +function getFilterGroups(orgName: string | undefined): ButtonGroup[] { + return [ + { + name: 'Personal', + items: [ + { + id: PersonalListFilterValue.owned, + label: 'Owned', + icon: SettingsIcon, + }, + { + id: PersonalListFilterValue.following, + label: 'Following', + icon: PlaylistPlayIcon, + }, + ], + }, + { + name: orgName ?? 'Company', + items: [ + { + id: PersonalListFilterValue.all, + label: 'All', + }, + ], + }, + ]; +} + +export const PersonalListPicker = () => { + const classes = useStyles(); + const configApi = useApi(configApiRef); + const identityApi = useApi(identityApiRef); + const orgName = configApi.getOptionalString('organization.name') ?? 'Company'; + const filterGroups = getFilterGroups(orgName); + + const { loading: loadingOwnership, value: ownershipRefs } = + useAsync(async () => { + const { ownershipEntityRefs } = await identityApi.getBackstageIdentity(); + return ownershipEntityRefs; + }, []); + + const isOwnedPlaylist = useMemo(() => { + const myOwnerRefs = new Set(ownershipRefs ?? []); + return (playlist: Playlist) => myOwnerRefs.has(playlist.owner); + }, [ownershipRefs]); + + const { + filters, + updateFilters, + backendPlaylists, + queryParameters: { personal: personalParameter }, + loading: loadingBackendPlaylists, + } = usePlaylistList(); + + const loading = loadingBackendPlaylists || loadingOwnership; + + // Static filters; used for generating counts of potentially unselected options + const ownedFilter = useMemo( + () => + new PersonalListFilter(PersonalListFilterValue.owned, isOwnedPlaylist), + [isOwnedPlaylist], + ); + const followingFilter = useMemo( + () => + new PersonalListFilter( + PersonalListFilterValue.following, + isOwnedPlaylist, + ), + [isOwnedPlaylist], + ); + + const queryParamPersonalFilter = useMemo( + () => [personalParameter].flat()[0], + [personalParameter], + ); + + const [selectedPersonalFilter, setSelectedPersonalFilter] = useState( + queryParamPersonalFilter ?? PersonalListFilterValue.all, + ); + + // To show proper counts for each section, apply all other frontend filters _except_ the personal + // filter that's controlled by this picker. + const playlistsWithoutPersonalFilter = useMemo( + () => + backendPlaylists.filter(playlist => + compact(Object.values({ ...filters, personal: undefined })).every( + (filter: PlaylistFilter) => + !filter.filterPlaylist || filter.filterPlaylist(playlist), + ), + ), + [filters, backendPlaylists], + ); + + const filterCounts = useMemo>( + () => ({ + all: playlistsWithoutPersonalFilter.length, + following: playlistsWithoutPersonalFilter.filter(playlist => + followingFilter.filterPlaylist(playlist), + ).length, + owned: playlistsWithoutPersonalFilter.filter(playlist => + ownedFilter.filterPlaylist(playlist), + ).length, + }), + [playlistsWithoutPersonalFilter, followingFilter, ownedFilter], + ); + + // Set selected personal filter on query parameter updates; this happens at initial page load and from + // external updates to the page location. + useEffect(() => { + if (queryParamPersonalFilter) { + setSelectedPersonalFilter(queryParamPersonalFilter); + } + }, [queryParamPersonalFilter]); + + useEffect(() => { + if ( + !loading && + !!selectedPersonalFilter && + selectedPersonalFilter !== PersonalListFilterValue.all && + filterCounts[selectedPersonalFilter] === 0 + ) { + setSelectedPersonalFilter(PersonalListFilterValue.all); + } + }, [ + loading, + filterCounts, + selectedPersonalFilter, + setSelectedPersonalFilter, + ]); + + useEffect(() => { + updateFilters({ + personal: selectedPersonalFilter + ? new PersonalListFilter( + selectedPersonalFilter as PersonalListFilterValue, + isOwnedPlaylist, + ) + : undefined, + }); + }, [selectedPersonalFilter, isOwnedPlaylist, updateFilters]); + + return ( + + {filterGroups.map(group => ( + + + {group.name} + + + + {group.items.map(item => ( + setSelectedPersonalFilter(item.id)} + selected={item.id === selectedPersonalFilter} + className={classes.menuItem} + disabled={filterCounts[item.id] === 0} + data-testid={`personal-picker-${item.id}`} + tabIndex={0} + ContainerProps={{ role: 'menuitem' }} + > + {item.icon && ( + + + + )} + + {item.label} + + + {filterCounts[item.id] || '-'} + + + ))} + + + + ))} + + ); +}; diff --git a/plugins/playlist/src/components/PersonalListPicker/index.ts b/plugins/playlist/src/components/PersonalListPicker/index.ts new file mode 100644 index 0000000000..f67f18ab39 --- /dev/null +++ b/plugins/playlist/src/components/PersonalListPicker/index.ts @@ -0,0 +1,17 @@ +/* + * 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 * from './PersonalListPicker'; diff --git a/plugins/playlist/src/components/PlaylistCard/PlaylistCard.test.tsx b/plugins/playlist/src/components/PlaylistCard/PlaylistCard.test.tsx new file mode 100644 index 0000000000..177cc23b81 --- /dev/null +++ b/plugins/playlist/src/components/PlaylistCard/PlaylistCard.test.tsx @@ -0,0 +1,57 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { entityRouteRef } from '@backstage/plugin-catalog-react'; +import { renderInTestApp } from '@backstage/test-utils'; +import { lightTheme } from '@backstage/theme'; +import { ThemeProvider } from '@material-ui/core'; +import React from 'react'; + +import { rootRouteRef } from '../../routes'; +import { PlaylistCard } from './PlaylistCard'; + +describe('', () => { + it('renders playlist info', async () => { + const rendered = await renderInTestApp( + + + , + { + mountedRoutes: { + '/playlists': rootRouteRef, + '/catalog/:namespace/:kind/:name': entityRouteRef, + }, + }, + ); + + expect(rendered.getByText('playlist-1')).toBeInTheDocument(); + expect(rendered.getByText('test description')).toBeInTheDocument(); + expect(rendered.getByText('some-owner')).toBeInTheDocument(); + expect(rendered.getByText('3 entities')).toBeInTheDocument(); + expect(rendered.getByText('2 followers')).toBeInTheDocument(); + }); +}); diff --git a/plugins/playlist/src/components/PlaylistCard/PlaylistCard.tsx b/plugins/playlist/src/components/PlaylistCard/PlaylistCard.tsx new file mode 100644 index 0000000000..2db7e85f7e --- /dev/null +++ b/plugins/playlist/src/components/PlaylistCard/PlaylistCard.tsx @@ -0,0 +1,131 @@ +/* + * 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 { + Button, + ItemCardHeader, + MarkdownContent, +} from '@backstage/core-components'; +import { useRouteRef } from '@backstage/core-plugin-api'; +import { EntityRefLinks } from '@backstage/plugin-catalog-react'; +import { Playlist } from '@backstage/plugin-playlist-common'; +import { BackstageTheme } from '@backstage/theme'; +import { + Box, + Card, + CardActions, + CardContent, + CardMedia, + Chip, + makeStyles, + Tooltip, + Typography, +} from '@material-ui/core'; +import LockIcon from '@material-ui/icons/Lock'; +import React from 'react'; + +import { playlistRouteRef } from '../../routes'; + +const useStyles = makeStyles((theme: BackstageTheme) => ({ + cardHeader: { + position: 'relative', + }, + title: { + backgroundImage: theme.getPageTheme({ themeId: 'home' }).backgroundImage, + }, + box: { + overflow: 'hidden', + textOverflow: 'ellipsis', + display: '-webkit-box', + '-webkit-line-clamp': 10, + '-webkit-box-orient': 'vertical', + paddingBottom: '0.8em', + }, + label: { + color: theme.palette.text.secondary, + textTransform: 'uppercase', + fontSize: '0.65rem', + fontWeight: 'bold', + letterSpacing: 0.5, + lineHeight: 1, + paddingBottom: '0.2rem', + }, + chip: { + marginRight: 'auto', + }, + privateIcon: { + position: 'absolute', + top: theme.spacing(0.5), + right: theme.spacing(0.5), + padding: '0.25rem', + }, +})); + +export type PlaylistCardProps = { + playlist: Playlist; +}; + +export const PlaylistCard = ({ playlist }: PlaylistCardProps) => { + const classes = useStyles(); + const playlistRoute = useRouteRef(playlistRouteRef); + + return ( + + + {!playlist.public && ( + + + + )} + + + + + + + + + Description + + + + + + Owner + + + + + + + + + ); +}; diff --git a/plugins/playlist/src/components/PlaylistCard/index.ts b/plugins/playlist/src/components/PlaylistCard/index.ts new file mode 100644 index 0000000000..d043c8b6d0 --- /dev/null +++ b/plugins/playlist/src/components/PlaylistCard/index.ts @@ -0,0 +1,17 @@ +/* + * 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 * from './PlaylistCard'; diff --git a/plugins/playlist/src/components/PlaylistEditDialog/PlaylistEditDialog.test.tsx b/plugins/playlist/src/components/PlaylistEditDialog/PlaylistEditDialog.test.tsx new file mode 100644 index 0000000000..9f30d7608c --- /dev/null +++ b/plugins/playlist/src/components/PlaylistEditDialog/PlaylistEditDialog.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 { IdentityApi, identityApiRef } from '@backstage/core-plugin-api'; +import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; +import { fireEvent, getByRole, waitFor } from '@testing-library/react'; +import { act } from '@testing-library/react-hooks'; +import React from 'react'; + +import { PlaylistEditDialog } from './PlaylistEditDialog'; + +describe('', () => { + it('handle saving with an edited playlist', async () => { + const identityApi: Partial = { + getBackstageIdentity: async () => ({ + type: 'user', + userEntityRef: 'user:default/me', + ownershipEntityRefs: ['group:default/test-owner', 'user:default/me'], + }), + }; + + const mockOnSave = jest.fn().mockImplementation(async () => {}); + const rendered = await renderInTestApp( + + + , + ); + + act(() => { + fireEvent.input( + getByRole(rendered.getByTestId('edit-dialog-name-input'), 'textbox'), + { + target: { + value: 'test playlist', + }, + }, + ); + + fireEvent.input( + getByRole( + rendered.getByTestId('edit-dialog-description-input'), + 'textbox', + ), + { + target: { + value: 'test description', + }, + }, + ); + + fireEvent.mouseDown( + getByRole(rendered.getByTestId('edit-dialog-owner-select'), 'button'), + ); + + fireEvent.click(rendered.getByText('test-owner')); + + fireEvent.click( + getByRole(rendered.getByTestId('edit-dialog-public-option'), 'radio'), + ); + + fireEvent.click(rendered.getByTestId('edit-dialog-save-button')); + }); + + await waitFor(() => { + expect(mockOnSave).toHaveBeenCalledWith({ + name: 'test playlist', + description: 'test description', + owner: 'group:default/test-owner', + public: true, + }); + }); + }); +}); diff --git a/plugins/playlist/src/components/PlaylistEditDialog/PlaylistEditDialog.tsx b/plugins/playlist/src/components/PlaylistEditDialog/PlaylistEditDialog.tsx new file mode 100644 index 0000000000..27cc13fede --- /dev/null +++ b/plugins/playlist/src/components/PlaylistEditDialog/PlaylistEditDialog.tsx @@ -0,0 +1,217 @@ +/* + * 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 { parseEntityRef } from '@backstage/catalog-model'; +import { identityApiRef, useApi } from '@backstage/core-plugin-api'; +import { humanizeEntityRef } from '@backstage/plugin-catalog-react'; +import { PlaylistMetadata } from '@backstage/plugin-playlist-common'; +import { + Button, + CircularProgress, + Dialog, + DialogActions, + DialogContent, + FormControl, + FormControlLabel, + InputLabel, + makeStyles, + MenuItem, + LinearProgress, + Radio, + RadioGroup, + Select, + TextField, +} from '@material-ui/core'; +import React from 'react'; +import { useForm, Controller } from 'react-hook-form'; +import useAsync from 'react-use/lib/useAsync'; +import useAsyncFn from 'react-use/lib/useAsyncFn'; + +const useStyles = makeStyles({ + buttonWrapper: { + position: 'relative', + }, + buttonProgress: { + position: 'absolute', + top: '50%', + left: '50%', + marginTop: -12, + marginLeft: -12, + }, +}); + +export type PlaylistEditDialogProps = { + open: boolean; + onClose: () => void; + onSave: (playlist: Omit) => Promise; + playlist?: Omit; +}; + +export const PlaylistEditDialog = ({ + open, + onClose, + onSave, + playlist = { + name: '', + description: '', + owner: '', + public: false, + }, +}: PlaylistEditDialogProps) => { + const classes = useStyles(); + const identityApi = useApi(identityApiRef); + + const { loading: loadingOwnership, value: ownershipRefs } = + useAsync(async () => { + const { ownershipEntityRefs } = await identityApi.getBackstageIdentity(); + return ownershipEntityRefs; + }, []); + + const defaultValues = { + ...playlist, + public: playlist.public.toString(), + }; + + const { + control, + formState: { errors }, + handleSubmit, + reset, + } = useForm({ defaultValues }); + + const [saving, savePlaylist] = useAsyncFn( + formValues => + onSave({ ...formValues, public: JSON.parse(formValues.public) }), + [onSave], + ); + + const closeDialog = () => { + if (!saving.loading) { + onClose(); + reset(defaultValues); + } + }; + + return ( +

+ + ( + + )} + /> + ( + + )} + /> + {loadingOwnership ? ( + + ) : ( + ( + + Owner + + + )} + /> + )} + ( + + + } + /> + } + /> + + + )} + /> + + + +
+ + {saving.loading && ( + + )} +
+
+
+ ); +}; diff --git a/plugins/playlist/src/components/PlaylistEditDialog/index.ts b/plugins/playlist/src/components/PlaylistEditDialog/index.ts new file mode 100644 index 0000000000..3355443b82 --- /dev/null +++ b/plugins/playlist/src/components/PlaylistEditDialog/index.ts @@ -0,0 +1,17 @@ +/* + * 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 * from './PlaylistEditDialog'; diff --git a/plugins/playlist/src/components/PlaylistIndexPage/PlaylistIndexPage.test.tsx b/plugins/playlist/src/components/PlaylistIndexPage/PlaylistIndexPage.test.tsx new file mode 100644 index 0000000000..6dae17d3bc --- /dev/null +++ b/plugins/playlist/src/components/PlaylistIndexPage/PlaylistIndexPage.test.tsx @@ -0,0 +1,52 @@ +/* + * 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 { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; +import { AuthorizeResult } from '@backstage/plugin-permission-common'; +import { + PermissionApi, + permissionApiRef, +} from '@backstage/plugin-permission-react'; +import React from 'react'; + +import { PlaylistApi, playlistApiRef } from '../../api'; +import { rootRouteRef } from '../../routes'; +import { PlaylistIndexPage } from './PlaylistIndexPage'; + +const playlistApi: Partial = { + getAllPlaylists: async () => [], +}; + +const permissionApi: Partial = { + authorize: async () => ({ result: AuthorizeResult.ALLOW }), +}; + +describe('PlaylistIndexPage', () => { + it('should render', async () => { + const rendered = await renderInTestApp( + + + , + { mountedRoutes: { '/playlists': rootRouteRef } }, + ); + expect(rendered.getByText('Playlists')).toBeInTheDocument(); + }); +}); diff --git a/plugins/playlist/src/components/PlaylistIndexPage/PlaylistIndexPage.tsx b/plugins/playlist/src/components/PlaylistIndexPage/PlaylistIndexPage.tsx new file mode 100644 index 0000000000..0ee829018a --- /dev/null +++ b/plugins/playlist/src/components/PlaylistIndexPage/PlaylistIndexPage.tsx @@ -0,0 +1,56 @@ +/* + * 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 { + PageWithHeader, + Content, + ContentHeader, + SupportButton, +} from '@backstage/core-components'; +import { CatalogFilterLayout } from '@backstage/plugin-catalog-react'; + +import { PlaylistListProvider } from '../../hooks'; +import { CreatePlaylistButton } from '../CreatePlaylistButton'; +import { PersonalListPicker } from '../PersonalListPicker'; +import { PlaylistList } from '../PlaylistList'; +import { PlaylistOwnerPicker } from '../PlaylistOwnerPicker'; +import { PlaylistSearchBar } from '../PlaylistSearchBar'; +import { PlaylistSortPicker } from '../PlaylistSortPicker'; + +export const PlaylistIndexPage = () => ( + + + + + + + + + + + + + + + + + + + + + +); diff --git a/plugins/playlist/src/components/PlaylistIndexPage/index.ts b/plugins/playlist/src/components/PlaylistIndexPage/index.ts new file mode 100644 index 0000000000..06858a8262 --- /dev/null +++ b/plugins/playlist/src/components/PlaylistIndexPage/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 { PlaylistIndexPage } from './PlaylistIndexPage'; diff --git a/plugins/playlist/src/components/PlaylistList/PlaylistList.test.tsx b/plugins/playlist/src/components/PlaylistList/PlaylistList.test.tsx new file mode 100644 index 0000000000..27030ec1c7 --- /dev/null +++ b/plugins/playlist/src/components/PlaylistList/PlaylistList.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 { Playlist } from '@backstage/plugin-playlist-common'; +import { render } from '@testing-library/react'; +import React from 'react'; + +import { MockPlaylistListProvider } from '../../testUtils'; +import { PlaylistList } from './PlaylistList'; + +jest.mock('../PlaylistCard', () => ({ + PlaylistCard: ({ playlist }: { playlist: Playlist }) => ( +
{playlist.name}
+ ), +})); + +describe('', () => { + it('renders error on error', () => { + const rendered = render( + + + , + ); + + expect(rendered.getByText('Test Error')).toBeInTheDocument(); + }); + + it('handles no playlists', () => { + const rendered = render( + + + , + ); + + expect( + rendered.getByText('No playlists found that match your filter.'), + ).toBeInTheDocument(); + }); + + it('renders playlists', () => { + const rendered = render( + + + , + ); + + expect(rendered.getByText('playlist-1')).toBeInTheDocument(); + expect(rendered.getByText('playlist-2')).toBeInTheDocument(); + }); +}); diff --git a/plugins/playlist/src/components/PlaylistList/PlaylistList.tsx b/plugins/playlist/src/components/PlaylistList/PlaylistList.tsx new file mode 100644 index 0000000000..fcc3971542 --- /dev/null +++ b/plugins/playlist/src/components/PlaylistList/PlaylistList.tsx @@ -0,0 +1,58 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { + Content, + ItemCardGrid, + Progress, + WarningPanel, +} from '@backstage/core-components'; +import { Typography } from '@material-ui/core'; + +import { usePlaylistList } from '../../hooks'; +import { PlaylistCard } from '../PlaylistCard'; + +export const PlaylistList = () => { + const { loading, error, playlists } = usePlaylistList(); + + return ( + <> + {loading && } + + {error && ( + + {error.message} + + )} + + {!error && !loading && !playlists.length && ( + + No playlists found that match your filter. + + )} + + + + {playlists?.length > 0 && + playlists.map(playlist => ( + + ))} + + + + ); +}; diff --git a/plugins/playlist/src/components/PlaylistList/index.ts b/plugins/playlist/src/components/PlaylistList/index.ts new file mode 100644 index 0000000000..59fa5cf0fb --- /dev/null +++ b/plugins/playlist/src/components/PlaylistList/index.ts @@ -0,0 +1,17 @@ +/* + * 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 * from './PlaylistList'; diff --git a/plugins/playlist/src/components/PlaylistOwnerPicker/PlaylistOwnerPicker.test.tsx b/plugins/playlist/src/components/PlaylistOwnerPicker/PlaylistOwnerPicker.test.tsx new file mode 100644 index 0000000000..c74e6f6853 --- /dev/null +++ b/plugins/playlist/src/components/PlaylistOwnerPicker/PlaylistOwnerPicker.test.tsx @@ -0,0 +1,215 @@ +/* + * 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 { parseEntityRef } from '@backstage/catalog-model'; +import { humanizeEntityRef } from '@backstage/plugin-catalog-react'; +import { Playlist } from '@backstage/plugin-playlist-common'; +import { fireEvent, render } from '@testing-library/react'; +import React from 'react'; +import { MockPlaylistListProvider } from '../../testUtils'; +import { + PlaylistOwnerFilter, + PlaylistOwnerPicker, +} from './PlaylistOwnerPicker'; + +const samplePlaylists: Playlist[] = [ + { + id: 'id1', + name: 'playlist-1', + owner: 'group:default/some-owner', + public: true, + entities: 1, + followers: 2, + isFollowing: false, + }, + { + id: 'id2', + name: 'playlist-2', + owner: 'group:default/another-owner', + public: true, + entities: 2, + followers: 1, + isFollowing: true, + }, + { + id: 'id3', + name: 'playlist-3', + owner: 'group:default/another-owner', + public: true, + entities: 2, + followers: 1, + isFollowing: true, + }, + { + id: 'id4', + name: 'playlist-4', + owner: 'user:default/owner', + public: true, + entities: 2, + followers: 1, + isFollowing: true, + }, +]; + +describe('', () => { + it('renders all owners', () => { + const rendered = render( + + + , + ); + expect(rendered.getByText('Owner')).toBeInTheDocument(); + + fireEvent.click(rendered.getByTestId('owner-picker-expand')); + samplePlaylists + .map(p => + humanizeEntityRef(parseEntityRef(p.owner), { defaultKind: 'group' }), + ) + .forEach(owner => { + expect(rendered.getByText(owner as string)).toBeInTheDocument(); + }); + }); + + it('renders unique owners in alphabetical order', () => { + const rendered = render( + + + , + ); + expect(rendered.getByText('Owner')).toBeInTheDocument(); + + fireEvent.click(rendered.getByTestId('owner-picker-expand')); + + expect(rendered.getAllByRole('option').map(o => o.textContent)).toEqual([ + 'another-owner', + 'some-owner', + 'user:owner', + ]); + }); + + it('respects the query parameter filter value', () => { + const updateFilters = jest.fn(); + const queryParameters = { owners: ['group:default/another-owner'] }; + render( + + + , + ); + + expect(updateFilters).toHaveBeenLastCalledWith({ + owners: new PlaylistOwnerFilter(['group:default/another-owner']), + }); + }); + + it('adds owners to filters', () => { + const updateFilters = jest.fn(); + const rendered = render( + + + , + ); + expect(updateFilters).toHaveBeenLastCalledWith({ + owners: undefined, + }); + + fireEvent.click(rendered.getByTestId('owner-picker-expand')); + fireEvent.click(rendered.getByText('some-owner')); + expect(updateFilters).toHaveBeenLastCalledWith({ + owners: new PlaylistOwnerFilter(['group:default/some-owner']), + }); + }); + + it('removes owners from filters', () => { + const updateFilters = jest.fn(); + const rendered = render( + + + , + ); + expect(updateFilters).toHaveBeenLastCalledWith({ + owners: new PlaylistOwnerFilter(['group:default/some-owner']), + }); + fireEvent.click(rendered.getByTestId('owner-picker-expand')); + expect(rendered.getByLabelText('some-owner')).toBeChecked(); + + fireEvent.click(rendered.getByLabelText('some-owner')); + expect(updateFilters).toHaveBeenLastCalledWith({ + owner: undefined, + }); + }); + + it('responds to external queryParameters changes', () => { + const updateFilters = jest.fn(); + const rendered = render( + + + , + ); + expect(updateFilters).toHaveBeenLastCalledWith({ + owners: new PlaylistOwnerFilter(['group:default/team-a']), + }); + rendered.rerender( + + + , + ); + expect(updateFilters).toHaveBeenLastCalledWith({ + owners: new PlaylistOwnerFilter(['group:default/team-b']), + }); + }); +}); diff --git a/plugins/playlist/src/components/PlaylistOwnerPicker/PlaylistOwnerPicker.tsx b/plugins/playlist/src/components/PlaylistOwnerPicker/PlaylistOwnerPicker.tsx new file mode 100644 index 0000000000..7def794c6b --- /dev/null +++ b/plugins/playlist/src/components/PlaylistOwnerPicker/PlaylistOwnerPicker.tsx @@ -0,0 +1,134 @@ +/* + * 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 { parseEntityRef } from '@backstage/catalog-model'; +import { humanizeEntityRef } from '@backstage/plugin-catalog-react'; +import { Playlist } from '@backstage/plugin-playlist-common'; +import { + Box, + Checkbox, + Chip, + FormControlLabel, + TextField, + Typography, +} from '@material-ui/core'; +import CheckBoxIcon from '@material-ui/icons/CheckBox'; +import CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank'; +import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; +import { Autocomplete } from '@material-ui/lab'; +import React, { useEffect, useMemo, useState } from 'react'; + +import { usePlaylistList } from '../../hooks'; +import { PlaylistFilter } from '../../types'; + +export class PlaylistOwnerFilter implements PlaylistFilter { + constructor(readonly values: string[]) {} + + filterPlaylist(playlist: Playlist): boolean { + return this.values.some(v => playlist.owner === v); + } + + toQueryValue(): string[] { + return this.values; + } +} + +const icon = ; +const checkedIcon = ; + +export const PlaylistOwnerPicker = () => { + const { + updateFilters, + backendPlaylists, + filters, + queryParameters: { owners: ownersParameter }, + } = usePlaylistList(); + + const queryParamOwners = useMemo( + () => [ownersParameter].flat().filter(Boolean) as string[], + [ownersParameter], + ); + + const [selectedOwners, setSelectedOwners] = useState( + queryParamOwners.length ? queryParamOwners : filters.owners?.values ?? [], + ); + + // Set selected owners on query parameter updates; this happens at initial page load and from + // external updates to the page location. + useEffect(() => { + if (queryParamOwners.length) { + setSelectedOwners(queryParamOwners); + } + }, [queryParamOwners]); + + useEffect(() => { + updateFilters({ + owners: selectedOwners.length + ? new PlaylistOwnerFilter(selectedOwners) + : undefined, + }); + }, [selectedOwners, updateFilters]); + + const availableOwners = useMemo( + () => [...new Set(backendPlaylists.map(p => p.owner))].sort(), + [backendPlaylists], + ); + + if (!availableOwners.length) return null; + + return ( + + + Owner + setSelectedOwners(value)} + renderTags={(values: string[], getTagProps: Function) => + values.map((val, index) => ( + + )) + } + renderOption={(option, { selected }) => ( + + } + label={humanizeEntityRef(parseEntityRef(option), { + defaultKind: 'group', + })} + /> + )} + size="small" + popupIcon={} + renderInput={params => } + /> + + + ); +}; diff --git a/plugins/playlist/src/components/PlaylistOwnerPicker/index.ts b/plugins/playlist/src/components/PlaylistOwnerPicker/index.ts new file mode 100644 index 0000000000..fcde27e956 --- /dev/null +++ b/plugins/playlist/src/components/PlaylistOwnerPicker/index.ts @@ -0,0 +1,17 @@ +/* + * 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 * from './PlaylistOwnerPicker'; diff --git a/plugins/playlist/src/components/PlaylistPage/AddEntitiesDrawer.test.tsx b/plugins/playlist/src/components/PlaylistPage/AddEntitiesDrawer.test.tsx new file mode 100644 index 0000000000..d1bdf1d46a --- /dev/null +++ b/plugins/playlist/src/components/PlaylistPage/AddEntitiesDrawer.test.tsx @@ -0,0 +1,159 @@ +/* + * 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 { + CatalogApi, + catalogApiRef, + entityRouteRef, +} from '@backstage/plugin-catalog-react'; +import { SearchApi, searchApiRef } from '@backstage/plugin-search-react'; +import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; +import { fireEvent, getByText } from '@testing-library/react'; +import { act } from '@testing-library/react-hooks'; +import React from 'react'; + +import { AddEntitiesDrawer } from './AddEntitiesDrawer'; + +describe('AddEntitiesDrawer', () => { + const catalogApi: Partial = { + getEntityFacets: jest.fn().mockImplementation(async () => ({ + facets: { + kind: [{ value: 'component' }], + }, + })), + }; + + const mockOnAdd = jest.fn(); + const sampleCurrentEntities = [ + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'system', + metadata: { namespace: 'default', name: 'test-ent' }, + }, + ]; + + const mockSearchResults = [ + { + type: 'software-catalog', + document: { + title: 'Test Ent', + text: 'This is test ent', + location: '/catalog/default/system/test-ent', + kind: 'system', + }, + }, + { + type: 'software-catalog', + document: { + title: 'Test Ent 2', + text: 'This is test ent 2', + location: '/catalog/foo/component/test-ent2', + kind: 'component', + type: 'library', + }, + }, + { + type: 'software-catalog', + document: { + title: 'Test Ent 3', + text: 'This is test ent 3', + location: '/catalog/bar/api/test-ent3', + kind: 'api', + type: 'openapi', + }, + }, + ]; + + const searchApi: Partial = { + query: jest + .fn() + .mockImplementation(async () => ({ results: mockSearchResults })), + }; + + const element = ( + + + + ); + + const render = async () => + renderInTestApp(element, { + mountedRoutes: { '/catalog/:namespace/:kind/:name': entityRouteRef }, + }); + + beforeEach(() => { + mockOnAdd.mockClear(); + }); + + it('should render available entities correctly', async () => { + const rendered = await render(); + expect(searchApi.query).toHaveBeenLastCalledWith({ + filters: {}, + term: '', + types: ['software-catalog'], + }); + + expect(rendered.getByText('Test Ent')).toBeInTheDocument(); + expect(rendered.getByText('This is test ent')).toBeInTheDocument(); + expect(rendered.getByText('Kind: system')).toBeInTheDocument(); + + expect(rendered.getByText('Test Ent 2')).toBeInTheDocument(); + expect(rendered.getByText('This is test ent 2')).toBeInTheDocument(); + expect(rendered.getByText('Kind: component')).toBeInTheDocument(); + expect(rendered.getByText('Type: library')).toBeInTheDocument(); + + expect(rendered.getByText('Test Ent 3')).toBeInTheDocument(); + expect(rendered.getByText('This is test ent 3')).toBeInTheDocument(); + expect(rendered.getByText('Kind: api')).toBeInTheDocument(); + expect(rendered.getByText('Type: openapi')).toBeInTheDocument(); + }); + + it('should disable options that are already added', async () => { + const rendered = await render(); + + const addButtons = rendered.getAllByTestId('entity-drawer-add-button'); + expect(addButtons.length).toEqual(3); + + expect(getByText(addButtons[0], 'Added')).toBeInTheDocument(); + expect(addButtons[0]).toBeDisabled(); + + expect(getByText(addButtons[1], 'Add')).toBeInTheDocument(); + expect(addButtons[1]).not.toBeDisabled(); + + expect(getByText(addButtons[2], 'Add')).toBeInTheDocument(); + expect(addButtons[2]).not.toBeDisabled(); + }); + + it('should add entities correctly', async () => { + const rendered = await render(); + + act(() => { + fireEvent.click(rendered.getAllByTestId('entity-drawer-add-button')[1]); + }); + + expect(mockOnAdd).toHaveBeenCalledWith('component:foo/test-ent2'); + }); +}); diff --git a/plugins/playlist/src/components/PlaylistPage/AddEntitiesDrawer.tsx b/plugins/playlist/src/components/PlaylistPage/AddEntitiesDrawer.tsx new file mode 100644 index 0000000000..05dd4da231 --- /dev/null +++ b/plugins/playlist/src/components/PlaylistPage/AddEntitiesDrawer.tsx @@ -0,0 +1,239 @@ +/* + * 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 { + Entity, + getCompoundEntityRef, + stringifyEntityRef, +} from '@backstage/catalog-model'; +import { useApi, useRouteRef } from '@backstage/core-plugin-api'; +import { CatalogEntityDocument } from '@backstage/plugin-catalog-common'; +import { catalogApiRef, entityRouteRef } from '@backstage/plugin-catalog-react'; +import { + SearchBar, + SearchContextProvider, + SearchFilter, + SearchResult, + SearchResultPager, + useSearch, +} from '@backstage/plugin-search-react'; +import { + Box, + Button, + Chip, + createStyles, + Divider, + Drawer, + Grid, + List, + ListItem, + ListItemSecondaryAction, + ListItemText, + makeStyles, + Paper, + Theme, + Typography, +} from '@material-ui/core'; +import React, { useCallback, useEffect, useMemo } from 'react'; + +const useStyles = makeStyles((theme: Theme) => + createStyles({ + paper: { + width: '50%', + padding: theme.spacing(2.5), + }, + searchBarContainer: { + borderRadius: 30, + display: 'flex', + height: '2.4em', + }, + gridContainer: { + height: '100%', + }, + searchResults: { + overflow: 'auto', + }, + itemContainer: { + flexWrap: 'wrap', + paddingRight: '75px', + }, + itemText: { + width: '100%', + wordBreak: 'break-word', + marginBottom: '1rem', + }, + }), +); + +const RestrictCatalogIndexResults = () => { + const { setTypes } = useSearch(); + useEffect(() => setTypes(['software-catalog']), [setTypes]); + return null; +}; + +export type AddEntitiesDrawerProps = { + currentEntities: Entity[]; + open: boolean; + onAdd: (entityRef: string) => void; + onClose: () => void; +}; + +export const AddEntitiesDrawer = ({ + currentEntities, + open, + onAdd, + onClose, +}: AddEntitiesDrawerProps) => { + const classes = useStyles(); + const catalogApi = useApi(catalogApiRef); + const entityRoute = useRouteRef(entityRouteRef); + const entityLocationRegex = useMemo(() => { + const forwardSlashRegex = new RegExp('/', 'g'); + const locationRegex = entityRoute({ + namespace: '(?.+?)', + kind: '(?.+?)', + name: '(?.+?)', + }).replace(forwardSlashRegex, '\\/'); + + return new RegExp(`${locationRegex}$`); + }, [entityRoute]); + + const currentEntityLocations = useMemo( + () => + currentEntities.map(entity => + entityRoute(getCompoundEntityRef(entity)).toLocaleLowerCase('en-US'), + ), + [currentEntities, entityRoute], + ); + + const getEntityKinds = async () => { + return ( + await catalogApi.getEntityFacets({ facets: ['kind'] }) + ).facets.kind.map(f => f.value); + }; + + const addEntity = useCallback( + entityResult => { + // TODO (kuangp): this parsing of the location is not great. Ideally `CatalogEntityDocument` + // contains the `metadata.name` field so we can derive the full ref and we only fall back to + // parsing location if it's missing (ie. for older versions) + const { groups } = entityResult.location.match(entityLocationRegex); + if (groups) { + onAdd(stringifyEntityRef(groups)); + } else { + // eslint-disable-next-line no-console + console.error( + `Failed to parse entity ref from entity location: ${entityResult.location}`, + ); + } + }, + [entityLocationRegex, onAdd], + ); + + return ( + + + + + + + Let's find something for your playlist + + + + + + + + + + + + + {({ results }) => ( + + {results.map(({ document }) => ( + + +
+ + + + + + {(document as CatalogEntityDocument).kind && ( + + )} + {(document as CatalogEntityDocument).type && ( + + )} + +
+
+ +
+ ))} +
+ )} +
+ +
+
+
+
+ ); +}; diff --git a/plugins/playlist/src/components/PlaylistPage/PlaylistEntitiesTable.test.tsx b/plugins/playlist/src/components/PlaylistPage/PlaylistEntitiesTable.test.tsx new file mode 100644 index 0000000000..f7720b25c1 --- /dev/null +++ b/plugins/playlist/src/components/PlaylistPage/PlaylistEntitiesTable.test.tsx @@ -0,0 +1,175 @@ +/* + * 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 { ErrorApi, errorApiRef } from '@backstage/core-plugin-api'; +import { entityRouteRef } from '@backstage/plugin-catalog-react'; +import { AuthorizeResult } from '@backstage/plugin-permission-common'; +import { + PermissionApi, + permissionApiRef, +} from '@backstage/plugin-permission-react'; +import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; +import { Button } from '@material-ui/core'; +import { fireEvent, waitFor } from '@testing-library/react'; +import { act } from '@testing-library/react-hooks'; +import React from 'react'; +import { SWRConfig } from 'swr'; + +import { PlaylistApi, playlistApiRef } from '../../api'; +import { PlaylistEntitiesTable } from './PlaylistEntitiesTable'; + +jest.mock('./AddEntitiesDrawer', () => ({ + AddEntitiesDrawer: ({ onAdd, open }: { onAdd: Function; open: boolean }) => + open ? ( + +
+ + {deleting.loading && ( + + )} +
+ + +
+ ); +}; diff --git a/plugins/playlist/src/components/PlaylistPage/PlaylistPage.test.tsx b/plugins/playlist/src/components/PlaylistPage/PlaylistPage.test.tsx new file mode 100644 index 0000000000..65d3d79be6 --- /dev/null +++ b/plugins/playlist/src/components/PlaylistPage/PlaylistPage.test.tsx @@ -0,0 +1,141 @@ +/* + * 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 { ErrorApi, errorApiRef } from '@backstage/core-plugin-api'; +import { AuthorizeResult } from '@backstage/plugin-permission-common'; +import { + PermissionApi, + permissionApiRef, +} from '@backstage/plugin-permission-react'; +import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; +import { fireEvent, getByText, waitFor } from '@testing-library/react'; +import { act } from '@testing-library/react-hooks'; +import React from 'react'; +import { SWRConfig } from 'swr'; + +import { PlaylistApi, playlistApiRef } from '../../api'; +import { PlaylistPage } from './PlaylistPage'; + +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ playlistId: 'id1' }), +})); + +// Mock out nested components to simplify tests +jest.mock('./PlaylistEntitiesTable', () => ({ + PlaylistEntitiesTable: () => null, +})); + +jest.mock('./PlaylistHeader', () => ({ + PlaylistHeader: () => null, +})); + +describe('PlaylistPage', () => { + const testPlaylist = { + id: 'id1', + name: 'playlist-1', + description: 'test description', + owner: 'group:default/some-owner', + public: true, + entities: 1, + followers: 2, + isFollowing: false, + }; + + const errorApi: Partial = { post: jest.fn() }; + const playlistApi: Partial = { + getPlaylist: jest.fn().mockImplementation(async () => testPlaylist), + followPlaylist: jest.fn().mockImplementation(async () => {}), + unfollowPlaylist: jest.fn().mockImplementation(async () => {}), + }; + const mockAuthorize = jest + .fn() + .mockImplementation(async () => ({ result: AuthorizeResult.ALLOW })); + const permissionApi: Partial = { authorize: mockAuthorize }; + + // SWR used by the usePermission hook needs cache to be reset for each test + const element = ( + new Map() }}> + + + + + ); + + beforeEach(() => { + mockAuthorize.mockClear(); + }); + + it('show render the playlist info', async () => { + const rendered = await renderInTestApp(element); + expect(playlistApi.getPlaylist).toHaveBeenCalledWith('id1'); + expect(rendered.getByText('test description')).toBeInTheDocument(); + expect( + rendered.getByTestId('playlist-page-follow-button'), + ).toBeInTheDocument(); + expect( + getByText(rendered.getByTestId('playlist-page-follow-button'), 'Follow'), + ).toBeInTheDocument(); + }); + + it('should not render the follow button if unauthorized', async () => { + mockAuthorize.mockImplementationOnce(async () => ({ + result: AuthorizeResult.DENY, + })); + const rendered = await renderInTestApp(element); + expect(rendered.queryByTestId('playlist-page-follow-button')).toBeNull(); + }); + + it('should reflect and toggle the following state of the playlist', async () => { + const rendered = await renderInTestApp(element); + + act(() => { + fireEvent.click(rendered.getByTestId('playlist-page-follow-button')); + testPlaylist.isFollowing = true; + }); + + await waitFor(() => { + expect(playlistApi.followPlaylist).toHaveBeenCalledWith('id1'); + expect( + getByText( + rendered.getByTestId('playlist-page-follow-button'), + 'Following', + ), + ).toBeInTheDocument(); + }); + + act(() => { + fireEvent.click(rendered.getByTestId('playlist-page-follow-button')); + testPlaylist.isFollowing = false; + }); + + await waitFor(() => { + expect(playlistApi.unfollowPlaylist).toHaveBeenCalledWith('id1'); + expect( + getByText( + rendered.getByTestId('playlist-page-follow-button'), + 'Follow', + ), + ).toBeInTheDocument(); + }); + }); +}); diff --git a/plugins/playlist/src/components/PlaylistPage/PlaylistPage.tsx b/plugins/playlist/src/components/PlaylistPage/PlaylistPage.tsx new file mode 100644 index 0000000000..4c9a0edbb7 --- /dev/null +++ b/plugins/playlist/src/components/PlaylistPage/PlaylistPage.tsx @@ -0,0 +1,133 @@ +/* + * 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, ErrorPage, Page } from '@backstage/core-components'; +import { errorApiRef, useApi } from '@backstage/core-plugin-api'; +import { ResponseError } from '@backstage/errors'; +import { usePermission } from '@backstage/plugin-permission-react'; +import { permissions } from '@backstage/plugin-playlist-common'; +import { + Button, + Card, + CardContent, + CardHeader, + Divider, + LinearProgress, + makeStyles, + Typography, +} from '@material-ui/core'; +import React, { useEffect } from 'react'; +import { useParams } from 'react-router-dom'; +import useAsyncFn from 'react-use/lib/useAsyncFn'; + +import { playlistApiRef } from '../../api'; +import { PlaylistEntitiesTable } from './PlaylistEntitiesTable'; +import { PlaylistHeader } from './PlaylistHeader'; + +const useStyles = makeStyles({ + followButton: { + top: '6px', + right: '8px', + }, +}); + +export const PlaylistPage = () => { + const classes = useStyles(); + const errorApi = useApi(errorApiRef); + const playlistApi = useApi(playlistApiRef); + const { playlistId } = useParams(); + + const [{ value: playlist, loading, error }, loadPlaylist] = useAsyncFn( + () => playlistApi.getPlaylist(playlistId!), + [playlistApi], + ); + + useEffect(() => { + loadPlaylist(); + }, [loadPlaylist]); + + const { allowed: followAllowed } = usePermission({ + permission: permissions.playlistFollowersUpdate, + resourceRef: playlist?.id, + }); + + const [{ loading: loadingFollowRequest }, followPlaylist] = + useAsyncFn(async () => { + try { + if (playlist!.isFollowing) { + await playlistApi.unfollowPlaylist(playlist!.id); + } else { + await playlistApi.followPlaylist(playlist!.id); + } + + loadPlaylist(); + } catch (e) { + errorApi.post(e); + } + }, [errorApi, loadPlaylist, playlist, playlistApi]); + + if (error) { + return ( + + ); + } + + return ( + <> + {loading && } + + {playlist && ( + <> + + + + + {playlist.isFollowing ? 'Following' : 'Follow'} + + ) + } + /> + + + + {playlist.description} + + + +
+ +
+ + )} +
+ + ); +}; diff --git a/plugins/playlist/src/components/PlaylistPage/index.ts b/plugins/playlist/src/components/PlaylistPage/index.ts new file mode 100644 index 0000000000..695b243cd0 --- /dev/null +++ b/plugins/playlist/src/components/PlaylistPage/index.ts @@ -0,0 +1,17 @@ +/* + * 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 * from './PlaylistPage'; diff --git a/plugins/playlist/src/components/PlaylistSearchBar/PlaylistSearchBar.test.tsx b/plugins/playlist/src/components/PlaylistSearchBar/PlaylistSearchBar.test.tsx new file mode 100644 index 0000000000..84650e4f41 --- /dev/null +++ b/plugins/playlist/src/components/PlaylistSearchBar/PlaylistSearchBar.test.tsx @@ -0,0 +1,52 @@ +/* + * 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 { fireEvent, render, waitFor } from '@testing-library/react'; +import { DefaultPlaylistFilters } from '../../hooks'; +import { MockPlaylistListProvider } from '../../testUtils'; +import { PlaylistSearchBar, PlaylistTextFilter } from './PlaylistSearchBar'; + +describe('PlaylistSearchBar', () => { + it('should display search value and execute set callback', async () => { + const updateFilters = jest.fn(); + + const filters: DefaultPlaylistFilters = { + text: new PlaylistTextFilter('hello'), + }; + + const { getByDisplayValue } = render( + + + , + ); + + const searchInput = getByDisplayValue('hello'); + expect(searchInput).toBeInTheDocument(); + + fireEvent.change(searchInput, { target: { value: 'world' } }); + await waitFor(() => expect(updateFilters.mock.calls.length).toBe(1)); + expect(updateFilters).toHaveBeenCalledWith({ + text: new PlaylistTextFilter('world'), + }); + + fireEvent.change(searchInput, { target: { value: '' } }); + await waitFor(() => expect(updateFilters.mock.calls.length).toBe(2)); + expect(updateFilters).toHaveBeenCalledWith({ + text: undefined, + }); + }); +}); diff --git a/plugins/playlist/src/components/PlaylistSearchBar/PlaylistSearchBar.tsx b/plugins/playlist/src/components/PlaylistSearchBar/PlaylistSearchBar.tsx new file mode 100644 index 0000000000..94a22a23f5 --- /dev/null +++ b/plugins/playlist/src/components/PlaylistSearchBar/PlaylistSearchBar.tsx @@ -0,0 +1,102 @@ +/* + * 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 { Playlist } from '@backstage/plugin-playlist-common'; +import { + FormControl, + IconButton, + Input, + InputAdornment, + makeStyles, + Toolbar, +} from '@material-ui/core'; +import Clear from '@material-ui/icons/Clear'; +import Search from '@material-ui/icons/Search'; +import React, { useState } from 'react'; +import useDebounce from 'react-use/lib/useDebounce'; + +import { usePlaylistList } from '../../hooks'; +import { PlaylistFilter } from '../../types'; + +export class PlaylistTextFilter implements PlaylistFilter { + constructor(readonly value: string) {} + + filterPlaylist(playlist: Playlist): boolean { + const upperCaseValue = this.value.toLocaleUpperCase('en-US'); + return ( + playlist.name.toLocaleUpperCase('en-US').includes(upperCaseValue) || + !!playlist.description + ?.toLocaleUpperCase('en-US') + .includes(upperCaseValue) + ); + } +} + +const useStyles = makeStyles(_theme => ({ + searchToolbar: { + paddingLeft: 0, + paddingRight: 0, + }, +})); + +export const PlaylistSearchBar = () => { + const classes = useStyles(); + + const { filters, updateFilters } = usePlaylistList(); + const [search, setSearch] = useState(filters.text?.value ?? ''); + + useDebounce( + () => { + updateFilters({ + text: search.length ? new PlaylistTextFilter(search) : undefined, + }); + }, + 250, + [search, updateFilters], + ); + + return ( + + + setSearch(event.target.value)} + value={search} + startAdornment={ + + + + } + endAdornment={ + + setSearch('')} + edge="end" + disabled={search.length === 0} + > + + + + } + /> + + + ); +}; diff --git a/plugins/playlist/src/components/PlaylistSearchBar/index.ts b/plugins/playlist/src/components/PlaylistSearchBar/index.ts new file mode 100644 index 0000000000..65b7e181cf --- /dev/null +++ b/plugins/playlist/src/components/PlaylistSearchBar/index.ts @@ -0,0 +1,17 @@ +/* + * 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 * from './PlaylistSearchBar'; diff --git a/plugins/playlist/src/components/PlaylistSortPicker/PlaylistSortPicker.test.tsx b/plugins/playlist/src/components/PlaylistSortPicker/PlaylistSortPicker.test.tsx new file mode 100644 index 0000000000..9317bfd4c1 --- /dev/null +++ b/plugins/playlist/src/components/PlaylistSortPicker/PlaylistSortPicker.test.tsx @@ -0,0 +1,68 @@ +/* + * 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 { fireEvent, getByRole, render, waitFor } from '@testing-library/react'; +import { act } from '@testing-library/react-hooks'; +import React from 'react'; + +import { MockPlaylistListProvider } from '../../testUtils'; +import { + DefaultPlaylistSortTypes, + DefaultSortCompareFunctions, + PlaylistSortPicker, +} from './PlaylistSortPicker'; + +describe('PlaylistSortPicker', () => { + it('should update sort based on selection', async () => { + const updateSort = jest.fn(); + + const { getByText, getByTestId } = render( + + + , + ); + + act(() => { + fireEvent.mouseDown( + getByRole(getByTestId('sort-picker-select'), 'button'), + ); + }); + const abcSort = getByText('Alphabetical'); + expect(abcSort).toBeInTheDocument(); + + fireEvent.click(abcSort); + await waitFor(() => { + expect(updateSort).toHaveBeenLastCalledWith( + DefaultSortCompareFunctions[DefaultPlaylistSortTypes.alphabetical], + ); + }); + + act(() => { + fireEvent.mouseDown( + getByRole(getByTestId('sort-picker-select'), 'button'), + ); + }); + const entitiesSort = getByText('# Entities'); + expect(entitiesSort).toBeInTheDocument(); + + fireEvent.click(entitiesSort); + await waitFor(() => { + expect(updateSort).toHaveBeenLastCalledWith( + DefaultSortCompareFunctions[DefaultPlaylistSortTypes.numEntities], + ); + }); + }); +}); diff --git a/plugins/playlist/src/components/PlaylistSortPicker/PlaylistSortPicker.tsx b/plugins/playlist/src/components/PlaylistSortPicker/PlaylistSortPicker.tsx new file mode 100644 index 0000000000..21c961eb91 --- /dev/null +++ b/plugins/playlist/src/components/PlaylistSortPicker/PlaylistSortPicker.tsx @@ -0,0 +1,115 @@ +/* + * 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 { Playlist } from '@backstage/plugin-playlist-common'; +import { + ListSubheader, + makeStyles, + MenuItem, + Select, + Typography, +} from '@material-ui/core'; +import SwapVertIcon from '@material-ui/icons/SwapVert'; +import React from 'react'; +import useEffectOnce from 'react-use/lib/useEffectOnce'; + +import { usePlaylistList } from '../../hooks'; +import { PlaylistSortCompareFunction } from '../../types'; + +export const enum DefaultPlaylistSortTypes { + popular = 'popular', + alphabetical = 'alphabetical', + numEntities = 'numEntities', +} + +export const DefaultSortCompareFunctions: { + [type in DefaultPlaylistSortTypes]: PlaylistSortCompareFunction; +} = { + [DefaultPlaylistSortTypes.popular]: (a: Playlist, b: Playlist) => { + if (a.followers < b.followers) { + return 1; + } else if (a.followers > b.followers) { + return -1; + } + return 0; + }, + [DefaultPlaylistSortTypes.alphabetical]: (a: Playlist, b: Playlist) => + a.name.localeCompare(b.name), + [DefaultPlaylistSortTypes.numEntities]: (a: Playlist, b: Playlist) => { + if (a.entities < b.entities) { + return 1; + } else if (a.entities > b.entities) { + return -1; + } + return 0; + }, +}; + +const sortTypeLabels = { + [DefaultPlaylistSortTypes.popular]: 'Popular', + [DefaultPlaylistSortTypes.alphabetical]: 'Alphabetical', + [DefaultPlaylistSortTypes.numEntities]: '# Entities', +}; + +const useStyles = makeStyles({ + select: { + width: '10rem', + marginRight: '1rem', + }, + icon: { + verticalAlign: 'bottom', + }, +}); + +export const PlaylistSortPicker = () => { + const classes = useStyles(); + const { updateSort } = usePlaylistList(); + + useEffectOnce(() => + updateSort(DefaultSortCompareFunctions[DefaultPlaylistSortTypes.popular]), + ); + + return ( + + ); +}; diff --git a/plugins/playlist/src/components/PlaylistSortPicker/index.ts b/plugins/playlist/src/components/PlaylistSortPicker/index.ts new file mode 100644 index 0000000000..04ea5268ef --- /dev/null +++ b/plugins/playlist/src/components/PlaylistSortPicker/index.ts @@ -0,0 +1,17 @@ +/* + * 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 * from './PlaylistSortPicker'; diff --git a/plugins/playlist/src/components/Router/Router.test.tsx b/plugins/playlist/src/components/Router/Router.test.tsx new file mode 100644 index 0000000000..ea8620ec42 --- /dev/null +++ b/plugins/playlist/src/components/Router/Router.test.tsx @@ -0,0 +1,51 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { PlaylistIndexPage } from '../PlaylistIndexPage'; +import { PlaylistPage } from '../PlaylistPage'; +import { Router } from './Router'; +import { renderInTestApp } from '@backstage/test-utils'; + +jest.mock('../PlaylistIndexPage', () => ({ + PlaylistIndexPage: jest.fn(() => null), +})); + +jest.mock('../PlaylistPage', () => ({ + PlaylistPage: jest.fn(() => null), +})); + +describe('Router', () => { + beforeEach(() => { + (PlaylistPage as jest.Mock).mockClear(); + (PlaylistIndexPage as jest.Mock).mockClear(); + }); + describe('/', () => { + it('should render the PlaylistIndexPage', async () => { + await renderInTestApp(); + expect(PlaylistIndexPage).toHaveBeenCalled(); + }); + }); + + describe('/:playlistId', () => { + it('should render the PlaylistPage page', async () => { + await renderInTestApp(, { + routeEntries: ['/my-playlist'], + }); + expect(PlaylistPage).toHaveBeenCalled(); + }); + }); +}); diff --git a/plugins/playlist/src/components/Router/Router.tsx b/plugins/playlist/src/components/Router/Router.tsx new file mode 100644 index 0000000000..5791a0817c --- /dev/null +++ b/plugins/playlist/src/components/Router/Router.tsx @@ -0,0 +1,29 @@ +/* + * 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 { Routes, Route } from 'react-router'; + +import { playlistRouteRef } from '../../routes'; +import { PlaylistIndexPage } from '../PlaylistIndexPage'; +import { PlaylistPage } from '../PlaylistPage'; + +export const Router = () => ( + + } /> + } /> + +); diff --git a/plugins/playlist/src/components/Router/index.ts b/plugins/playlist/src/components/Router/index.ts new file mode 100644 index 0000000000..6606629fee --- /dev/null +++ b/plugins/playlist/src/components/Router/index.ts @@ -0,0 +1,17 @@ +/* + * 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 * from './Router'; diff --git a/plugins/playlist/src/components/index.ts b/plugins/playlist/src/components/index.ts new file mode 100644 index 0000000000..2be300ac51 --- /dev/null +++ b/plugins/playlist/src/components/index.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './CreatePlaylistButton'; +export * from './EntityPlaylistDialog'; +export * from './PersonalListPicker'; +export * from './PlaylistCard'; +export * from './PlaylistEditDialog'; +export * from './PlaylistIndexPage'; +export * from './PlaylistList'; +export * from './PlaylistOwnerPicker'; +export * from './PlaylistPage'; +export * from './PlaylistSearchBar'; +export * from './PlaylistSortPicker'; diff --git a/plugins/playlist/src/hooks/index.ts b/plugins/playlist/src/hooks/index.ts new file mode 100644 index 0000000000..316121b515 --- /dev/null +++ b/plugins/playlist/src/hooks/index.ts @@ -0,0 +1,17 @@ +/* + * 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 * from './usePlaylistList'; diff --git a/plugins/playlist/src/hooks/usePlaylistList.test.tsx b/plugins/playlist/src/hooks/usePlaylistList.test.tsx new file mode 100644 index 0000000000..d04996513e --- /dev/null +++ b/plugins/playlist/src/hooks/usePlaylistList.test.tsx @@ -0,0 +1,225 @@ +/* + * 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 { + ConfigApi, + configApiRef, + IdentityApi, + identityApiRef, +} from '@backstage/core-plugin-api'; +import { Playlist } from '@backstage/plugin-playlist-common'; +import { TestApiProvider } from '@backstage/test-utils'; +import { act, renderHook } from '@testing-library/react-hooks'; +import qs from 'qs'; +import React, { PropsWithChildren } from 'react'; +import { MemoryRouter } from 'react-router'; +import { PlaylistApi, playlistApiRef } from '../api'; +import { + DefaultSortCompareFunctions, + DefaultPlaylistSortTypes, + PersonalListFilter, + PersonalListFilterValue, + PersonalListPicker, + PlaylistOwnerPicker, +} from '../components'; +import { PlaylistListProvider, usePlaylistList } from './usePlaylistList'; + +const playlists: Playlist[] = [ + { + id: 'id1', + name: 'list-1', + owner: 'user:default/guest', + public: true, + entities: 2, + followers: 5, + isFollowing: false, + }, + { + id: 'id2', + name: 'list-2', + owner: 'group:default/foo', + public: true, + entities: 3, + followers: 2, + isFollowing: true, + }, +]; + +const mockConfigApi = { + getOptionalString: () => '', +} as Partial; + +const mockIdentityApi: Partial = { + getBackstageIdentity: async () => ({ + type: 'user', + userEntityRef: 'user:default/guest', + ownershipEntityRefs: [], + }), +}; + +const mockPlaylistApi: Partial = { + getAllPlaylists: jest.fn().mockImplementation(async () => playlists), +}; + +const wrapper = ({ + location, + children, +}: PropsWithChildren<{ + location?: string; +}>) => { + return ( + + + + + + {children} + + + + ); +}; + +describe('', () => { + const origReplaceState = window.history.replaceState; + beforeEach(() => { + window.history.replaceState = jest.fn(); + }); + afterEach(() => { + window.history.replaceState = origReplaceState; + }); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('resolves backend filters', async () => { + const { result, waitForValueToChange } = renderHook( + () => usePlaylistList(), + { + wrapper, + }, + ); + await waitForValueToChange(() => result.current.backendPlaylists); + expect(result.current.backendPlaylists.length).toBe(2); + expect(mockPlaylistApi.getAllPlaylists).toHaveBeenCalled(); + }); + + it('resolves frontend filters', async () => { + const { result, waitFor } = renderHook(() => usePlaylistList(), { + wrapper, + }); + await waitFor(() => !!result.current.playlists.length); + expect(result.current.backendPlaylists.length).toBe(2); + + act(() => + result.current.updateFilters({ + personal: new PersonalListFilter( + PersonalListFilterValue.owned, + playlist => playlist.name === 'list-1', + ), + }), + ); + + await waitFor(() => { + expect(result.current.backendPlaylists.length).toBe(2); + expect(result.current.playlists.length).toBe(1); + expect(mockPlaylistApi.getAllPlaylists).toHaveBeenCalledTimes(1); + }); + }); + + it('resolves query param filter values', async () => { + const query = qs.stringify({ + filters: { personal: 'all', owners: ['user:default/guest'] }, + }); + const { result, waitFor } = renderHook(() => usePlaylistList(), { + wrapper, + initialProps: { + location: `/playlist?${query}`, + }, + }); + await waitFor(() => !!result.current.queryParameters); + expect(result.current.queryParameters).toEqual({ + personal: 'all', + owners: ['user:default/guest'], + }); + }); + + it('does not fetch when only frontend filters change', async () => { + const { result, waitFor } = renderHook(() => usePlaylistList(), { + wrapper, + }); + + await waitFor(() => { + expect(result.current.playlists.length).toBe(2); + expect(mockPlaylistApi.getAllPlaylists).toHaveBeenCalledTimes(1); + }); + + act(() => + result.current.updateFilters({ + personal: new PersonalListFilter( + PersonalListFilterValue.owned, + playlist => playlist.name === 'list-1', + ), + }), + ); + + await waitFor(() => { + expect(result.current.playlists.length).toBe(1); + expect(mockPlaylistApi.getAllPlaylists).toHaveBeenCalledTimes(1); + }); + }); + + it('applies custom sorting', async () => { + const { result, waitFor } = renderHook(() => usePlaylistList(), { + wrapper, + }); + + await waitFor(() => { + expect(result.current.playlists.length).toBe(2); + expect(result.current.playlists[0].name).toEqual('list-1'); + expect(result.current.playlists[1].name).toEqual('list-2'); + }); + + act(() => + result.current.updateSort( + DefaultSortCompareFunctions[DefaultPlaylistSortTypes.numEntities], + ), + ); + + await waitFor(() => { + expect(result.current.playlists.length).toBe(2); + expect(result.current.playlists[0].name).toEqual('list-2'); + expect(result.current.playlists[1].name).toEqual('list-1'); + }); + }); + + it('returns an error on playlistApi failure', async () => { + mockPlaylistApi.getAllPlaylists = jest.fn().mockRejectedValue('error'); + const { result, waitFor } = renderHook(() => usePlaylistList(), { + wrapper, + }); + await waitFor(() => { + expect(result.current.error).toBeDefined(); + }); + }); +}); diff --git a/plugins/playlist/src/hooks/usePlaylistList.tsx b/plugins/playlist/src/hooks/usePlaylistList.tsx new file mode 100644 index 0000000000..93c0becbfd --- /dev/null +++ b/plugins/playlist/src/hooks/usePlaylistList.tsx @@ -0,0 +1,284 @@ +/* + * 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 { useApi } from '@backstage/core-plugin-api'; +import { Playlist } from '@backstage/plugin-playlist-common'; +import { compact, isEqual } from 'lodash'; +import qs from 'qs'; +import React, { + createContext, + PropsWithChildren, + useCallback, + useContext, + useMemo, + useState, +} from 'react'; +import { useLocation } from 'react-router'; +import useAsyncFn from 'react-use/lib/useAsyncFn'; +import useDebounce from 'react-use/lib/useDebounce'; +import useMountedState from 'react-use/lib/useMountedState'; + +import { playlistApiRef } from '../api'; +import { PersonalListFilter } from '../components/PersonalListPicker'; +import { PlaylistOwnerFilter } from '../components/PlaylistOwnerPicker'; +import { PlaylistTextFilter } from '../components/PlaylistSearchBar'; +import { + DefaultPlaylistSortTypes, + DefaultSortCompareFunctions, +} from '../components/PlaylistSortPicker'; +import { PlaylistFilter, PlaylistSortCompareFunction } from '../types'; + +class NoopFilter implements PlaylistFilter { + getBackendFilters() { + return { '': null }; + } +} + +export type DefaultPlaylistFilters = { + noop?: NoopFilter; + owners?: PlaylistOwnerFilter; + personal?: PersonalListFilter; + text?: PlaylistTextFilter; +}; + +export type PlaylistListContextProps< + PlaylistFilters extends DefaultPlaylistFilters = DefaultPlaylistFilters, +> = { + /** + * The currently registered filters, adhering to the shape of DefaultPlaylistFilters + */ + filters: PlaylistFilters; + + /** + * The resolved list of playlists, after all filters are applied. + */ + playlists: Playlist[]; + + /** + * The resolved list of playlists, after _only playlist-backend_ filters are applied. + */ + backendPlaylists: Playlist[]; + + /** + * Update one or more of the registered filters. Optional filters can be set to `undefined` to + * reset the filter. + */ + updateFilters: ( + filters: + | Partial + | ((prevFilters: PlaylistFilters) => Partial), + ) => void; + + /** + * Update the compare function used to sort playlists. + */ + updateSort: (compareFn: PlaylistSortCompareFunction) => void; + + /** + * Filter values from query parameters. + */ + queryParameters: Partial>; + + loading: boolean; + error?: Error; +}; + +export const PlaylistListContext = createContext< + PlaylistListContextProps | undefined +>(undefined); + +const reduceBackendFilters = ( + filters: PlaylistFilter[], +): Record => { + return filters.reduce((compoundFilter, filter) => { + return { + ...compoundFilter, + ...(filter.getBackendFilters ? filter.getBackendFilters() : {}), + }; + }, {} as Record); +}; + +type OutputState = { + appliedFilters: PlaylistFilters; + playlists: Playlist[]; + backendPlaylists: Playlist[]; +}; + +export const PlaylistListProvider = < + PlaylistFilters extends DefaultPlaylistFilters, +>({ + children, +}: PropsWithChildren<{}>) => { + const isMounted = useMountedState(); + const playlistApi = useApi(playlistApiRef); + const [sortCompareFn, setSortCompareFn] = + useState( + () => DefaultSortCompareFunctions[DefaultPlaylistSortTypes.popular], + ); + const [requestedFilters, setRequestedFilters] = useState( + {} as PlaylistFilters, + ); + + // We use react-router's useLocation hook so updates from external sources trigger an update to + // the queryParameters in outputState. Updates from this hook use replaceState below and won't + // trigger a useLocation change; this would instead come from an external source, such as a manual + // update of the URL or two sidebar links with different filters. + const location = useLocation(); + const queryParameters = useMemo( + () => + (qs.parse(location.search, { + ignoreQueryPrefix: true, + }).filters ?? {}) as Record, + [location], + ); + + const [outputState, setOutputState] = useState>({ + appliedFilters: { + noop: new NoopFilter(), // Init with a noop filter to trigger intial request + } as PlaylistFilters, + playlists: [], + backendPlaylists: [], + }); + + // The main async filter worker. Note that while it has a lot of dependencies + // in terms of its implementation, the triggering only happens (debounced) + // based on the requested filters/sortCompareFn changing. + const [{ loading, error }, refresh] = useAsyncFn( + async () => { + const compacted: PlaylistFilter[] = compact( + Object.values(requestedFilters), + ); + const playlistFilter = (p: Playlist) => + compacted.every( + filter => !filter.filterPlaylist || filter.filterPlaylist(p), + ); + const backendFilter = reduceBackendFilters(compacted); + const previousBackendFilter = reduceBackendFilters( + compact(Object.values(outputState.appliedFilters)), + ); + + const queryParams = Object.keys(requestedFilters).reduce( + (params, key) => { + const filter: PlaylistFilter | undefined = + requestedFilters[key as keyof PlaylistFilters]; + if (filter?.toQueryValue) { + params[key] = filter.toQueryValue(); + } + return params; + }, + {} as Record, + ); + + if (!isEqual(previousBackendFilter, backendFilter)) { + const response = await playlistApi.getAllPlaylists({ + filter: backendFilter, + }); + setOutputState({ + appliedFilters: requestedFilters, + backendPlaylists: response, + playlists: response.filter(playlistFilter).sort(sortCompareFn), + }); + } else { + setOutputState({ + appliedFilters: requestedFilters, + backendPlaylists: outputState.backendPlaylists, + playlists: outputState.backendPlaylists + .filter(playlistFilter) + .sort(sortCompareFn), + }); + } + + if (isMounted()) { + const oldParams = qs.parse(location.search, { + ignoreQueryPrefix: true, + }); + const newParams = qs.stringify( + { ...oldParams, filters: queryParams }, + { addQueryPrefix: true, arrayFormat: 'repeat' }, + ); + const newUrl = `${window.location.pathname}${newParams}`; + // We use direct history manipulation since useSearchParams and + // useNavigate in react-router-dom cause unnecessary extra rerenders. + // Also make sure to replace the state rather than pushing, since we + // don't want there to be back/forward slots for every single filter + // change. + window.history?.replaceState(null, document.title, newUrl); + } + }, + [ + playlistApi, + queryParameters, + requestedFilters, + sortCompareFn, + outputState, + ], + { 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, sortCompareFn]); + + const updateFilters = useCallback( + ( + update: + | Partial + | ((prevFilters: PlaylistFilters) => Partial), + ) => { + setRequestedFilters(prevFilters => { + const newFilters = + typeof update === 'function' ? update(prevFilters) : update; + return { ...prevFilters, ...newFilters }; + }); + }, + [], + ); + + const updateSort = useCallback( + (compareFn: PlaylistSortCompareFunction) => + setSortCompareFn(() => compareFn), + [], + ); + + const value = useMemo( + () => ({ + filters: outputState.appliedFilters, + playlists: outputState.playlists, + backendPlaylists: outputState.backendPlaylists, + updateFilters, + updateSort, + queryParameters, + loading, + error, + }), + [outputState, updateFilters, updateSort, queryParameters, loading, error], + ); + + return ( + + {children} + + ); +}; + +export function usePlaylistList< + PlaylistFilters extends DefaultPlaylistFilters = DefaultPlaylistFilters, +>(): PlaylistListContextProps { + const context = useContext(PlaylistListContext); + if (!context) + throw new Error('usePlaylistList must be used within PlaylistListProvider'); + return context; +} diff --git a/plugins/playlist/src/index.ts b/plugins/playlist/src/index.ts new file mode 100644 index 0000000000..3b7004ce22 --- /dev/null +++ b/plugins/playlist/src/index.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. + */ + +/** + * Playlist frontend plugin + * + * @packageDocumentation + */ +export type { EntityPlaylistDialogProps } from './components'; +export { + EntityPlaylistDialog, + playlistPlugin, + PlaylistIndexPage, +} from './plugin'; +export * from './api'; diff --git a/plugins/playlist/src/plugin.test.ts b/plugins/playlist/src/plugin.test.ts new file mode 100644 index 0000000000..a2dfc7fcd7 --- /dev/null +++ b/plugins/playlist/src/plugin.test.ts @@ -0,0 +1,22 @@ +/* + * 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 { playlistPlugin } from './plugin'; + +describe('playlist', () => { + it('should export plugin', () => { + expect(playlistPlugin).toBeDefined(); + }); +}); diff --git a/plugins/playlist/src/plugin.ts b/plugins/playlist/src/plugin.ts new file mode 100644 index 0000000000..8e73fffe37 --- /dev/null +++ b/plugins/playlist/src/plugin.ts @@ -0,0 +1,74 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + createApiFactory, + createComponentExtension, + createPlugin, + createRoutableExtension, + discoveryApiRef, + fetchApiRef, +} from '@backstage/core-plugin-api'; + +import { playlistApiRef, PlaylistClient } from './api'; +import { rootRouteRef } from './routes'; + +/** + * @public + */ +export const playlistPlugin = createPlugin({ + id: 'playlist', + routes: { + root: rootRouteRef, + }, + apis: [ + createApiFactory({ + api: playlistApiRef, + deps: { + discoveryApi: discoveryApiRef, + fetchApi: fetchApiRef, + }, + factory: ({ discoveryApi, fetchApi }) => + new PlaylistClient({ discoveryApi, fetchApi }), + }), + ], +}); + +/** + * @public + */ +export const PlaylistIndexPage = playlistPlugin.provide( + createRoutableExtension({ + name: 'PlaylistIndexPage', + component: () => import('./components/Router').then(m => m.Router), + mountPoint: rootRouteRef, + }), +); + +/** + * @public + */ +export const EntityPlaylistDialog = playlistPlugin.provide( + createComponentExtension({ + name: 'EntityPlaylistDialog', + component: { + lazy: () => + import('./components/EntityPlaylistDialog').then( + m => m.EntityPlaylistDialog, + ), + }, + }), +); diff --git a/plugins/playlist/src/routes.ts b/plugins/playlist/src/routes.ts new file mode 100644 index 0000000000..632dc06439 --- /dev/null +++ b/plugins/playlist/src/routes.ts @@ -0,0 +1,26 @@ +/* + * 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 { createRouteRef, createSubRouteRef } from '@backstage/core-plugin-api'; + +export const rootRouteRef = createRouteRef({ + id: 'playlist:index-page', +}); + +export const playlistRouteRef = createSubRouteRef({ + id: 'playlist:playlist-page', + parent: rootRouteRef, + path: '/:playlistId', +}); diff --git a/plugins/playlist/src/setupTests.ts b/plugins/playlist/src/setupTests.ts new file mode 100644 index 0000000000..9bb3e72355 --- /dev/null +++ b/plugins/playlist/src/setupTests.ts @@ -0,0 +1,17 @@ +/* + * 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 '@testing-library/jest-dom'; +import 'cross-fetch/polyfill'; diff --git a/plugins/playlist/src/testUtils/MockPlaylistListProvider.tsx b/plugins/playlist/src/testUtils/MockPlaylistListProvider.tsx new file mode 100644 index 0000000000..2acef15e14 --- /dev/null +++ b/plugins/playlist/src/testUtils/MockPlaylistListProvider.tsx @@ -0,0 +1,102 @@ +/* + * 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, { + PropsWithChildren, + useCallback, + useMemo, + useState, +} from 'react'; +import { + DefaultPlaylistSortTypes, + DefaultSortCompareFunctions, +} from '../components'; +import { + DefaultPlaylistFilters, + PlaylistListContext, + PlaylistListContextProps, +} from '../hooks'; +import { PlaylistSortCompareFunction } from '../types'; + +export const MockPlaylistListProvider = ({ + children, + value, +}: PropsWithChildren<{ + value?: Partial; +}>) => { + const [filters, setFilters] = useState( + value?.filters ?? {}, + ); + + const [_, setSortCompareFn] = useState( + () => DefaultSortCompareFunctions[DefaultPlaylistSortTypes.popular], + ); + + const updateFilters = useCallback( + ( + update: + | Partial + | (( + prevFilters: DefaultPlaylistFilters, + ) => Partial), + ) => { + setFilters(prevFilters => { + const newFilters = + typeof update === 'function' ? update(prevFilters) : update; + return { ...prevFilters, ...newFilters }; + }); + }, + [], + ); + + const updateSort = useCallback( + (compareFn: PlaylistSortCompareFunction) => + setSortCompareFn(() => compareFn), + [], + ); + + // Memoize the default values since pickers have useEffect triggers on these; naively defaulting + // below with `?? ` breaks referential equality on subsequent updates. + const defaultValues = useMemo( + () => ({ + playlists: [], + backendPlaylists: [], + queryParameters: {}, + }), + [], + ); + + const resolvedValue: PlaylistListContextProps = useMemo( + () => ({ + playlists: value?.playlists ?? defaultValues.playlists, + backendPlaylists: + value?.backendPlaylists ?? defaultValues.backendPlaylists, + updateFilters: value?.updateFilters ?? updateFilters, + filters, + updateSort: value?.updateSort ?? updateSort, + loading: value?.loading ?? false, + queryParameters: value?.queryParameters ?? defaultValues.queryParameters, + error: value?.error, + }), + [value, defaultValues, filters, updateFilters, updateSort], + ); + + return ( + + {children} + + ); +}; diff --git a/plugins/playlist/src/testUtils/index.ts b/plugins/playlist/src/testUtils/index.ts new file mode 100644 index 0000000000..9b6f333a59 --- /dev/null +++ b/plugins/playlist/src/testUtils/index.ts @@ -0,0 +1,17 @@ +/* + * 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 * from './MockPlaylistListProvider'; diff --git a/plugins/playlist/src/types.ts b/plugins/playlist/src/types.ts new file mode 100644 index 0000000000..fbd348f98a --- /dev/null +++ b/plugins/playlist/src/types.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Playlist } from '@backstage/plugin-playlist-common'; + +export type PlaylistFilter = { + getBackendFilters?: () => Record; + + filterPlaylist?: (playlist: Playlist) => boolean; + + toQueryValue?: () => string | string[]; +}; + +export type PlaylistSortCompareFunction = (a: Playlist, b: Playlist) => number; diff --git a/plugins/proxy-backend/CHANGELOG.md b/plugins/proxy-backend/CHANGELOG.md index 08e89d6910..329827d9de 100644 --- a/plugins/proxy-backend/CHANGELOG.md +++ b/plugins/proxy-backend/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-proxy-backend +## 0.2.30 + +### Patch Changes + +- f6be17460d: 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/backend-common@0.15.1 + - @backstage/config@1.0.2 + ## 0.2.30-next.2 ### Patch Changes diff --git a/plugins/proxy-backend/package.json b/plugins/proxy-backend/package.json index 1870c1ec7d..553c43051d 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.2.30-next.2", + "version": "0.2.30", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,8 +32,8 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/config": "^1.0.2-next.0", + "@backstage/backend-common": "workspace:^", + "@backstage/config": "workspace:^", "@types/express": "^4.17.6", "express": "^4.17.1", "express-promise-router": "^4.1.0", @@ -46,7 +46,7 @@ "yup": "^0.32.9" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", + "@backstage/cli": "workspace:^", "@types/http-proxy-middleware": "^0.19.3", "@types/supertest": "^2.0.8", "@types/uuid": "^8.0.0", diff --git a/plugins/rollbar-backend/CHANGELOG.md b/plugins/rollbar-backend/CHANGELOG.md index 8f821f6e8f..6700252ae2 100644 --- a/plugins/rollbar-backend/CHANGELOG.md +++ b/plugins/rollbar-backend/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-rollbar-backend +## 0.1.33 + +### 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/backend-common@0.15.1 + - @backstage/config@1.0.2 + ## 0.1.33-next.3 ### Patch Changes diff --git a/plugins/rollbar-backend/package.json b/plugins/rollbar-backend/package.json index eb3b74e69a..aca54df1b2 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.33-next.3", + "version": "0.1.33", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,8 +33,8 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/config": "^1.0.2-next.0", + "@backstage/backend-common": "workspace:^", + "@backstage/config": "workspace:^", "@types/express": "^4.17.6", "camelcase-keys": "^7.0.1", "compression": "^1.7.4", @@ -49,8 +49,8 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/backend-test-utils": "^0.1.28-next.3", - "@backstage/cli": "^0.19.0-next.3", + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", "@types/supertest": "^2.0.8", "msw": "^0.47.0", "supertest": "^6.1.3" diff --git a/plugins/rollbar/CHANGELOG.md b/plugins/rollbar/CHANGELOG.md index 6d1464aa02..c6c7e427ed 100644 --- a/plugins/rollbar/CHANGELOG.md +++ b/plugins/rollbar/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-rollbar +## 0.4.9 + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/catalog-model@1.1.1 + ## 0.4.9-next.3 ### Patch Changes diff --git a/plugins/rollbar/package.json b/plugins/rollbar/package.json index 9cf5aa4964..6c31befc6b 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.9-next.3", + "version": "0.4.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,11 +33,11 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", - "@backstage/theme": "^0.2.16", + "@backstage/catalog-model": "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.57", @@ -51,10 +51,10 @@ "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/react-hooks": "^8.0.0", diff --git a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md index 77c0282940..e8f57c5426 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-scaffolder-backend-module-cookiecutter +## 0.2.11 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- 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/plugin-scaffolder-backend@1.6.0 + - @backstage/integration@1.3.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + ## 0.2.11-next.2 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-cookiecutter/package.json b/plugins/scaffolder-backend-module-cookiecutter/package.json index 5c19a3d4cf..200b7bffa0 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.11-next.2", + "version": "0.2.11", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,19 +23,19 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/config": "^1.0.2-next.0", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/integration": "^1.3.1-next.2", - "@backstage/plugin-scaffolder-backend": "^1.6.0-next.3", - "@backstage/types": "^1.0.0", + "@backstage/backend-common": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/integration": "workspace:^", + "@backstage/plugin-scaffolder-backend": "workspace:^", + "@backstage/types": "workspace:^", "command-exists": "^1.2.9", "fs-extra": "10.1.0", "winston": "^3.2.1", "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", + "@backstage/cli": "workspace:^", "@types/command-exists": "^1.2.0", "@types/fs-extra": "^9.0.1", "@types/mock-fs": "^4.13.0", diff --git a/plugins/scaffolder-backend-module-rails/CHANGELOG.md b/plugins/scaffolder-backend-module-rails/CHANGELOG.md index ceb954110b..649d08dca0 100644 --- a/plugins/scaffolder-backend-module-rails/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-rails/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-scaffolder-backend-module-rails +## 0.4.4 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- Updated dependencies + - @backstage/backend-common@0.15.1 + - @backstage/plugin-scaffolder-backend@1.6.0 + - @backstage/integration@1.3.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + ## 0.4.4-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-rails/package.json b/plugins/scaffolder-backend-module-rails/package.json index e60e643880..9418190ece 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.4-next.1", + "version": "0.4.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,17 +23,17 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/config": "^1.0.2-next.0", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/integration": "^1.3.1-next.2", - "@backstage/plugin-scaffolder-backend": "^1.6.0-next.3", - "@backstage/types": "^1.0.0", + "@backstage/backend-common": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/integration": "workspace:^", + "@backstage/plugin-scaffolder-backend": "workspace:^", + "@backstage/types": "workspace:^", "command-exists": "^1.2.9", "fs-extra": "^10.0.1" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", + "@backstage/cli": "workspace:^", "@types/command-exists": "^1.2.0", "@types/fs-extra": "^9.0.1", "@types/mock-fs": "^4.13.0", diff --git a/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md b/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md index 1769ad172e..6a0ddacab6 100644 --- a/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-scaffolder-backend-module-yeoman +## 0.2.9 + +### Patch Changes + +- 7d47def9c4: Removed dependency on `@types/jest`. +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.6.0 + - @backstage/config@1.0.2 + ## 0.2.9-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-yeoman/package.json b/plugins/scaffolder-backend-module-yeoman/package.json index eac08016f8..a7fa872f6d 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.9-next.1", + "version": "0.2.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,15 +22,15 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/config": "^1.0.2-next.0", - "@backstage/plugin-scaffolder-backend": "^1.6.0-next.3", - "@backstage/types": "^1.0.0", + "@backstage/config": "workspace:^", + "@backstage/plugin-scaffolder-backend": "workspace:^", + "@backstage/types": "workspace:^", "winston": "^3.2.1", "yeoman-environment": "^3.9.1" }, "devDependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/cli": "^0.19.0-next.3" + "@backstage/backend-common": "workspace:^", + "@backstage/cli": "workspace:^" }, "files": [ "dist" diff --git a/plugins/scaffolder-backend/CHANGELOG.md b/plugins/scaffolder-backend/CHANGELOG.md index bf0b46c509..3c7624553c 100644 --- a/plugins/scaffolder-backend/CHANGELOG.md +++ b/plugins/scaffolder-backend/CHANGELOG.md @@ -1,5 +1,56 @@ # @backstage/plugin-scaffolder-backend +## 1.6.0 + +### Minor Changes + +- ea2eee9e6a: Add the option for a homepage when using the `github:publish` action +- 8872cc735d: Fixed a bug in plugin-scaffolder-backend where it ignores the skip migration database options. + + To use this new implementation you need to create the instance of `DatabaseTaskStore` using the `PluginDatabaseManager` instead of `Knex`; + + ``` + import { DatabaseManager, getRootLogger, loadBackendConfig } from '@backstage/backend-common'; + import { DatabaseTaskStore } from '@backstage/plugin-scaffolder-backend'; + + const config = await loadBackendConfig({ argv: process.argv, logger: getRootLogger() }); + const databaseManager = DatabaseManager.fromConfig(config, { migrations: { skip: true } }); + const databaseTaskStore = await DatabaseTaskStore.create(databaseManager); + ``` + +- 7db9613671: Added `projectId` for gitlab projects to be displayed in the `gitlab:publish` output +- d1f7ba58e3: Added `repositoryId` output when create a repository in Azure +- 1ff817b3f0: add entity metadata to the template info type + +### Patch Changes + +- eadf56bbbf: Bump `git-url-parse` version to `^13.0.0` +- de8ee4afe3: Provide information about the user into scaffolder template action's context +- 096631e571: Added support for handling broken symlinks within the scaffolder backend. This is intended for templates that may hold a symlink that is invalid at build time but valid within the destination repo. +- 0d8d650e32: Applied the fix from version 1.5.1 of this package, which is part of the v1.5.1 release of Backstage. +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- 2df9955f4a: Removed the depreacated `publish:file` action, use the template editor to test templates instead. +- 0ecc9a6784: Properly set `ctx.isDryRun` when running actions in dry run mode. Also always log action inputs for debugging purposes when running in dry run mode. +- 6b9f6c0a4d: Added alpha `scaffolderPlugin` to be used with experimental backend system. +- 83c037cd46: Disable octokit throttling in publish:github:pull-request +- 2cbd533426: Uptake the `IdentityApi` change to use `getIdentity` instead of `authenticate` for retrieving the logged in users identity. +- ef9ab322de: Minor API signatures cleanup +- 50467bc15b: The number of task workers used to execute templates now default to 3, rather than 1. +- Updated dependencies + - @backstage/backend-plugin-api@0.1.2 + - @backstage/backend-common@0.15.1 + - @backstage/plugin-auth-node@0.2.5 + - @backstage/plugin-catalog-node@1.1.0 + - @backstage/integration@1.3.1 + - @backstage/plugin-catalog-backend@1.4.0 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + - @backstage/plugin-scaffolder-common@1.2.0 + ## 1.6.0-next.3 ### Patch Changes diff --git a/plugins/scaffolder-backend/api-report.md b/plugins/scaffolder-backend/api-report.md index 44bf45061b..0d5fbcb31f 100644 --- a/plugins/scaffolder-backend/api-report.md +++ b/plugins/scaffolder-backend/api-report.md @@ -31,6 +31,7 @@ import { TaskSpec } from '@backstage/plugin-scaffolder-common'; import { TaskSpecV1beta3 } from '@backstage/plugin-scaffolder-common'; import { TemplateInfo } from '@backstage/plugin-scaffolder-common'; import { UrlReader } from '@backstage/backend-common'; +import { UserEntity } from '@backstage/catalog-model'; import { Writable } from 'stream'; // @public @@ -44,6 +45,10 @@ export type ActionContext = { createTemporaryDirectory(): Promise; templateInfo?: TemplateInfo; isDryRun?: boolean; + user?: { + entity?: UserEntity; + ref?: string; + }; }; // @public diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index 5b72ab2f07..2812150b39 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.6.0-next.3", + "version": "1.6.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,18 +34,18 @@ "build:assets": "node scripts/build-nunjucks.js" }, "dependencies": { - "@backstage/backend-common": "^0.15.1-next.3", - "@backstage/backend-plugin-api": "^0.1.2-next.2", - "@backstage/catalog-client": "^1.1.0-next.2", - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/config": "^1.0.2-next.0", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/integration": "^1.3.1-next.2", - "@backstage/plugin-auth-node": "^0.2.5-next.3", - "@backstage/plugin-catalog-backend": "^1.4.0-next.3", - "@backstage/plugin-catalog-node": "^1.1.0-next.2", - "@backstage/plugin-scaffolder-common": "^1.2.0-next.1", - "@backstage/types": "^1.0.0", + "@backstage/backend-common": "workspace:^", + "@backstage/backend-plugin-api": "workspace:^", + "@backstage/catalog-client": "workspace:^", + "@backstage/catalog-model": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/integration": "workspace:^", + "@backstage/plugin-auth-node": "workspace:^", + "@backstage/plugin-catalog-backend": "workspace:^", + "@backstage/plugin-catalog-node": "workspace:^", + "@backstage/plugin-scaffolder-common": "workspace:^", + "@backstage/types": "workspace:^", "@gitbeaker/core": "^35.6.0", "@gitbeaker/node": "^35.1.0", "@octokit/webhooks": "^10.0.0", @@ -79,8 +79,8 @@ "zod": "^3.11.6" }, "devDependencies": { - "@backstage/backend-test-utils": "^0.1.28-next.3", - "@backstage/cli": "^0.19.0-next.3", + "@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", diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/types.ts b/plugins/scaffolder-backend/src/scaffolder/actions/types.ts index ff15300b4a..666f7a0d50 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/types.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/types.ts @@ -18,8 +18,9 @@ import { Logger } from 'winston'; import { Writable } from 'stream'; import { JsonValue, JsonObject } from '@backstage/types'; import { Schema } from 'jsonschema'; -import { TaskSecrets } from '../tasks/types'; +import { TaskSecrets } from '../tasks'; import { TemplateInfo } from '@backstage/plugin-scaffolder-common'; +import { UserEntity } from '@backstage/catalog-model'; /** * ActionContext is passed into scaffolder actions. @@ -45,6 +46,20 @@ export type ActionContext = { * This will only ever be true if the actions as marked as supporting dry-runs. */ isDryRun?: boolean; + + /** + * The user which triggered the action. + */ + user?: { + /** + * The decorated entity from the Catalog + */ + entity?: UserEntity; + /** + * An entity ref for the author of the task + */ + ref?: string; + }; }; /** @public */ diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.test.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.test.ts index 3627d83aa7..24a35078e2 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.test.ts @@ -56,9 +56,11 @@ describe('DefaultWorkflowRunner', () => { const createMockTaskWithSpec = ( spec: TaskSpec, secrets?: TaskSecrets, + isDryRun?: boolean, ): TaskContext => ({ spec, secrets, + isDryRun, complete: async () => {}, done: false, emitLog: async () => {}, @@ -66,7 +68,7 @@ describe('DefaultWorkflowRunner', () => { }); beforeEach(() => { - winston.format.simple(); // put logform the require cache before mocking fs + winston.format.simple(); // put logform in the require.cache before mocking fs mockFs({ '/tmp': mockFs.directory(), ...realFiles, @@ -85,6 +87,7 @@ describe('DefaultWorkflowRunner', () => { actionRegistry.register({ id: 'jest-validated-action', description: 'Mock action for testing', + supportsDryRun: true, handler: fakeActionHandler, schema: { input: { @@ -169,6 +172,21 @@ describe('DefaultWorkflowRunner', () => { it('should pass metadata through', async () => { const entityRef = `template:default/templateName`; + + const userEntity: UserEntity = { + apiVersion: 'backstage.io/v1beta1', + kind: 'User', + metadata: { + name: 'user', + }, + spec: { + profile: { + displayName: 'Bogdan Nechyporenko', + email: 'bnechyporenko@company.com', + }, + }, + }; + const task = createMockTaskWithSpec({ apiVersion: 'scaffolder.backstage.io/v1beta3', parameters: {}, @@ -182,6 +200,9 @@ describe('DefaultWorkflowRunner', () => { }, ], templateInfo: { entityRef }, + user: { + entity: userEntity, + }, }); await runner.execute(task); @@ -189,6 +210,10 @@ describe('DefaultWorkflowRunner', () => { expect(fakeActionHandler.mock.calls[0][0].templateInfo).toEqual({ entityRef, }); + + expect(fakeActionHandler.mock.calls[0][0].user).toEqual({ + entity: userEntity, + }); }); it('should pass token through', async () => { @@ -618,4 +643,32 @@ describe('DefaultWorkflowRunner', () => { }); }); }); + + describe('dry run', () => { + it('sets isDryRun flag correctly', async () => { + const task = createMockTaskWithSpec( + { + apiVersion: 'scaffolder.backstage.io/v1beta3', + parameters: {}, + output: {}, + steps: [ + { + id: 'test', + name: 'name', + action: 'jest-validated-action', + input: { foo: 1 }, + }, + ], + }, + { + backstageToken: 'secret', + }, + true, + ); + + await runner.execute(task); + + expect(fakeActionHandler.mock.calls[0][0].isDryRun).toEqual(true); + }); + }); }); diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts index 97e37fd3eb..009ea1357d 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts @@ -236,25 +236,53 @@ export class NunjucksWorkflowRunner implements WorkflowRunner { const action = this.options.actionRegistry.get(step.action); const { taskLogger, streamLogger } = createStepLogger({ task, step }); - if (task.isDryRun && !action.supportsDryRun) { - task.emitLog( - `Skipping because ${action.id} does not support dry-run`, - { - stepId: step.id, - status: 'skipped', - }, + if (task.isDryRun) { + const redactedSecrets = Object.fromEntries( + Object.entries(task.secrets ?? {}).map(secret => [ + secret[0], + '[REDACTED]', + ]), ); - const outputSchema = action.schema?.output; - if (outputSchema) { - context.steps[step.id] = { - output: generateExampleOutput(outputSchema) as { - [name in string]: JsonValue; + const debugInput = + (step.input && + this.render( + step.input, + { + ...context, + secrets: redactedSecrets, + }, + renderTemplate, + )) ?? + {}; + taskLogger.info( + `Running ${ + action.id + } in dry-run mode with inputs (secrets redacted): ${JSON.stringify( + debugInput, + undefined, + 2, + )}`, + ); + if (!action.supportsDryRun) { + task.emitLog( + `Skipping because ${action.id} does not support dry-run`, + { + stepId: step.id, + status: 'skipped', }, - }; - } else { - context.steps[step.id] = { output: {} }; + ); + const outputSchema = action.schema?.output; + if (outputSchema) { + context.steps[step.id] = { + output: generateExampleOutput(outputSchema) as { + [name in string]: JsonValue; + }, + }; + } else { + context.steps[step.id] = { output: {} }; + } + continue; } - continue; } // Secrets are only passed when templating the input to actions for security reasons @@ -300,6 +328,8 @@ export class NunjucksWorkflowRunner implements WorkflowRunner { stepOutput[name] = value; }, templateInfo: task.spec.templateInfo, + user: task.spec.user, + isDryRun: task.isDryRun, }); // Remove all temporary directories that were created when executing the action diff --git a/plugins/scaffolder-common/CHANGELOG.md b/plugins/scaffolder-common/CHANGELOG.md index f7cdcfe3b0..4d05c26cee 100644 --- a/plugins/scaffolder-common/CHANGELOG.md +++ b/plugins/scaffolder-common/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-scaffolder-common +## 1.2.0 + +### Minor Changes + +- 1ff817b3f0: add entity metadata to the template info type + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.1 + ## 1.2.0-next.1 ### Patch Changes diff --git a/plugins/scaffolder-common/package.json b/plugins/scaffolder-common/package.json index 40ef29a3ae..ab7508d215 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.2.0-next.1", + "version": "1.2.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -38,10 +38,10 @@ "url": "https://github.com/backstage/backstage/issues" }, "dependencies": { - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/types": "^1.0.0" + "@backstage/catalog-model": "workspace:^", + "@backstage/types": "workspace:^" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3" + "@backstage/cli": "workspace:^" } } diff --git a/plugins/scaffolder/CHANGELOG.md b/plugins/scaffolder/CHANGELOG.md index d30be1c8fc..2c1640c5e8 100644 --- a/plugins/scaffolder/CHANGELOG.md +++ b/plugins/scaffolder/CHANGELOG.md @@ -1,5 +1,43 @@ # @backstage/plugin-scaffolder +## 1.6.0 + +### Minor Changes + +- 3424a8075d: Added support for `async` validation for the `next` version of the plugin +- ad036784e9: Ability to modify the layout of the step form +- 192d856495: Implementing review step for the scaffolder under `create/next` + +### Patch Changes + +- 817f3196f6: Updated React Router dependencies to be peer dependencies. +- eadf56bbbf: Bump `git-url-parse` version to `^13.0.0` +- 9ffb75616d: Fix bug with empty strings in `EntityPicker` +- 3f739be9d9: Minor API signatures cleanup +- 763fb81e82: Internal refactor to use more type safe code when dealing with route parameters. +- a66d44b72b: Fixing bug when the workspace would not be automatically saved when using `allowedOwners` +- 7d47def9c4: Removed dependency on `@types/jest`. +- 6522e459aa: Support displaying and ordering by counts in `EntityTagPicker` field. Add the `showCounts` option to enable this. Also support configuring `helperText`. +- f0510a20b5: Addition of a dismissible Error Banner in Scaffolder page +- 667d917488: Updated dependency `msw` to `^0.47.0`. +- 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`. +- 9097278df2: Updated dependency `json-schema-library` to `^7.0.0`. +- bf5e9030eb: Updated dependency `msw` to `^0.45.0`. +- de336de9cd: fix uiSchema generation when using complex dependencies +- Updated dependencies + - @backstage/core-components@0.11.1 + - @backstage/core-plugin-api@1.0.6 + - @backstage/plugin-catalog-react@1.1.4 + - @backstage/plugin-permission-react@0.4.5 + - @backstage/integration@1.3.1 + - @backstage/catalog-client@1.1.0 + - @backstage/catalog-model@1.1.1 + - @backstage/config@1.0.2 + - @backstage/errors@1.1.1 + - @backstage/integration-react@1.1.4 + - @backstage/plugin-scaffolder-common@1.2.0 + - @backstage/plugin-catalog-common@1.0.6 + ## 1.6.0-next.3 ### Patch Changes diff --git a/plugins/scaffolder/api-report.md b/plugins/scaffolder/api-report.md index 8e2858e706..121f01ec56 100644 --- a/plugins/scaffolder/api-report.md +++ b/plugins/scaffolder/api-report.md @@ -16,6 +16,7 @@ import { ExternalRouteRef } from '@backstage/core-plugin-api'; import { FetchApi } from '@backstage/core-plugin-api'; import { FieldProps } from '@rjsf/core'; import { FieldValidation } from '@rjsf/core'; +import type { FormProps } from '@rjsf/core'; import { IdentityApi } from '@backstage/core-plugin-api'; import { JsonObject } from '@backstage/types'; import { JSONSchema7 } from 'json-schema'; @@ -37,6 +38,11 @@ export function createScaffolderFieldExtension< options: FieldExtensionOptions, ): Extension>; +// @public +export function createScaffolderLayout( + options: LayoutOptions, +): Extension>; + // @public export type CustomFieldValidator = ( data: TFieldReturnValue, @@ -110,6 +116,20 @@ export type FieldExtensionOptions< validation?: CustomFieldValidator; }; +// @public +export type LayoutComponent<_TInputProps> = () => null; + +// @public +export interface LayoutOptions

{ + // (undocumented) + component: LayoutTemplate

; + // (undocumented) + name: string; +} + +// @public +export type LayoutTemplate = FormProps['ObjectFieldTemplate']; + // @public export type ListActionsResponse = Array<{ id: string; @@ -349,6 +369,9 @@ export interface ScaffolderGetIntegrationsListResponse { }[]; } +// @public +export const ScaffolderLayouts: React.ComponentType; + // @public (undocumented) export type ScaffolderOutputLink = { title?: string; diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index 341251c286..0debc7dd23 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.6.0-next.3", + "version": "1.6.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,21 +33,20 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-client": "^1.1.0-next.2", - "@backstage/catalog-model": "^1.1.1-next.0", - "@backstage/config": "^1.0.2-next.0", - "@backstage/core-components": "^0.11.1-next.3", - "@backstage/core-plugin-api": "^1.0.6-next.3", - "@backstage/errors": "^1.1.1-next.0", - "@backstage/integration": "^1.3.1-next.2", - "@backstage/integration-react": "^1.1.4-next.2", - "@backstage/plugin-catalog": "^1.5.1-next.2", - "@backstage/plugin-catalog-common": "^1.0.6-next.0", - "@backstage/plugin-catalog-react": "^1.1.4-next.2", - "@backstage/plugin-permission-react": "^0.4.5-next.2", - "@backstage/plugin-scaffolder-common": "^1.2.0-next.1", - "@backstage/theme": "^0.2.16", - "@backstage/types": "^1.0.0", + "@backstage/catalog-client": "workspace:^", + "@backstage/catalog-model": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/integration": "workspace:^", + "@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/theme": "workspace:^", + "@backstage/types": "workspace:^", "@codemirror/language": "^6.0.0", "@codemirror/legacy-modes": "^6.1.0", "@codemirror/view": "^6.0.0", @@ -80,11 +79,11 @@ "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/cli": "^0.19.0-next.3", - "@backstage/core-app-api": "^1.1.0-next.3", - "@backstage/dev-utils": "^1.0.6-next.2", - "@backstage/plugin-catalog": "^1.5.1-next.3", - "@backstage/test-utils": "^1.2.0-next.3", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/plugin-catalog": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/react-hooks": "^8.0.0", diff --git a/plugins/scaffolder/src/components/MultistepJsonForm/MultistepJsonForm.tsx b/plugins/scaffolder/src/components/MultistepJsonForm/MultistepJsonForm.tsx index 43e12ae85f..8c71df67b6 100644 --- a/plugins/scaffolder/src/components/MultistepJsonForm/MultistepJsonForm.tsx +++ b/plugins/scaffolder/src/components/MultistepJsonForm/MultistepJsonForm.tsx @@ -36,6 +36,7 @@ import { transformSchemaToProps } from './schema'; import { Content, StructuredMetadataTable } from '@backstage/core-components'; import cloneDeep from 'lodash/cloneDeep'; import * as fieldOverrides from './FieldOverrides'; +import { LayoutOptions } from '../../layouts'; const Form = withTheme(MuiTheme); type Step = { @@ -55,6 +56,7 @@ type Props = { widgets?: FormProps['widgets']; fields?: FormProps['fields']; finishButtonLabel?: string; + layouts: LayoutOptions[]; }; export function getUiSchemasFromSteps(steps: Step[]): UiSchema[] { @@ -119,6 +121,7 @@ export const MultistepJsonForm = (props: Props) => { fields, widgets, finishButtonLabel, + layouts, } = props; const [activeStep, setActiveStep] = useState(0); const [disableButtons, setDisableButtons] = useState(false); @@ -214,7 +217,7 @@ export const MultistepJsonForm = (props: Props) => { if (e.errors.length === 0) handleNext(); }} {...formProps} - {...transformSchemaToProps(schema)} + {...transformSchemaToProps(schema, layouts)} >