diff --git a/.changeset/angry-bottles-mix.md b/.changeset/angry-bottles-mix.md new file mode 100644 index 0000000000..cd05ef6514 --- /dev/null +++ b/.changeset/angry-bottles-mix.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Added a new experimental and hidden `backstage-cli repo lint` command that can be used to lint all packages in the project, similar to `lerna run lint`. diff --git a/.changeset/beige-cherries-knock.md b/.changeset/beige-cherries-knock.md new file mode 100644 index 0000000000..ac738e9942 --- /dev/null +++ b/.changeset/beige-cherries-knock.md @@ -0,0 +1,8 @@ +--- +'@backstage/plugin-scaffolder-common': patch +--- + +Added `TemplateEntityV1beta2` which was moved here from +`@backstage/plugin-scaffolder-common`. It has also been marked as deprecated in +the process - please consider [migrating to `v1beta3` +templates](https://backstage.io/docs/features/software-templates/migrating-from-v1beta2-to-v1beta3). diff --git a/.changeset/beige-feet-tap.md b/.changeset/beige-feet-tap.md new file mode 100644 index 0000000000..b37d249700 --- /dev/null +++ b/.changeset/beige-feet-tap.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs-backend': patch +--- + +Do not use cross-fetch in the backend diff --git a/.changeset/brave-singers-burn.md b/.changeset/brave-singers-burn.md new file mode 100644 index 0000000000..e8ccfb42e7 --- /dev/null +++ b/.changeset/brave-singers-burn.md @@ -0,0 +1,13 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +The following processors now properly accept an `ScmIntegrationRegistry` (an +interface) instead of an `ScmIntegrations` (which is a concrete class). + +- `AzureDevOpsDiscoveryProcessor` +- `CodeOwnersProcessor` +- `GitLabDiscoveryProcessor` +- `GithubDiscoveryProcessor` +- `GithubMultiOrgReaderProcessor` +- `GithubOrgReaderProcessor` diff --git a/.changeset/bright-games-eat.md b/.changeset/bright-games-eat.md new file mode 100644 index 0000000000..3bae70283f --- /dev/null +++ b/.changeset/bright-games-eat.md @@ -0,0 +1,24 @@ +--- +'@backstage/create-app': patch +--- + +Remove SearchContextProvider from `` + +The `SidebarSearchModal` exported from `plugin-search` internally renders `SearchContextProvider`, so it can be removed from `Root.tsx`: + +```diff +-import { +- SidebarSearchModal, +- SearchContextProvider, +-} from '@backstage/plugin-search'; ++import { SidebarSearchModal } from '@backstage/plugin-search'; + +... omitted ... + + } to="/search"> +- +- +- ++ + +``` diff --git a/.changeset/brown-impalas-greet.md b/.changeset/brown-impalas-greet.md new file mode 100644 index 0000000000..1717c33451 --- /dev/null +++ b/.changeset/brown-impalas-greet.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-scaffolder-backend': patch +--- + +Fix error handling of the `runCommand` helper to return `Error` +instance. diff --git a/.changeset/chatty-walls-judge.md b/.changeset/chatty-walls-judge.md new file mode 100644 index 0000000000..72e636e026 --- /dev/null +++ b/.changeset/chatty-walls-judge.md @@ -0,0 +1,123 @@ +--- +'@backstage/app-defaults': patch +'@backstage/backend-common': patch +'@backstage/backend-tasks': patch +'@backstage/backend-test-utils': patch +'@backstage/catalog-client': patch +'@backstage/catalog-model': patch +'@backstage/cli': patch +'@backstage/cli-common': patch +'@backstage/codemods': 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 +'@backstage/search-common': patch +'@techdocs/cli': patch +'@backstage/techdocs-common': patch +'@backstage/test-utils': patch +'@backstage/theme': patch +'@backstage/types': patch +'@backstage/version-bridge': 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-app-backend': patch +'@backstage/plugin-auth-backend': patch +'@backstage/plugin-auth-node': patch +'@backstage/plugin-azure-devops': patch +'@backstage/plugin-azure-devops-backend': patch +'@backstage/plugin-azure-devops-common': patch +'@backstage/plugin-badges': patch +'@backstage/plugin-badges-backend': patch +'@backstage/plugin-bazaar': patch +'@backstage/plugin-bazaar-backend': patch +'@backstage/plugin-bitrise': patch +'@backstage/plugin-catalog': patch +'@backstage/plugin-catalog-backend': patch +'@backstage/plugin-catalog-backend-module-ldap': patch +'@backstage/plugin-catalog-backend-module-msgraph': patch +'@backstage/plugin-catalog-common': patch +'@backstage/plugin-catalog-graph': patch +'@backstage/plugin-catalog-graphql': patch +'@backstage/plugin-catalog-import': patch +'@backstage/plugin-catalog-react': patch +'@backstage/plugin-cicd-statistics': patch +'@backstage/plugin-circleci': patch +'@backstage/plugin-cloudbuild': patch +'@backstage/plugin-code-coverage': patch +'@backstage/plugin-code-coverage-backend': patch +'@backstage/plugin-config-schema': patch +'@backstage/plugin-cost-insights': patch +'@backstage/plugin-explore': patch +'@backstage/plugin-explore-react': patch +'@backstage/plugin-firehydrant': patch +'@backstage/plugin-fossa': patch +'@backstage/plugin-gcp-projects': patch +'@backstage/plugin-git-release-manager': patch +'@backstage/plugin-github-actions': patch +'@backstage/plugin-github-deployments': 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': patch +'@backstage/plugin-jenkins-backend': patch +'@backstage/plugin-kafka': patch +'@backstage/plugin-kafka-backend': patch +'@backstage/plugin-kubernetes': patch +'@backstage/plugin-kubernetes-backend': patch +'@backstage/plugin-kubernetes-common': patch +'@backstage/plugin-lighthouse': patch +'@backstage/plugin-newrelic': patch +'@backstage/plugin-newrelic-dashboard': patch +'@backstage/plugin-org': patch +'@backstage/plugin-pagerduty': patch +'@backstage/plugin-permission-backend': patch +'@backstage/plugin-permission-common': patch +'@backstage/plugin-permission-node': patch +'@backstage/plugin-permission-react': patch +'@backstage/plugin-proxy-backend': patch +'@backstage/plugin-rollbar': patch +'@backstage/plugin-rollbar-backend': patch +'@backstage/plugin-scaffolder': patch +'@backstage/plugin-scaffolder-backend': patch +'@backstage/plugin-scaffolder-backend-module-cookiecutter': patch +'@backstage/plugin-scaffolder-backend-module-rails': patch +'@backstage/plugin-scaffolder-backend-module-yeoman': patch +'@backstage/plugin-scaffolder-common': patch +'@backstage/plugin-search': patch +'@backstage/plugin-search-backend': patch +'@backstage/plugin-search-backend-module-elasticsearch': patch +'@backstage/plugin-search-backend-module-pg': patch +'@backstage/plugin-search-backend-node': patch +'@backstage/plugin-sentry': patch +'@backstage/plugin-shortcuts': patch +'@backstage/plugin-sonarqube': patch +'@backstage/plugin-splunk-on-call': patch +'@backstage/plugin-tech-insights': patch +'@backstage/plugin-tech-insights-backend': patch +'@backstage/plugin-tech-insights-backend-module-jsonfc': patch +'@backstage/plugin-tech-insights-common': patch +'@backstage/plugin-tech-insights-node': patch +'@backstage/plugin-tech-radar': patch +'@backstage/plugin-techdocs': patch +'@backstage/plugin-techdocs-backend': patch +'@backstage/plugin-todo': patch +'@backstage/plugin-todo-backend': patch +'@backstage/plugin-user-settings': patch +'@backstage/plugin-xcmetrics': patch +--- + +Added `backstage.role` to `package.json` diff --git a/.changeset/clever-pears-turn.md b/.changeset/clever-pears-turn.md new file mode 100644 index 0000000000..33e08c231b --- /dev/null +++ b/.changeset/clever-pears-turn.md @@ -0,0 +1,11 @@ +--- +'@backstage/plugin-catalog': patch +'@backstage/plugin-catalog-backend': patch +'@backstage/plugin-catalog-graph': patch +'@backstage/plugin-catalog-react': patch +'@backstage/plugin-org': patch +'@backstage/plugin-scaffolder': patch +'@backstage/plugin-tech-insights-backend': patch +--- + +Use updated type names from `@backstage/catalog-client` diff --git a/.changeset/curvy-worms-exercise.md b/.changeset/curvy-worms-exercise.md new file mode 100644 index 0000000000..b88e9b5891 --- /dev/null +++ b/.changeset/curvy-worms-exercise.md @@ -0,0 +1,6 @@ +--- +'@backstage/catalog-model': patch +--- + +Deprecated `parseLocationReference` and `stringifyLocationReference`, +introducing `parseLocationRef` and `stringifyLocationRef` in their place. diff --git a/.changeset/cyan-oranges-sit.md b/.changeset/cyan-oranges-sit.md new file mode 100644 index 0000000000..8a3244745f --- /dev/null +++ b/.changeset/cyan-oranges-sit.md @@ -0,0 +1,5 @@ +--- +'@backstage/catalog-model': patch +--- + +Deprecates the `Location` type export from this package. Imports of the `Location` type should now be done from the `@backstage/catalog-client` package instead. diff --git a/.changeset/dependabot-8ed326b.md b/.changeset/dependabot-8ed326b.md new file mode 100644 index 0000000000..88a91baeac --- /dev/null +++ b/.changeset/dependabot-8ed326b.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-search-backend-module-elasticsearch': patch +--- + +chore(deps-dev): bump `@elastic/elasticsearch-mock` from 0.3.0 to 1.0.0 diff --git a/.changeset/dependabot-adaba58.md b/.changeset/dependabot-adaba58.md new file mode 100644 index 0000000000..b10abe506a --- /dev/null +++ b/.changeset/dependabot-adaba58.md @@ -0,0 +1,8 @@ +--- +'@backstage/backend-common': patch +'@backstage/plugin-app-backend': patch +'@backstage/plugin-graphql-backend': patch +'@backstage/plugin-kubernetes-backend': patch +--- + +chore(deps): bump `helmet` from 4.4.1 to 5.0.2 diff --git a/.changeset/dirty-ears-wash.md b/.changeset/dirty-ears-wash.md new file mode 100644 index 0000000000..060dc808f1 --- /dev/null +++ b/.changeset/dirty-ears-wash.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-kubernetes-backend': patch +--- + +Fixed a potential issue in AWS token encoding, where they might not always be properly converted to URL-safe base64. diff --git a/.changeset/dry-lies-move.md b/.changeset/dry-lies-move.md new file mode 100644 index 0000000000..b0eb1be6f7 --- /dev/null +++ b/.changeset/dry-lies-move.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-catalog-react': patch +'@backstage/plugin-todo-backend': patch +--- + +Replace usage of `serializeEntityRef` with `stringifyEntityRef` diff --git a/.changeset/eighty-rice-happen.md b/.changeset/eighty-rice-happen.md new file mode 100644 index 0000000000..8a1b450af7 --- /dev/null +++ b/.changeset/eighty-rice-happen.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs': patch +--- + +Match text size of admonitions to main content text size. diff --git a/.changeset/fair-bees-join.md b/.changeset/fair-bees-join.md new file mode 100644 index 0000000000..455547cec2 --- /dev/null +++ b/.changeset/fair-bees-join.md @@ -0,0 +1,5 @@ +--- +'@backstage/catalog-model': patch +--- + +Deprecated `ENTITY_DEFAULT_NAMESPACE` constant in favour of `DEFAULT_NAMESPACE`. diff --git a/.changeset/fair-emus-check.md b/.changeset/fair-emus-check.md new file mode 100644 index 0000000000..328d5498b9 --- /dev/null +++ b/.changeset/fair-emus-check.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog': patch +--- + +Replaced use of deprecated `compareEntityToRef` utility. diff --git a/.changeset/fair-eyes-collect.md b/.changeset/fair-eyes-collect.md new file mode 100644 index 0000000000..5a0cfafaab --- /dev/null +++ b/.changeset/fair-eyes-collect.md @@ -0,0 +1,5 @@ +--- +'@backstage/catalog-model': patch +--- + +Deprecated `compareEntityToRef` due to low usage and provided value. diff --git a/.changeset/fast-lizards-fly.md b/.changeset/fast-lizards-fly.md new file mode 100644 index 0000000000..e6772b056f --- /dev/null +++ b/.changeset/fast-lizards-fly.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend': patch +--- + +Bump `passport-oauth2` to version 1.6.1 diff --git a/.changeset/fast-mangos-tell.md b/.changeset/fast-mangos-tell.md new file mode 100644 index 0000000000..bfcf429485 --- /dev/null +++ b/.changeset/fast-mangos-tell.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend': minor +--- + +**BREAKING**: Updated `TemplateAction` and related types to have its type parameter extend `JsonObject` instead of `InputBase`. The `createTemplateAction` has also been updated to pass through the `TInput` type parameter to the return type, meaning the `TemplateAction` retains its type. This can lead to breakages during type checking especially within tests. diff --git a/.changeset/fast-stingrays-hope.md b/.changeset/fast-stingrays-hope.md new file mode 100644 index 0000000000..688f14c548 --- /dev/null +++ b/.changeset/fast-stingrays-hope.md @@ -0,0 +1,8 @@ +--- +'@backstage/plugin-catalog': patch +'@backstage/plugin-catalog-backend': patch +'@backstage/plugin-catalog-react': patch +'@backstage/plugin-catalog-backend-module-ldap': patch +--- + +Import `Location` from the `@backstage/catalog-client` package. diff --git a/.changeset/flat-crabs-smash.md b/.changeset/flat-crabs-smash.md new file mode 100644 index 0000000000..b56b340605 --- /dev/null +++ b/.changeset/flat-crabs-smash.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +The `versions:bump` command now filters out `npm_` environment configuration when running `yarn install`. This has the effect of allowing it to consider local configuration files within the repository, which is the behavior that one would expect. diff --git a/.changeset/fresh-ears-knock.md b/.changeset/fresh-ears-knock.md new file mode 100644 index 0000000000..1e8b33fd03 --- /dev/null +++ b/.changeset/fresh-ears-knock.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-shortcuts': minor +--- + +Use Avatar instead of custom icon for ShortcutIcon diff --git a/.changeset/funny-crabs-drop.md b/.changeset/funny-crabs-drop.md new file mode 100644 index 0000000000..764f7c042a --- /dev/null +++ b/.changeset/funny-crabs-drop.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog': minor +--- + +Removed `CatalogClientWrapper` as usage have been replaced by the `fetchApiRef`. diff --git a/.changeset/green-bobcats-burn.md b/.changeset/green-bobcats-burn.md new file mode 100644 index 0000000000..c28f4da678 --- /dev/null +++ b/.changeset/green-bobcats-burn.md @@ -0,0 +1,22 @@ +--- +'@backstage/plugin-permission-backend': minor +--- + +Add a warning if the permission backend is used without setting `permission.enabled=true`. + +**BREAKING** Permission backend's `createRouter` now requires a `config` option. + +```diff +// packages/backend/src/plugins/permission.ts + +... +export default async function createPlugin({ + ... ++ config, +}: PluginEnvironment) { + return createRouter({ + ... ++ config, + }); +} +``` diff --git a/.changeset/happy-lemons-drop.md b/.changeset/happy-lemons-drop.md new file mode 100644 index 0000000000..e4c6f52409 --- /dev/null +++ b/.changeset/happy-lemons-drop.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-permission-common': minor +--- + +**BREAKING** `PermissionCriteria` now requires at least one condition in `anyOf` and `allOf` arrays. This addresses some ambiguous behavior outlined in #9280. diff --git a/.changeset/hip-carrots-suffer.md b/.changeset/hip-carrots-suffer.md new file mode 100644 index 0000000000..3823cf982f --- /dev/null +++ b/.changeset/hip-carrots-suffer.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs-backend': patch +--- + +Fix bug where tech docs collator stores search indices with wrong entity ref casing. Make the collator to conform legacyPathCasing configuration option. diff --git a/.changeset/honest-shrimps-clap.md b/.changeset/honest-shrimps-clap.md new file mode 100644 index 0000000000..12ae623704 --- /dev/null +++ b/.changeset/honest-shrimps-clap.md @@ -0,0 +1,9 @@ +--- +'@backstage/catalog-client': minor +--- + +**BREAKING**: Removed the explicit `DiscoveryApi` and `FetchApi` export symbols, +which were unnecessary duplicates from the well known core ones. + +The `CATALOG_FILTER_EXISTS` symbol's value has changed. However, this should not +affect any code in practice. diff --git a/.changeset/hungry-apples-sparkle.md b/.changeset/hungry-apples-sparkle.md new file mode 100644 index 0000000000..6cfad2d2da --- /dev/null +++ b/.changeset/hungry-apples-sparkle.md @@ -0,0 +1,5 @@ +--- +'@backstage/catalog-model': patch +--- + +Deprecated the `EntityRefContext` type which had limited use. diff --git a/.changeset/lazy-jeans-obey.md b/.changeset/lazy-jeans-obey.md new file mode 100644 index 0000000000..9124b983dc --- /dev/null +++ b/.changeset/lazy-jeans-obey.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Update internal `Location` validation. diff --git a/.changeset/little-ravens-kick.md b/.changeset/little-ravens-kick.md new file mode 100644 index 0000000000..1e14f2f37e --- /dev/null +++ b/.changeset/little-ravens-kick.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +The `versions:bump` command now also considers the root `package.json` when searching for updates. It has also received updates to its output, including a link the [Backstage upgrade helper](https://backstage.github.io/upgrade-helper) and silenced `yarn install` output. diff --git a/.changeset/long-dragons-kneel.md b/.changeset/long-dragons-kneel.md new file mode 100644 index 0000000000..9380d95b55 --- /dev/null +++ b/.changeset/long-dragons-kneel.md @@ -0,0 +1,11 @@ +--- +'@backstage/plugin-home': patch +--- + +Add Renderer support for the HomePageToolkit component. + +Previously `` would +result in the error `can't access property "map", props.tools is undefined`. +This change adds a context that can pass props down to the HomePageToolkit. +Also introduced is an `expanded` prop on the `ComponentAccordion` to setting +the default expanded state. See `In Accordian` story for details. diff --git a/.changeset/mean-cups-invite.md b/.changeset/mean-cups-invite.md new file mode 100644 index 0000000000..ba82c66043 --- /dev/null +++ b/.changeset/mean-cups-invite.md @@ -0,0 +1,15 @@ +--- +'@backstage/plugin-api-docs': patch +'@backstage/plugin-auth-backend': patch +'@backstage/plugin-badges-backend': patch +'@backstage/plugin-catalog': patch +'@backstage/plugin-catalog-graph': patch +'@backstage/plugin-catalog-import': patch +'@backstage/plugin-catalog-react': patch +'@backstage/plugin-explore': patch +'@backstage/plugin-fossa': patch +'@backstage/plugin-scaffolder': patch +'@backstage/plugin-todo-backend': patch +--- + +Adapt to the new `CatalogApi.getLocationByRef` diff --git a/.changeset/mighty-beds-fix.md b/.changeset/mighty-beds-fix.md new file mode 100644 index 0000000000..3e5ab735dd --- /dev/null +++ b/.changeset/mighty-beds-fix.md @@ -0,0 +1,11 @@ +--- +'@backstage/catalog-client': patch +'@backstage/techdocs-common': patch +'@backstage/plugin-catalog-backend': patch +'@backstage/plugin-catalog-react': patch +'@backstage/plugin-github-deployments': patch +'@backstage/plugin-scaffolder-backend': patch +'@backstage/plugin-todo-backend': patch +--- + +Updated to use new names for `parseLocationRef` and `stringifyLocationRef` diff --git a/.changeset/modern-mayflies-join.md b/.changeset/modern-mayflies-join.md new file mode 100644 index 0000000000..58d8de95fc --- /dev/null +++ b/.changeset/modern-mayflies-join.md @@ -0,0 +1,9 @@ +--- +'@backstage/plugin-catalog-backend': patch +'@backstage/plugin-catalog-react': patch +'@backstage/plugin-scaffolder': patch +'@backstage/plugin-scaffolder-backend': patch +--- + +Use `TemplateEntityV1beta2` from `@backstage/plugin-scaffolder-common` instead +of `@backstage/catalog-model`. diff --git a/.changeset/moody-knives-jump.md b/.changeset/moody-knives-jump.md new file mode 100644 index 0000000000..84e80d9f84 --- /dev/null +++ b/.changeset/moody-knives-jump.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-cicd-statistics': patch +--- + +Updated `@backstage/core-plugin-api` dependency. diff --git a/.changeset/nine-wombats-talk.md b/.changeset/nine-wombats-talk.md new file mode 100644 index 0000000000..769bd9b085 --- /dev/null +++ b/.changeset/nine-wombats-talk.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-user-settings': patch +--- + +Updated example code for registering feature flags in the `EmptyFlags` component diff --git a/.changeset/old-dolls-visit.md b/.changeset/old-dolls-visit.md new file mode 100644 index 0000000000..c363ebd43f --- /dev/null +++ b/.changeset/old-dolls-visit.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': minor +--- + +Bumped Webpack and Rollup `svgr` dependencies and updated the AST template for `.icon.svg` modules. This means that SVG icon imports are now using SVGO v2. diff --git a/.changeset/olive-flies-reflect.md b/.changeset/olive-flies-reflect.md new file mode 100644 index 0000000000..80075d8fb0 --- /dev/null +++ b/.changeset/olive-flies-reflect.md @@ -0,0 +1,6 @@ +--- +'@backstage/catalog-model': minor +--- + +**BREAKING**: Remove deprecated validation methods `analyzeLocationSchema`, `locationSchema` and `locationSpecSchema`. +This functionality was primarily used internally by the `catalog-backend`. diff --git a/.changeset/perfect-papayas-crash.md b/.changeset/perfect-papayas-crash.md new file mode 100644 index 0000000000..99c93d1b8d --- /dev/null +++ b/.changeset/perfect-papayas-crash.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-permission-node': minor +--- + +**BREAKING** `PermissionCriteria` now requires at least one condition in `anyOf` and `allOf` arrays. This addresses some ambiguous behavior outlined in #9280. diff --git a/.changeset/pink-onions-ring.md b/.changeset/pink-onions-ring.md new file mode 100644 index 0000000000..2b81ad4b43 --- /dev/null +++ b/.changeset/pink-onions-ring.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog': minor +--- + +**BREAKING** Completely removed the `EntitySystemDiagramCard` component which was deprecated in a previous release. Any remaining references to this component are now broken and should be replaced with `EntityCatalogGraphCard`, which can be imported from package `@backstage/plugin-catalog-graph`. diff --git a/.changeset/plenty-boxes-wink.md b/.changeset/plenty-boxes-wink.md new file mode 100644 index 0000000000..0011641938 --- /dev/null +++ b/.changeset/plenty-boxes-wink.md @@ -0,0 +1,5 @@ +--- +'@backstage/catalog-model': minor +--- + +**BREAKING**: Remove deprecated `serializeEntityRef` which is replaced by `stringifyEntityRef`. diff --git a/.changeset/polite-bulldogs-repeat.md b/.changeset/polite-bulldogs-repeat.md new file mode 100644 index 0000000000..c4e3babe30 --- /dev/null +++ b/.changeset/polite-bulldogs-repeat.md @@ -0,0 +1,17 @@ +--- +'@backstage/cli': patch +--- + +Several changes were made to the new experimental package roles system. Unless you have been experimenting with using this new system, these changes have no affect on your project. + +Renamed the `backstage-cli migrate package-role` command to `backstage-cli migrate package-roles`. + +Updated the package role definitions by renaming `app` to `frontend`, `plugin-frontend` to `frontend-plugin`, `plugin-frontend-module` to `frontend-plugin-module`, `plugin-backend` to `backend-plugin`, and `plugin-backend-module` to `backend-plugin-module` + +The `backstage-cli migrate package-scripts` received several tweaks to make it more accurate. It now tries to maintain existing script arguments, like `--config` parameters for `build` and `start` scripts. + +The `script` command category has been renamed to `package`. + +The `backstage-cli package build` command set an incorrect target directory for `app` and `backend` packages, which has been fixed. + +The `backend:bundle` and `repo build` command for the `backend` role was previously ignoring building of bundled packages that had migrated to use package roles and the standard build script, this has now been fixed. diff --git a/.changeset/polite-dots-train.md b/.changeset/polite-dots-train.md new file mode 100644 index 0000000000..dbd11d3e60 --- /dev/null +++ b/.changeset/polite-dots-train.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-yeoman': patch +--- + +Bump `yeoman-environment` dependency from `^3.6.0` to `^3.9.1`. diff --git a/.changeset/pretty-gorillas-cheat.md b/.changeset/pretty-gorillas-cheat.md new file mode 100644 index 0000000000..d1500c6575 --- /dev/null +++ b/.changeset/pretty-gorillas-cheat.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend': minor +--- + +**BREAKING**: `ctx.token` is now `ctx.secrets.backstageToken` in Actions. Please update any of your Actions that might call out to Backstage API's with this token. diff --git a/.changeset/proud-fishes-carry.md b/.changeset/proud-fishes-carry.md new file mode 100644 index 0000000000..3dd8a445e6 --- /dev/null +++ b/.changeset/proud-fishes-carry.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-catalog': minor +--- + +Removed deprecated `Router` and `EntityPageLayout` exports. +`Router` is replaced by plugin extensions and `EntityPageLayout` is replaced by `CatalogEntityPage`. diff --git a/.changeset/purple-files-hang.md b/.changeset/purple-files-hang.md new file mode 100644 index 0000000000..680de46a80 --- /dev/null +++ b/.changeset/purple-files-hang.md @@ -0,0 +1,5 @@ +--- +'@backstage/catalog-client': patch +--- + +Export the `Location` type that was previously exported by the `@backstage/catalog-model` package. diff --git a/.changeset/rude-tables-grab.md b/.changeset/rude-tables-grab.md new file mode 100644 index 0000000000..5eaae102a5 --- /dev/null +++ b/.changeset/rude-tables-grab.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-common': minor +--- + +**BREAKING**: Removed the `templateEntityV1beta3Schema` export diff --git a/.changeset/seven-birds-eat.md b/.changeset/seven-birds-eat.md new file mode 100644 index 0000000000..1aa6cd4fff --- /dev/null +++ b/.changeset/seven-birds-eat.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-auth-backend': patch +'@backstage/plugin-rollbar-backend': patch +'@backstage/plugin-scaffolder-backend': patch +--- + +Removed unused `helmet` dependency. diff --git a/.changeset/seven-rocks-share.md b/.changeset/seven-rocks-share.md new file mode 100644 index 0000000000..db131a85dc --- /dev/null +++ b/.changeset/seven-rocks-share.md @@ -0,0 +1,5 @@ +--- +'@backstage/integration-react': patch +--- + +Updated the `ScmAuth` error message for missing provider configurations to link to `ScmAuthApi` setup documentation. diff --git a/.changeset/shy-peaches-begin.md b/.changeset/shy-peaches-begin.md new file mode 100644 index 0000000000..4787fe8dea --- /dev/null +++ b/.changeset/shy-peaches-begin.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-react': patch +--- + +Fix CatalogPage showing all components when owned filter was pre-selected diff --git a/.changeset/silly-ghosts-dance.md b/.changeset/silly-ghosts-dance.md new file mode 100644 index 0000000000..e83fc87521 --- /dev/null +++ b/.changeset/silly-ghosts-dance.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs': patch +--- + +Improve overall appearance of highlighted code in docs. diff --git a/.changeset/silver-beds-wonder.md b/.changeset/silver-beds-wonder.md new file mode 100644 index 0000000000..73ce3f9567 --- /dev/null +++ b/.changeset/silver-beds-wonder.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-components': patch +--- + +Port supported react-use functions to react-hookz. diff --git a/.changeset/smart-rivers-reflect.md b/.changeset/smart-rivers-reflect.md new file mode 100644 index 0000000000..da3f9c5806 --- /dev/null +++ b/.changeset/smart-rivers-reflect.md @@ -0,0 +1,8 @@ +--- +'@backstage/catalog-model': minor +--- + +**BREAKING**: Removed `TemplateEntityV1beta2` from the model and moved it to +`@backstage/plugin-scaffolder-common` where `TemplateEntityV1beta3` already +lived. It has also been marked as deprecated in the process - please consider +[migrating to `v1beta3` templates](https://backstage.io/docs/features/software-templates/migrating-from-v1beta2-to-v1beta3). diff --git a/.changeset/sour-hats-love.md b/.changeset/sour-hats-love.md new file mode 100644 index 0000000000..f2cc88e66a --- /dev/null +++ b/.changeset/sour-hats-love.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-common': patch +--- + +Updated `isDatabaseConflictError` to handle modern sqlite conflict errors diff --git a/.changeset/spicy-items-itch.md b/.changeset/spicy-items-itch.md new file mode 100644 index 0000000000..e6617a42a3 --- /dev/null +++ b/.changeset/spicy-items-itch.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-jenkins-backend': patch +--- + +The `DefaultJenkinsInfoProvider.fromConfig` now requires an implementation of the `CatalogApi` rather than a `CatalogClient` instance. diff --git a/.changeset/strange-taxis-perform.md b/.changeset/strange-taxis-perform.md new file mode 100644 index 0000000000..4d1ad18821 --- /dev/null +++ b/.changeset/strange-taxis-perform.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-plugin-api': patch +--- + +Removes unused react-use dependency. diff --git a/.changeset/stupid-cows-design.md b/.changeset/stupid-cows-design.md new file mode 100644 index 0000000000..2df99664fb --- /dev/null +++ b/.changeset/stupid-cows-design.md @@ -0,0 +1,5 @@ +--- +'@backstage/catalog-model': patch +--- + +Deprecates the following exports which all have very limited and internal use. `ENTITY_META_GENERATED_FIELDS`, `entityHasChanges`, `generateEntityEtag`, `generateEntityUid`, `generateUpdatedEntity`, `ENTITY_META_GENERATED_FIELDS`. diff --git a/.changeset/sweet-keys-dress.md b/.changeset/sweet-keys-dress.md new file mode 100644 index 0000000000..4217f2fcf4 --- /dev/null +++ b/.changeset/sweet-keys-dress.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Updated the default [sucrase](https://github.com/alangpierce/sucrase)-based Jest transform to include source maps if the environment variable `ENABLE_SOURCE_MAPS` is non-empty. This can be used to better support editor test debugging integrations. diff --git a/.changeset/swift-dolls-bow.md b/.changeset/swift-dolls-bow.md new file mode 100644 index 0000000000..0e7a261055 --- /dev/null +++ b/.changeset/swift-dolls-bow.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-scaffolder-backend': minor +--- + +**BREAKING** - Removed the `CatalogEntityClient` export. This is no longer provider by this package, +but you can implement one pretty simply yourself using the `CatalogApi` and applying filters to fetch templates. diff --git a/.changeset/tall-planes-grow.md b/.changeset/tall-planes-grow.md new file mode 100644 index 0000000000..d5e07256c9 --- /dev/null +++ b/.changeset/tall-planes-grow.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-github-actions': patch +--- + +Fixed an issue where an error message was being displayed on the initial component render. This was due to values owner/repo not yet being set. diff --git a/.changeset/tasty-eagles-retire.md b/.changeset/tasty-eagles-retire.md new file mode 100644 index 0000000000..c39f30d57f --- /dev/null +++ b/.changeset/tasty-eagles-retire.md @@ -0,0 +1,11 @@ +--- +'@backstage/catalog-client': patch +--- + +Deprecated the following types used by the catalog client, and created new +corresponding types to make them more consistent: + +- `CatalogEntitiesRequest` -> `GetEntitiesRequest` +- `CatalogListResponse` was removed and generally replaced with `GetEntitiesResponse` (which does not use a type parameter argument) +- `CatalogEntityAncestorsRequest`-> `GetEntityAncestorsRequest` +- `CatalogEntityAncestorsResponse` -> `GetEntityAncestorsResponse` diff --git a/.changeset/tasty-taxis-dance.md b/.changeset/tasty-taxis-dance.md new file mode 100644 index 0000000000..34ed30f686 --- /dev/null +++ b/.changeset/tasty-taxis-dance.md @@ -0,0 +1,14 @@ +--- +'@backstage/catalog-client': patch +'@backstage/plugin-catalog': patch +'@backstage/plugin-catalog-backend': patch +'@backstage/plugin-catalog-backend-module-ldap': patch +'@backstage/plugin-catalog-backend-module-msgraph': patch +'@backstage/plugin-catalog-react': patch +'@backstage/plugin-github-deployments': patch +'@backstage/plugin-scaffolder-backend': patch +'@backstage/plugin-todo': patch +'@backstage/plugin-todo-backend': patch +--- + +Replaces use of deprecated catalog-model constants. diff --git a/.changeset/tender-meals-move.md b/.changeset/tender-meals-move.md new file mode 100644 index 0000000000..03721b37b1 --- /dev/null +++ b/.changeset/tender-meals-move.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +The `test` command now automatically adds `--passWithNoTests` to the Jest invocation. To revert this behavior, pass `--passWithNoTests=false` or `--no-passWithNoTests`. diff --git a/.changeset/three-roses-swim.md b/.changeset/three-roses-swim.md new file mode 100644 index 0000000000..ae6ad44845 --- /dev/null +++ b/.changeset/three-roses-swim.md @@ -0,0 +1,18 @@ +--- +'@backstage/techdocs-common': patch +'@backstage/plugin-auth-backend': patch +'@backstage/plugin-badges': patch +'@backstage/plugin-badges-backend': patch +'@backstage/plugin-catalog': patch +'@backstage/plugin-catalog-backend': patch +'@backstage/plugin-catalog-graph': patch +'@backstage/plugin-catalog-react': patch +'@backstage/plugin-cost-insights': patch +'@backstage/plugin-ilert': patch +'@backstage/plugin-org': patch +'@backstage/plugin-pagerduty': patch +'@backstage/plugin-search': patch +'@backstage/plugin-techdocs-backend': patch +--- + +Replace use of deprecated `ENTITY_DEFAULT_NAMESPACE` constant with `DEFAULT_NAMESPACE`. diff --git a/.changeset/tidy-boxes-sell.md b/.changeset/tidy-boxes-sell.md new file mode 100644 index 0000000000..82ee16af57 --- /dev/null +++ b/.changeset/tidy-boxes-sell.md @@ -0,0 +1,18 @@ +--- +'@backstage/plugin-search': minor +--- + +**BREAKING**: `useSearch` doesn't return anymore `open` and `toggleModal`. +The two properties have been moved to the `useSearchModal` hook. + +``` +import { SearchModal, useSearchModal } from '@backstage/plugin-search'; + +const Foo = () => { + const { state, setOpen, toggleModal } = useSearchModal(); + + return ( + + ); +}; +``` diff --git a/.changeset/tough-stingrays-sit.md b/.changeset/tough-stingrays-sit.md new file mode 100644 index 0000000000..5cef08c8e3 --- /dev/null +++ b/.changeset/tough-stingrays-sit.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Optimized entity provider mutations with large numbers of new additions, such as big initial startup commits diff --git a/.changeset/twenty-dodos-rule.md b/.changeset/twenty-dodos-rule.md new file mode 100644 index 0000000000..5167811a3d --- /dev/null +++ b/.changeset/twenty-dodos-rule.md @@ -0,0 +1,6 @@ +--- +'@backstage/catalog-model': patch +--- + +Deprecates `EDIT_URL_ANNOTATION`, `LOCATION_ANNOTATION`, `ORIGIN_LOCATION_ANNOTATION`, `SOURCE_LOCATION_ANNOTATION`, `VIEW_URL_ANNOTATION` +and replaces these constants all prefixed with ANNOTATION\_ `ANNOTATION_EDIT_URL`, `ANNOTATION_LOCATION`, `ANNOTATION_ORIGIN_LOCATION`, `ANNOTATION_SOURCE_LOCATION`, `ANNOTATION_VIEW_URL` diff --git a/.changeset/unlucky-dodos-scream.md b/.changeset/unlucky-dodos-scream.md new file mode 100644 index 0000000000..c44c3c7032 --- /dev/null +++ b/.changeset/unlucky-dodos-scream.md @@ -0,0 +1,14 @@ +--- +'@backstage/catalog-client': minor +--- + +Removed `CatalogApi.geLocationByEntity` and `CatalogApi.getOriginLocationByEntity`, and replaced them with `CatalogApi.getLocationByRef`. + +If you were using one of the two old methods, you can update your code as follows: + +```diff +-const originLocation = catalogApi.getOriginLocationByEntity(entity); ++const originLocation = catalogApi.getLocationByRef(entity.metadata.annotations[ANNOTATION_ORIGIN_LOCATION]!); +-const location = catalogApi.getLocationByEntity(entity); ++const location = catalogApi.getLocationByRef(entity.metadata.annotations[ANNOTATION_LOCATION]!); +``` diff --git a/.changeset/warm-lizards-sin.md b/.changeset/warm-lizards-sin.md new file mode 100644 index 0000000000..1e2aa1f857 --- /dev/null +++ b/.changeset/warm-lizards-sin.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-scaffolder-backend': minor +--- + +Remove the previously deprecated `scaffolder.provider` config for all providers. +This config is no longer used anywhere, and adopters should use [`integrations` config](https://backstage.io/docs/integrations) instead. diff --git a/.changeset/weak-timers-punch.md b/.changeset/weak-timers-punch.md new file mode 100644 index 0000000000..a25724cb8f --- /dev/null +++ b/.changeset/weak-timers-punch.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-gcp-projects': patch +--- + +Switches to use react-hookz in place of react-use. diff --git a/.changeset/witty-mails-search.md b/.changeset/witty-mails-search.md new file mode 100644 index 0000000000..a98fc52884 --- /dev/null +++ b/.changeset/witty-mails-search.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-scaffolder-backend-module-cookiecutter': minor +'@backstage/plugin-scaffolder-backend-module-rails': minor +'@backstage/plugin-scaffolder-backend-module-yeoman': minor +--- + +Updated to the latest version of `@backstage/plugin-scaffolder-backend`, meaning the `TemplateAction` now exposes the precise input type rather than `any`. diff --git a/.github/workflows/automate_techdocs-project-board.yml b/.github/workflows/automate_techdocs-project-board.yml deleted file mode 100644 index f551412f95..0000000000 --- a/.github/workflows/automate_techdocs-project-board.yml +++ /dev/null @@ -1,57 +0,0 @@ -name: Automate TechDocs project board -# Development of TechDocs in Backstage is managed by this Kanban board - https://github.com/orgs/backstage/projects/1 -# New issues and PRs with TechDocs in their title or docs-like-code label will be added to the board. -# Caveat: New PRs created from forks will not be added since GitHub Actions don't share credentials with forks. - -on: - issues: - types: [opened, reopened, labeled, edited] - pull_request: - types: [opened, reopened, labeled, edited] - -jobs: - assign_issue_or_pr_to_project: - runs-on: ubuntu-latest - name: Triage - env: - MY_GITHUB_TOKEN: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }} - steps: - - name: Assign new issue to Incoming based on its title. - uses: srggrs/assign-one-project-github-action@1.2.0 - if: | - env.MY_GITHUB_TOKEN != null && - contains(github.event.issue.title, 'TechDocs') || - contains(github.event.issue.title, 'techdocs') || - contains(github.event.issue.title, 'Techdocs') - with: - project: 'https://github.com/orgs/backstage/projects/1' - column_name: 'Incoming' - - - name: Assign new issue to Incoming based on its label. - uses: srggrs/assign-one-project-github-action@1.2.0 - if: | - env.MY_GITHUB_TOKEN != null && - contains(github.event.issue.labels.*.name, 'docs-like-code') - with: - project: 'https://github.com/orgs/backstage/projects/1' - column_name: 'Incoming' - - - name: Assign new PR to Incoming based on its title. - uses: srggrs/assign-one-project-github-action@1.2.0 - if: | - env.MY_GITHUB_TOKEN != null && - contains(github.event.pull_request.title, 'TechDocs') || - contains(github.event.pull_request.title, 'techdocs') || - contains(github.event.pull_request.title, 'Techdocs') - with: - project: 'https://github.com/orgs/backstage/projects/1' - column_name: 'Incoming' - - - name: Assign new PR to Incoming based on its label. - uses: srggrs/assign-one-project-github-action@1.2.0 - if: | - env.MY_GITHUB_TOKEN != null && - contains(github.event.pull_request.labels.*.name, 'docs-like-code') - with: - project: 'https://github.com/orgs/backstage/projects/1' - column_name: 'Incoming' diff --git a/ADOPTERS.md b/ADOPTERS.md index 531660a877..772651d54c 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -74,7 +74,7 @@ | [GoTo](https://www.goto.com) | [Lorenzo Orsatti](https://github.com/lorsatti) | Improve onboarding experience of new developers. Discover faster and painlessly developer documentation, API definitions and team information. Provide useful dev metrics in a central place. Provide easy-to-use templates for new services. | | [Telstra](https://www.telstra.com.au) | [@kiranpatel11](https://github.com/kiranpatel11), [JasonC](https://github.com/JasonC17) | Primary usage: software catalog and templates
Emerging usage : TechDocs, Explore Ecosystem, TechRadar, etc | | [Mosaico](https://www.mosaico.com.br/) | [Wédney Yuri](https://github.com/wedneyyuri),[@tino.milton](https://github.com/miltonjacomini) | A centralized service catalog of our documentation for our service engineers. | -| [Mox Bank](https://www.mox.com/) | [Nick Laqua](https://github.com/nick-laqua-dragon), [Gauthier Roebroeck](https://github.com/gauthier-roebroeck-mox) | "Single pane of glass" developer portal for providing a best-in-class developer experience to our product teams and making Mox the best tech environment in Hongkong 🥰🚀 | +| [Mox Bank](https://www.mox.com/) | [Nick Laqua](https://github.com/nick-laqua-dragon) | "Single pane of glass" developer portal for providing a best-in-class developer experience to our product teams and making Mox the best tech environment in Hongkong 🥰🚀 | | [Keyloop](https://www.keyloop.com/) | [Andre Wanlin](https://github.com/awanlin) | Future-motive Developer Portal to help our teams create technology to make everything about buying and owning a car better. 🚗 | | [Simply Business](https://sbtech.simplybusiness.co.uk/) | [@addersuk](https://github.com/addersuk), [@LightningStairs](https://github.com/LightningStairs), [@punitcse](https://github.com/punitcse), [@moltenice](https://github.com/moltenice) | Central developer portal to access everything a developer needs such as docs, internal service catalog, and the ability to quickly create a new service from a template. Internally developed Backstage plugins allow us to customise the experience to how we work. | | [Overwolf](https://www.overwolf.com) | [@tomwolfgang](https://github.com/tomwolfgang) | Dev portal - software catalog, tech-docs, scaffolding | @@ -93,3 +93,4 @@ | [Invitae](https://www.invitae.com/en) | [@ryan-hanchett](https://github.com/ryan-hanchett), [@gmandler42](https://github.com/gmandler42) | Centralized Developer Experience portal, putting all of our tooling behind a single pane of glass and creating a living service catalog. | | [Fortum](https://www.fortum.com/) | [@brunoamaroalmeida](https://github.com/brunoamaroalmeida), [@dhaval-vithalani](https://github.com/dhaval-vithalani), [@sunilkumarmohanty](https://github.com/sunilkumarmohanty) | A central portal containing information about our applications, services, processes and other software assets to be used by Fortum software engineering community. | | [Procore](https://www.procore.com/jobs/engineering) | [@shayon](https://github.com/Shayon), [@jamesdabbs-procore](https://github.com/jamesdabbs-procore) | Developer portal - centralized software catalog and templates to enable self serve and reduce cognitive load. | +| [Bradesco](https://banco.bradesco/html/classic/sobre/index.shtm) | [@danilosoarescardoso](https://github.com/danilosoarescardoso) | Centralized developer portal with software catalog, software templates, techdocs and some plugins from community and by our own. | \ No newline at end of file diff --git a/contrib/chart/backstage/templates/ingress.yaml b/contrib/chart/backstage/templates/ingress.yaml index 3fa052485e..cac9b61553 100644 --- a/contrib/chart/backstage/templates/ingress.yaml +++ b/contrib/chart/backstage/templates/ingress.yaml @@ -15,7 +15,6 @@ metadata: {{- if .Values.issuer.email }} cert-manager.io/cluster-issuer: {{ .Values.issuer.clusterIssuer }} {{- end }} - kubernetes.io/ingress.class: nginx nginx.ingress.kubernetes.io/ssl-redirect: "false" nginx.ingress.kubernetes.io/configuration-snippet: | if ($scheme = https) { diff --git a/contrib/docker/devops/Dockerfile b/contrib/docker/devops/Dockerfile index 9bb80a0a2c..a7c194618a 100644 --- a/contrib/docker/devops/Dockerfile +++ b/contrib/docker/devops/Dockerfile @@ -9,7 +9,8 @@ WORKDIR /tmp # update package sources # `--virtual` is used to enable removal of these dependencies as a named group -# - python: required by node-gyp +# - python3: required by node-gyp +# - g++: required to build @vscode/sqlite3 # - pixman: required by node-canvas # - pkgconfig: required by pixman # -------------------------------------------- @@ -32,7 +33,8 @@ WORKDIR /tmp RUN apk update \ && apk add --no-cache \ --virtual ${APK_VIRTUAL_NAME} \ - python \ + python3 \ + g++ \ pixman \ pkgconfig \ alpine-sdk \ @@ -51,6 +53,10 @@ RUN wget -qO- ${VALE_INSTALL_URL} \ | tar xvz -C /bin vale \ && chmod +x /bin/vale +# needed for sqlite3 build that needs python +RUN ln -s /usr/bin/python3 /usr/bin/python && \ + ln -s /usr/bin/pip3 /usr/bin/pip + RUN mkdir /app WORKDIR /app diff --git a/docs/assets/getting-started/sidebar-with-catalog.png b/docs/assets/getting-started/sidebar-with-catalog.png new file mode 100644 index 0000000000..d80346c211 Binary files /dev/null and b/docs/assets/getting-started/sidebar-with-catalog.png differ diff --git a/docs/assets/getting-started/sidebar-without-catalog.png b/docs/assets/getting-started/sidebar-without-catalog.png new file mode 100644 index 0000000000..bfeab13235 Binary files /dev/null and b/docs/assets/getting-started/sidebar-without-catalog.png differ diff --git a/docs/assets/getting-started/simple-homepage.png b/docs/assets/getting-started/simple-homepage.png new file mode 100644 index 0000000000..128707e9ff Binary files /dev/null and b/docs/assets/getting-started/simple-homepage.png differ diff --git a/docs/auth/index.md b/docs/auth/index.md index e407480f65..6bda35232a 100644 --- a/docs/auth/index.md +++ b/docs/auth/index.md @@ -56,18 +56,15 @@ allows a single auth backend to serve multiple environments, such as running a local frontend against a deployed backend. The provider configuration matching the local `auth.environment` setting will be selected. -### Adding the provider to the sign-in page +## Using an authentication provider for sign-in -After configuring an authentication provider, the `app` frontend package needs a -small update to show this provider as a login option. The `SignInPage` component -handles this, and takes either a `provider` or `providers` (array) prop of -`SignInProviderConfig` definitions. +If you want to use an authentication provider for sign-in, as opposed to just accessing external resources, you'll need to configure that in your app as well. This is done by providing a custom `SignInPage` component to the app, which will require the user to sign in before they can access the app. Note that this does not block access to the app, which you can read more about [here](./using-auth.md). -These reference the `ApiRef` exported by the provider. Again, an example using -GitHub that can be adapted to any of the built-in providers: +If you want to, you can use the `SignInPage` component that is provided by `@backstage/core-components`, which takes either a `provider` or `providers` (array) prop of `SignInProviderConfig` definitions. These reference the `ApiRef` exported for the provider. + +Again, the following example for GitHub shows the additions needed to `packages/app/src/App.tsx`, and can be adapted to any of the built-in providers: ```diff -# packages/app/src/App.tsx + import { githubAuthApiRef } from '@backstage/core-plugin-api'; + import { SignInProviderConfig, SignInPage } from '@backstage/core-components'; @@ -78,8 +75,8 @@ GitHub that can be adapted to any of the built-in providers: + apiRef: githubAuthApiRef, +}; + -const app = createApp({ - apis, + const app = createApp({ + apis, + components: { + SignInPage: props => ( + + ), + }, - bindRoutes({ bind }) { + bindRoutes({ bind }) { ``` To also allow unauthenticated guest access, use the `providers` prop for `SignInPage`: ```diff -const app = createApp({ - apis, + const app = createApp({ + apis, + components: { + SignInPage: props => ( + + ), + }, - bindRoutes({ bind }) { + bindRoutes({ bind }) { ``` ## Adding a custom authentication provider @@ -119,3 +116,26 @@ Backstage uses [Passport](http://www.passportjs.org/) under the hood, which has a wide library of authentication strategies for different providers. See [Add authentication provider](add-auth-provider.md) for details on adding a new Passport-supported authentication method. + +## Custom ScmAuthApi Implementation + +If you are using any custom authentication providers, like for example one for GitHub Enterprise, then you are likely to need a custom implementation of the [`ScmAuthApi`](https://backstage.io/docs/reference/integration-react.scmauthapi). It is an API used to authenticate towards different SCM systems in a generic way, based on what resource is being accessed, and is used for example by the Scaffolder (Software Templates) and Catalog Import plugins. + +To set up a custom `ScmAuthApi` implementation, you'll need to add an API factory entry to `packages/app/src/apis.ts`. The following example shows an implementation that supports both public GitHub via `githubAuthApi` as well as a GitHub Enterprise installation hosted at `ghe.example.com` via `gheAuthApi`: + +```ts +createApiFactory({ + api: scmAuthApiRef, + deps: { + gheAuthApi: gheAuthApiRef, + githubAuthApi: githubAuthApiRef, + }, + factory: ({ githubAuthApi, gheAuthApi }) => + ScmAuth.merge( + ScmAuth.forGithub(githubAuthApi), + ScmAuth.forGithub(gheAuthApi, { + host: 'ghe.example.com', + }), + ), +}); +``` diff --git a/docs/features/search/getting-started.md b/docs/features/search/getting-started.md index 285e399cb4..7c3717e22e 100644 --- a/docs/features/search/getting-started.md +++ b/docs/features/search/getting-started.md @@ -114,15 +114,13 @@ const routes = ( In `Root.tsx`, add the `SidebarSearchModal` component: ```bash -import { SidebarSearchModal, SearchContextProvider } from '@backstage/plugin-search'; +import { SidebarSearchModal } from '@backstage/plugin-search'; export const Root = ({ children }: PropsWithChildren<{}>) => ( - - - + ... ``` diff --git a/docs/getting-started/app-custom-theme.md b/docs/getting-started/app-custom-theme.md index fc68008ae8..34eca2429a 100644 --- a/docs/getting-started/app-custom-theme.md +++ b/docs/getting-started/app-custom-theme.md @@ -257,68 +257,4 @@ const LogoFull = () => { ## Custom Homepage In addition to a custom theme, a custom logo, you can also customize the -homepage of your app. To do that we need to go through a few steps. - -### Setting up the Home Page - -1. Create a Home Page Component that will be used for composition. - -`packages/app/src/components/home/HomePage.tsx` - -```tsx -import React from 'react'; - -export const HomePage = () => { - return { - /* TODO: Compose a Home Page here */ - }; -}; -``` - -2. Add a route where the homepage will live, presumably `/`. - -`packages/app/src/App.tsx` - -```tsx -import { HomepageCompositionRoot } from '@backstage/plugin-home'; -import { HomePage } from './components/home/HomePage'; - -// ... -}> - -; -// ... -``` - -### Composing your Home Page - -Composing a Home Page is no different from creating a regular React Component, -i.e. the App Integrator is free to include whatever content they like. However, -there are components developed with the Home Page in mind. If you are looking -for components to use when composing your homepage, you can take a look at the -[collection of Homepage components](https://backstage.io/?path=/story/plugins-home-components) -in storybook. If you don't find a component that suits your needs but want to -contribute, check the -[Contributing documentation](https://github.com/backstage/backstage/blob/master/plugins/home/README.md#contributing). - -> If you want to use one of the available homepage templates you can find the -> [templates](https://backstage.io/storybook/?path=/story/plugins-home-templates) -> in the storybook under the "Home" plugin. And if you would like to contribute -> a template, please see the -> [Contributing documentation](https://github.com/backstage/backstage/blob/master/plugins/home/README.md#contributing) - -```tsx -import React from 'react'; -import Grid from '@material-ui/core/Grid'; -import { HomePageCompanyLogo } from '@backstage/plugin-home'; - -export const HomePage = () => { - return ( - - - - - - ); -}; -``` +homepage of your app. Read the full guide on the [next page](homepage.md). diff --git a/docs/getting-started/create-an-app.md b/docs/getting-started/create-an-app.md index 1d65f25d1b..05c12ffb75 100644 --- a/docs/getting-started/create-an-app.md +++ b/docs/getting-started/create-an-app.md @@ -16,8 +16,7 @@ may want to [Run Backstage Locally](./running-backstage-locally.md) instead. ## Create an app To create a Backstage app, you will need to have -[Node.js](https://nodejs.org/en/download/) Active LTS Release installed -(currently v14). +Node.js [Active LTS Release](https://nodejs.org/en/about/releases/) installed. Backstage provides a utility for creating new apps. It guides you through the initial setup of selecting the name of the app and a database for the backend. diff --git a/docs/getting-started/homepage.md b/docs/getting-started/homepage.md new file mode 100644 index 0000000000..59272a285b --- /dev/null +++ b/docs/getting-started/homepage.md @@ -0,0 +1,166 @@ +--- +id: homepage +title: Backstage homepage - Setup and Customization +description: Documentation on setting up and customizing Backstage homepage +--- + +## Homepage + +Having a good Backstage homepage can significantly improve the discoverability of the platform. You want your users to find all the things they need right from the homepage and never have to remember direct URLs in Backstage. The [Home plugin](https://github.com/backstage/backstage/tree/master/plugins/home) introduces a system for composing a homepage for Backstage in order to surface relevant info and provide convenient shortcuts for common tasks. It's designed with composability in mind with an open ecosystem that allows anyone to contribute with any component, to be included in any homepage. + +For App Integrators, the system is designed to be composable to give total freedom in designing a Homepage that suits the needs of the organization. From the perspective of a Component Developer who wishes to contribute with building blocks to be included in Homepages, there's a convenient interface for bundling the different parts and exporting them with both error boundary and lazy loading handled under the surface. + +At the end of this tutorial, you can expect: + +- Your Backstage app to have a dedicated homepage instead of Software Catalog. +- Understand the composability of homepage and how to start customizing it for your own organization. + +### Prerequisites + +Before we begin, make sure + +- You have created your own standalone Backstage app using [`@backstage/create-app`](index.md#create-your-backstage-app) and not using a fork of the [backstage](https://github.com/backstage/backstage) repository. +- You do not have an existing homepage, and by default you are redirected to Software Catalog when you open Backstage. + +Now, let's get started by installing the home plugin and creating a simple homepage for your Backstage app. + +### Setup homepage + +#### 1. Install the plugin + +``` +# From your Backstage application directory +cd packages/app +yarn add @backstage/plugin-home +``` + +#### 2. Create a new HomePage component + +Inside your `packages/app` directory, create a new file where our new homepage component is going to live. Create `packages/app/src/components/home/HomePage.tsx` with the following initial code + +```tsx +import React from 'react'; + +export const HomePage = () => { + /* We will shortly compose a pretty homepage here. */ + return

Welcome to Backstage!

; +}; +``` + +#### 3. Update router for the root `/` route + +If you don't have a homepage already, most likely you have a redirect setup to use the Catalog homepage as a homepage. + +Inside your `packages/app/src/App.tsx`, look for + +```tsx +const routes = ( + + +``` + +Let's replace the `` line and use the new component we created in the previous step as the new homepage. + +```diff +// File: packages/app/src/App.tsx + ++ import { HomepageCompositionRoot } from '@backstage/plugin-home'; ++ import { HomePage } from './components/home/HomePage'; + +// ... +const routes = ( + +- ++ }> ++ ++ +// ... + +) +``` + +### 4. Update sidebar items + +Let's update the route for "Home" in the Backstage sidebar to point to the new homepage. We'll also add a Sidebar item to quickly open Catalog. + + + + + + + + +
Sidebar without Catalog + Sidebar with Catalog +
BeforeAfter
+ +The code for the Backstage sidebar is most likely inside your [`packages/app/src/components/Root/Root.tsx`](https://github.com/backstage/backstage/blob/master/packages/app/src/components/Root/Root.tsx). + +Let's make the following changes + +```diff +// Other imports ++ import CategoryIcon from '@material-ui/icons/Category'; + +export const Root = ({ children }: PropsWithChildren<{}>) => ( + + + + # ... + }> + {/* Global nav, not org-specific */} +- ++ ++ + + + + + {/* End global nav */} + +``` + +That's it! You should now have _(although slightly boring)_ a homepage! + +Screenshot of a blank homepage + +In the next steps, we will make it interesting and useful! + +### Use the default template + +There is a default homepage template ([storybook link](https://backstage.io/storybook/?path=/story/plugins-home-templates--default-template)) which we will use to set up our homepage. Checkout the [blog post announcement](https://backstage.io/blog/2022/01/25/backstage-homepage-templates) about the Backstage homepage templates for more information. + + + +### Composing your homepage + +Composing a homepage is no different from creating a regular React Component, +i.e. the App Integrator is free to include whatever content they like. However, +there are components developed with the homepage in mind. If you are looking +for components to use when composing your homepage, you can take a look at the +[collection of Homepage components](https://backstage.io/storybook?path=/story/plugins-home-components) +in storybook. If you don't find a component that suits your needs but want to +contribute, check the +[Contributing documentation](https://github.com/backstage/backstage/blob/master/plugins/home/README.md#contributing). + +> If you want to use one of the available homepage templates you can find the +> [templates](https://backstage.io/storybook/?path=/story/plugins-home-templates) +> in the storybook under the "Home" plugin. And if you would like to contribute +> a template, please see the +> [Contributing documentation](https://github.com/backstage/backstage/blob/master/plugins/home/README.md#contributing) + +```tsx +import React from 'react'; +import Grid from '@material-ui/core/Grid'; +import { HomePageCompanyLogo } from '@backstage/plugin-home'; + +export const HomePage = () => { + return ( + + + + + + ); +}; +``` diff --git a/docs/getting-started/index.md b/docs/getting-started/index.md index a622313739..8c2f6bc865 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 installed (currently v14) using one of these +- Node.js [Active LTS Release](https://nodejs.org/en/about/releases/) installed using one of these methods: - Using `nvm` (recommended) - [Installing nvm](https://github.com/nvm-sh/nvm#install--update-script) diff --git a/docs/getting-started/running-backstage-locally.md b/docs/getting-started/running-backstage-locally.md index daad7bf195..3443b85285 100644 --- a/docs/getting-started/running-backstage-locally.md +++ b/docs/getting-started/running-backstage-locally.md @@ -13,13 +13,14 @@ trying to contribute, follow the instructions to - Node.js -First make sure you are using Node.js with an Active LTS Release, currently v14. +First make sure you are using Node.js with an [Active LTS Release](https://nodejs.org/en/about/releases/). This is made easy with a version manager such as [nvm](https://github.com/nvm-sh/nvm) which allows for version switching. ```bash -# Installing a new version -nvm install 14 +# Installing current LTS release +nvm install --lts +> Installing latest LTS version. > Downloading and installing node v14.15.1... > Now using node v14.15.1 (npm v6.14.8) diff --git a/docs/integrations/github/locations.md b/docs/integrations/github/locations.md index 330b03eab9..3395c61117 100644 --- a/docs/integrations/github/locations.md +++ b/docs/integrations/github/locations.md @@ -57,6 +57,22 @@ public GitHub, for which we can infer them). The `apiBaseUrl` will always be preferred over the other if a `token` is given, otherwise `rawBaseUrl` will be preferred. +### Token scopes + +When creating a personal access token on GitHub, you must select scopes to +define the level of access for the token. The scopes required vary depending on +your use of the integration: + +- Reading software components: + - `repo` +- Reading organization data: + - `read:org` + - `read:user` + - `user:email` +- Publishing software templates: + - `repo` + - `workflow` (if templates include GitHub workflows) + ## Authentication with GitHub Apps Alternatively, Backstage can use GitHub Apps for backend authentication. This diff --git a/docs/integrations/github/org.md b/docs/integrations/github/org.md index 7140ffa505..5843944e8a 100644 --- a/docs/integrations/github/org.md +++ b/docs/integrations/github/org.md @@ -22,19 +22,6 @@ entities that mirror your org setup. The processor that performs the import, `GithubOrgReaderProcessor`, comes installed with the default setup of Backstage. -If you have _replaced_ the set of processors in your installation using -`replaceProcessors`, you can import and add it as follows: - -```ts -// Typically in packages/backend/src/plugins/catalog.ts -import { GithubOrgReaderProcessor } from '@backstage/plugin-catalog-backend'; - -builder.replaceProcessors( - GithubOrgReaderProcessor.fromConfig(config, { logger }), - // ... -); -``` - ## Configuration The following configuration enables an import of the teams and users under the @@ -51,10 +38,12 @@ If Backstage is configured to use GitHub Apps authentication you must grant `Read-Only` access for `Members` under `Organization` in order to ingest users correctly. You can modify the app's permissions under the organization settings, `https://github.com/organizations/{ORG}/settings/apps/{APP_NAME}/permissions`. + ![permissions](../../assets/integrations/github/permissions.png) **Please note that when you change permissions, the app owner will get an email that must be approved first before the changes are applied.** + ![email](../../assets/integrations/github/email.png) Locations point out the specific org(s) you want to import. The `type` of these @@ -65,3 +54,22 @@ The authorization for loading org information comes from a configured [GitHub integration](locations.md#configuration). When using a personal access token, the token needs to have at least the scopes `read:org`, `read:user`, and `user:email` in the given `target`. + +## Addendum + +Some Backstage apps have _replaced_ the catalog processors to override the +default catalog processing behavior. These apps will already have a call to +`replaceProcessors` in the catalog initialization. + +In the unlikely scenario that this applies to your app, you can import and +add the `GithubOrgReaderProcessor` as follows: + +```ts +// Typically in packages/backend/src/plugins/catalog.ts +import { GithubOrgReaderProcessor } from '@backstage/plugin-catalog-backend'; + +builder.replaceProcessors( + // ... other processor replacements + GithubOrgReaderProcessor.fromConfig(config, { logger }), +); +``` diff --git a/docs/local-dev/cli-build-system.md b/docs/local-dev/cli-build-system.md index fdfede6e05..c4a08afc56 100644 --- a/docs/local-dev/cli-build-system.md +++ b/docs/local-dev/cli-build-system.md @@ -444,8 +444,9 @@ working directory to the package that the test is in. Where small customizations are needed, such as setting coverage thresholds or support for specific transforms, it is possible to override the Jest -configuration through the `"jest"` field in `package.json`. These overrides will -be loaded in from all `package.json` files in the directory ancestry, meaning +configuration through the `"jest"` field in `package.json`. For a full list of +options, see the [Jest documentation](https://jestjs.io/docs/en/configuration). +These overrides will be loaded in from all `package.json` files in the directory ancestry, meaning that you can place common configuration in the `package.json` at the root of a monorepo. If multiple overrides are found, they will be merged together with configuration further down in the directory tree taking precedence. @@ -464,6 +465,45 @@ The overrides in a single `package.json` may for example look like this: }, ``` +If you want to configure editor integration for tests we recommend executing the bundled configuration directly with Jest rather than running through the Yarn test script. For example, with the Jest extension for VS Code the configuration would look something like this: + +```jsonc +{ + "jest.jestCommandLine": "node_modules/.bin/jest --config node_modules/@backstage/cli/config/jest.js", + // In a large repo like the Backstage main repo you likely want to disable + // watch mode and the initial test run too, leaving just manual and perhaps + // on-save test runs in place. + "jest.autoRun": { + "watch": false, + "onSave": "test-src-file" + } +} +``` + +If you also want to enable source maps when debugging tests, you can do so by setting the `ENABLE_SOURCE_MAPS` environment variable. For example, a complete launch configuration for VS Code debugging may look like this: + +```json +{ + "type": "node", + "name": "vscode-jest-tests", + "request": "launch", + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen", + "disableOptimisticBPs": true, + "program": "${workspaceFolder}/node_modules/.bin/jest", + "cwd": "${workspaceFolder}", + "env": { + "ENABLE_SOURCE_MAPS": "true" + }, + "args": [ + "--config", + "node_modules/@backstage/cli/config/jest.js", + "--runInBand", + "--watchAll=false" + ] +} +``` + ## Publishing Package publishing is an optional part of the Backstage build system and not diff --git a/docs/local-dev/cli-commands.md b/docs/local-dev/cli-commands.md index daf53ac0b2..eff6404e3b 100644 --- a/docs/local-dev/cli-commands.md +++ b/docs/local-dev/cli-commands.md @@ -440,22 +440,7 @@ a yarn workspaces monorepo by automatically creating one grouped configuration that includes all packages that have `backstage-cli test` in their package `test` script. -If needed, the configuration can be extended using a `"jest"` field in -`package.json`, both within the target package and the monorepo root, with -configuration in the target package taking precedence. Refer to the -[Jest configuration documentation](https://jestjs.io/docs/en/configuration) for -a full list of configuration options. - -In addition to the Jest configuration there's an optional `transformModules` -option, which is an array of module names to include in transformations. -Normally modules inside `node_modules` are not transformed, but there are cases -were published packages are not transpiled far enough to be usable by Jest, in -which case you need to enable transform of them. - -Another way to override the Jest configuration is to place a `jest.config.js` or -`jest.config.ts` file in the package root. As opposed to the `package.json` way -of overriding config, this completely removes the base config, and so you need -to set it up from scratch. +For more information about configuration overrides and editor support, see the [Jest Configuration section](./cli-build-system.md#jest-configuration) in the build system documentation. ```text Usage: backstage-cli test [options] diff --git a/docs/plugins/github-apps.md b/docs/plugins/github-apps.md index 1be1502b6b..434c9a4882 100644 --- a/docs/plugins/github-apps.md +++ b/docs/plugins/github-apps.md @@ -109,11 +109,21 @@ privateKey: | This will result in backstage preventing the use of any installation that is not within the allow list. -### Permissions for pull requests +### App permissions -These are the minimum permissions required for creating a pull request with -Backstage software templates: +When creating a GitHub App, you must select permissions to define the level of +access for the app. The permissions required vary depending on your use of the +integration: -- Read and Write permissions for `Contents`. -- Read and write permissions for `Pull Requests` and `Issues`. -- Read permissions on `Metadata`. +- Reading software components: + - `Contents`: `Read-only` +- Reading organization data: + - `Members`: `Read-only` +- Publishing software templates: + + - `Administration`: `Read & write` (for creating repositories) + - `Contents`: `Read & write` + - `Metadata`: `Read-only` + - `Pull requests`: `Read & write` + - `Issues`: `Read & write` + - `Workflows`: `Read & write` (if templates include GitHub workflows) diff --git a/docs/plugins/integrating-plugin-into-software-catalog.md b/docs/plugins/integrating-plugin-into-software-catalog.md index 71430e25a0..97efa56ac3 100644 --- a/docs/plugins/integrating-plugin-into-software-catalog.md +++ b/docs/plugins/integrating-plugin-into-software-catalog.md @@ -107,7 +107,7 @@ const systemPage = ( - + {/* Adding a new tab to the system view */} diff --git a/microsite/blog/2022-01-25-backstage-homepage-templates.md b/microsite/blog/2022-01-25-backstage-homepage-templates.md index 7ed5ee92e3..8ca8b7373e 100644 --- a/microsite/blog/2022-01-25-backstage-homepage-templates.md +++ b/microsite/blog/2022-01-25-backstage-homepage-templates.md @@ -33,7 +33,7 @@ _Example of the default homepage template in Backstage Storybook_ ## How to get started -To get started, you first need to set up your homepage plugin in the app if you have not already, then you can move on to composing your homepage. You can find our step-by-step documentation of how to do this under the [App Configuration - Customize the look-and-feel of your App documentation](https://backstage.io/docs/getting-started/app-custom-theme#custom-homepage). You can also access the [Backstage UI Kit in Figma](https://www.figma.com/file/nUaAw56hTgC0RIOYkuLSrB/Backstage-Design-System?node-id=2185%3A2978) to duplicate your own version and play around with a fitting homepage for your own organization. +To get started, you first need to set up your homepage plugin in the app if you have not already, then you can move on to composing your homepage. You can find our step-by-step documentation of how to do this under the [App Configuration - Customize the look-and-feel of your App documentation](https://backstage.io/docs/getting-started/homepage). You can also access the [Backstage UI Kit in Figma](https://www.figma.com/file/nUaAw56hTgC0RIOYkuLSrB/Backstage-Design-System?node-id=2185%3A2978) to duplicate your own version and play around with a fitting homepage for your own organization. ![Example of homepage components in the Backstage UI Kit in Figma](assets/22-01-25/homepage-components-figma.png) _Example of the homepage components in the Backstage UI Kit in Figma_ diff --git a/microsite/pages/en/link.js b/microsite/pages/en/link.js index ddac35e545..727b15bfd8 100644 --- a/microsite/pages/en/link.js +++ b/microsite/pages/en/link.js @@ -5,6 +5,7 @@ const React = require('react'); const redirects = { 'bind-routes': '/docs/plugins/composability#binding-external-routes-in-the-app', + 'scm-auth': '/docs/auth/#custom-scmauthapi-implementation', }; const fallback = '/docs'; diff --git a/microsite/sidebars.json b/microsite/sidebars.json index cb7c0d5036..5369182013 100644 --- a/microsite/sidebars.json +++ b/microsite/sidebars.json @@ -22,7 +22,8 @@ "label": "App configuration", "ids": [ "getting-started/configure-app-with-plugins", - "getting-started/app-custom-theme" + "getting-started/app-custom-theme", + "getting-started/homepage" ] }, "getting-started/keeping-backstage-updated", diff --git a/packages/app-defaults/package.json b/packages/app-defaults/package.json index c7cb87faa4..09c5af2b1c 100644 --- a/packages/app-defaults/package.json +++ b/packages/app-defaults/package.json @@ -8,6 +8,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "web-library" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -21,12 +24,13 @@ "main": "src/index.ts", "types": "src/index.ts", "scripts": { - "build": "backstage-cli build --outputs types,esm", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean", + "start": "backstage-cli package start" }, "dependencies": { "@backstage/core-components": "^0.8.8", diff --git a/packages/app/package.json b/packages/app/package.json index bdade7974a..e853597e9e 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -2,6 +2,9 @@ "name": "example-app", "version": "0.2.64", "private": true, + "backstage": { + "role": "frontend" + }, "bundled": true, "dependencies": { "@backstage/app-defaults": "^0.1.7", @@ -56,10 +59,10 @@ "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", "@octokit/rest": "^18.5.3", - "@roadiehq/backstage-plugin-github-insights": "^1.4.2", - "@roadiehq/backstage-plugin-github-pull-requests": "^1.3.2", - "@roadiehq/backstage-plugin-travis-ci": "^1.3.2", - "@roadiehq/backstage-plugin-buildkite": "^1.3.4", + "@roadiehq/backstage-plugin-github-insights": "^1.5.0", + "@roadiehq/backstage-plugin-github-pull-requests": "^1.4.0", + "@roadiehq/backstage-plugin-travis-ci": "^1.3.6", + "@roadiehq/backstage-plugin-buildkite": "^1.3.8", "history": "^5.0.0", "prop-types": "^15.7.2", "react": "^17.0.2", @@ -89,13 +92,13 @@ "start-server-and-test": "^1.10.11" }, "scripts": { - "start": "backstage-cli app:serve", - "build": "backstage-cli app:build", - "clean": "backstage-cli clean", - "test": "backstage-cli test", + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "clean": "backstage-cli package clean", + "test": "backstage-cli package test", "test:e2e": "start-server-and-test start http://localhost:3000 cy:dev", "test:e2e:ci": "start-server-and-test start http://localhost:3000 cy:run", - "lint": "backstage-cli lint", + "lint": "backstage-cli package lint", "cy:dev": "cypress open", "cy:run": "cypress run" }, diff --git a/packages/app/src/components/Root/Root.tsx b/packages/app/src/components/Root/Root.tsx index 57f1fa536f..2441ace27b 100644 --- a/packages/app/src/components/Root/Root.tsx +++ b/packages/app/src/components/Root/Root.tsx @@ -34,10 +34,7 @@ import { Settings as SidebarSettings, UserSettingsSignInAvatar, } from '@backstage/plugin-user-settings'; -import { - SidebarSearchModal, - SearchContextProvider, -} from '@backstage/plugin-search'; +import { SidebarSearchModal } from '@backstage/plugin-search'; import { Shortcuts } from '@backstage/plugin-shortcuts'; import { Sidebar, @@ -89,9 +86,7 @@ export const Root = ({ children }: PropsWithChildren<{}>) => ( } to="/search"> - - - + }> diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index 13a34a1d81..092a8b1ea7 100644 --- a/packages/backend-common/package.json +++ b/packages/backend-common/package.json @@ -11,6 +11,9 @@ "types": "dist/index.d.ts", "alphaTypes": "dist/index.alpha.d.ts" }, + "backstage": { + "role": "node-library" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -22,12 +25,13 @@ ], "license": "Apache-2.0", "scripts": { - "build": "backstage-cli build --experimental-type-build --outputs cjs,types", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build --experimental-type-build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean", + "start": "backstage-cli package start" }, "dependencies": { "@backstage/cli-common": "^0.1.6", @@ -53,7 +57,7 @@ "express-promise-router": "^4.1.0", "fs-extra": "9.1.0", "git-url-parse": "^11.6.0", - "helmet": "^4.0.0", + "helmet": "^5.0.2", "isomorphic-git": "^1.8.0", "jose": "^1.27.1", "keyv": "^4.0.3", diff --git a/packages/backend-common/src/database/util.ts b/packages/backend-common/src/database/util.ts index 607554f294..a96eeb3a7b 100644 --- a/packages/backend-common/src/database/util.ts +++ b/packages/backend-common/src/database/util.ts @@ -27,7 +27,7 @@ export function isDatabaseConflictError(e: unknown) { return ( typeof message === 'string' && - (/SQLITE_CONSTRAINT: UNIQUE/.test(message) || + (/SQLITE_CONSTRAINT(?:_UNIQUE)?: UNIQUE/.test(message) || /unique constraint/.test(message)) ); } diff --git a/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts b/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts index d155287b34..105704159b 100644 --- a/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts +++ b/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts @@ -19,7 +19,7 @@ import compression from 'compression'; import cors from 'cors'; import express, { Router, ErrorRequestHandler } from 'express'; import helmet from 'helmet'; -import { ContentSecurityPolicyOptions } from 'helmet/dist/middlewares/content-security-policy'; +import { ContentSecurityPolicyOptions } from 'helmet/dist/types/middlewares/content-security-policy'; import * as http from 'http'; import stoppable from 'stoppable'; import { Logger } from 'winston'; @@ -215,8 +215,17 @@ export class ServiceBuilderImpl implements ServiceBuilder { httpsSettings: this.httpsSettings, helmetOptions: { contentSecurityPolicy: { + useDefaults: false, directives: applyCspDirectives(this.cspOptions), }, + // These are all disabled in order to maintain backwards compatibility + // when bumping helmet v5. We can't enable these by default because + // there is no way for users to configure them. + // TODO(Rugvip): We should give control of this setup to consumers + crossOriginEmbedderPolicy: false, + crossOriginOpenerPolicy: false, + crossOriginResourcePolicy: false, + originAgentCluster: false, }, }; } @@ -232,6 +241,11 @@ export function applyCspDirectives( // It should be replaced by any other solution that doesn't require unsafe-eval. result['script-src'] = ["'self'", "'unsafe-eval'"]; + // TODO(Rugvip): This is removed so that we maintained backwards compatibility + // when bumping to helmet v5, we could remove this as well as + // skip setting `useDefaults: false` in the future. + delete result['form-action']; + if (directives) { for (const [key, value] of Object.entries(directives)) { if (value === false) { diff --git a/packages/backend-tasks/package.json b/packages/backend-tasks/package.json index 364f1d1380..eca6f64f81 100644 --- a/packages/backend-tasks/package.json +++ b/packages/backend-tasks/package.json @@ -10,6 +10,9 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "node-library" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -21,12 +24,13 @@ ], "license": "Apache-2.0", "scripts": { - "build": "backstage-cli build --outputs cjs,types", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean", + "start": "backstage-cli package start" }, "dependencies": { "@backstage/backend-common": "^0.10.7", diff --git a/packages/backend-test-utils/package.json b/packages/backend-test-utils/package.json index 8a9767b292..21ff0afc4b 100644 --- a/packages/backend-test-utils/package.json +++ b/packages/backend-test-utils/package.json @@ -10,6 +10,9 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "node-library" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -22,12 +25,13 @@ ], "license": "Apache-2.0", "scripts": { - "build": "backstage-cli build --outputs cjs,types", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean", + "start": "backstage-cli package start" }, "dependencies": { "@backstage/backend-common": "^0.10.7", diff --git a/packages/backend/package.json b/packages/backend/package.json index eddf7a0664..787530550a 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -5,6 +5,9 @@ "types": "src/index.ts", "license": "Apache-2.0", "private": true, + "backstage": { + "role": "backend" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -15,12 +18,12 @@ "backstage" ], "scripts": { - "build": "backstage-cli backend:bundle", + "build": "backstage-cli package build", "build-image": "docker build ../.. -f Dockerfile --tag example-backend", - "start": "backstage-cli backend:dev", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "clean": "backstage-cli clean", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", "migrate:create": "knex migrate:make -x ts" }, "dependencies": { diff --git a/packages/backend/src/plugins/permission.ts b/packages/backend/src/plugins/permission.ts index 276d16ff97..557cea9a26 100644 --- a/packages/backend/src/plugins/permission.ts +++ b/packages/backend/src/plugins/permission.ts @@ -35,8 +35,9 @@ class AllowAllPermissionPolicy implements PermissionPolicy { export default async function createPlugin( env: PluginEnvironment, ): Promise { - const { logger, discovery } = env; + const { logger, discovery, config } = env; return await createRouter({ + config, logger, discovery, policy: new AllowAllPermissionPolicy(), diff --git a/packages/catalog-client/api-report.md b/packages/catalog-client/api-report.md index 13b2e6b5f0..56ba4a834f 100644 --- a/packages/catalog-client/api-report.md +++ b/packages/catalog-client/api-report.md @@ -5,7 +5,7 @@ ```ts import { Entity } from '@backstage/catalog-model'; import { EntityName } from '@backstage/catalog-model'; -import { Location as Location_2 } from '@backstage/catalog-model'; +import { LocationSpec } from '@backstage/catalog-model'; // @public export type AddLocationRequest = { @@ -32,27 +32,23 @@ export interface CatalogApi { options?: CatalogRequestOptions, ): Promise; getEntities( - request?: CatalogEntitiesRequest, + request?: GetEntitiesRequest, options?: CatalogRequestOptions, - ): Promise>; + ): Promise; getEntityAncestors( - request: CatalogEntityAncestorsRequest, + request: GetEntityAncestorsRequest, options?: CatalogRequestOptions, - ): Promise; + ): Promise; getEntityByName( name: EntityName, options?: CatalogRequestOptions, ): Promise; - getLocationByEntity( - entity: Entity, - options?: CatalogRequestOptions, - ): Promise; getLocationById( id: string, options?: CatalogRequestOptions, ): Promise; - getOriginLocationByEntity( - entity: Entity, + getLocationByRef( + locationRef: string, options?: CatalogRequestOptions, ): Promise; refreshEntity( @@ -71,23 +67,31 @@ export interface CatalogApi { // @public export class CatalogClient implements CatalogApi { - constructor(options: { discoveryApi: DiscoveryApi; fetchApi?: FetchApi }); + constructor(options: { + discoveryApi: { + getBaseUrl(pluginId: string): Promise; + }; + fetchApi?: { + fetch: typeof fetch; + }; + }); addLocation( { type, target, dryRun, presence }: AddLocationRequest, options?: CatalogRequestOptions, ): Promise; getEntities( - request?: CatalogEntitiesRequest, + request?: GetEntitiesRequest, options?: CatalogRequestOptions, - ): Promise>; + ): Promise; getEntityAncestors( - request: CatalogEntityAncestorsRequest, + request: GetEntityAncestorsRequest, options?: CatalogRequestOptions, - ): Promise; + ): Promise; getEntityByName( compoundName: EntityName, options?: CatalogRequestOptions, ): Promise; + // @deprecated (undocumented) getLocationByEntity( entity: Entity, options?: CatalogRequestOptions, @@ -96,6 +100,11 @@ export class CatalogClient implements CatalogApi { id: string, options?: CatalogRequestOptions, ): Promise; + getLocationByRef( + locationRef: string, + options?: CatalogRequestOptions, + ): Promise; + // @deprecated (undocumented) getOriginLocationByEntity( entity: Entity, options?: CatalogRequestOptions, @@ -114,53 +123,66 @@ export class CatalogClient implements CatalogApi { ): Promise; } -// @public -export type CatalogEntitiesRequest = { - filter?: - | Record[] - | Record - | undefined; - fields?: string[] | undefined; - offset?: number; - limit?: number; - after?: string; -}; +// @public @deprecated (undocumented) +export type CatalogEntitiesRequest = GetEntitiesRequest; + +// @public @deprecated (undocumented) +export type CatalogEntityAncestorsRequest = GetEntityAncestorsRequest; + +// @public @deprecated (undocumented) +export type CatalogEntityAncestorsResponse = GetEntityAncestorsResponse; + +// @public @deprecated (undocumented) +export type CatalogListResponse<_Entity> = GetEntitiesResponse; // @public -export type CatalogEntityAncestorsRequest = { - entityRef: string; -}; - -// @public -export type CatalogEntityAncestorsResponse = { - rootEntityRef: string; - items: { - entity: Entity; - parentEntityRefs: string[]; - }[]; -}; - -// @public -export type CatalogListResponse = { - items: T[]; -}; - -// @public -export type CatalogRequestOptions = { +export interface CatalogRequestOptions { + // (undocumented) token?: string; -}; - -// @public -export type DiscoveryApi = { - getBaseUrl(pluginId: string): Promise; -}; +} // @public export const ENTITY_STATUS_CATALOG_PROCESSING_TYPE = 'backstage.io/catalog-processing'; // @public -export type FetchApi = { - fetch: typeof fetch; -}; +export interface GetEntitiesRequest { + after?: string; + fields?: string[] | undefined; + filter?: + | Record[] + | Record + | undefined; + limit?: number; + offset?: number; +} + +// @public +export interface GetEntitiesResponse { + // (undocumented) + items: Entity[]; +} + +// @public +export interface GetEntityAncestorsRequest { + // (undocumented) + entityRef: string; +} + +// @public +export interface GetEntityAncestorsResponse { + // (undocumented) + items: Array<{ + entity: Entity; + parentEntityRefs: string[]; + }>; + // (undocumented) + rootEntityRef: string; +} + +// @public +type Location_2 = { + id: string; +} & LocationSpec; +export { Location_2 as Location }; ``` diff --git a/packages/catalog-client/package.json b/packages/catalog-client/package.json index 3a45a74680..eb24c3100c 100644 --- a/packages/catalog-client/package.json +++ b/packages/catalog-client/package.json @@ -12,6 +12,9 @@ "module": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "common-library" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -22,12 +25,12 @@ "backstage" ], "scripts": { - "build": "backstage-cli build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/catalog-model": "^0.9.10", diff --git a/packages/catalog-client/src/CatalogClient.test.ts b/packages/catalog-client/src/CatalogClient.test.ts index 1331f8e874..0035691f2c 100644 --- a/packages/catalog-client/src/CatalogClient.test.ts +++ b/packages/catalog-client/src/CatalogClient.test.ts @@ -18,7 +18,7 @@ import { Entity } from '@backstage/catalog-model'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { CatalogClient } from './CatalogClient'; -import { CATALOG_FILTER_EXISTS, CatalogListResponse } from './types/api'; +import { CATALOG_FILTER_EXISTS, GetEntitiesResponse } from './types/api'; import { DiscoveryApi } from './types/discovery'; const server = setupServer(); @@ -60,7 +60,7 @@ describe('CatalogClient', () => { }, }, ]; - const defaultResponse: CatalogListResponse = { + const defaultResponse: GetEntitiesResponse = { items: defaultServiceResponse.reverse(), }; diff --git a/packages/catalog-client/src/CatalogClient.ts b/packages/catalog-client/src/CatalogClient.ts index a446d249c0..583f5a85bd 100644 --- a/packages/catalog-client/src/CatalogClient.ts +++ b/packages/catalog-client/src/CatalogClient.ts @@ -15,14 +15,13 @@ */ import { + ANNOTATION_LOCATION, + ANNOTATION_ORIGIN_LOCATION, Entity, EntityName, - Location, - LOCATION_ANNOTATION, - ORIGIN_LOCATION_ANNOTATION, parseEntityRef, stringifyEntityRef, - stringifyLocationReference, + stringifyLocationRef, } from '@backstage/catalog-model'; import { ResponseError } from '@backstage/errors'; import crossFetch from 'cross-fetch'; @@ -31,43 +30,41 @@ import { AddLocationRequest, AddLocationResponse, CatalogApi, - CatalogEntitiesRequest, - CatalogListResponse, + GetEntitiesRequest, + GetEntitiesResponse, CatalogRequestOptions, - CatalogEntityAncestorsRequest, - CatalogEntityAncestorsResponse, + GetEntityAncestorsRequest, + GetEntityAncestorsResponse, + Location, } from './types/api'; import { DiscoveryApi } from './types/discovery'; import { FetchApi } from './types/fetch'; /** - * A frontend and backend compatible client for communicating with the Backstage Catalog. + * A frontend and backend compatible client for communicating with the Backstage + * software catalog. * * @public - * */ + */ export class CatalogClient implements CatalogApi { private readonly discoveryApi: DiscoveryApi; private readonly fetchApi: FetchApi; - constructor(options: { discoveryApi: DiscoveryApi; fetchApi?: FetchApi }) { + constructor(options: { + discoveryApi: { getBaseUrl(pluginId: string): Promise }; + fetchApi?: { fetch: typeof fetch }; + }) { this.discoveryApi = options.discoveryApi; this.fetchApi = options.fetchApi || { fetch: crossFetch }; } /** - * Gets the Ancestors of an Entity. - * - * @param request - A request type for retrieving Entity ancestors. - * @param options - An object with your preferred options. - * - * @returns A CatalogEntityAncestorsResponse. - * - * @public + * {@inheritdoc CatalogApi.getEntityAncestors} */ async getEntityAncestors( - request: CatalogEntityAncestorsRequest, + request: GetEntityAncestorsRequest, options?: CatalogRequestOptions, - ): Promise { + ): Promise { const { kind, namespace, name } = parseEntityRef(request.entityRef); return await this.requestRequired( 'GET', @@ -79,14 +76,7 @@ export class CatalogClient implements CatalogApi { } /** - * Gets a Location by Id. - * - * @param id - A string containing the Id. - * @param options - An object with your preferred options. - * - * @returns A {@link catalog-model#Location_2}. - * - * @public + * {@inheritdoc CatalogApi.getLocationById} */ async getLocationById( id: string, @@ -100,19 +90,12 @@ export class CatalogClient implements CatalogApi { } /** - * Gets a set of Entities. - * - * @param request - A request type for retrieving an Entity. - * @param options - An object with your preferred options. - * - * @returns A CatalogListResponse. - * - * @public + * {@inheritdoc CatalogApi.getEntities} */ async getEntities( - request?: CatalogEntitiesRequest, + request?: GetEntitiesRequest, options?: CatalogRequestOptions, - ): Promise> { + ): Promise { const { filter = [], fields = [], offset, limit, after } = request ?? {}; const filterItems = [filter].flat(); const params: string[] = []; @@ -187,14 +170,7 @@ export class CatalogClient implements CatalogApi { } /** - * Gets a given Entity based on a provided name. - * - * @param compoundName - A string containing the name. - * @param options - An object with your preferred options. - * - * @returns An {@link catalog-model#Entity}. - * - * @public + * {@inheritdoc CatalogApi.getEntityByName} */ async getEntityByName( compoundName: EntityName, @@ -211,12 +187,7 @@ export class CatalogClient implements CatalogApi { } /** - * Refreshes an Entity. - * - * @param entityRef - A string containing the entityREf - * @param options - An object with your preferred options. - * - * @public + * {@inheritdoc CatalogApi.refreshEntity} */ async refreshEntity(entityRef: string, options?: CatalogRequestOptions) { const response = await this.fetchApi.fetch( @@ -237,14 +208,7 @@ export class CatalogClient implements CatalogApi { } /** - * Adds a location. - * - * @param options - An object with your preferred options. - * @param AddLocationRequest - A request object for adding locations. - * - * @returns An AddLocationResponse - * - * @public + * {@inheritdoc CatalogApi.addLocation} */ async addLocation( { type = 'url', target, dryRun, presence }: AddLocationRequest, @@ -282,21 +246,14 @@ export class CatalogClient implements CatalogApi { } /** - * Gets an origin Location By Entity. - * - * @param entity - An Entity - * @param options - An object with your preferred options. - * - * @returns A {@link catalog-model#Location_2}. - * - * @public + * @deprecated please use getLocationByRef instead */ async getOriginLocationByEntity( entity: Entity, options?: CatalogRequestOptions, ): Promise { const locationCompound = - entity.metadata.annotations?.[ORIGIN_LOCATION_ANNOTATION]; + entity.metadata.annotations?.[ANNOTATION_ORIGIN_LOCATION]; if (!locationCompound) { return undefined; } @@ -307,24 +264,17 @@ export class CatalogClient implements CatalogApi { ); return all .map(r => r.data) - .find(l => locationCompound === stringifyLocationReference(l)); + .find(l => locationCompound === stringifyLocationRef(l)); } /** - * Gets a Location by Entity. - * - * @param entity - An Entity - * @param options - An object with your preferred options. - * - * @returns A {@link catalog-model#Location_2}. - * - * @public + * @deprecated please use getLocationByRef instead */ async getLocationByEntity( entity: Entity, options?: CatalogRequestOptions, ): Promise { - const locationCompound = entity.metadata.annotations?.[LOCATION_ANNOTATION]; + const locationCompound = entity.metadata.annotations?.[ANNOTATION_LOCATION]; if (!locationCompound) { return undefined; } @@ -335,16 +285,28 @@ export class CatalogClient implements CatalogApi { ); return all .map(r => r.data) - .find(l => locationCompound === stringifyLocationReference(l)); + .find(l => locationCompound === stringifyLocationRef(l)); } /** - * Removes a location as identified by Id. - * - * @param id - A string containing the Id - * @param options - An object with your preferred options. - * - * @public + * {@inheritdoc CatalogApi.getLocationByRef} + */ + async getLocationByRef( + locationRef: string, + options?: CatalogRequestOptions, + ): Promise { + const all: { data: Location }[] = await this.requestRequired( + 'GET', + '/locations', + options, + ); + return all + .map(r => r.data) + .find(l => locationRef === stringifyLocationRef(l)); + } + + /** + * {@inheritdoc CatalogApi.removeLocationById} */ async removeLocationById( id: string, @@ -358,12 +320,7 @@ export class CatalogClient implements CatalogApi { } /** - * Removes an Entity as identified by Uid. - * - * @param uid - A string containing the Uid - * @param options - An object with your preferred options. - * - * @public + * {@inheritdoc CatalogApi.removeEntityByUid} */ async removeEntityByUid( uid: string, diff --git a/packages/catalog-client/src/types/api.ts b/packages/catalog-client/src/types/api.ts index 0622d654fa..b3d4bc2397 100644 --- a/packages/catalog-client/src/types/api.ts +++ b/packages/catalog-client/src/types/api.ts @@ -14,21 +14,26 @@ * limitations under the License. */ -import { Entity, EntityName, Location } from '@backstage/catalog-model'; +import { Entity, EntityName, LocationSpec } from '@backstage/catalog-model'; /** - * A Symbol to define if a catalog filter exists or not. + * This symbol can be used in place of a value when passed to filters in e.g. + * {@link CatalogClient.getEntities}, to signify that you want to filter on the + * presence of that key no matter what its value is. * * @public */ -export const CATALOG_FILTER_EXISTS = Symbol('CATALOG_FILTER_EXISTS'); +export const CATALOG_FILTER_EXISTS = Symbol.for( + // Random UUID to ensure no collisions + 'CATALOG_FILTER_EXISTS_0e15b590c0b343a2bae3e787e84c2111', +); /** - * A request type for retrieving catalog Entities. + * The request type for {@link CatalogClient.getEntities}. * * @public */ -export type CatalogEntitiesRequest = { +export interface GetEntitiesRequest { /** * If given, return only entities that match the given patterns. * @@ -104,175 +109,59 @@ export type CatalogEntitiesRequest = { * request. */ after?: string; -}; +} /** - * A request type for Catalog Entity Ancestor information. + * The response type for {@link CatalogClient.getEntities}. * * @public */ -export type CatalogEntityAncestorsRequest = { +export interface GetEntitiesResponse { + items: Entity[]; +} + +/** + * The request type for {@link CatalogClient.getEntityAncestors}. + * + * @public + */ +export interface GetEntityAncestorsRequest { entityRef: string; -}; +} /** - * A response type for Catalog Entity Ancestor information. + * The response type for {@link CatalogClient.getEntityAncestors}. * * @public */ -export type CatalogEntityAncestorsResponse = { +export interface GetEntityAncestorsResponse { rootEntityRef: string; - items: { entity: Entity; parentEntityRefs: string[] }[]; -}; - -/** - * A response type for the result of a catalog operation in list form. - * - * @public - */ -export type CatalogListResponse = { - items: T[]; -}; + items: Array<{ + entity: Entity; + parentEntityRefs: string[]; + }>; +} /** * Options you can pass into a catalog request for additional information. * * @public */ -export type CatalogRequestOptions = { +export interface CatalogRequestOptions { token?: string; -}; - -/** - * Public functions for interacting with the Catalog API. - * - * @public - */ -export interface CatalogApi { - /** - * Gets the Entities from the catalog based on your request and options. - * - * @param request - An object with your filters and fields. - * @param options - An object with your preferred options. - * - * @returns A CatalogListResponse with items typed Catalog Model Entity. - * - */ - getEntities( - request?: CatalogEntitiesRequest, - options?: CatalogRequestOptions, - ): Promise>; - /** - * Gets the Entity ancestor information from the catalog based on your request and options. - * - * @param request - An object with your filters and fields. - * @param options - An object with your preferred options. - * - * @returns A CatalogEntityAncestorsResponse. - */ - getEntityAncestors( - request: CatalogEntityAncestorsRequest, - options?: CatalogRequestOptions, - ): Promise; - /** - * Gets a single Entity from the catalog by Entity name. - * - * @param name - A complete Entity name, with the full kind-namespace-name triplet. - * @param options - An object with your preferred options. - * - * @returns A {@link catalog-model#Entity}. - */ - getEntityByName( - name: EntityName, - options?: CatalogRequestOptions, - ): Promise; - /** - * Removes a single Entity from the catalog by Entity UID. - * - * @param uid - A string of the Entity UID. - * @param options - An object with your preferred options. - * - */ - removeEntityByUid( - uid: string, - options?: CatalogRequestOptions, - ): Promise; - /** - * Refreshes an Entity in the catalog. - * - * @param entityRef - A string in the form of 'Kind/default:foo'. - * @param options - An object with your preferred options. - * - */ - refreshEntity( - entityRef: string, - options?: CatalogRequestOptions, - ): Promise; - - // Locations - /** - * Gets a Location object by ID from the catalog. - * - * @param id - A string in of the Location Id. - * @param options - An object with your preferred options. - * - * @returns A {@link catalog-model#Location_2}. - */ - getLocationById( - id: string, - options?: CatalogRequestOptions, - ): Promise; - /** - * Gets origin location by Entity. - * - * @param entity - An {@link catalog-model#Entity}. - * @param options - An object with your preferred options. - * - * @returns A {@link catalog-model#Location_2}. - */ - getOriginLocationByEntity( - entity: Entity, - options?: CatalogRequestOptions, - ): Promise; - /** - * Gets Location by Entity. - * - * @param entity - An {@link catalog-model#Entity}. - * @param options - An object with your preferred options. - * - * @returns A {@link catalog-model#Location_2}. - */ - getLocationByEntity( - entity: Entity, - options?: CatalogRequestOptions, - ): Promise; - /** - * Adds a Location. - * - * @param location - A request type for adding a Location to the catalog. - * @param options - An object with your preferred options. - * - * @returns A AddLocationResponse. - */ - addLocation( - location: AddLocationRequest, - options?: CatalogRequestOptions, - ): Promise; - /** - * Removes a Location by Id. - * - * @param id - A string in of the Location Id. - * @param options - An object with your preferred options. - * - */ - removeLocationById( - id: string, - options?: CatalogRequestOptions, - ): Promise; } /** - * A request type for adding a Location to the catalog. + * Entity location for a specific entity. + * + * @public + */ +export type Location = { + id: string; +} & LocationSpec; + +/** + * The request type for {@link CatalogClient.addLocation}. * * @public */ @@ -284,13 +173,124 @@ export type AddLocationRequest = { }; /** - * A response type for adding a Location to the catalog. + * The response type for {@link CatalogClient.addLocation}. * * @public */ export type AddLocationResponse = { location: Location; entities: Entity[]; - // Exists is only set in DryRun mode. + // Only set in dryRun mode. exists?: boolean; }; + +/** + * A client for interacting with the Backstage software catalog through its API. + * + * @public + */ +export interface CatalogApi { + /** + * Lists catalog entities. + * + * @param request - Request parameters + * @param options - Additional options + */ + getEntities( + request?: GetEntitiesRequest, + options?: CatalogRequestOptions, + ): Promise; + + /** + * Gets entity ancestor information, i.e. the hierarchy of parent entities + * whose processing resulted in a given entity appearing in the catalog. + * + * @param request - Request parameters + * @param options - Additional options + */ + getEntityAncestors( + request: GetEntityAncestorsRequest, + options?: CatalogRequestOptions, + ): Promise; + + /** + * Gets a single entity from the catalog by its ref (kind, namespace, name) + * triplet. + * + * @param name - A complete entity ref + * @param options - Additional options + */ + getEntityByName( + name: EntityName, + options?: CatalogRequestOptions, + ): Promise; + + /** + * Removes a single entity from the catalog by entity UID. + * + * @param uid - An entity UID + * @param options - Additional options + */ + removeEntityByUid( + uid: string, + options?: CatalogRequestOptions, + ): Promise; + + /** + * Refreshes (marks for reprocessing) an entity in the catalog. + * + * @param entityRef - An entity ref on string form (e.g. + * 'component/default:my-component') + * @param options - Additional options + */ + refreshEntity( + entityRef: string, + options?: CatalogRequestOptions, + ): Promise; + + // Locations + + /** + * Gets a registered location by its ID. + * + * @param id - A location ID + * @param options - Additional options + */ + getLocationById( + id: string, + options?: CatalogRequestOptions, + ): Promise; + + /** + * Gets a registered location by its ref. + * + * @param locationRef - A location ref, e.g. "url:https://github.com/..." + * @param options - Additional options + */ + getLocationByRef( + locationRef: string, + options?: CatalogRequestOptions, + ): Promise; + + /** + * Registers a new location. + * + * @param location - Request parameters + * @param options - Additional options + */ + addLocation( + location: AddLocationRequest, + options?: CatalogRequestOptions, + ): Promise; + + /** + * Removes a registered Location by its ID. + * + * @param id - A location ID + * @param options - Additional options + */ + removeLocationById( + id: string, + options?: CatalogRequestOptions, + ): Promise; +} diff --git a/packages/catalog-client/src/types/deprecated.ts b/packages/catalog-client/src/types/deprecated.ts new file mode 100644 index 0000000000..0b145f3024 --- /dev/null +++ b/packages/catalog-client/src/types/deprecated.ts @@ -0,0 +1,43 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + GetEntitiesRequest, + GetEntitiesResponse, + GetEntityAncestorsRequest, + GetEntityAncestorsResponse, +} from './api'; + +/** + * @public + * @deprecated use GetEntitiesRequest instead + */ +export type CatalogEntitiesRequest = GetEntitiesRequest; +/** + * @public + * @deprecated use GetEntitiesResponse instead + */ +export type CatalogListResponse<_Entity> = GetEntitiesResponse; +/** + * @public + * @deprecated use GetEntityAncestorsRequest instead + */ +export type CatalogEntityAncestorsRequest = GetEntityAncestorsRequest; +/** + * @public + * @deprecated use GetEntityAncestorsResponse instead + */ +export type CatalogEntityAncestorsResponse = GetEntityAncestorsResponse; diff --git a/packages/catalog-client/src/types/discovery.ts b/packages/catalog-client/src/types/discovery.ts index 5fa14372e3..19f304b1fd 100644 --- a/packages/catalog-client/src/types/discovery.ts +++ b/packages/catalog-client/src/types/discovery.ts @@ -16,8 +16,6 @@ /** * This is a copy of the DiscoveryApi, to avoid importing core-plugin-api. - * - * @public */ export type DiscoveryApi = { getBaseUrl(pluginId: string): Promise; diff --git a/packages/catalog-client/src/types/fetch.ts b/packages/catalog-client/src/types/fetch.ts index 59de6a68f1..047a9f3558 100644 --- a/packages/catalog-client/src/types/fetch.ts +++ b/packages/catalog-client/src/types/fetch.ts @@ -16,8 +16,6 @@ /** * This is a copy of FetchApi, to avoid importing core-plugin-api. - * - * @public */ export type FetchApi = { fetch: typeof fetch; diff --git a/packages/catalog-client/src/types/index.ts b/packages/catalog-client/src/types/index.ts index f3c6fab4e9..580bb7330d 100644 --- a/packages/catalog-client/src/types/index.ts +++ b/packages/catalog-client/src/types/index.ts @@ -14,17 +14,17 @@ * limitations under the License. */ +export { CATALOG_FILTER_EXISTS } from './api'; export type { AddLocationRequest, AddLocationResponse, CatalogApi, - CatalogEntitiesRequest, - CatalogListResponse, CatalogRequestOptions, - CatalogEntityAncestorsRequest, - CatalogEntityAncestorsResponse, + GetEntitiesRequest, + GetEntitiesResponse, + GetEntityAncestorsRequest, + GetEntityAncestorsResponse, + Location, } from './api'; -export type { DiscoveryApi } from './discovery'; -export type { FetchApi } from './fetch'; -export { CATALOG_FILTER_EXISTS } from './api'; export { ENTITY_STATUS_CATALOG_PROCESSING_TYPE } from './status'; +export * from './deprecated'; diff --git a/packages/catalog-model/api-report.md b/packages/catalog-model/api-report.md index a0460fc4f2..9a0991a9dc 100644 --- a/packages/catalog-model/api-report.md +++ b/packages/catalog-model/api-report.md @@ -7,17 +7,27 @@ import { JsonObject } from '@backstage/types'; import { JSONSchema7 } from 'json-schema'; import { JsonValue } from '@backstage/types'; import { SerializedError } from '@backstage/errors'; -import * as yup from 'yup'; // @alpha export interface AlphaEntity extends Entity { status?: EntityStatus; } -// @public @deprecated -export const analyzeLocationSchema: yup.SchemaOf<{ - location: LocationSpec; -}>; +// @public +export const ANNOTATION_EDIT_URL = 'backstage.io/edit-url'; + +// @public +export const ANNOTATION_LOCATION = 'backstage.io/managed-by-location'; + +// @public +export const ANNOTATION_ORIGIN_LOCATION = + 'backstage.io/managed-by-origin-location'; + +// @public +export const ANNOTATION_SOURCE_LOCATION = 'backstage.io/source-location'; + +// @public +export const ANNOTATION_VIEW_URL = 'backstage.io/view-url'; // @public interface ApiEntityV1alpha1 extends Entity { @@ -56,11 +66,14 @@ export class CommonValidatorFunctions { static isValidUrl(value: unknown): boolean; } -// @public +// @public @deprecated export function compareEntityToRef( entity: Entity, ref: EntityRef | EntityName, - context?: EntityRefContext, + context?: { + defaultKind?: string; + defaultNamespace?: string; + }, ): boolean; // @public @@ -87,6 +100,9 @@ export { ComponentEntityV1alpha1 }; // @public export const componentEntityV1alpha1Validator: KindValidator; +// @public +export const DEFAULT_NAMESPACE = 'default'; + // @public export class DefaultNamespaceEntityPolicy implements EntityPolicy { constructor(namespace?: string); @@ -111,7 +127,7 @@ export { DomainEntityV1alpha1 }; // @public export const domainEntityV1alpha1Validator: KindValidator; -// @public +// @public @deprecated export const EDIT_URL_ANNOTATION = 'backstage.io/edit-url'; // @public @@ -123,10 +139,10 @@ export type Entity = { relations?: EntityRelation[]; }; -// @public +// @public @deprecated export const ENTITY_DEFAULT_NAMESPACE = 'default'; -// @public +// @public @deprecated export const ENTITY_META_GENERATED_FIELDS: readonly [ 'uid', 'etag', @@ -148,7 +164,7 @@ export function entityEnvelopeSchemaValidator< T extends EntityEnvelope = EntityEnvelope, >(schema?: unknown): (data: unknown) => T; -// @public +// @public @deprecated export function entityHasChanges(previous: Entity, next: Entity): boolean; // @public @@ -205,7 +221,7 @@ export type EntityRef = name: string; }; -// @public +// @public @deprecated export type EntityRefContext = { defaultKind?: string; defaultNamespace?: string; @@ -252,13 +268,13 @@ export class FieldFormatEntityPolicy implements EntityPolicy { enforce(entity: Entity): Promise; } -// @public +// @public @deprecated export function generateEntityEtag(): string; -// @public +// @public @deprecated export function generateEntityUid(): string; -// @public +// @public @deprecated export function generateUpdatedEntity(previous: Entity, next: Entity): Entity; // @public @@ -325,13 +341,13 @@ export class KubernetesValidatorFunctions { static isValidObjectName(value: unknown): boolean; } -// @public +// @public @deprecated type Location_2 = { id: string; } & LocationSpec; export { Location_2 as Location }; -// @public +// @public @deprecated export const LOCATION_ANNOTATION = 'backstage.io/managed-by-location'; // @public @@ -354,9 +370,6 @@ export { LocationEntityV1alpha1 }; // @public export const locationEntityV1alpha1Validator: KindValidator; -// @public @deprecated -export const locationSchema: yup.SchemaOf; - // @public export type LocationSpec = { type: string; @@ -364,9 +377,6 @@ export type LocationSpec = { presence?: 'optional' | 'required'; }; -// @public @deprecated -export const locationSpecSchema: yup.SchemaOf; - // @public export function makeValidator(overrides?: Partial): Validators; @@ -377,14 +387,17 @@ export class NoForeignRootFieldsEntityPolicy implements EntityPolicy { enforce(entity: Entity): Promise; } -// @public +// @public @deprecated export const ORIGIN_LOCATION_ANNOTATION = 'backstage.io/managed-by-origin-location'; // @public export function parseEntityName( ref: EntityRef, - context?: EntityRefContext, + context?: { + defaultKind?: string; + defaultNamespace?: string; + }, ): EntityName; // @public @@ -421,6 +434,12 @@ export function parseEntityRef( }; // @public +export function parseLocationRef(ref: string): { + type: string; + target: string; +}; + +// @public @deprecated export function parseLocationReference(ref: string): { type: string; target: string; @@ -496,17 +515,6 @@ export class SchemaValidEntityPolicy implements EntityPolicy { } // @public @deprecated -export function serializeEntityRef( - ref: - | Entity - | { - kind?: string; - namespace?: string; - name: string; - }, -): EntityRef; - -// @public export const SOURCE_LOCATION_ANNOTATION = 'backstage.io/source-location'; // @public @@ -521,6 +529,12 @@ export function stringifyEntityRef( ): string; // @public +export function stringifyLocationRef(ref: { + type: string; + target: string; +}): string; + +// @public @deprecated export function stringifyLocationReference(ref: { type: string; target: string; @@ -544,33 +558,6 @@ export { SystemEntityV1alpha1 }; // @public export const systemEntityV1alpha1Validator: KindValidator; -// @public -export interface TemplateEntityV1beta2 extends Entity { - // (undocumented) - apiVersion: 'backstage.io/v1beta2'; - // (undocumented) - kind: 'Template'; - // (undocumented) - spec: { - type: string; - parameters?: JsonObject | JsonObject[]; - steps: Array<{ - id?: string; - name?: string; - action: string; - input?: JsonObject; - if?: string | boolean; - }>; - output?: { - [name: string]: string; - }; - owner?: string; - }; -} - -// @public -export const templateEntityV1beta2Validator: KindValidator; - // @public interface UserEntityV1alpha1 extends Entity { // (undocumented) @@ -606,6 +593,6 @@ export type Validators = { isValidTag(value: unknown): boolean; }; -// @public +// @public @deprecated export const VIEW_URL_ANNOTATION = 'backstage.io/view-url'; ``` diff --git a/packages/catalog-model/package.json b/packages/catalog-model/package.json index efe32cccff..9cc8807a29 100644 --- a/packages/catalog-model/package.json +++ b/packages/catalog-model/package.json @@ -13,6 +13,9 @@ "types": "dist/index.d.ts", "alphaTypes": "dist/index.alpha.d.ts" }, + "backstage": { + "role": "common-library" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -23,24 +26,22 @@ "backstage" ], "scripts": { - "build": "backstage-cli build --experimental-type-build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build --experimental-type-build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/config": "^0.1.13", "@backstage/errors": "^0.2.0", "@backstage/types": "^0.1.1", "@types/json-schema": "^7.0.5", - "@types/yup": "^0.29.13", "ajv": "^7.0.3", "json-schema": "^0.4.0", "lodash": "^4.17.21", - "uuid": "^8.0.0", - "yup": "^0.32.9" + "uuid": "^8.0.0" }, "devDependencies": { "@backstage/cli": "^0.13.2-next.0", diff --git a/packages/catalog-model/src/entity/constants.ts b/packages/catalog-model/src/entity/constants.ts index 6daf6b78d9..6cef19cac9 100644 --- a/packages/catalog-model/src/entity/constants.ts +++ b/packages/catalog-model/src/entity/constants.ts @@ -18,13 +18,22 @@ * The namespace that entities without an explicit namespace fall into. * * @public + * @deprecated use {@link DEFAULT_NAMESPACE} instead. */ export const ENTITY_DEFAULT_NAMESPACE = 'default'; +/** + * The namespace that entities without an explicit namespace fall into. + * + * @public + */ +export const DEFAULT_NAMESPACE = 'default'; + /** * The keys of EntityMeta that are auto-generated. * * @public + * @deprecated will be removed in a future release. */ export const ENTITY_META_GENERATED_FIELDS = [ 'uid', @@ -36,6 +45,7 @@ export const ENTITY_META_GENERATED_FIELDS = [ * Annotation for linking to entity page from catalog pages. * * @public + * @deprecated use {@link ANNOTATION_VIEW_URL} instead. */ export const VIEW_URL_ANNOTATION = 'backstage.io/view-url'; @@ -43,5 +53,20 @@ export const VIEW_URL_ANNOTATION = 'backstage.io/view-url'; * Annotation for linking to entity edit page from catalog pages. * * @public + * @deprecated use {@link ANNOTATION_EDIT_URL} instead. */ export const EDIT_URL_ANNOTATION = 'backstage.io/edit-url'; + +/** + * Annotation for linking to entity page from catalog pages. + * + * @public + */ +export const ANNOTATION_VIEW_URL = 'backstage.io/view-url'; + +/** + * Annotation for linking to entity edit page from catalog pages. + * + * @public + */ +export const ANNOTATION_EDIT_URL = 'backstage.io/edit-url'; diff --git a/packages/catalog-model/src/entity/index.ts b/packages/catalog-model/src/entity/index.ts index ce1e76a20b..938bdb2b9b 100644 --- a/packages/catalog-model/src/entity/index.ts +++ b/packages/catalog-model/src/entity/index.ts @@ -17,8 +17,11 @@ export { EDIT_URL_ANNOTATION, ENTITY_DEFAULT_NAMESPACE, + DEFAULT_NAMESPACE, ENTITY_META_GENERATED_FIELDS, VIEW_URL_ANNOTATION, + ANNOTATION_EDIT_URL, + ANNOTATION_VIEW_URL, } from './constants'; export type { AlphaEntity, @@ -40,7 +43,6 @@ export { getEntityName, parseEntityName, parseEntityRef, - serializeEntityRef, stringifyEntityRef, } from './ref'; export type { EntityRefContext } from './ref'; diff --git a/packages/catalog-model/src/entity/ref.test.ts b/packages/catalog-model/src/entity/ref.test.ts index cf4bf0d869..f80b588d55 100644 --- a/packages/catalog-model/src/entity/ref.test.ts +++ b/packages/catalog-model/src/entity/ref.test.ts @@ -16,12 +16,7 @@ import { ENTITY_DEFAULT_NAMESPACE } from './constants'; import { Entity } from './Entity'; -import { - compareEntityToRef, - parseEntityName, - parseEntityRef, - serializeEntityRef, -} from './ref'; +import { compareEntityToRef, parseEntityName, parseEntityRef } from './ref'; describe('ref', () => { describe('parseEntityName', () => { @@ -329,64 +324,6 @@ describe('ref', () => { }); }); - describe('serializeEntityRef', () => { - it('handles partials', () => { - expect( - serializeEntityRef({ kind: 'a', namespace: 'b', name: 'c' }), - ).toEqual('a:b/c'); - expect(serializeEntityRef({ namespace: 'b', name: 'c' })).toEqual('b/c'); - expect(serializeEntityRef({ kind: 'a', name: 'c' })).toEqual('a:c'); - expect(serializeEntityRef({ name: 'c' })).toEqual('c'); - }); - - it('handles entities', () => { - const entityWithNamespace: Entity = { - apiVersion: 'a', - kind: 'b', - metadata: { - name: 'c', - namespace: 'd', - }, - }; - const entityWithoutNamespace: Entity = { - apiVersion: 'a', - kind: 'b', - metadata: { - name: 'c', - }, - }; - expect(serializeEntityRef(entityWithNamespace)).toEqual('b:d/c'); - expect(serializeEntityRef(entityWithoutNamespace)).toEqual('b:c'); - }); - - it('picks the least complex form', () => { - expect( - serializeEntityRef({ kind: 'a', namespace: 'b', name: 'c' }), - ).toEqual('a:b/c'); - expect(serializeEntityRef({ namespace: 'b', name: 'c' })).toEqual('b/c'); - expect(serializeEntityRef({ kind: 'a', name: 'c' })).toEqual('a:c'); - expect(serializeEntityRef({ name: 'c' })).toEqual('c'); - expect( - serializeEntityRef({ kind: 'a:x', namespace: 'b', name: 'c' }), - ).toEqual({ kind: 'a:x', namespace: 'b', name: 'c' }); - expect( - serializeEntityRef({ kind: 'a/x', namespace: 'b', name: 'c' }), - ).toEqual({ kind: 'a/x', namespace: 'b', name: 'c' }); - expect( - serializeEntityRef({ kind: 'a', namespace: 'b:x', name: 'c' }), - ).toEqual({ kind: 'a', namespace: 'b:x', name: 'c' }); - expect( - serializeEntityRef({ kind: 'a', namespace: 'b/x', name: 'c' }), - ).toEqual({ kind: 'a', namespace: 'b/x', name: 'c' }); - expect( - serializeEntityRef({ kind: 'a', namespace: 'b', name: 'c:x' }), - ).toEqual({ kind: 'a', namespace: 'b', name: 'c:x' }); - expect( - serializeEntityRef({ kind: 'a', namespace: 'b', name: 'c/x' }), - ).toEqual({ kind: 'a', namespace: 'b', name: 'c/x' }); - }); - }); - describe('compareEntityToRef', () => { const entityWithNamespace: Entity = { apiVersion: 'a', diff --git a/packages/catalog-model/src/entity/ref.ts b/packages/catalog-model/src/entity/ref.ts index 958f750e32..122fe0b31a 100644 --- a/packages/catalog-model/src/entity/ref.ts +++ b/packages/catalog-model/src/entity/ref.ts @@ -57,6 +57,7 @@ export function getEntityName(entity: Entity): EntityName { * The context of defaults that entity reference parsing happens within. * * @public + * @deprecated type inlined, will be removed in a future release. */ export type EntityRefContext = { /** The default kind, if none is given in the reference */ @@ -82,7 +83,12 @@ export type EntityRefContext = { */ export function parseEntityName( ref: EntityRef, - context: EntityRefContext = {}, + context: { + /** The default kind, if none is given in the reference */ + defaultKind?: string; + /** The default namespace, if none is given in the reference */ + defaultNamespace?: string; + } = {}, ): EntityName { const { kind, namespace, name } = parseEntityRef(ref, { defaultNamespace: ENTITY_DEFAULT_NAMESPACE, @@ -149,7 +155,12 @@ export function parseEntityRef( */ export function parseEntityRef( ref: EntityRef, - context: EntityRefContext = {}, + context: { + /** The default kind, if none is given in the reference */ + defaultKind?: string; + /** The default namespace, if none is given in the reference */ + defaultNamespace?: string; + } = {}, ): { kind?: string; namespace?: string; @@ -184,54 +195,6 @@ export function parseEntityRef( }; } -/** - * Takes an entity reference or name, and outputs an entity reference on the - * most compact form possible. I.e. if the parts do not contain any - * special/reserved characters, it outputs the string form, otherwise it - * outputs the compound form. - * - * @public - * @deprecated Use `stringifyEntityRef` instead - * @param ref - The reference to serialize - * @returns The same reference on either string or compound form - */ -export function serializeEntityRef( - ref: - | Entity - | { - kind?: string; - namespace?: string; - name: string; - }, -): EntityRef { - let kind; - let namespace; - let name; - - if ('metadata' in ref) { - kind = ref.kind; - namespace = ref.metadata.namespace; - name = ref.metadata.name; - } else { - kind = ref.kind; - namespace = ref.namespace; - name = ref.name; - } - - if ( - kind?.includes(':') || - kind?.includes('/') || - namespace?.includes(':') || - namespace?.includes('/') || - name.includes(':') || - name.includes('/') - ) { - return { kind, namespace, name }; - } - - return `${kind ? `${kind}:` : ''}${namespace ? `${namespace}/` : ''}${name}`; -} - /** * Takes an entity or entity name/reference, and returns the string form of an * entity ref. @@ -282,11 +245,17 @@ export function stringifyEntityRef( * @param context - An optional context of default kind and namespace, that apply * to the ref if given * @returns True if matching, false otherwise + * @deprecated compare using stringifyEntityRef instead. */ export function compareEntityToRef( entity: Entity, ref: EntityRef | EntityName, - context?: EntityRefContext, + context?: { + /** The default kind, if none is given in the reference */ + defaultKind?: string; + /** The default namespace, if none is given in the reference */ + defaultNamespace?: string; + }, ): boolean { const entityKind = entity.kind; const entityNamespace = entity.metadata.namespace || ENTITY_DEFAULT_NAMESPACE; diff --git a/packages/catalog-model/src/entity/util.ts b/packages/catalog-model/src/entity/util.ts index 4506a8d852..78359b45f4 100644 --- a/packages/catalog-model/src/entity/util.ts +++ b/packages/catalog-model/src/entity/util.ts @@ -23,6 +23,7 @@ import { Entity, AlphaEntity } from './Entity'; * * @public * @returns A string with enough randomness to uniquely identify an entity + * @deprecated use `uuidv4()` instead. */ export function generateEntityUid(): string { return uuidv4(); @@ -34,6 +35,7 @@ export function generateEntityUid(): string { * @public * @returns A string with enough randomness to uniquely identify an entity * revision + * @deprecated will be removed in a future release. */ export function generateEntityEtag(): string { return Buffer.from(uuidv4(), 'utf8').toString('base64').replace(/[^\w]/g, ''); @@ -55,6 +57,7 @@ export function generateEntityEtag(): string { * @public * @param previous - The old state of the entity * @param next - The new state of the entity + * @deprecated will be removed in a future release. */ export function entityHasChanges(previous: Entity, next: Entity): boolean { const e1 = lodash.cloneDeep(previous); @@ -109,6 +112,7 @@ export function entityHasChanges(previous: Entity, next: Entity): boolean { * @param previous - The old state of the entity * @param next - The new state of the entity * @returns An entity with the merged state of both + * @deprecated will be removed in a future release. */ export function generateUpdatedEntity(previous: Entity, next: Entity): Entity { const { uid, etag, generation } = previous.metadata; diff --git a/packages/catalog-model/src/kinds/index.ts b/packages/catalog-model/src/kinds/index.ts index be9f7a0d6a..7211c25a8d 100644 --- a/packages/catalog-model/src/kinds/index.ts +++ b/packages/catalog-model/src/kinds/index.ts @@ -50,8 +50,6 @@ export type { SystemEntityV1alpha1 as SystemEntity, SystemEntityV1alpha1, } from './SystemEntityV1alpha1'; -export { templateEntityV1beta2Validator } from './TemplateEntityV1beta2'; -export type { TemplateEntityV1beta2 } from './TemplateEntityV1beta2'; export type { KindValidator } from './types'; export { userEntityV1alpha1Validator } from './UserEntityV1alpha1'; export type { diff --git a/packages/catalog-model/src/location/annotation.ts b/packages/catalog-model/src/location/annotation.ts index 8eb393f555..3ff624360e 100644 --- a/packages/catalog-model/src/location/annotation.ts +++ b/packages/catalog-model/src/location/annotation.ts @@ -17,17 +17,41 @@ /** * Constant storing location annotation. * - * @public */ + * @public + * @deprecated use {@link ANNOTATION_LOCATION} instead. + * */ export const LOCATION_ANNOTATION = 'backstage.io/managed-by-location'; /** * Constant storing origin location annotation * - * @public */ + * @public + * @deprecated use {@link ANNOTATION_ORIGIN_LOCATION} instead. + */ export const ORIGIN_LOCATION_ANNOTATION = 'backstage.io/managed-by-origin-location'; /** * Contant storing source location annotation * - * @public */ + * @public + * @deprecated use {@link ANNOTATION_SOURCE_LOCATION} instead. + * */ export const SOURCE_LOCATION_ANNOTATION = 'backstage.io/source-location'; + +/** + * Constant storing location annotation. + * + * @public */ +export const ANNOTATION_LOCATION = 'backstage.io/managed-by-location'; +/** + * Constant storing origin location annotation + * + * @public */ +export const ANNOTATION_ORIGIN_LOCATION = + 'backstage.io/managed-by-origin-location'; + +/** + * Contant storing source location annotation + * + * @public */ +export const ANNOTATION_SOURCE_LOCATION = 'backstage.io/source-location'; diff --git a/packages/catalog-model/src/location/helpers.test.ts b/packages/catalog-model/src/location/helpers.test.ts index 020f7be1a1..91a2137611 100644 --- a/packages/catalog-model/src/location/helpers.test.ts +++ b/packages/catalog-model/src/location/helpers.test.ts @@ -16,47 +16,47 @@ import { getEntitySourceLocation, - parseLocationReference, - stringifyLocationReference, + parseLocationRef, + stringifyLocationRef, } from './helpers'; -describe('parseLocationReference', () => { +describe('parseLocationRef', () => { it('works for the simple case', () => { - expect(parseLocationReference('url:https://www.google.com')).toEqual({ + expect(parseLocationRef('url:https://www.google.com')).toEqual({ type: 'url', target: 'https://www.google.com', }); }); it('rejects faulty inputs', () => { - expect(() => parseLocationReference(7 as any)).toThrow( - "Unable to parse location reference '7', unexpected argument number", + expect(() => parseLocationRef(7 as any)).toThrow( + "Unable to parse location ref '7', unexpected argument number", ); - expect(() => parseLocationReference('')).toThrow( - "Unable to parse location reference '', expected ':', e.g. 'url:https://host/path'", + expect(() => parseLocationRef('')).toThrow( + "Unable to parse location ref '', expected ':', e.g. 'url:https://host/path'", ); - expect(() => parseLocationReference('hello')).toThrow( - "Unable to parse location reference 'hello', expected ':', e.g. 'url:https://host/path'", + expect(() => parseLocationRef('hello')).toThrow( + "Unable to parse location ref 'hello', expected ':', e.g. 'url:https://host/path'", ); - expect(() => parseLocationReference(':hello')).toThrow( - "Unable to parse location reference ':hello', expected ':', e.g. 'url:https://host/path'", + expect(() => parseLocationRef(':hello')).toThrow( + "Unable to parse location ref ':hello', expected ':', e.g. 'url:https://host/path'", ); - expect(() => parseLocationReference('hello:')).toThrow( - "Unable to parse location reference 'hello:', expected ':', e.g. 'url:https://host/path'", + expect(() => parseLocationRef('hello:')).toThrow( + "Unable to parse location ref 'hello:', expected ':', e.g. 'url:https://host/path'", ); - expect(() => parseLocationReference('http://blah')).toThrow( - "Invalid location reference 'http://blah', please prefix it with 'url:', e.g. 'url:http://blah'", + expect(() => parseLocationRef('http://blah')).toThrow( + "Invalid location ref 'http://blah', please prefix it with 'url:', e.g. 'url:http://blah'", ); - expect(() => parseLocationReference('https://bleh')).toThrow( - "Invalid location reference 'https://bleh', please prefix it with 'url:', e.g. 'url:https://bleh'", + expect(() => parseLocationRef('https://bleh')).toThrow( + "Invalid location ref 'https://bleh', please prefix it with 'url:', e.g. 'url:https://bleh'", ); }); }); -describe('stringifyLocationReference', () => { +describe('stringifyLocationRef', () => { it('works for the simple case', () => { expect( - stringifyLocationReference({ + stringifyLocationRef({ type: 'url', target: 'https://www.google.com', }), @@ -64,12 +64,12 @@ describe('stringifyLocationReference', () => { }); it('rejects faulty inputs', () => { - expect(() => - stringifyLocationReference({ type: '', target: 'hello' }), - ).toThrow('Unable to stringify location reference, empty type'); - expect(() => - stringifyLocationReference({ type: 'hello', target: '' }), - ).toThrow('Unable to stringify location reference, empty target'); + expect(() => stringifyLocationRef({ type: '', target: 'hello' })).toThrow( + 'Unable to stringify location ref, empty type', + ); + expect(() => stringifyLocationRef({ type: 'hello', target: '' })).toThrow( + 'Unable to stringify location ref, empty target', + ); }); }); diff --git a/packages/catalog-model/src/location/helpers.ts b/packages/catalog-model/src/location/helpers.ts index 1edd4e5ec5..d308c00449 100644 --- a/packages/catalog-model/src/location/helpers.ts +++ b/packages/catalog-model/src/location/helpers.ts @@ -14,8 +14,9 @@ * limitations under the License. */ +import { ANNOTATION_SOURCE_LOCATION } from '.'; import { Entity, stringifyEntityRef } from '../entity'; -import { LOCATION_ANNOTATION, SOURCE_LOCATION_ANNOTATION } from './annotation'; +import { ANNOTATION_LOCATION } from './annotation'; /** * Parses a string form location reference. @@ -26,36 +27,53 @@ import { LOCATION_ANNOTATION, SOURCE_LOCATION_ANNOTATION } from './annotation'; * @public * @param ref - A string-form location reference, e.g. `'url:https://host'` * @returns A location reference, e.g. `{ type: 'url', target: 'https://host' }` + * @deprecated use {@link parseLocationRef} instead */ -export function parseLocationReference(ref: string): { +export function parseLocationReference(ref: string) { + return parseLocationRef(ref); +} + +/** + * Parses a string form location reference. + * + * @remarks + * + * Note that the return type is not `LocationSpec`, because we do not want to + * conflate the string form with the additional properties of that type. + * + * @public + * @param ref - A string-form location ref, e.g. `'url:https://host'` + * @returns A location ref, e.g. `{ type: 'url', target: 'https://host' }` + */ +export function parseLocationRef(ref: string): { type: string; target: string; } { if (typeof ref !== 'string') { throw new TypeError( - `Unable to parse location reference '${ref}', unexpected argument ${typeof ref}`, + `Unable to parse location ref '${ref}', unexpected argument ${typeof ref}`, ); } const splitIndex = ref.indexOf(':'); if (splitIndex < 0) { throw new TypeError( - `Unable to parse location reference '${ref}', expected ':', e.g. 'url:https://host/path'`, + `Unable to parse location ref '${ref}', expected ':', e.g. 'url:https://host/path'`, ); } - const type = ref.substr(0, splitIndex).trim(); - const target = ref.substr(splitIndex + 1).trim(); + const type = ref.substring(0, splitIndex).trim(); + const target = ref.substring(splitIndex + 1).trim(); if (!type || !target) { throw new TypeError( - `Unable to parse location reference '${ref}', expected ':', e.g. 'url:https://host/path'`, + `Unable to parse location ref '${ref}', expected ':', e.g. 'url:https://host/path'`, ); } if (type === 'http' || type === 'https') { throw new TypeError( - `Invalid location reference '${ref}', please prefix it with 'url:', e.g. 'url:${ref}'`, + `Invalid location ref '${ref}', please prefix it with 'url:', e.g. 'url:${ref}'`, ); } @@ -73,17 +91,37 @@ export function parseLocationReference(ref: string): { * @public * @param ref - A location reference, e.g. `{ type: 'url', target: 'https://host' }` * @returns A string-form location reference, e.g. `'url:https://host'` + * @deprecated use {@link stringifyLocationRef} instead */ export function stringifyLocationReference(ref: { type: string; target: string; +}): string { + return stringifyLocationRef(ref); +} + +/** + * Turns a location ref into its string form. + * + * @remarks + * + * Note that the input type is not `LocationSpec`, because we do not want to + * conflate the string form with the additional properties of that type. + * + * @public + * @param ref - A location ref, e.g. `{ type: 'url', target: 'https://host' }` + * @returns A string-form location ref, e.g. `'url:https://host'` + */ +export function stringifyLocationRef(ref: { + type: string; + target: string; }): string { const { type, target } = ref; if (!type) { - throw new TypeError(`Unable to stringify location reference, empty type`); + throw new TypeError(`Unable to stringify location ref, empty type`); } else if (!target) { - throw new TypeError(`Unable to stringify location reference, empty target`); + throw new TypeError(`Unable to stringify location ref, empty target`); } return `${type}:${target}`; @@ -105,8 +143,8 @@ export function getEntitySourceLocation(entity: Entity): { target: string; } { const locationRef = - entity.metadata?.annotations?.[SOURCE_LOCATION_ANNOTATION] ?? - entity.metadata?.annotations?.[LOCATION_ANNOTATION]; + entity.metadata?.annotations?.[ANNOTATION_SOURCE_LOCATION] ?? + entity.metadata?.annotations?.[ANNOTATION_LOCATION]; if (!locationRef) { throw new Error( @@ -114,5 +152,5 @@ export function getEntitySourceLocation(entity: Entity): { ); } - return parseLocationReference(locationRef); + return parseLocationRef(locationRef); } diff --git a/packages/catalog-model/src/location/index.ts b/packages/catalog-model/src/location/index.ts index ead4a6b564..8302ec202f 100644 --- a/packages/catalog-model/src/location/index.ts +++ b/packages/catalog-model/src/location/index.ts @@ -15,18 +15,18 @@ */ export { + ANNOTATION_LOCATION, + ANNOTATION_ORIGIN_LOCATION, + ANNOTATION_SOURCE_LOCATION, LOCATION_ANNOTATION, ORIGIN_LOCATION_ANNOTATION, SOURCE_LOCATION_ANNOTATION, } from './annotation'; export { - parseLocationReference, - stringifyLocationReference, getEntitySourceLocation, + parseLocationRef, + parseLocationReference, + stringifyLocationRef, + stringifyLocationReference, } from './helpers'; export type { Location, LocationSpec } from './types'; -export { - analyzeLocationSchema, - locationSchema, - locationSpecSchema, -} from './validation'; diff --git a/packages/catalog-model/src/location/types.ts b/packages/catalog-model/src/location/types.ts index 725f873f2d..2ed8fd717b 100644 --- a/packages/catalog-model/src/location/types.ts +++ b/packages/catalog-model/src/location/types.ts @@ -35,6 +35,7 @@ export type LocationSpec = { * Entity location for a specific entity. * * @public + * @deprecated import from {@link @backstage/catalog-client#Location} instead. */ export type Location = { id: string; diff --git a/packages/catalog-model/src/location/validation.ts b/packages/catalog-model/src/location/validation.ts deleted file mode 100644 index 2fd692e649..0000000000 --- a/packages/catalog-model/src/location/validation.ts +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import * as yup from 'yup'; -import { LocationSpec, Location } from './types'; - -/** - * Deprecated. - * - * @public - * @deprecated Use {@link JSONSchema} or validators instead. - */ -export const locationSpecSchema: yup.SchemaOf = yup - .object({ - type: yup.string().required(), - target: yup.string().required(), - presence: yup.mixed().oneOf(['required', 'optional']), - }) - .noUnknown() - .required(); - -/** - * Deprecated. - * - * @public - * @deprecated Use {@link JSONSchema} or validators instead. - */ -export const locationSchema: yup.SchemaOf = yup - .object({ - id: yup.string().required(), - type: yup.string().required(), - target: yup.string().required(), - presence: yup.mixed().oneOf(['required', 'optional']), - }) - .noUnknown() - .required(); - -/** - * Deprecated. - * - * @public - * @deprecated Use {@link JSONSchema} or validators instead. - */ -export const analyzeLocationSchema: yup.SchemaOf<{ location: LocationSpec }> = - yup - .object({ - location: locationSpecSchema, - }) - .noUnknown() - .required(); diff --git a/packages/cli-common/package.json b/packages/cli-common/package.json index cdb4b01b6d..5d259ce2f3 100644 --- a/packages/cli-common/package.json +++ b/packages/cli-common/package.json @@ -10,6 +10,9 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "node-library" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -21,12 +24,13 @@ ], "license": "Apache-2.0", "scripts": { - "build": "backstage-cli build --outputs cjs,types", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean", + "start": "backstage-cli package start" }, "devDependencies": { "@types/jest": "^26.0.7", diff --git a/packages/cli/.snyk b/packages/cli/.snyk index 3ad43bd3de..0a32a6ac12 100644 --- a/packages/cli/.snyk +++ b/packages/cli/.snyk @@ -3,80 +3,65 @@ version: v1.22.1 # ignores vulnerabilities until expiry date; change duration by modifying expiry date ignore: SNYK-JS-ANSIHTML-1296849: - - 'webpack-dev-server > ansi-html': + - webpack-dev-server > ansi-html: reason: Developer tools are not a valid target for ReDoS attacks expires: 2022-03-06T17:18:55.019Z created: 2021-09-06T17:18:55.027Z - SNYK-JS-ANSIREGEX-1583908: - '*': reason: Developer tools are not a valid target for ReDoS attacks expires: 2022-03-06T17:18:55.019Z created: 2021-09-06T17:18:55.027Z - SNYK-JS-CSSWHAT-1298035: - '*': reason: Developer tools are not a valid target for ReDoS attacks expires: 2022-03-06T17:18:55.019Z created: 2021-09-06T17:18:55.027Z - SNYK-JS-BROWSERSLIST-1090194: - '*': reason: Developer tools are not a valid target for ReDoS attacks expires: 2022-03-06T17:18:55.019Z created: 2021-09-06T17:18:55.027Z - SNYK-JS-ISSVG-1243891: - '*': reason: Developer tools are not a valid target for ReDoS attacks expires: 2022-03-06T17:18:55.019Z created: 2021-09-06T17:18:55.027Z - SNYK-JS-ISSVG-1085627: - '*': reason: Developer tools are not a valid target for ReDoS attacks expires: 2022-03-06T17:18:55.019Z created: 2021-09-06T17:18:55.027Z - SNYK-JS-POSTCSS-1255640: - '*': reason: Developer tools are not a valid target for ReDoS attacks expires: 2022-03-06T17:18:55.019Z created: 2021-09-06T17:18:55.027Z - SNYK-JS-POSTCSS-1090595: - '*': reason: Developer tools are not a valid target for ReDoS attacks expires: 2022-03-06T17:18:55.019Z created: 2021-09-06T17:18:55.027Z - SNYK-JS-WS-1296835: - '*': reason: Developer tools are not a valid target for ReDoS attacks expires: 2022-03-06T17:18:55.019Z created: 2021-09-06T17:18:55.027Z - - SNYK-JS-IMMER-1540542: - - '*': - reason: Prototype pollution is not an effective attack against a CLI as it already executes arbitrary code - expires: 2022-03-06T17:18:55.019Z - created: 2021-09-06T17:18:55.027Z - - SNYK-JS-SETVALUE-1540541: - - '*': - reason: Prototype pollution is not an effective attack against a CLI as it already executes arbitrary code - expires: 2022-03-06T17:18:55.019Z - created: 2021-09-06T17:18:55.027Z - 'snyk:lic:npm:rollup-plugin-dts:LGPL-3.0': - '*': - reason: Backstage itself does not redistribute this dependency in minified form + reason: This is a development dependency only and is therefore acceptable expires: 2031-09-06T17:18:55.027Z created: 2021-09-06T17:18:55.027Z - 'snyk:lic:npm:axe-core:MPL-2.0': - '*': - reason: Backstage itself does not redistribute this dependency in minified form + reason: This is a development dependency only and is therefore acceptable expires: 2031-09-06T17:18:55.027Z created: 2021-09-06T17:18:55.027Z + SNYK-JS-UNSETVALUE-2400660: + - '*': + reason: >- + The pollution in this vulnerability does not allow injection of + arbitrary values and is therefore a negligible risk for a CLI. + expires: 2022-08-17T21:54:43.658Z + created: 2022-02-15T21:54:43.668Z patch: {} diff --git a/packages/cli/config/jest.js b/packages/cli/config/jest.js index 978c598584..91cdd3c41b 100644 --- a/packages/cli/config/jest.js +++ b/packages/cli/config/jest.js @@ -102,9 +102,10 @@ async function getProjectConfig(targetPath, displayName) { }, transform: { - '\\.(js|jsx|ts|tsx|mjs|cjs)$': require.resolve( - './jestSucraseTransform.js', - ), + '\\.(js|jsx|ts|tsx|mjs|cjs)$': [ + require.resolve('./jestSucraseTransform.js'), + { enableSourceMaps: Boolean(process.env.ENABLE_SOURCE_MAPS) }, + ], '\\.(bmp|gif|jpg|jpeg|png|frag|xml|svg|eot|woff|woff2|ttf)$': require.resolve('./jestFileTransform.js'), '\\.(yaml)$': require.resolve('jest-transform-yaml'), diff --git a/packages/cli/config/jestSucraseTransform.js b/packages/cli/config/jestSucraseTransform.js index c88909d21f..d0400f4f3b 100644 --- a/packages/cli/config/jestSucraseTransform.js +++ b/packages/cli/config/jestSucraseTransform.js @@ -21,50 +21,71 @@ const sucrasePluginPkg = require('@sucrase/jest-plugin/package.json'); const ESM_REGEX = /\b(?:import|export)\b/; -function process(source, filePath) { - let transforms; +function createTransformer(config) { + const process = (source, filePath) => { + let transforms; - if (filePath.endsWith('.esm.js')) { - transforms = ['imports']; - } else if (filePath.endsWith('.js')) { - // This is a very rough filter to avoid transforming things that we quickly - // can be sure are definitely not ESM modules. - if (ESM_REGEX.test(source)) { - transforms = ['imports', 'jsx']; // JSX within .js is currently allowed + if (filePath.endsWith('.esm.js')) { + transforms = ['imports']; + } else if (filePath.endsWith('.js')) { + // This is a very rough filter to avoid transforming things that we quickly + // can be sure are definitely not ESM modules. + if (ESM_REGEX.test(source)) { + transforms = ['imports', 'jsx']; // JSX within .js is currently allowed + } + } else if (filePath.endsWith('.jsx')) { + transforms = ['jsx', 'imports']; + } else if (filePath.endsWith('.ts')) { + transforms = ['typescript', 'imports']; + } else if (filePath.endsWith('.tsx')) { + transforms = ['typescript', 'jsx', 'imports']; } - } else if (filePath.endsWith('.jsx')) { - transforms = ['jsx', 'imports']; - } else if (filePath.endsWith('.ts')) { - transforms = ['typescript', 'imports']; - } else if (filePath.endsWith('.tsx')) { - transforms = ['typescript', 'jsx', 'imports']; - } - // Only apply the jest transform to the test files themselves - if (transforms && filePath.includes('.test.')) { - transforms.push('jest'); - } + // Only apply the jest transform to the test files themselves + if (transforms && filePath.includes('.test.')) { + transforms.push('jest'); + } - if (transforms) { - return transform(source, { - transforms, - filePath, - disableESTransforms: true, - }).code; - } + if (transforms) { + const { code, sourceMap: map } = transform(source, { + transforms, + filePath, + disableESTransforms: true, + sourceMapOptions: { + compiledFilename: filePath, + }, + }); + if (config.enableSourceMaps) { + const b64 = Buffer.from(JSON.stringify(map), 'utf8').toString('base64'); + const suffix = `//# sourceMappingURL=data:application/json;charset=utf-8;base64,${b64}`; + // Include both inline and object source maps, as inline source maps are + // needed for support of some editor integrations. + return { code: `${code}\n${suffix}`, map }; + } + // We only return the `map` result if source maps are enabled, as they + // have a negative impact on the coverage accuracy. + return code; + } - return source; + return source; + }; + + // TODO: contribute something like this to @sucrase/jest-plugin + const getCacheKey = sourceText => { + return createHash('md5') + .update(sourceText) + .update(Buffer.alloc(1)) + .update(sucrasePkg.version) + .update(Buffer.alloc(1)) + .update(sucrasePluginPkg.version) + .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 }; } -// TODO: contribute something like this to @sucrase/jest-plugin -function getCacheKey(sourceText) { - return createHash('md5') - .update(sourceText) - .update(Buffer.alloc(1)) - .update(sucrasePkg.version) - .update(Buffer.alloc(1)) - .update(sucrasePluginPkg.version) - .digest('hex'); -} - -module.exports = { process, getCacheKey }; +module.exports = { createTransformer }; diff --git a/packages/cli/package.json b/packages/cli/package.json index 589ac58646..b811fc8eda 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -6,6 +6,9 @@ "publishConfig": { "access": "public" }, + "backstage": { + "role": "cli" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -18,10 +21,10 @@ "license": "Apache-2.0", "main": "dist/index.cjs.js", "scripts": { - "build": "backstage-cli build --outputs cjs", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "clean": "backstage-cli clean", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", "start": "nodemon --" }, "bin": { @@ -48,8 +51,8 @@ "@sucrase/webpack-loader": "^2.0.0", "@svgr/plugin-jsx": "6.2.x", "@svgr/plugin-svgo": "6.2.x", - "@svgr/rollup": "5.5.x", - "@svgr/webpack": "5.5.x", + "@svgr/rollup": "6.2.x", + "@svgr/webpack": "6.2.x", "@types/webpack-env": "^1.15.2", "@typescript-eslint/eslint-plugin": "^5.9.0", "@typescript-eslint/parser": "^5.9.0", @@ -138,6 +141,7 @@ "@types/recursive-readdir": "^2.2.0", "@types/rollup-plugin-peer-deps-external": "^2.2.0", "@types/rollup-plugin-postcss": "^2.0.0", + "@types/svgo": "^2.6.2", "@types/tar": "^6.1.1", "@types/terser-webpack-plugin": "^5.0.4", "@types/yarnpkg__lockfile": "^1.1.4", diff --git a/packages/cli/src/commands/build/buildBackend.ts b/packages/cli/src/commands/build/buildBackend.ts index e32b7956db..0768728f00 100644 --- a/packages/cli/src/commands/build/buildBackend.ts +++ b/packages/cli/src/commands/build/buildBackend.ts @@ -49,19 +49,20 @@ export async function buildBackend(options: BuildBackendOptions) { // We built the target backend package using the regular build process, but the result of // that has now been packed into the dist workspace, so clean up the dist dir. - await fs.remove(targetDir); - await fs.mkdir(targetDir); + const distDir = resolvePath(targetDir, 'dist'); + await fs.remove(distDir); + await fs.mkdir(distDir); // Move out skeleton.tar.gz before we create the main bundle, no point having that included up twice. await fs.move( resolvePath(tmpDir, SKELETON_FILE), - resolvePath(targetDir, SKELETON_FILE), + resolvePath(distDir, SKELETON_FILE), ); // Create main bundle.tar.gz, with some tweaks to make it more likely hit Docker build cache. await tar.create( { - file: resolvePath(targetDir, BUNDLE_FILE), + file: resolvePath(distDir, BUNDLE_FILE), cwd: tmpDir, portable: true, noMtime: true, diff --git a/packages/cli/src/commands/build/buildApp.ts b/packages/cli/src/commands/build/buildFrontend.ts similarity index 95% rename from packages/cli/src/commands/build/buildApp.ts rename to packages/cli/src/commands/build/buildFrontend.ts index b0959b2d6a..6d7ca2e6a9 100644 --- a/packages/cli/src/commands/build/buildApp.ts +++ b/packages/cli/src/commands/build/buildFrontend.ts @@ -26,7 +26,7 @@ interface BuildAppOptions { configPaths: string[]; } -export async function buildApp(options: BuildAppOptions) { +export async function buildFrontend(options: BuildAppOptions) { const { targetDir, writeStats, configPaths } = options; const { name } = await fs.readJson(resolvePath(targetDir, 'package.json')); await buildBundle({ diff --git a/packages/cli/src/commands/build/command.ts b/packages/cli/src/commands/build/command.ts index 1189883b12..5c8065dbb4 100644 --- a/packages/cli/src/commands/build/command.ts +++ b/packages/cli/src/commands/build/command.ts @@ -18,22 +18,22 @@ import { Command } from 'commander'; import { buildPackage, Output } from '../../lib/builder'; import { findRoleFromCommand, getRoleInfo } from '../../lib/role'; import { paths } from '../../lib/paths'; -import { buildApp } from './buildApp'; +import { buildFrontend } from './buildFrontend'; import { buildBackend } from './buildBackend'; export async function command(cmd: Command): Promise { const role = await findRoleFromCommand(cmd); - if (role === 'app') { - return buildApp({ - targetDir: paths.resolveTarget('dist'), + if (role === 'frontend') { + return buildFrontend({ + targetDir: paths.targetDir, configPaths: cmd.config as string[], writeStats: Boolean(cmd.stats), }); } if (role === 'backend') { return buildBackend({ - targetDir: paths.resolveTarget('dist'), + targetDir: paths.targetDir, skipBuildDependencies: Boolean(cmd.skipBuildDependencies), }); } diff --git a/packages/cli/src/commands/index.ts b/packages/cli/src/commands/index.ts index 770d216ba2..d3baa37b3f 100644 --- a/packages/cli/src/commands/index.ts +++ b/packages/cli/src/commands/index.ts @@ -42,18 +42,36 @@ export function registerRepoCommand(program: CommanderStatic) { 'Build all packages, including bundled app and backend packages.', ) .action(lazy(() => import('./repo/build').then(m => m.command))); + + command + .command('lint') + .description('Lint all packages in the project') + .option( + '--format ', + 'Lint report output format', + 'eslint-formatter-friendly', + ) + .option( + '--since ', + 'Only lint packages that changed since the specified ref', + ) + .option('--fix', 'Attempt to automatically fix violations') + .action(lazy(() => import('./repo/lint').then(m => m.command))); } export function registerScriptCommand(program: CommanderStatic) { const command = program - .command('script [command]', { hidden: true }) - .description('Lifecycle scripts for Backstage packages [EXPERIMENTAL]'); + .command('package [command]', { hidden: true }) + .description('Lifecycle scripts for individual packages [EXPERIMENTAL]'); command .command('start') .description('Start a package for local development') .option(...configOption) - .option('--role ', 'Run the command with an explicit package role') + .option( + '--role ', + 'Run the command with an explicit package role [EXPERIMENTAL]', + ) .option('--check', 'Enable type checking and linting if available') .option('--inspect', 'Enable debugger in Node.js environments') .option( @@ -65,6 +83,10 @@ export function registerScriptCommand(program: CommanderStatic) { command .command('build') .description('Build a package for production deployment or publishing') + .option( + '--role ', + 'Run the command with an explicit package role [EXPERIMENTAL]', + ) .option( '--minify', 'Minify the generated code. Does not apply to app or backend packages.', @@ -89,7 +111,7 @@ export function registerScriptCommand(program: CommanderStatic) { ) .action(lazy(() => import('./build').then(m => m.command))); - program + command .command('lint') .option( '--format ', @@ -100,7 +122,7 @@ export function registerScriptCommand(program: CommanderStatic) { .description('Lint a package') .action(lazy(() => import('./lint').then(m => m.default))); - program + command .command('test') .allowUnknownOption(true) // Allows the command to run, but we still need to parse raw args .helpOption(', --backstage-cli-help') // Let Jest handle help @@ -129,7 +151,7 @@ export function registerMigrateCommand(program: CommanderStatic) { .description('Migration utilities [EXPERIMENTAL]'); command - .command('package-role') + .command('package-roles') .description(`Add package role field to packages that don't have it`) .action(lazy(() => import('./migrate/packageRole').then(m => m.default))); @@ -142,7 +164,7 @@ export function registerMigrateCommand(program: CommanderStatic) { } export function registerCommands(program: CommanderStatic) { - // TODO(Rugvip): Deprecate in favor of script variant + // TODO(Rugvip): Deprecate in favor of package variant program .command('app:build') .description('Build an app for a production release') @@ -150,7 +172,7 @@ export function registerCommands(program: CommanderStatic) { .option(...configOption) .action(lazy(() => import('./app/build').then(m => m.default))); - // TODO(Rugvip): Deprecate in favor of script variant + // TODO(Rugvip): Deprecate in favor of package variant program .command('app:serve') .description('Serve an app for local development') @@ -158,7 +180,7 @@ export function registerCommands(program: CommanderStatic) { .option(...configOption) .action(lazy(() => import('./app/serve').then(m => m.default))); - // TODO(Rugvip): Deprecate in favor of script variant + // TODO(Rugvip): Deprecate in favor of package variant program .command('backend:build') .description('Build a backend plugin') @@ -166,7 +188,7 @@ export function registerCommands(program: CommanderStatic) { .option('--experimental-type-build', 'Enable experimental type build') .action(lazy(() => import('./backend/build').then(m => m.default))); - // TODO(Rugvip): Deprecate in favor of script variant + // TODO(Rugvip): Deprecate in favor of package variant program .command('backend:bundle') .description('Bundle the backend into a deployment archive') @@ -176,7 +198,7 @@ export function registerCommands(program: CommanderStatic) { ) .action(lazy(() => import('./backend/bundle').then(m => m.default))); - // TODO(Rugvip): Deprecate in favor of script variant + // TODO(Rugvip): Deprecate in favor of package variant program .command('backend:dev') .description('Start local development server with HMR for the backend') @@ -225,7 +247,7 @@ export function registerCommands(program: CommanderStatic) { lazy(() => import('./create-plugin/createPlugin').then(m => m.default)), ); - // TODO(Rugvip): Deprecate in favor of script variant + // TODO(Rugvip): Deprecate in favor of package variant program .command('plugin:build') .description('Build a plugin') @@ -233,7 +255,7 @@ export function registerCommands(program: CommanderStatic) { .option('--experimental-type-build', 'Enable experimental type build') .action(lazy(() => import('./plugin/build').then(m => m.default))); - // TODO(Rugvip): Deprecate in favor of script variant + // TODO(Rugvip): Deprecate in favor of package variant program .command('plugin:serve') .description('Serves the dev/ folder of a plugin') @@ -248,7 +270,7 @@ export function registerCommands(program: CommanderStatic) { .description('Diff an existing plugin with the creation template') .action(lazy(() => import('./plugin/diff').then(m => m.default))); - // TODO(Rugvip): Deprecate in favor of script variant + // TODO(Rugvip): Deprecate in favor of package variant program .command('build') .description('Build a package for publishing') @@ -257,7 +279,7 @@ export function registerCommands(program: CommanderStatic) { .option('--experimental-type-build', 'Enable experimental type build') .action(lazy(() => import('./oldBuild').then(m => m.default))); - // TODO(Rugvip): Deprecate in favor of script variant + // TODO(Rugvip): Deprecate in favor of package variant program .command('lint') .option( @@ -269,7 +291,7 @@ export function registerCommands(program: CommanderStatic) { .description('Lint a package') .action(lazy(() => import('./lint').then(m => m.default))); - // TODO(Rugvip): Deprecate in favor of script variant + // TODO(Rugvip): Deprecate in favor of package variant program .command('test') .allowUnknownOption(true) // Allows the command to run, but we still need to parse raw args @@ -355,19 +377,19 @@ export function registerCommands(program: CommanderStatic) { .description('Check Backstage package versioning') .action(lazy(() => import('./versions/lint').then(m => m.default))); - // TODO(Rugvip): Deprecate in favor of script variant + // TODO(Rugvip): Deprecate in favor of package variant program .command('prepack') .description('Prepares a package for packaging before publishing') .action(lazy(() => import('./pack').then(m => m.pre))); - // TODO(Rugvip): Deprecate in favor of script variant + // TODO(Rugvip): Deprecate in favor of package variant program .command('postpack') .description('Restores the changes made by the prepack command') .action(lazy(() => import('./pack').then(m => m.post))); - // TODO(Rugvip): Deprecate in favor of script variant + // TODO(Rugvip): Deprecate in favor of package variant program .command('clean') .description('Delete cache directories') diff --git a/packages/cli/src/commands/migrate/packageScripts.ts b/packages/cli/src/commands/migrate/packageScripts.ts index a3fdd20018..c7dab9466b 100644 --- a/packages/cli/src/commands/migrate/packageScripts.ts +++ b/packages/cli/src/commands/migrate/packageScripts.ts @@ -19,6 +19,8 @@ import { resolve as resolvePath } from 'path'; import { PackageGraph } from '../../lib/monorepo'; import { getRoleFromPackage, getRoleInfo, PackageRole } from '../../lib/role'; +const configArgPattern = /--config[=\s][^\s$]+/; + const noStartRoles: PackageRole[] = ['cli', 'common-library']; export async function command() { @@ -33,17 +35,52 @@ export async function command() { const roleInfo = getRoleInfo(role); const hasStart = !noStartRoles.includes(role); - const isBundled = roleInfo.output.includes('bundle'); + const needsPack = !(roleInfo.output.includes('bundle') || role === 'cli'); + const scripts = packageJson.scripts ?? {}; + + const startCmd = ['start']; + if (scripts.start?.includes('--check')) { + startCmd.push('--check'); + } + if (scripts.start?.includes('--config')) { + startCmd.push(...(scripts.start.match(configArgPattern) ?? [])); + } + + const buildCmd = ['build']; + if (scripts.build?.includes('--minify')) { + buildCmd.push('--minify'); + } + if (scripts.build?.includes('--experimental-type-build')) { + buildCmd.push('--experimental-type-build'); + } + if (scripts.build?.includes('--config')) { + buildCmd.push(...(scripts.build.match(configArgPattern) ?? [])); + } + + // For test scripts we keep all existing flags except for --passWithNoTests, since that's now default + const testCmd = ['test']; + if (scripts.test?.startsWith('backstage-cli test')) { + const args = scripts.test + .slice('backstage-cli test'.length) + .split(' ') + .filter(Boolean); + if (args.includes('--passWithNoTests')) { + args.splice(args.indexOf('--passWithNoTests'), 1); + } + testCmd.push(...args); + } const expectedScripts = { - ...(hasStart && { start: 'backstage-cli script start' }), - build: 'backstage-cli script build', - lint: 'backstage-cli script lint', - test: 'backstage-cli script test', - clean: 'backstage-cli script clean', - ...(!isBundled && { - postpack: 'backstage-cli script postpack', - prepack: 'backstage-cli script prepack', + ...(hasStart && { + start: `backstage-cli package ${startCmd.join(' ')}`, + }), + build: `backstage-cli package ${buildCmd.join(' ')}`, + lint: 'backstage-cli package lint', + test: `backstage-cli package ${testCmd.join(' ')}`, + clean: 'backstage-cli package clean', + ...(needsPack && { + postpack: 'backstage-cli package postpack', + prepack: 'backstage-cli package prepack', }), }; @@ -52,7 +89,12 @@ export async function command() { (packageJson.scripts = packageJson.scripts || {}); for (const [name, value] of Object.entries(expectedScripts)) { - if (currentScripts[name] !== value) { + const currentScript = currentScripts[name]; + + const isMissing = !currentScript; + const isDifferent = currentScript !== value; + const isBackstageScript = currentScript?.includes('backstage-cli'); + if (isMissing || (isDifferent && isBackstageScript)) { changed = true; currentScripts[name] = value; } diff --git a/packages/cli/src/commands/repo/build.ts b/packages/cli/src/commands/repo/build.ts index 9c32386304..ceb468ebfa 100644 --- a/packages/cli/src/commands/repo/build.ts +++ b/packages/cli/src/commands/repo/build.ts @@ -23,7 +23,7 @@ import { ExtendedPackage } from '../../lib/monorepo/PackageGraph'; import { runParallelWorkers } from '../../lib/parallel'; import { paths } from '../../lib/paths'; import { detectRoleFromPackage } from '../../lib/role'; -import { buildApp } from '../build/buildApp'; +import { buildFrontend } from '../build/buildFrontend'; import { buildBackend } from '../build/buildBackend'; function createScriptOptionsParser(anyCmd: Command, commandPath: string[]) { @@ -43,7 +43,9 @@ function createScriptOptionsParser(anyCmd: Command, commandPath: string[]) { } if (!targetCmd) { - throw new Error(`Could not find script command '${commandPath.join(' ')}'`); + throw new Error( + `Could not find package command '${commandPath.join(' ')}'`, + ); } const cmd = targetCmd; @@ -80,7 +82,7 @@ export async function command(cmd: Command): Promise { const apps = new Array(); const backends = new Array(); - const parseBuildScript = createScriptOptionsParser(cmd, ['script', 'build']); + const parseBuildScript = createScriptOptionsParser(cmd, ['package', 'build']); const options = packages.flatMap(pkg => { const role = @@ -90,7 +92,7 @@ export async function command(cmd: Command): Promise { return []; } - if (role === 'app') { + if (role === 'frontend') { apps.push(pkg); return []; } else if (role === 'backend') { @@ -137,7 +139,7 @@ export async function command(cmd: Command): Promise { ); return; } - await buildApp({ + await buildFrontend({ targetDir: pkg.dir, configPaths: (buildOptions.config as string[]) ?? [], writeStats: Boolean(buildOptions.stats), diff --git a/packages/cli/src/commands/repo/lint.ts b/packages/cli/src/commands/repo/lint.ts new file mode 100644 index 0000000000..b054dabe34 --- /dev/null +++ b/packages/cli/src/commands/repo/lint.ts @@ -0,0 +1,113 @@ +/* + * 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 chalk from 'chalk'; +import { Command } from 'commander'; +import { relative as relativePath } from 'path'; +import { PackageGraph, ExtendedPackageJSON } from '../../lib/monorepo'; +import { runWorkerQueueThreads } from '../../lib/parallel'; +import { paths } from '../../lib/paths'; + +function depCount(pkg: ExtendedPackageJSON) { + const deps = pkg.dependencies ? Object.keys(pkg.dependencies).length : 0; + const devDeps = pkg.devDependencies + ? Object.keys(pkg.devDependencies).length + : 0; + return deps + devDeps; +} + +export async function command(cmd: Command): Promise { + let packages = await PackageGraph.listTargetPackages(); + + if (cmd.since) { + const graph = PackageGraph.fromPackages(packages); + packages = await graph.listChangedPackages({ ref: cmd.since }); + } + + // Packages are ordered from most to least number of dependencies, as a + // very cheap way of guessing which packages are more likely to be larger. + packages.sort((a, b) => depCount(b.packageJson) - depCount(a.packageJson)); + + // This formatter uses the cwd to format file paths, so let's have that happen from the root instead + if (cmd.format === 'eslint-formatter-friendly') { + process.chdir(paths.targetRoot); + } + + // Make sure lint output is colored unless the user explicitly disabled it + if (!process.env.FORCE_COLOR) { + process.env.FORCE_COLOR = '1'; + } + + const resultsList = await runWorkerQueueThreads({ + items: packages.map(pkg => ({ + fullDir: pkg.dir, + relativeDir: relativePath(paths.targetRoot, pkg.dir), + })), + workerData: { + fix: Boolean(cmd.fix), + format: cmd.format as string | undefined, + }, + workerFactory: async ({ fix, format }) => { + const { ESLint } = require('eslint'); + + return async ({ + fullDir, + relativeDir, + }): Promise<{ relativeDir: string; resultText: string }> => { + // Bit of a hack to make file resolutions happen from the correct directory + // since some lint rules don't respect the cwd of ESLint + process.cwd = () => fullDir; + + const start = Date.now(); + const eslint = new ESLint({ + cwd: fullDir, + fix, + extensions: ['js', 'jsx', 'ts', 'tsx', 'mjs', 'cjs'], + }); + const formatter = await eslint.loadFormatter(format); + + const results = await eslint.lintFiles(['.']); + + const count = String(results.length).padStart(3); + const time = ((Date.now() - start) / 1000).toFixed(2); + console.log(`Checked ${count} files in ${relativeDir} ${time}s`); + + if (fix) { + await ESLint.outputFixes(results); + } + + const resultText = formatter.format(results); + + return { relativeDir, resultText }; + }; + }, + }); + + let failed = false; + for (const { relativeDir, resultText } of resultsList) { + if (resultText) { + console.log(); + console.log(chalk.red(`Lint failed in ${relativeDir}:`)); + console.log(resultText.trimLeft()); + + failed = true; + } + } + + if (failed) { + process.exit(1); + } +} diff --git a/packages/cli/src/commands/start/command.ts b/packages/cli/src/commands/start/command.ts index 6615d5fd46..7a11028800 100644 --- a/packages/cli/src/commands/start/command.ts +++ b/packages/cli/src/commands/start/command.ts @@ -31,19 +31,19 @@ export async function command(cmd: Command): Promise { switch (role) { case 'backend': - case 'plugin-backend': - case 'plugin-backend-module': + case 'backend-plugin': + case 'backend-plugin-module': case 'node-library': return startBackend(options); - case 'app': + case 'frontend': return startFrontend({ ...options, entry: 'src/index', verifyVersions: true, }); case 'web-library': - case 'plugin-frontend': - case 'plugin-frontend-module': + case 'frontend-plugin': + case 'frontend-plugin-module': return startFrontend({ entry: 'dev/index', ...options }); default: throw new Error( diff --git a/packages/cli/src/commands/testCommand.ts b/packages/cli/src/commands/testCommand.ts index 24a4e06f9e..7165b20925 100644 --- a/packages/cli/src/commands/testCommand.ts +++ b/packages/cli/src/commands/testCommand.ts @@ -29,7 +29,11 @@ function includesAnyOf(hayStack: string[], ...needles: string[]) { export default async (cmd: Command) => { // all args are forwarded to jest - const rawArgs = cmd.parent.rawArgs as string[]; + let parent = cmd; + while (parent.parent) { + parent = parent.parent; + } + const rawArgs = parent.rawArgs as string[]; const args = rawArgs.slice(rawArgs.indexOf('test') + 1); // Only include our config if caller isn't passing their own config @@ -37,6 +41,10 @@ export default async (cmd: Command) => { 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 && diff --git a/packages/cli/src/commands/versions/bump.test.ts b/packages/cli/src/commands/versions/bump.test.ts index 73ecc0284e..e7b3c858aa 100644 --- a/packages/cli/src/commands/versions/bump.test.ts +++ b/packages/cli/src/commands/versions/bump.test.ts @@ -31,6 +31,7 @@ import { rest } from 'msw'; // Remove log coloring to simplify log matching jest.mock('chalk', () => ({ + red: (str: string) => str, blue: (str: string) => str, cyan: (str: string) => str, green: (str: string) => str, @@ -38,6 +39,18 @@ jest.mock('chalk', () => ({ yellow: (str: string) => str, })); +jest.mock('ora', () => ({ + __esModule: true, + default({ prefixText }: any) { + console.log(prefixText); + return { + start: () => ({ + succeed: () => {}, + }), + }; + }, +})); + const REGISTRY_VERSIONS: { [name: string]: string } = { '@backstage/core': '1.0.6', '@backstage/core-api': '1.0.7', @@ -177,7 +190,11 @@ describe('bump', () => { ); expect(runObj.run).toHaveBeenCalledTimes(1); - expect(runObj.run).toHaveBeenCalledWith('yarn', ['install']); + expect(runObj.run).toHaveBeenCalledWith( + 'yarn', + ['install'], + expect.any(Object), + ); const lockfileContents = await fs.readFile('/yarn.lock', 'utf8'); expect(lockfileContents).toBe(lockfileMockResult); @@ -273,7 +290,7 @@ describe('bump', () => { 'unlocking @backstage/core-api@^1.0.6 ~> 1.0.7', 'unlocking @backstage/core-api@^1.0.3 ~> 1.0.7', 'bumping @backstage/theme in b to ^5.0.0', - 'Creating backstage.json', + 'Your project is now at version 0.0.1, which has been written to backstage.json', 'Running yarn install to install new versions', '⚠️ The following packages may have breaking changes:', ' @backstage/theme : 1.0.0 ~> 5.0.0', @@ -296,7 +313,11 @@ describe('bump', () => { ); expect(runObj.run).toHaveBeenCalledTimes(1); - expect(runObj.run).toHaveBeenCalledWith('yarn', ['install']); + expect(runObj.run).toHaveBeenCalledWith( + 'yarn', + ['install'], + expect.any(Object), + ); const lockfileContents = await fs.readFile('/yarn.lock', 'utf8'); expect(lockfileContents).toBe(lockfileMockResult); @@ -389,7 +410,7 @@ describe('bump', () => { 'Some packages are outdated, updating', 'bumping @backstage/core in a to ^5.0.0', 'bumping @backstage/core in b to ^5.0.0', - 'Creating backstage.json', + 'Your project is now at version 2.0.0, which has been written to backstage.json', 'Running yarn install to install new versions', '⚠️ The following packages may have breaking changes:', ' @backstage/core : 1.0.3 ~> 5.0.0', @@ -398,7 +419,11 @@ describe('bump', () => { ]); expect(runObj.run).toHaveBeenCalledTimes(1); - expect(runObj.run).toHaveBeenCalledWith('yarn', ['install']); + expect(runObj.run).toHaveBeenCalledWith( + 'yarn', + ['install'], + expect.any(Object), + ); const packageA = await fs.readJson('/packages/a/package.json'); expect(packageA).toEqual({ @@ -512,7 +537,7 @@ describe('bump', () => { 'unlocking @backstage/core-api@^1.0.6 ~> 1.0.7', 'unlocking @backstage/core-api@^1.0.3 ~> 1.0.7', 'bumping @backstage/theme in b to ^5.0.0', - 'Creating backstage.json', + 'Your project is now at version 1.0.0, which has been written to backstage.json', 'Running yarn install to install new versions', '⚠️ The following packages may have breaking changes:', ' @backstage/theme : 1.0.0 ~> 5.0.0', @@ -645,7 +670,11 @@ describe('bump', () => { ); expect(runObj.run).toHaveBeenCalledTimes(1); - expect(runObj.run).toHaveBeenCalledWith('yarn', ['install']); + expect(runObj.run).toHaveBeenCalledWith( + 'yarn', + ['install'], + expect.any(Object), + ); const lockfileContents = await fs.readFile('/yarn.lock', 'utf8'); expect(lockfileContents).toEqual(customLockfileMockResult); @@ -765,8 +794,16 @@ describe('bumpBackstageJsonVersion', () => { .spyOn(paths, 'resolveTargetRoot') .mockImplementation((...path) => resolvePath('/', ...path)); - await bumpBackstageJsonVersion('1.4.1'); + const { log } = await withLogCollector(async () => { + await bumpBackstageJsonVersion('1.4.1'); + }); expect(await fs.readJson('/backstage.json')).toEqual({ version: '1.4.1' }); + expect(log).toEqual([ + 'Upgraded from release 0.0.1 to 1.4.1, please review these template changes:', + undefined, + ' https://backstage.github.io/upgrade-helper/?from=0.0.1&to=1.4.1', + undefined, + ]); }); it("should create backstage.json if doesn't exist", async () => { @@ -777,8 +814,13 @@ describe('bumpBackstageJsonVersion', () => { .spyOn(paths, 'resolveTargetRoot') .mockImplementation((...path) => resolvePath('/', ...path)); - await bumpBackstageJsonVersion(latest); + const { log } = await withLogCollector(async () => { + await bumpBackstageJsonVersion(latest); + }); expect(await fs.readJson('/backstage.json')).toEqual({ version: latest }); + expect(log).toEqual([ + 'Your project is now at version 1.4.1, which has been written to backstage.json', + ]); }); }); diff --git a/packages/cli/src/commands/versions/bump.ts b/packages/cli/src/commands/versions/bump.ts index 8c3c661996..b9d318bccc 100644 --- a/packages/cli/src/commands/versions/bump.ts +++ b/packages/cli/src/commands/versions/bump.ts @@ -16,6 +16,7 @@ import fs from 'fs-extra'; import chalk from 'chalk'; +import ora from 'ora'; import semver from 'semver'; import minimatch from 'minimatch'; import { Command } from 'commander'; @@ -259,12 +260,8 @@ export default async (cmd: Command) => { ), ); } - console.log(); - console.log( - `Running ${chalk.blue('yarn install')} to install new versions`, - ); - console.log(); - await run('yarn', ['install']); + + await runYarnInstall(); if (breakingUpdates.size > 0) { console.log(); @@ -420,17 +417,34 @@ export async function bumpBackstageJsonVersion(version: string) { throw e; }); - if (backstageJson?.version === version) { + const prevVersion = backstageJson?.version; + + if (prevVersion === version) { return; } - console.log( - chalk.yellow( - typeof backstageJson === 'undefined' - ? `Creating ${BACKSTAGE_JSON}` - : `Bumping version in ${BACKSTAGE_JSON}`, - ), - ); + const { yellow, cyan, green } = chalk; + if (prevVersion) { + const from = encodeURIComponent(prevVersion); + const to = encodeURIComponent(version); + const link = `https://backstage.github.io/upgrade-helper/?from=${from}&to=${to}`; + console.log( + yellow( + `Upgraded from release ${green(prevVersion)} to ${green( + version, + )}, please review these template changes:`, + ), + ); + console.log(); + console.log(` ${cyan(link)}`); + console.log(); + } else { + console.log( + yellow( + `Your project is now at version ${version}, which has been written to ${BACKSTAGE_JSON}`, + ), + ); + } await fs.writeJson( backstageJsonPath, @@ -441,3 +455,35 @@ export async function bumpBackstageJsonVersion(version: string) { }, ); } + +async function runYarnInstall() { + const spinner = ora({ + prefixText: `Running ${chalk.blue('yarn install')} to install new versions`, + spinner: 'arc', + color: 'green', + }).start(); + + const installOutput = new Array(); + try { + await run('yarn', ['install'], { + env: { + FORCE_COLOR: 'true', + // We filter out all of the npm_* environment variables that are added when + // executing through yarn. This works around an issue where these variables + // incorrectly override local yarn or npm config in the project directory. + ...Object.fromEntries( + Object.entries(process.env).map(([name, value]) => + name.startsWith('npm_') ? [name, undefined] : [name, value], + ), + ), + }, + stdoutLogFunc: data => installOutput.push(data), + stderrLogFunc: data => installOutput.push(data), + }); + spinner.succeed(); + } catch (error) { + spinner.fail(); + process.stdout.write(Buffer.concat(installOutput)); + throw error; + } +} diff --git a/packages/cli/src/lib/builder/buildTypeDefinitions.ts b/packages/cli/src/lib/builder/buildTypeDefinitions.ts index 85e54850e4..3bf3a4495f 100644 --- a/packages/cli/src/lib/builder/buildTypeDefinitions.ts +++ b/packages/cli/src/lib/builder/buildTypeDefinitions.ts @@ -16,10 +16,10 @@ import fs from 'fs-extra'; import chalk from 'chalk'; -import { Worker } from 'worker_threads'; import { relative as relativePath, resolve as resolvePath } from 'path'; import { paths } from '../paths'; import { buildTypeDefinitionsWorker } from './buildTypeDefinitionsWorker'; +import { runWorkerThreads } from '../parallel'; // These message types are ignored since we want to avoid duplicating the logic of // handling them correctly, and we already have the API Reports warning about them. @@ -84,59 +84,46 @@ export async function buildTypeDefinitions( const typescriptDir = paths.resolveTargetRoot('node_modules/typescript'); const hasTypescript = await fs.pathExists(typescriptDir); const typescriptCompilerFolder = hasTypescript ? typescriptDir : undefined; - - const worker = new Worker(`(${buildTypeDefinitionsWorker})()`, { - eval: true, + await runWorkerThreads({ + threadCount: 1, workerData: { entryPoints, workerConfigs, typescriptCompilerFolder, }, - }); - - await new Promise((resolve, reject) => { - worker.once('error', reject); - worker.once('exit', code => { - if (code) { - reject(new Error(`Worker exited with code ${code}`)); + worker: buildTypeDefinitionsWorker, + onMessage: ({ + message, + targetTypesDir, + }: { + message: any; + targetTypesDir: string; + }) => { + if (ignoredMessages.has(message.messageId)) { + return; } - }); - worker.on('message', data => { - if (data.type === 'done') { - if (data.error) { - reject(data.error); - } else { - resolve(); - } - } else if (data.type === 'message') { - const { message, targetTypesDir } = data; - if (ignoredMessages.has(message.messageId)) { - return; - } - - let text = `${message.text} (${message.messageId})`; - if (message.sourceFilePath) { - text += ' at '; - text += relativePath(targetTypesDir, message.sourceFilePath); - if (message.sourceFileLine) { - text += `:${message.sourceFileLine}`; - if (message.sourceFileColumn) { - text += `:${message.sourceFileColumn}`; - } + let text = `${message.text} (${message.messageId})`; + if (message.sourceFilePath) { + text += ' at '; + text += relativePath(targetTypesDir, message.sourceFilePath); + if (message.sourceFileLine) { + text += `:${message.sourceFileLine}`; + if (message.sourceFileColumn) { + text += `:${message.sourceFileColumn}`; } } - if (message.logLevel === 'error') { - console.error(chalk.red(`Error: ${text}`)); - } else if ( - message.logLevel === 'warning' || - message.category === 'Extractor' - ) { - console.warn(`Warning: ${text}`); - } else { - console.log(text); - } } - }); + if (message.logLevel === 'error') { + console.error(chalk.red(`Error: ${text}`)); + } else if ( + message.logLevel === 'warning' || + message.category === 'Extractor' + ) { + console.warn(`Warning: ${text}`); + } else { + console.log(text); + } + }, }); } diff --git a/packages/cli/src/lib/builder/buildTypeDefinitionsWorker.ts b/packages/cli/src/lib/builder/buildTypeDefinitionsWorker.ts index 8cb843f58e..43e5cbc526 100644 --- a/packages/cli/src/lib/builder/buildTypeDefinitionsWorker.ts +++ b/packages/cli/src/lib/builder/buildTypeDefinitionsWorker.ts @@ -20,7 +20,10 @@ * be self-contained. * Using TypeScript is fine as it is transpiled before being stringified. */ -export function buildTypeDefinitionsWorker() { +export async function buildTypeDefinitionsWorker( + workerData: any, + sendMessage: (message: any) => void, +) { try { require('@microsoft/api-extractor'); } catch (error) { @@ -31,7 +34,6 @@ export function buildTypeDefinitionsWorker() { } const { dirname } = require('path'); - const { workerData, parentPort } = require('worker_threads'); const { entryPoints, workerConfigs, typescriptCompilerFolder } = workerData; const apiExtractor = require('@microsoft/api-extractor'); @@ -63,7 +65,6 @@ export function buildTypeDefinitionsWorker() { return old.call(this, path); }; - let success = true; let compilerState; for (const { extractorOptions, targetTypesDir } of workerConfigs) { const extractorConfig = ExtractorConfig.prepare(extractorOptions); @@ -82,24 +83,15 @@ export function buildTypeDefinitionsWorker() { showDiagnostics: false, messageCallback: (message: any) => { message.handled = true; - parentPort.postMessage({ type: 'message', message, targetTypesDir }); + sendMessage({ message, targetTypesDir }); }, }); if (!extractorResult.succeeded) { - parentPort.postMessage({ - type: 'done', - error: new Error( - `Type definition build completed with ${extractorResult.errorCount} errors` + - ` and ${extractorResult.warningCount} warnings`, - ), - }); - success = false; - break; + throw new Error( + `Type definition build completed with ${extractorResult.errorCount} errors` + + ` and ${extractorResult.warningCount} warnings`, + ); } } - - if (success) { - parentPort.postMessage({ type: 'done' }); - } } diff --git a/packages/cli/src/lib/diff/handlers.ts b/packages/cli/src/lib/diff/handlers.ts index 5bd90e3d22..55e9cddd3d 100644 --- a/packages/cli/src/lib/diff/handlers.ts +++ b/packages/cli/src/lib/diff/handlers.ts @@ -173,6 +173,14 @@ class PackageJsonHandler { return; } + // Skip diffing package scripts that have been migrated to the new commands + const hasNewScript = Object.values(targetScripts).some(script => + String(script).includes('backstage-cli package '), + ); + if (hasNewScript) { + return; + } + for (const key of Object.keys(pkgScripts)) { await this.syncField(key, pkgScripts, targetScripts, 'scripts'); } diff --git a/packages/cli/src/lib/git.test.ts b/packages/cli/src/lib/git.test.ts new file mode 100644 index 0000000000..2e5d464796 --- /dev/null +++ b/packages/cli/src/lib/git.test.ts @@ -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 { runGit, listChangedFiles } from './git'; + +describe('runGit', () => { + it('runs a git command', async () => { + await expect(runGit('log', 'HEAD..HEAD')).resolves.toEqual(['']); + }); + + it('fails for unknown commands', async () => { + await expect(runGit('ryckbegäran')).rejects.toThrow( + /^git ryckbegäran failed, git: 'ryckbegäran' is not a git command/, + ); + }); + + it('forwards failures', async () => { + await expect( + runGit( + 'show', + '--quiet', + '--pretty=format:%s', + '0000000000000000000000000000000000000000', + ), + ).rejects.toThrow( + 'git show failed, fatal: bad object 0000000000000000000000000000000000000000', + ); + }); +}); + +describe('listChangedFiles', () => { + it('requires a ref', async () => { + await expect(listChangedFiles('')).rejects.toThrow('ref is required'); + }); + + it('should return something', async () => { + await expect(listChangedFiles('HEAD')).resolves.toEqual(expect.any(Array)); + }); +}); diff --git a/packages/cli/src/lib/git.ts b/packages/cli/src/lib/git.ts new file mode 100644 index 0000000000..f8783804d1 --- /dev/null +++ b/packages/cli/src/lib/git.ts @@ -0,0 +1,59 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { assertError, ForwardedError } from '@backstage/errors'; +import { execFile as execFileCb } from 'child_process'; +import { promisify } from 'util'; +import { paths } from './paths'; + +const execFile = promisify(execFileCb); + +/** + * Run a git command, trimming the output splitting it into lines. + */ +export async function runGit(...args: string[]) { + try { + const { stdout } = await execFile('git', args, { + shell: true, + cwd: paths.targetRoot, + }); + return stdout.trim().split(/\r\n|\r|\n/); + } catch (error) { + assertError(error); + if (error.stderr || typeof error.code === 'number') { + const stderr = (error.stderr as undefined | Buffer)?.toString('utf8'); + const msg = stderr?.trim() ?? `with exit code ${error.code}`; + throw new Error(`git ${args[0]} failed, ${msg}`); + } + throw new ForwardedError('Unknown execution error', error); + } +} + +/** + * Returns a sorted list of all files that have changed since the merge base + * of the provided `ref` and HEAD, as well as all files that are not tracked by git. + */ +export async function listChangedFiles(ref: string) { + if (!ref) { + throw new Error('ref is required'); + } + const [base] = await runGit('merge-base', 'HEAD', ref); + + const tracked = await runGit('diff', '--name-only', base); + const untracked = await runGit('ls-files', '--others', '--exclude-standard'); + + return Array.from(new Set([...tracked, ...untracked])); +} diff --git a/packages/cli/src/lib/logging.ts b/packages/cli/src/lib/logging.ts index 8745585d1e..59473d7f64 100644 --- a/packages/cli/src/lib/logging.ts +++ b/packages/cli/src/lib/logging.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -export type LogFunc = (data: Buffer | string) => void; +export type LogFunc = (data: Buffer) => void; export type LogPipe = (dst: NodeJS.WriteStream) => LogFunc; export type LogOptions = { diff --git a/packages/cli/src/lib/monorepo/PackageGraph.test.ts b/packages/cli/src/lib/monorepo/PackageGraph.test.ts index e8e531bc93..06427a7313 100644 --- a/packages/cli/src/lib/monorepo/PackageGraph.test.ts +++ b/packages/cli/src/lib/monorepo/PackageGraph.test.ts @@ -15,8 +15,20 @@ */ import { getPackages } from '@manypkg/get-packages'; -import { paths } from '../paths'; import { PackageGraph } from './PackageGraph'; +import { listChangedFiles } from '../git'; + +jest.mock('../git'); + +const mockListChangedFiles = listChangedFiles as jest.MockedFunction< + typeof listChangedFiles +>; + +jest.mock('../paths', () => ({ + paths: { + targetRoot: '/', + }, +})); const testPackages = [ { @@ -53,7 +65,7 @@ const testPackages = [ describe('PackageGraph', () => { it('is able to construct a graph from this repo', async () => { - const { packages } = await getPackages(paths.ownDir); + const { packages } = await getPackages(__dirname); const graph = PackageGraph.fromPackages(packages); expect(graph.has('@backstage/cli')).toBe(true); }); @@ -124,4 +136,24 @@ describe('PackageGraph', () => { `Package 'unknown' not found`, ); }); + + it('lists changed packages', async () => { + const graph = PackageGraph.fromPackages(testPackages); + + mockListChangedFiles.mockResolvedValueOnce( + [ + 'README.md', + 'packages/a/src/foo.ts', + 'packages/a/src/bar.ts', + 'packages/b/package.json', + 'packages/f/src/foo.ts', + 'packages/f/README.md', + 'plugins/foo/src/index.ts', + ].sort(), + ); + + await expect( + graph.listChangedPackages({ ref: 'origin/master' }), + ).resolves.toEqual([graph.get('a'), graph.get('b')]); + }); }); diff --git a/packages/cli/src/lib/monorepo/PackageGraph.ts b/packages/cli/src/lib/monorepo/PackageGraph.ts index 89d5f79cd2..a1f77299df 100644 --- a/packages/cli/src/lib/monorepo/PackageGraph.ts +++ b/packages/cli/src/lib/monorepo/PackageGraph.ts @@ -14,9 +14,11 @@ * limitations under the License. */ +import { relative as relativePath, posix as posixPath } from 'path'; import { getPackages, Package } from '@manypkg/get-packages'; import { paths } from '../paths'; import { PackageRole } from '../role'; +import { listChangedFiles } from '../git'; type PackageJSON = Package['packageJson']; @@ -158,4 +160,47 @@ export class PackageGraph extends Map { return targets; } + + async listChangedPackages(options: { ref: string }) { + const changedFiles = await listChangedFiles(options.ref); + + const dirMap = new Map( + Array.from(this.values()).map(pkg => [ + posixPath.normalize(relativePath(paths.targetRoot, pkg.dir)) + + posixPath.sep, + pkg, + ]), + ); + const packageDirs = Array.from(dirMap.keys()); + + const result = new Array(); + let searchIndex = 0; + + changedFiles.sort(); + packageDirs.sort(); + + for (const packageDir of packageDirs) { + // Skip through changes that appear before our package dir + while ( + searchIndex < changedFiles.length && + changedFiles[searchIndex] < packageDir + ) { + searchIndex += 1; + } + + // Check if we arrived at a match, otherwise we move on to the next package dir + if (changedFiles[searchIndex]?.startsWith(packageDir)) { + searchIndex += 1; + + result.push(dirMap.get(packageDir)!); + + // Skip through the rest of the changed files for the same package + while (changedFiles[searchIndex]?.startsWith(packageDir)) { + searchIndex += 1; + } + } + } + + return result; + } } diff --git a/packages/cli/src/lib/monorepo/index.ts b/packages/cli/src/lib/monorepo/index.ts index aa12c63abc..7156975c07 100644 --- a/packages/cli/src/lib/monorepo/index.ts +++ b/packages/cli/src/lib/monorepo/index.ts @@ -15,4 +15,8 @@ */ export { PackageGraph } from './PackageGraph'; -export type { PackageGraphNode } from './PackageGraph'; +export type { + PackageGraphNode, + ExtendedPackage, + ExtendedPackageJSON, +} from './PackageGraph'; diff --git a/packages/cli/src/lib/packager/createDistWorkspace.ts b/packages/cli/src/lib/packager/createDistWorkspace.ts index 15ccda30c2..bce6c5c14c 100644 --- a/packages/cli/src/lib/packager/createDistWorkspace.ts +++ b/packages/cli/src/lib/packager/createDistWorkspace.ts @@ -38,6 +38,7 @@ import { Output, } from '../builder'; import { copyPackageDist } from './copyPackageDist'; +import { getRoleInfo } from '../role'; // These packages aren't safe to pack in parallel since the CLI depends on them const UNSAFE_PACKAGES = [ @@ -131,7 +132,9 @@ export async function createDistWorkspace( } const role = pkg.packageJson.backstage?.role; if (!role) { - console.warn(`Ignored ${pkg.packageJson.name} because it has no role`); + console.warn( + `Building ${pkg.packageJson.name} separately because it has no role`, + ); customBuild.push(pkg.packageJson.name); continue; } @@ -142,9 +145,17 @@ export async function createDistWorkspace( continue; } - if (!buildScript.startsWith('backstage-cli script build')) { + if (!buildScript.startsWith('backstage-cli package build')) { console.warn( - `Ignored ${pkg.packageJson.name} because it has a custom build script, '${buildScript}'`, + `Building ${pkg.packageJson.name} separately because it has a custom build script, '${buildScript}'`, + ); + customBuild.push(pkg.packageJson.name); + continue; + } + + if (getRoleInfo(role).output.includes('bundle')) { + console.warn( + `Building ${pkg.packageJson.name} separately because it is a bundled package`, ); customBuild.push(pkg.packageJson.name); continue; @@ -216,7 +227,7 @@ export async function createDistWorkspace( const FAST_PACK_SCRIPTS = [ undefined, 'backstage-cli prepack', - 'backstage-cli script prepack', + 'backstage-cli package prepack', ]; async function moveToDistWorkspace( diff --git a/packages/cli/src/lib/parallel.test.ts b/packages/cli/src/lib/parallel.test.ts index d851f33f82..032d66afac 100644 --- a/packages/cli/src/lib/parallel.test.ts +++ b/packages/cli/src/lib/parallel.test.ts @@ -14,12 +14,17 @@ * limitations under the License. */ +import os from 'os'; import { parseParallelismOption, getEnvironmentParallelism, runParallelWorkers, + runWorkerQueueThreads, + runWorkerThreads, } from './parallel'; +const defaultParallelism = Math.ceil(os.cpus().length / 2); + describe('parseParallelismOption', () => { it('coerces false no parallelism', () => { expect(parseParallelismOption(false)).toBe(1); @@ -27,10 +32,10 @@ describe('parseParallelismOption', () => { }); it('coerces true or undefined to default parallelism', () => { - expect(parseParallelismOption(true)).toBe(4); - expect(parseParallelismOption('true')).toBe(4); - expect(parseParallelismOption(undefined)).toBe(4); - expect(parseParallelismOption(null)).toBe(4); + expect(parseParallelismOption(true)).toBe(defaultParallelism); + expect(parseParallelismOption('true')).toBe(defaultParallelism); + expect(parseParallelismOption(undefined)).toBe(defaultParallelism); + expect(parseParallelismOption(null)).toBe(defaultParallelism); }); it('coerces number string to number', () => { @@ -50,13 +55,13 @@ describe('getEnvironmentParallelism', () => { expect(getEnvironmentParallelism()).toBe(2); process.env.BACKSTAGE_CLI_BUILD_PARALLEL = 'true'; - expect(getEnvironmentParallelism()).toBe(4); + expect(getEnvironmentParallelism()).toBe(defaultParallelism); process.env.BACKSTAGE_CLI_BUILD_PARALLEL = 'false'; expect(getEnvironmentParallelism()).toBe(1); delete process.env.BACKSTAGE_CLI_BUILD_PARALLEL; - expect(getEnvironmentParallelism()).toBe(4); + expect(getEnvironmentParallelism()).toBe(defaultParallelism); }); }); @@ -68,6 +73,7 @@ describe('runParallelWorkers', () => { const work = runParallelWorkers({ items: [0, 1, 2, 3, 4], + parallelismSetting: 4, parallelismFactor: 0.5, // 2 at a time worker: async item => { started.push(item); @@ -142,3 +148,68 @@ describe('runParallelWorkers', () => { expect(done).toEqual([0, 1, 2, 3, 4]); }); }); + +describe('runWorkerQueueThreads', () => { + it('should execute work in parallel', async () => { + const sharedData = new SharedArrayBuffer(10); + const sharedView = new Uint8Array(sharedData); + + const results = await runWorkerQueueThreads({ + threadCount: 4, + workerData: sharedData, + items: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + workerFactory: data => { + const view = new Uint8Array(data); + + return async (i: number) => { + view[i] = 10 + i; + return 20 + i; + }; + }, + }); + + expect(Array.from(sharedView)).toEqual([ + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + ]); + expect(results).toEqual([20, 21, 22, 23, 24, 25, 26, 27, 28, 29]); + }); +}); + +describe('runWorkerThreads', () => { + it('should run a single thread without items', async () => { + const [result] = await runWorkerThreads({ + threadCount: 1, + workerData: 'foo', + worker: async data => `${data}bar`, + }); + + expect(result).toBe('foobar'); + }); + + it('should run multiple threads without items', async () => { + const results = await runWorkerThreads({ + threadCount: 4, + worker: async () => 'foo', + }); + + expect(results).toEqual(['foo', 'foo', 'foo', 'foo']); + }); + + it('should send messages', async () => { + const messages = new Array(); + + await runWorkerThreads({ + threadCount: 2, + worker: async (_data, sendMessage) => { + sendMessage('a'); + await new Promise(resolve => setTimeout(resolve, 10)); + sendMessage('b'); + await new Promise(resolve => setTimeout(resolve, 10)); + sendMessage('c'); + }, + onMessage: (message: string) => messages.push(message), + }); + + expect(messages.sort()).toEqual(['a', 'a', 'b', 'b', 'c', 'c']); + }); +}); diff --git a/packages/cli/src/lib/parallel.ts b/packages/cli/src/lib/parallel.ts index f8af967d22..7b4ae4609e 100644 --- a/packages/cli/src/lib/parallel.ts +++ b/packages/cli/src/lib/parallel.ts @@ -14,17 +14,21 @@ * limitations under the License. */ -export const DEFAULT_PARALLELISM = 4; +import os from 'os'; +import { ErrorLike } from '@backstage/errors'; +import { Worker } from 'worker_threads'; -export const PARALLEL_ENV_VAR = 'BACKSTAGE_CLI_BUILD_PARALLEL'; +const defaultParallelism = Math.ceil(os.cpus().length / 2); + +const PARALLEL_ENV_VAR = 'BACKSTAGE_CLI_BUILD_PARALLEL'; export type ParallelismOption = boolean | string | number | null | undefined; export function parseParallelismOption(parallel: ParallelismOption): number { if (parallel === undefined || parallel === null) { - return DEFAULT_PARALLELISM; + return defaultParallelism; } else if (typeof parallel === 'boolean') { - return parallel ? DEFAULT_PARALLELISM : 1; + return parallel ? defaultParallelism : 1; } else if (typeof parallel === 'number' && Number.isInteger(parallel)) { if (parallel < 1) { return 1; @@ -88,3 +92,249 @@ export async function runParallelWorkers( }), ); } + +type WorkerThreadMessage = + | { + type: 'done'; + } + | { + type: 'item'; + index: number; + item: unknown; + } + | { + type: 'start'; + } + | { + type: 'result'; + index: number; + result: unknown; + } + | { + type: 'error'; + error: ErrorLike; + } + | { + type: 'message'; + message: unknown; + }; + +export type WorkerQueueThreadsOptions = { + /** The items to process */ + items: Iterable; + /** + * A function that will be called within each worker thread at startup, + * which should return the worker function that will be called for each item. + * + * This function must be defined as an arrow function or using the + * function keyword, and must be entirely self contained, not referencing + * any variables outside of its scope. This is because the function source + * is stringified and evaluated in the worker thread. + * + * To pass data to the worker, use the `workerData` option and `items`, but + * note that they are both copied by value into the worker thread, except for + * types that are explicitly shareable across threads, such as `SharedArrayBuffer`. + */ + workerFactory: ( + data: TData, + ) => + | ((item: TItem) => Promise) + | Promise<(item: TItem) => Promise>; + /** Data supplied to each worker factory */ + workerData?: TData; + /** Number of threads, defaults to half of the number of available CPUs */ + threadCount?: number; +}; + +/** + * Spawns one or more worker threads using the `worker_threads` module. + * Each thread processes one item at a time from the provided `options.items`. + */ +export async function runWorkerQueueThreads( + options: WorkerQueueThreadsOptions, +): Promise { + const items = Array.from(options.items); + const { + workerFactory, + workerData, + threadCount = Math.min(getEnvironmentParallelism(), items.length), + } = options; + + const iterator = items[Symbol.iterator](); + const results = new Array(); + let itemIndex = 0; + + await Promise.all( + Array(threadCount) + .fill(0) + .map(async () => { + const thread = new Worker(`(${workerQueueThread})(${workerFactory})`, { + eval: true, + workerData, + }); + + return new Promise((resolve, reject) => { + thread.on('message', (message: WorkerThreadMessage) => { + if (message.type === 'start' || message.type === 'result') { + if (message.type === 'result') { + results[message.index] = message.result as TResult; + } + const { value, done } = iterator.next(); + if (done) { + thread.postMessage({ type: 'done' }); + } else { + thread.postMessage({ + type: 'item', + index: itemIndex, + item: value, + }); + itemIndex += 1; + } + } else if (message.type === 'error') { + const error = new Error(message.error.message); + error.name = message.error.name; + error.stack = message.error.stack; + reject(error); + } + }); + + thread.on('error', reject); + thread.on('exit', (code: number) => { + if (code !== 0) { + reject(new Error(`Worker thread exited with code ${code}`)); + } else { + resolve(); + } + }); + }); + }), + ); + + return results; +} + +function workerQueueThread( + workerFuncFactory: ( + data: unknown, + ) => Promise<(item: unknown) => Promise>, +) { + const { parentPort, workerData } = require('worker_threads'); + + Promise.resolve() + .then(() => workerFuncFactory(workerData)) + .then( + workerFunc => { + parentPort.on('message', async (message: WorkerThreadMessage) => { + if (message.type === 'done') { + parentPort.close(); + return; + } + if (message.type === 'item') { + try { + const result = await workerFunc(message.item); + parentPort.postMessage({ + type: 'result', + index: message.index, + result, + }); + } catch (error) { + parentPort.postMessage({ type: 'error', error }); + } + } + }); + + parentPort.postMessage({ type: 'start' }); + }, + error => parentPort.postMessage({ type: 'error', error }), + ); +} + +export type WorkerThreadsOptions = { + /** + * A function that is called by each worker thread to produce a result. + * + * This function must be defined as an arrow function or using the + * function keyword, and must be entirely self contained, not referencing + * any variables outside of its scope. This is because the function source + * is stringified and evaluated in the worker thread. + * + * To pass data to the worker, use the `workerData` option, but + * note that they are both copied by value into the worker thread, except for + * types that are explicitly shareable across threads, such as `SharedArrayBuffer`. + */ + worker: ( + data: TData, + sendMessage: (message: TMessage) => void, + ) => Promise; + /** Data supplied to each worker */ + workerData?: TData; + /** Number of threads, defaults to 1 */ + threadCount?: number; + /** An optional handler for messages posted from the worker thread */ + onMessage?: (message: TMessage) => void; +}; + +/** + * Spawns one or more worker threads using the `worker_threads` module. + */ +export async function runWorkerThreads( + options: WorkerThreadsOptions, +): Promise { + const { worker, workerData, threadCount = 1, onMessage } = options; + + return Promise.all( + Array(threadCount) + .fill(0) + .map(async () => { + const thread = new Worker(`(${workerThread})(${worker})`, { + eval: true, + workerData, + }); + + return new Promise((resolve, reject) => { + thread.on('message', (message: WorkerThreadMessage) => { + if (message.type === 'result') { + resolve(message.result as TResult); + } else if (message.type === 'error') { + reject(message.error); + } else if (message.type === 'message') { + onMessage?.(message.message as TMessage); + } + }); + + thread.on('error', reject); + thread.on('exit', (code: number) => { + reject( + new Error(`Unexpected worker thread exit with code ${code}`), + ); + }); + }); + }), + ); +} + +function workerThread( + workerFunc: ( + data: unknown, + sendMessage: (message: unknown) => void, + ) => Promise, +) { + const { parentPort, workerData } = require('worker_threads'); + + const sendMessage = (message: unknown) => { + parentPort.postMessage({ type: 'message', message }); + }; + + workerFunc(workerData, sendMessage).then( + result => { + parentPort.postMessage({ + type: 'result', + index: 0, + result, + }); + }, + error => { + parentPort.postMessage({ type: 'error', error }); + }, + ); +} diff --git a/packages/cli/src/lib/role/packageRoles.test.ts b/packages/cli/src/lib/role/packageRoles.test.ts index f6c9fb418a..759be462d2 100644 --- a/packages/cli/src/lib/role/packageRoles.test.ts +++ b/packages/cli/src/lib/role/packageRoles.test.ts @@ -31,8 +31,8 @@ describe('getRoleInfo', () => { output: ['types', 'esm'], }); - expect(getRoleInfo('app')).toEqual({ - role: 'app', + expect(getRoleInfo('frontend')).toEqual({ + role: 'frontend', platform: 'web', output: ['bundle'], }); @@ -56,10 +56,10 @@ describe('getRoleFromPackage', () => { expect( getRoleFromPackage({ backstage: { - role: 'app', + role: 'frontend', }, }), - ).toEqual('app'); + ).toEqual('frontend'); expect(() => getRoleFromPackage({ @@ -135,7 +135,7 @@ describe('detectRoleFromPackage', () => { 'cy:run': 'cypress run', }, }), - ).toEqual('app'); + ).toEqual('frontend'); }); it('detects the role of example-backend', () => { @@ -180,7 +180,7 @@ describe('detectRoleFromPackage', () => { clean: 'backstage-cli clean', }, }), - ).toEqual('plugin-frontend'); + ).toEqual('frontend-plugin'); }); it('detects the role of @backstage/plugin-catalog-backend', () => { @@ -204,7 +204,7 @@ describe('detectRoleFromPackage', () => { clean: 'backstage-cli clean', }, }), - ).toEqual('plugin-backend'); + ).toEqual('backend-plugin'); }); it('detects the role of @backstage/plugin-catalog-react', () => { @@ -274,7 +274,7 @@ describe('detectRoleFromPackage', () => { clean: 'backstage-cli clean', }, }), - ).toEqual('plugin-backend-module'); + ).toEqual('backend-plugin-module'); }); it('detects the role of @backstage/plugin-permission-node', () => { @@ -323,6 +323,6 @@ describe('detectRoleFromPackage', () => { clean: 'backstage-cli clean', }, }), - ).toEqual('plugin-frontend-module'); + ).toEqual('frontend-plugin-module'); }); }); diff --git a/packages/cli/src/lib/role/packageRoles.ts b/packages/cli/src/lib/role/packageRoles.ts index 7c855ee0fd..a33a7d715a 100644 --- a/packages/cli/src/lib/role/packageRoles.ts +++ b/packages/cli/src/lib/role/packageRoles.ts @@ -22,7 +22,7 @@ import { PackageRole, PackageRoleInfo } from './types'; const packageRoleInfos: PackageRoleInfo[] = [ { - role: 'app', + role: 'frontend', platform: 'web', output: ['bundle'], }, @@ -52,22 +52,22 @@ const packageRoleInfos: PackageRoleInfo[] = [ output: ['types', 'esm', 'cjs'], }, { - role: 'plugin-frontend', + role: 'frontend-plugin', platform: 'web', output: ['types', 'esm'], }, { - role: 'plugin-frontend-module', + role: 'frontend-plugin-module', platform: 'web', output: ['types', 'esm'], }, { - role: 'plugin-backend', + role: 'backend-plugin', platform: 'node', output: ['types', 'cjs'], }, { - role: 'plugin-backend-module', + role: 'backend-plugin-module', platform: 'node', output: ['types', 'cjs'], }, @@ -147,22 +147,22 @@ export function detectRoleFromPackage( const pkg = detectionSchema.parse(pkgJson); if (pkg.scripts?.start?.includes('app:serve')) { - return 'app'; + return 'frontend'; } if (pkg.scripts?.build?.includes('backend:bundle')) { return 'backend'; } if (pkg.name?.includes('plugin-') && pkg.name?.includes('-backend-module-')) { - return 'plugin-backend-module'; + return 'backend-plugin-module'; } if (pkg.name?.includes('plugin-') && pkg.name?.includes('-module-')) { - return 'plugin-frontend-module'; + return 'frontend-plugin-module'; } if (pkg.scripts?.start?.includes('plugin:serve')) { - return 'plugin-frontend'; + return 'frontend-plugin'; } if (pkg.scripts?.start?.includes('backend:dev')) { - return 'plugin-backend'; + return 'backend-plugin'; } const mainEntry = pkg.publishConfig?.main || pkg.main; diff --git a/packages/cli/src/lib/role/types.ts b/packages/cli/src/lib/role/types.ts index 6a89f7bdaf..a3961544f4 100644 --- a/packages/cli/src/lib/role/types.ts +++ b/packages/cli/src/lib/role/types.ts @@ -15,16 +15,16 @@ */ export type PackageRole = - | 'app' + | 'frontend' | 'backend' | 'cli' | 'web-library' | 'node-library' | 'common-library' - | 'plugin-frontend' - | 'plugin-frontend-module' - | 'plugin-backend' - | 'plugin-backend-module'; + | 'frontend-plugin' + | 'frontend-plugin-module' + | 'backend-plugin' + | 'backend-plugin-module'; export type PackagePlatform = 'node' | 'web' | 'common'; export type PackageOutputType = 'bundle' | 'types' | 'esm' | 'cjs'; diff --git a/packages/cli/src/lib/svgrTemplate.ts b/packages/cli/src/lib/svgrTemplate.ts index ca2a8c38fa..6af1b95e71 100644 --- a/packages/cli/src/lib/svgrTemplate.ts +++ b/packages/cli/src/lib/svgrTemplate.ts @@ -20,28 +20,23 @@ * them with .icon.svg */ export function svgrTemplate( - { template }: any, - _opts: any, - { imports, interfaces, componentName, jsx }: any, + { imports, interfaces, componentName, props, jsx }: any, + { tpl }: any, ) { - const iconName = { - ...componentName, - name: `${componentName.name.replace(/icon$/, '')}Icon`, - }; + const name = `${componentName.replace(/icon$/, '')}Icon`; const defaultExport = { type: 'ExportDefaultDeclaration', - declaration: iconName, + declaration: { type: 'Identifier', name }, }; - const typeScriptTemplate = template.smart({ plugins: ['typescript'] }); - return typeScriptTemplate.ast` + return tpl` ${imports} import SvgIcon from '@material-ui/core/SvgIcon'; ${interfaces} -const ${iconName} = props => React.createElement(SvgIcon, props, ${jsx.children}); +const ${name} = (${props}) => React.createElement(SvgIcon, ${props}, ${jsx.children}); ${defaultExport}`; } diff --git a/packages/cli/src/lib/versioning/packages.ts b/packages/cli/src/lib/versioning/packages.ts index 9f2f2bdc65..ed7266a692 100644 --- a/packages/cli/src/lib/versioning/packages.ts +++ b/packages/cli/src/lib/versioning/packages.ts @@ -67,7 +67,10 @@ export async function mapDependencies( targetDir: string, pattern: string, ): Promise> { - const { packages } = await getPackages(targetDir); + const { packages, root } = await getPackages(targetDir); + + // Include root package.json too + packages.push(root); const dependencyMap = new Map(); for (const pkg of packages) { diff --git a/packages/codemods/.snyk b/packages/codemods/.snyk new file mode 100644 index 0000000000..7926925d71 --- /dev/null +++ b/packages/codemods/.snyk @@ -0,0 +1,12 @@ +# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities. +version: v1.22.1 +# ignores vulnerabilities until expiry date; change duration by modifying expiry date +ignore: + SNYK-JS-UNSETVALUE-2400660: + - '*': + reason: >- + The pollution in this vulnerability does not allow injection of + arbitrary values and is therefore a negligible risk for a CLI. + expires: 2022-08-17T21:54:43.658Z + created: 2022-02-15T21:54:43.668Z +patch: {} diff --git a/packages/codemods/package.json b/packages/codemods/package.json index dc1fe6a537..eef854868c 100644 --- a/packages/codemods/package.json +++ b/packages/codemods/package.json @@ -7,6 +7,9 @@ "access": "public", "main": "dist/index.cjs.js" }, + "backstage": { + "role": "cli" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -20,12 +23,12 @@ "main": "src/index.ts", "scripts": { "start": "nodemon --", - "build": "backstage-cli build --outputs cjs", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "prepack": "backstage-cli prepack", "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "clean": "backstage-cli package clean" }, "bin": { "backstage-codemods": "bin/backstage-codemods" diff --git a/packages/config-loader/package.json b/packages/config-loader/package.json index b374a02fbf..22323643b0 100644 --- a/packages/config-loader/package.json +++ b/packages/config-loader/package.json @@ -9,6 +9,9 @@ "module": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "node-library" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -22,12 +25,13 @@ "main": "src/index.ts", "types": "src/index.ts", "scripts": { - "build": "backstage-cli build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean", + "start": "backstage-cli package start" }, "dependencies": { "@backstage/cli-common": "^0.1.6", diff --git a/packages/config/package.json b/packages/config/package.json index 02c63af2b5..b3cbc14988 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -9,6 +9,9 @@ "module": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "common-library" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -22,12 +25,12 @@ "main": "src/index.ts", "types": "src/index.ts", "scripts": { - "build": "backstage-cli build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/types": "^0.1.1", diff --git a/packages/core-app-api/package.json b/packages/core-app-api/package.json index 04e87b5d0c..b23eedd7c9 100644 --- a/packages/core-app-api/package.json +++ b/packages/core-app-api/package.json @@ -8,6 +8,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "web-library" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -21,12 +24,13 @@ "main": "src/index.ts", "types": "src/index.ts", "scripts": { - "build": "backstage-cli build --outputs types,esm", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean", + "start": "backstage-cli package start" }, "dependencies": { "@backstage/config": "^0.1.13", diff --git a/packages/core-components/package.json b/packages/core-components/package.json index ecb910c50b..497f0b6ed6 100644 --- a/packages/core-components/package.json +++ b/packages/core-components/package.json @@ -8,6 +8,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "web-library" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -21,12 +24,13 @@ "main": "src/index.ts", "types": "src/index.ts", "scripts": { - "build": "backstage-cli build --outputs types,esm", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean", + "start": "backstage-cli package start" }, "dependencies": { "@backstage/config": "^0.1.13", @@ -60,7 +64,8 @@ "react-sparklines": "^1.7.0", "react-syntax-highlighter": "^15.4.5", "react-text-truncate": "^0.17.0", - "react-use": "^17.2.4", + "react-use": "^17.3.2", + "@react-hookz/web": "^12.3.0", "react-virtualized-auto-sizer": "^1.0.6", "react-window": "^1.8.6", "remark-gfm": "^3.0.1", diff --git a/packages/core-components/src/components/LogViewer/useLogViewerSearch.tsx b/packages/core-components/src/components/LogViewer/useLogViewerSearch.tsx index 7f0069bc44..14f71984f4 100644 --- a/packages/core-components/src/components/LogViewer/useLogViewerSearch.tsx +++ b/packages/core-components/src/components/LogViewer/useLogViewerSearch.tsx @@ -15,7 +15,7 @@ */ import { useMemo, useState } from 'react'; -import useToggle from 'react-use/lib/useToggle'; +import { useToggle } from '@react-hookz/web'; import { AnsiLine } from './AnsiProcessor'; export function applySearchFilter(lines: AnsiLine[], searchText: string) { diff --git a/packages/core-components/src/components/OverflowTooltip/OverflowTooltip.tsx b/packages/core-components/src/components/OverflowTooltip/OverflowTooltip.tsx index 69952d487a..da489725e4 100644 --- a/packages/core-components/src/components/OverflowTooltip/OverflowTooltip.tsx +++ b/packages/core-components/src/components/OverflowTooltip/OverflowTooltip.tsx @@ -18,7 +18,7 @@ import { makeStyles } from '@material-ui/core/styles'; import Tooltip, { TooltipProps } from '@material-ui/core/Tooltip'; import React, { useState } from 'react'; import TextTruncate, { TextTruncateProps } from 'react-text-truncate'; -import useMountedState from 'react-use/lib/useMountedState'; +import { useIsMounted } from '@react-hookz/web'; type Props = { text: TextTruncateProps['text']; @@ -41,7 +41,7 @@ const useStyles = makeStyles( export function OverflowTooltip(props: Props) { const [hover, setHover] = useState(false); - const isMounted = useMountedState(); + const isMounted = useIsMounted(); const classes = useStyles(); const handleToggled = (truncated: boolean) => { diff --git a/packages/core-components/src/hooks/useQueryParamState.ts b/packages/core-components/src/hooks/useQueryParamState.ts index 72ccafd99f..16cd9e18c8 100644 --- a/packages/core-components/src/hooks/useQueryParamState.ts +++ b/packages/core-components/src/hooks/useQueryParamState.ts @@ -18,7 +18,7 @@ import { isEqual } from 'lodash'; import qs from 'qs'; import { useEffect, useState } from 'react'; import { useSearchParams } from 'react-router-dom'; -import useDebounce from 'react-use/lib/useDebounce'; +import { useDebouncedEffect } from '@react-hookz/web'; function stringify(queryParams: any): string { // Even though these setting don't look nice (e.g. escaped brackets), we should keep @@ -75,7 +75,7 @@ export function useQueryParamState( ); }, [searchParamsString, setQueryParamState, stateName]); - useDebounce( + useDebouncedEffect( () => { const queryString = joinQueryString( searchParamsString, @@ -87,8 +87,8 @@ export function useQueryParamState( setSearchParams(queryString, { replace: true }); } }, - debounceTime, [setSearchParams, queryParamState, searchParamsString, stateName], + debounceTime, ); return [queryParamState, setQueryParamState]; diff --git a/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInPage.tsx b/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInPage.tsx index adcd6ced8f..13a61d259f 100644 --- a/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInPage.tsx +++ b/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInPage.tsx @@ -20,7 +20,7 @@ import { useApi, } from '@backstage/core-plugin-api'; import React from 'react'; -import useAsync from 'react-use/lib/useAsync'; +import { useAsync, useMountEffect } from '@react-hookz/web'; import { ErrorPanel } from '../../components/ErrorPanel'; import { Progress } from '../../components/Progress'; import { ProxiedSignInIdentity } from './ProxiedSignInIdentity'; @@ -56,7 +56,7 @@ export type ProxiedSignInPageProps = SignInPageProps & { export const ProxiedSignInPage = (props: ProxiedSignInPageProps) => { const discoveryApi = useApi(discoveryApiRef); - const { loading, error } = useAsync(async () => { + const [{ status, error }, { execute }] = useAsync(async () => { const identity = new ProxiedSignInIdentity({ provider: props.provider, discoveryApi, @@ -65,9 +65,11 @@ export const ProxiedSignInPage = (props: ProxiedSignInPageProps) => { await identity.start(); props.onSignInSuccess(identity); - }, []); + }); - if (loading) { + useMountEffect(execute); + + if (status === 'loading') { return ; } else if (error) { return ( diff --git a/packages/core-components/src/layout/Sidebar/Intro.tsx b/packages/core-components/src/layout/Sidebar/Intro.tsx index 7b2c5fa4d7..1fcc54188f 100644 --- a/packages/core-components/src/layout/Sidebar/Intro.tsx +++ b/packages/core-components/src/layout/Sidebar/Intro.tsx @@ -21,7 +21,7 @@ import { makeStyles } from '@material-ui/core/styles'; import Typography from '@material-ui/core/Typography'; import CloseIcon from '@material-ui/icons/Close'; import React, { useContext, useState } from 'react'; -import useLocalStorage from 'react-use/lib/useLocalStorage'; +import { useLocalStorageValue } from '@react-hookz/web'; import { sidebarConfig, SidebarContext, @@ -155,7 +155,7 @@ export function SidebarIntro(_props: {}) { recentlyViewedItemsDismissed: false, }; const [dismissedIntro, setDismissedIntro] = - useLocalStorage(SIDEBAR_INTRO_LOCAL_STORAGE); + useLocalStorageValue(SIDEBAR_INTRO_LOCAL_STORAGE); const { starredItemsDismissed, recentlyViewedItemsDismissed } = dismissedIntro ?? {}; diff --git a/packages/core-components/src/layout/SignInPage/SignInPage.tsx b/packages/core-components/src/layout/SignInPage/SignInPage.tsx index 2eac16cbf4..6092f2862f 100644 --- a/packages/core-components/src/layout/SignInPage/SignInPage.tsx +++ b/packages/core-components/src/layout/SignInPage/SignInPage.tsx @@ -25,7 +25,7 @@ import Button from '@material-ui/core/Button'; import Grid from '@material-ui/core/Grid'; import Typography from '@material-ui/core/Typography'; import React, { useState } from 'react'; -import useMount from 'react-use/lib/useMount'; +import { useMountEffect } from '@react-hookz/web'; import { Progress } from '../../components/Progress'; import { Content } from '../Content/Content'; import { ContentHeader } from '../ContentHeader/ContentHeader'; @@ -149,7 +149,7 @@ export const SingleSignInPage = ({ } }; - useMount(() => login({ checkExisting: true })); + useMountEffect(() => login({ checkExisting: true })); return showLoginPage ? ( diff --git a/packages/core-plugin-api/package.json b/packages/core-plugin-api/package.json index c9f110b432..b4b94fbe7e 100644 --- a/packages/core-plugin-api/package.json +++ b/packages/core-plugin-api/package.json @@ -8,6 +8,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "web-library" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -21,12 +24,13 @@ "main": "src/index.ts", "types": "src/index.ts", "scripts": { - "build": "backstage-cli build --outputs types,esm", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean", + "start": "backstage-cli package start" }, "dependencies": { "@backstage/config": "^0.1.13", @@ -35,7 +39,6 @@ "history": "^5.0.0", "prop-types": "^15.7.2", "react-router-dom": "6.0.0-beta.0", - "react-use": "^17.2.4", "zen-observable": "^0.8.15" }, "peerDependencies": { diff --git a/packages/create-app/package.json b/packages/create-app/package.json index 991a241887..fc1ccc1803 100644 --- a/packages/create-app/package.json +++ b/packages/create-app/package.json @@ -6,6 +6,9 @@ "publishConfig": { "access": "public" }, + "backstage": { + "role": "cli" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -21,10 +24,10 @@ "backstage-create-app": "bin/backstage-create-app" }, "scripts": { - "build": "backstage-cli build --outputs cjs", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "clean": "backstage-cli clean", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", "prepack": "node scripts/prepack.js", "postpack": "node scripts/postpack.js", "start": "nodemon --" @@ -48,6 +51,7 @@ "ts-node": "^10.0.0" }, "peerDependencies": { + "@backstage/app-defaults": "", "@backstage/backend-common": "", "@backstage/backend-tasks": "", "@backstage/catalog-client": "", @@ -58,30 +62,35 @@ "@backstage/core-components": "", "@backstage/core-plugin-api": "", "@backstage/errors": "", + "@backstage/integration-react": "", "@backstage/plugin-api-docs": "", "@backstage/plugin-app-backend": "", "@backstage/plugin-auth-backend": "", "@backstage/plugin-catalog": "", "@backstage/plugin-catalog-backend": "", + "@backstage/plugin-catalog-common": "", "@backstage/plugin-catalog-graph": "", "@backstage/plugin-catalog-import": "", + "@backstage/plugin-catalog-react": "", + "@backstage/plugin-circleci": "", "@backstage/plugin-explore": "", "@backstage/plugin-github-actions": "", "@backstage/plugin-lighthouse": "", + "@backstage/plugin-org": "", "@backstage/plugin-permission-common": "", "@backstage/plugin-permission-node": "", + "@backstage/plugin-permission-react": "", "@backstage/plugin-proxy-backend": "", "@backstage/plugin-rollbar-backend": "", "@backstage/plugin-scaffolder": "", + "@backstage/plugin-scaffolder-backend": "", "@backstage/plugin-search": "", "@backstage/plugin-search-backend": "", "@backstage/plugin-search-backend-node": "", - "@backstage/plugin-scaffolder-backend": "", "@backstage/plugin-tech-radar": "", "@backstage/plugin-techdocs": "", "@backstage/plugin-techdocs-backend": "", "@backstage/plugin-user-settings": "", - "@backstage/integration-react": "", "@backstage/test-utils": "", "@backstage/theme": "" }, diff --git a/packages/create-app/templates/default-app/packages/app/src/components/Root/Root.tsx b/packages/create-app/templates/default-app/packages/app/src/components/Root/Root.tsx index 7e98c7d3e6..90738c44d4 100644 --- a/packages/create-app/templates/default-app/packages/app/src/components/Root/Root.tsx +++ b/packages/create-app/templates/default-app/packages/app/src/components/Root/Root.tsx @@ -28,10 +28,7 @@ import { Settings as SidebarSettings, UserSettingsSignInAvatar, } from '@backstage/plugin-user-settings'; -import { - SidebarSearchModal, - SearchContextProvider, -} from '@backstage/plugin-search'; +import { SidebarSearchModal } from '@backstage/plugin-search'; import { Sidebar, sidebarConfig, @@ -84,9 +81,7 @@ export const Root = ({ children }: PropsWithChildren<{}>) => ( } to="/search"> - - - {' '} + }> diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index 9d55d17592..40f6eef595 100644 --- a/packages/dev-utils/package.json +++ b/packages/dev-utils/package.json @@ -8,6 +8,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "web-library" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -21,12 +24,13 @@ "main": "src/index.ts", "types": "src/index.ts", "scripts": { - "build": "backstage-cli build --outputs types,esm", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean", + "start": "backstage-cli package start" }, "dependencies": { "@backstage/app-defaults": "^0.1.7", diff --git a/packages/e2e-test/package.json b/packages/e2e-test/package.json index bbf55fac17..bbbeed2312 100644 --- a/packages/e2e-test/package.json +++ b/packages/e2e-test/package.json @@ -3,6 +3,9 @@ "description": "E2E test for verifying Backstage packages", "version": "0.2.0", "private": true, + "backstage": { + "role": "cli" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -16,9 +19,11 @@ "main": "src/index.ts", "scripts": { "start": "nodemon --", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "test:e2e": "yarn start" + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "test:e2e": "yarn start", + "build": "backstage-cli package build", + "clean": "backstage-cli package clean" }, "bin": { "e2e-test": "bin/e2e-test" diff --git a/packages/errors/package.json b/packages/errors/package.json index f97adef8e1..17d32d7cd9 100644 --- a/packages/errors/package.json +++ b/packages/errors/package.json @@ -12,6 +12,9 @@ "module": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "common-library" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -22,12 +25,12 @@ "backstage" ], "scripts": { - "build": "backstage-cli build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/types": "^0.1.1", diff --git a/packages/integration-react/package.json b/packages/integration-react/package.json index 8413442b3d..ce7c402c77 100644 --- a/packages/integration-react/package.json +++ b/packages/integration-react/package.json @@ -11,14 +11,17 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "web-library" + }, "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/config": "^0.1.13", diff --git a/packages/integration-react/src/api/ScmAuth.test.ts b/packages/integration-react/src/api/ScmAuth.test.ts index 4ebfef749e..1ad391d8d2 100644 --- a/packages/integration-react/src/api/ScmAuth.test.ts +++ b/packages/integration-react/src/api/ScmAuth.test.ts @@ -238,7 +238,7 @@ describe('ScmAuth', () => { await expect( emptyMux.getCredentials({ url: 'http://example.com' }), ).rejects.toThrow( - "No authentication provider available for access to 'http://example.com'", + "No auth provider available for 'http://example.com', see https://backstage.io/link?scm-auth", ); const scmAuth = ScmAuth.merge( @@ -256,12 +256,12 @@ describe('ScmAuth', () => { await expect( scmAuth.getCredentials({ url: 'http://not.example.com' }), ).rejects.toThrow( - "No authentication provider available for access to 'http://not.example.com'", + "No auth provider available for 'http://not.example.com', see https://backstage.io/link?scm-auth", ); await expect( scmAuth.getCredentials({ url: 'http://example.com:8080' }), ).rejects.toThrow( - "No authentication provider available for access to 'http://example.com:8080'", + "No auth provider available for 'http://example.com:8080', see https://backstage.io/link?scm-auth", ); }); }); diff --git a/packages/integration-react/src/api/ScmAuth.ts b/packages/integration-react/src/api/ScmAuth.ts index 071374e6cb..b3dab4029e 100644 --- a/packages/integration-react/src/api/ScmAuth.ts +++ b/packages/integration-react/src/api/ScmAuth.ts @@ -53,7 +53,7 @@ class ScmAuthMux implements ScmAuthApi { const provider = this.#providers.find(p => p.isUrlSupported(url)); if (!provider) { throw new Error( - `No authentication provider available for access to '${options.url}'`, + `No auth provider available for '${options.url}', see https://backstage.io/link?scm-auth`, ); } diff --git a/packages/integration/package.json b/packages/integration/package.json index d6d0edd77a..be6a5e6a87 100644 --- a/packages/integration/package.json +++ b/packages/integration/package.json @@ -12,6 +12,9 @@ "module": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "common-library" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -22,12 +25,12 @@ "backstage" ], "scripts": { - "build": "backstage-cli build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/config": "^0.1.13", diff --git a/packages/release-manifests/package.json b/packages/release-manifests/package.json index 8ddbb73bca..a8990be2f0 100644 --- a/packages/release-manifests/package.json +++ b/packages/release-manifests/package.json @@ -11,6 +11,9 @@ "module": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "common-library" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -22,12 +25,12 @@ ], "license": "Apache-2.0", "scripts": { - "build": "backstage-cli build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "cross-fetch": "^3.1.5" diff --git a/packages/search-common/package.json b/packages/search-common/package.json index 10b03ab663..d4df8921f7 100644 --- a/packages/search-common/package.json +++ b/packages/search-common/package.json @@ -10,6 +10,9 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "common-library" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -25,12 +28,12 @@ "dist" ], "scripts": { - "build": "backstage-cli build --outputs cjs,types", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "bugs": { "url": "https://github.com/backstage/backstage/issues" diff --git a/packages/techdocs-cli-embedded-app/package.json b/packages/techdocs-cli-embedded-app/package.json index 975bfef43b..10b329ac80 100644 --- a/packages/techdocs-cli-embedded-app/package.json +++ b/packages/techdocs-cli-embedded-app/package.json @@ -2,6 +2,9 @@ "name": "techdocs-cli-embedded-app", "version": "0.2.63", "private": true, + "backstage": { + "role": "frontend" + }, "bundled": true, "dependencies": { "@backstage/app-defaults": "^0.1.7", @@ -39,11 +42,11 @@ "start-server-and-test": "^1.10.11" }, "scripts": { - "start": "backstage-cli app:serve --config ./app-config.yaml", - "build": "backstage-cli app:build --config ./app-config.yaml", - "clean": "backstage-cli clean", - "test": "backstage-cli test", - "lint": "backstage-cli lint", + "start": "backstage-cli package start --config ./app-config.yaml", + "build": "backstage-cli package build --config ./app-config.yaml", + "clean": "backstage-cli package clean", + "test": "backstage-cli package test", + "lint": "backstage-cli package lint", "test:e2e": "cross-env PORT=3001 start-server-and-test start http://localhost:3001 cy:dev", "test:e2e:ci": "cross-env PORT=3001 start-server-and-test start http://localhost:3001 cy:run", "cy:dev": "cypress open", diff --git a/packages/techdocs-cli/package.json b/packages/techdocs-cli/package.json index 19514b63d2..647ce6bdea 100644 --- a/packages/techdocs-cli/package.json +++ b/packages/techdocs-cli/package.json @@ -6,6 +6,9 @@ "publishConfig": { "access": "public" }, + "backstage": { + "role": "cli" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -21,10 +24,10 @@ "types": "", "scripts": { "start": "nodemon --", - "build": "backstage-cli build --outputs cjs", - "clean": "backstage-cli clean", - "lint": "backstage-cli lint", - "test": "backstage-cli test --testPathIgnorePatterns=src/e2e.test.ts", + "build": "backstage-cli package build", + "clean": "backstage-cli package clean", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test --testPathIgnorePatterns=src/e2e.test.ts", "test:e2e": "backstage-cli test src/e2e.test.ts", "test:e2e:ci": "backstage-cli test --watchAll=false --ci src/e2e.test.ts", "prepack": "./scripts/prepack.sh" diff --git a/packages/techdocs-common/package.json b/packages/techdocs-common/package.json index f45f842100..fd2e34b413 100644 --- a/packages/techdocs-common/package.json +++ b/packages/techdocs-common/package.json @@ -10,6 +10,9 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "node-library" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -25,12 +28,13 @@ "dist" ], "scripts": { - "build": "backstage-cli build --outputs cjs,types", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean", + "start": "backstage-cli package start" }, "bugs": { "url": "https://github.com/backstage/backstage/issues" diff --git a/packages/techdocs-common/src/helpers.ts b/packages/techdocs-common/src/helpers.ts index 7a9e4b18be..ccf1256381 100644 --- a/packages/techdocs-common/src/helpers.ts +++ b/packages/techdocs-common/src/helpers.ts @@ -18,7 +18,7 @@ import { resolveSafeChildPath, UrlReader } from '@backstage/backend-common'; import { Entity, getEntitySourceLocation, - parseLocationReference, + parseLocationRef, } from '@backstage/catalog-model'; import { InputError } from '@backstage/errors'; import { ScmIntegrationRegistry } from '@backstage/integration'; @@ -42,7 +42,7 @@ export const parseReferenceAnnotation = ( ); } - const { type, target } = parseLocationReference(annotation); + const { type, target } = parseLocationRef(annotation); return { type: type as RemoteProtocol, target, diff --git a/packages/techdocs-common/src/stages/publish/awsS3.test.ts b/packages/techdocs-common/src/stages/publish/awsS3.test.ts index 3e4c4c705b..357df73c8c 100644 --- a/packages/techdocs-common/src/stages/publish/awsS3.test.ts +++ b/packages/techdocs-common/src/stages/publish/awsS3.test.ts @@ -15,7 +15,7 @@ */ import { getVoidLogger } from '@backstage/backend-common'; -import { Entity, ENTITY_DEFAULT_NAMESPACE } from '@backstage/catalog-model'; +import { Entity, DEFAULT_NAMESPACE } from '@backstage/catalog-model'; import { ConfigReader } from '@backstage/config'; import express from 'express'; import request from 'supertest'; @@ -34,7 +34,7 @@ const getEntityRootDir = (entity: Entity) => { metadata: { namespace, name }, } = entity; - return path.join(rootDir, namespace || ENTITY_DEFAULT_NAMESPACE, kind, name); + return path.join(rootDir, namespace || DEFAULT_NAMESPACE, kind, name); }; const logger = getVoidLogger(); diff --git a/packages/techdocs-common/src/stages/publish/azureBlobStorage.test.ts b/packages/techdocs-common/src/stages/publish/azureBlobStorage.test.ts index e6fd45eed7..f1b660555e 100644 --- a/packages/techdocs-common/src/stages/publish/azureBlobStorage.test.ts +++ b/packages/techdocs-common/src/stages/publish/azureBlobStorage.test.ts @@ -15,7 +15,7 @@ */ import { getVoidLogger } from '@backstage/backend-common'; -import { Entity, ENTITY_DEFAULT_NAMESPACE } from '@backstage/catalog-model'; +import { Entity, DEFAULT_NAMESPACE } from '@backstage/catalog-model'; import { ConfigReader } from '@backstage/config'; import express from 'express'; import request from 'supertest'; @@ -34,7 +34,7 @@ const getEntityRootDir = (entity: Entity) => { metadata: { namespace, name }, } = entity; - return path.join(rootDir, namespace || ENTITY_DEFAULT_NAMESPACE, kind, name); + return path.join(rootDir, namespace || DEFAULT_NAMESPACE, kind, name); }; const logger = getVoidLogger(); diff --git a/packages/techdocs-common/src/stages/publish/googleStorage.test.ts b/packages/techdocs-common/src/stages/publish/googleStorage.test.ts index ed35f2e445..87a38402d0 100644 --- a/packages/techdocs-common/src/stages/publish/googleStorage.test.ts +++ b/packages/techdocs-common/src/stages/publish/googleStorage.test.ts @@ -15,7 +15,7 @@ */ import { getVoidLogger } from '@backstage/backend-common'; -import { Entity, ENTITY_DEFAULT_NAMESPACE } from '@backstage/catalog-model'; +import { Entity, DEFAULT_NAMESPACE } from '@backstage/catalog-model'; import { ConfigReader } from '@backstage/config'; import express from 'express'; import request from 'supertest'; @@ -34,7 +34,7 @@ const getEntityRootDir = (entity: Entity) => { metadata: { namespace, name }, } = entity; - return path.join(rootDir, namespace || ENTITY_DEFAULT_NAMESPACE, kind, name); + return path.join(rootDir, namespace || DEFAULT_NAMESPACE, kind, name); }; const logger = getVoidLogger(); diff --git a/packages/techdocs-common/src/stages/publish/helpers.test.ts b/packages/techdocs-common/src/stages/publish/helpers.test.ts index 6245898586..7acdb47ea7 100644 --- a/packages/techdocs-common/src/stages/publish/helpers.test.ts +++ b/packages/techdocs-common/src/stages/publish/helpers.test.ts @@ -16,7 +16,7 @@ import mockFs from 'mock-fs'; import * as os from 'os'; import * as path from 'path'; -import { Entity, ENTITY_DEFAULT_NAMESPACE } from '@backstage/catalog-model'; +import { Entity, DEFAULT_NAMESPACE } from '@backstage/catalog-model'; import { getStaleFiles, getFileTreeRecursively, @@ -189,7 +189,7 @@ describe('getCloudPathForLocalPath', () => { localPath, ); expect(remoteBucket).toBe( - `${ENTITY_DEFAULT_NAMESPACE}/component/backstage/${localPath}`, + `${DEFAULT_NAMESPACE}/component/backstage/${localPath}`, ); }); diff --git a/packages/techdocs-common/src/stages/publish/helpers.ts b/packages/techdocs-common/src/stages/publish/helpers.ts index cbecee51bc..decefae187 100644 --- a/packages/techdocs-common/src/stages/publish/helpers.ts +++ b/packages/techdocs-common/src/stages/publish/helpers.ts @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { Entity, ENTITY_DEFAULT_NAMESPACE } from '@backstage/catalog-model'; +import { Entity, DEFAULT_NAMESPACE } from '@backstage/catalog-model'; import mime from 'mime-types'; import path from 'path'; import createLimiter from 'p-limit'; @@ -188,9 +188,9 @@ export const getCloudPathForLocalPath = ( const relativeFilePathPosix = localPath.split(path.sep).join(path.posix.sep); // The / delimiter is intentional since it represents the cloud storage and not the local file system. - const entityRootDir = `${ - entity.metadata?.namespace ?? ENTITY_DEFAULT_NAMESPACE - }/${entity.kind}/${entity.metadata.name}`; + const entityRootDir = `${entity.metadata?.namespace ?? DEFAULT_NAMESPACE}/${ + entity.kind + }/${entity.metadata.name}`; const relativeFilePathTriplet = `${entityRootDir}/${relativeFilePathPosix}`; diff --git a/packages/techdocs-common/src/stages/publish/openStackSwift.test.ts b/packages/techdocs-common/src/stages/publish/openStackSwift.test.ts index ef06e26cfa..b240ce73da 100644 --- a/packages/techdocs-common/src/stages/publish/openStackSwift.test.ts +++ b/packages/techdocs-common/src/stages/publish/openStackSwift.test.ts @@ -18,7 +18,7 @@ import { getVoidLogger } from '@backstage/backend-common'; import { Entity, EntityName, - ENTITY_DEFAULT_NAMESPACE, + DEFAULT_NAMESPACE, } from '@backstage/catalog-model'; import { ConfigReader } from '@backstage/config'; import express from 'express'; @@ -59,7 +59,7 @@ const getEntityRootDir = (entity: Entity) => { metadata: { namespace, name }, } = entity; - return path.join(rootDir, namespace || ENTITY_DEFAULT_NAMESPACE, kind, name); + return path.join(rootDir, namespace || DEFAULT_NAMESPACE, kind, name); }; const getPosixEntityRootDir = (entity: Entity) => { @@ -70,7 +70,7 @@ const getPosixEntityRootDir = (entity: Entity) => { return path.posix.join( '/rootDir', - namespace || ENTITY_DEFAULT_NAMESPACE, + namespace || DEFAULT_NAMESPACE, kind, name, ); diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index 67b68e08cc..efde532268 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -8,6 +8,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "web-library" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -21,12 +24,13 @@ "main": "src/index.ts", "types": "src/index.ts", "scripts": { - "build": "backstage-cli build --outputs types,esm", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean", + "start": "backstage-cli package start" }, "dependencies": { "@backstage/config": "^0.1.13", diff --git a/packages/theme/package.json b/packages/theme/package.json index 2846db2805..24529d8c0d 100644 --- a/packages/theme/package.json +++ b/packages/theme/package.json @@ -8,6 +8,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "web-library" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -21,11 +24,13 @@ "main": "src/index.ts", "types": "src/index.ts", "scripts": { - "build": "backstage-cli build --outputs types,esm", - "lint": "backstage-cli lint", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean", + "start": "backstage-cli package start", + "test": "backstage-cli package test" }, "dependencies": { "@material-ui/core": "^4.12.2" diff --git a/packages/types/package.json b/packages/types/package.json index ae18fe519d..84237250b4 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -12,6 +12,9 @@ "module": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "common-library" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -22,12 +25,12 @@ "backstage" ], "scripts": { - "build": "backstage-cli build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": {}, "devDependencies": { diff --git a/packages/version-bridge/package.json b/packages/version-bridge/package.json index 6989aec3cf..cdf0858d38 100644 --- a/packages/version-bridge/package.json +++ b/packages/version-bridge/package.json @@ -8,6 +8,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "web-library" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -21,12 +24,13 @@ "main": "src/index.ts", "types": "src/index.ts", "scripts": { - "build": "backstage-cli build --outputs types,esm", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean", + "start": "backstage-cli package start" }, "peerDependencies": { "@types/react": "^16.13.1 || ^17.0.0", diff --git a/plugins/airbrake-backend/package.json b/plugins/airbrake-backend/package.json index 09d18079a1..0e94e6d998 100644 --- a/plugins/airbrake-backend/package.json +++ b/plugins/airbrake-backend/package.json @@ -4,7 +4,6 @@ "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", - "private": true, "publishConfig": { "access": "public", "main": "dist/index.cjs.js", diff --git a/plugins/airbrake/package.json b/plugins/airbrake/package.json index 45671a94cd..75844a483c 100644 --- a/plugins/airbrake/package.json +++ b/plugins/airbrake/package.json @@ -9,15 +9,18 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/catalog-model": "^0.9.10", diff --git a/plugins/allure/package.json b/plugins/allure/package.json index 5ea3129746..767d4c5cf1 100644 --- a/plugins/allure/package.json +++ b/plugins/allure/package.json @@ -11,15 +11,18 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/catalog-model": "^0.9.10", diff --git a/plugins/analytics-module-ga/package.json b/plugins/analytics-module-ga/package.json index 0b0c3a6cdc..c82ad9eefc 100644 --- a/plugins/analytics-module-ga/package.json +++ b/plugins/analytics-module-ga/package.json @@ -10,15 +10,18 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin-module" + }, "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/config": "^0.1.13", diff --git a/plugins/apache-airflow/package.json b/plugins/apache-airflow/package.json index e36e925fcb..7f740efcf5 100644 --- a/plugins/apache-airflow/package.json +++ b/plugins/apache-airflow/package.json @@ -9,15 +9,18 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/core-components": "^0.8.8", diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index 3b92cdf17e..7a0d04e85c 100644 --- a/plugins/api-docs/package.json +++ b/plugins/api-docs/package.json @@ -10,6 +10,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -20,14 +23,14 @@ "backstage" ], "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@asyncapi/react-component": "1.0.0-next.32", diff --git a/plugins/api-docs/src/components/ApiExplorerPage/DefaultApiExplorerPage.test.tsx b/plugins/api-docs/src/components/ApiExplorerPage/DefaultApiExplorerPage.test.tsx index 9e4c861e24..9b79263b5f 100644 --- a/plugins/api-docs/src/components/ApiExplorerPage/DefaultApiExplorerPage.test.tsx +++ b/plugins/api-docs/src/components/ApiExplorerPage/DefaultApiExplorerPage.test.tsx @@ -56,7 +56,7 @@ describe('DefaultApiExplorerPage', () => { }, ] as Entity[], }), - getLocationByEntity: () => + getLocationByRef: () => Promise.resolve({ id: 'id', type: 'github', target: 'url' }), getEntityByName: async entityName => { return { diff --git a/plugins/api-docs/src/components/ApisCards/ConsumedApisCard.test.tsx b/plugins/api-docs/src/components/ApisCards/ConsumedApisCard.test.tsx index 5e7b22524a..d04a36770d 100644 --- a/plugins/api-docs/src/components/ApisCards/ConsumedApisCard.test.tsx +++ b/plugins/api-docs/src/components/ApisCards/ConsumedApisCard.test.tsx @@ -36,7 +36,7 @@ describe('', () => { getEntityByName: jest.fn(), getEntities: jest.fn(), addLocation: jest.fn(), - getLocationByEntity: jest.fn(), + getLocationByRef: jest.fn(), removeEntityByUid: jest.fn(), } as any; let Wrapper: React.ComponentType; diff --git a/plugins/api-docs/src/components/ApisCards/HasApisCard.test.tsx b/plugins/api-docs/src/components/ApisCards/HasApisCard.test.tsx index 4102bebf0e..050eeb8707 100644 --- a/plugins/api-docs/src/components/ApisCards/HasApisCard.test.tsx +++ b/plugins/api-docs/src/components/ApisCards/HasApisCard.test.tsx @@ -36,7 +36,7 @@ describe('', () => { getEntityByName: jest.fn(), getEntities: jest.fn(), addLocation: jest.fn(), - getLocationByEntity: jest.fn(), + getLocationByRef: jest.fn(), removeEntityByUid: jest.fn(), } as any; let Wrapper: React.ComponentType; diff --git a/plugins/api-docs/src/components/ApisCards/ProvidedApisCard.test.tsx b/plugins/api-docs/src/components/ApisCards/ProvidedApisCard.test.tsx index b29075aee9..34043c519b 100644 --- a/plugins/api-docs/src/components/ApisCards/ProvidedApisCard.test.tsx +++ b/plugins/api-docs/src/components/ApisCards/ProvidedApisCard.test.tsx @@ -36,7 +36,7 @@ describe('', () => { getEntityByName: jest.fn(), getEntities: jest.fn(), addLocation: jest.fn(), - getLocationByEntity: jest.fn(), + getLocationByRef: jest.fn(), removeEntityByUid: jest.fn(), } as any; let Wrapper: React.ComponentType; diff --git a/plugins/api-docs/src/components/ComponentsCards/ConsumingComponentsCard.test.tsx b/plugins/api-docs/src/components/ComponentsCards/ConsumingComponentsCard.test.tsx index 06022eec69..c81b4750bc 100644 --- a/plugins/api-docs/src/components/ComponentsCards/ConsumingComponentsCard.test.tsx +++ b/plugins/api-docs/src/components/ComponentsCards/ConsumingComponentsCard.test.tsx @@ -32,7 +32,7 @@ describe('', () => { getEntityByName: jest.fn(), getEntities: jest.fn(), addLocation: jest.fn(), - getLocationByEntity: jest.fn(), + getLocationByRef: jest.fn(), removeEntityByUid: jest.fn(), } as any; let Wrapper: React.ComponentType; diff --git a/plugins/api-docs/src/components/ComponentsCards/ProvidingComponentsCard.test.tsx b/plugins/api-docs/src/components/ComponentsCards/ProvidingComponentsCard.test.tsx index 275338d2f9..84e45dc058 100644 --- a/plugins/api-docs/src/components/ComponentsCards/ProvidingComponentsCard.test.tsx +++ b/plugins/api-docs/src/components/ComponentsCards/ProvidingComponentsCard.test.tsx @@ -32,7 +32,7 @@ describe('', () => { getEntityByName: jest.fn(), getEntities: jest.fn(), addLocation: jest.fn(), - getLocationByEntity: jest.fn(), + getLocationByRef: jest.fn(), removeEntityByUid: jest.fn(), } as any; let Wrapper: React.ComponentType; diff --git a/plugins/app-backend/package.json b/plugins/app-backend/package.json index 52da00fed3..8821171df4 100644 --- a/plugins/app-backend/package.json +++ b/plugins/app-backend/package.json @@ -11,6 +11,9 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "backend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -21,13 +24,13 @@ "backstage" ], "scripts": { - "start": "backstage-cli backend:dev", - "build": "backstage-cli backend:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/backend-common": "^0.10.7", @@ -39,7 +42,7 @@ "express": "^4.17.1", "express-promise-router": "^4.1.0", "fs-extra": "9.1.0", - "helmet": "^4.0.0", + "helmet": "^5.0.2", "knex": "^1.0.2", "lodash": "^4.17.21", "luxon": "^2.0.2", diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index 580d8b8543..422683a09e 100644 --- a/plugins/auth-backend/package.json +++ b/plugins/auth-backend/package.json @@ -11,6 +11,9 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "backend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -21,13 +24,13 @@ "backstage" ], "scripts": { - "start": "backstage-cli backend:dev", - "build": "backstage-cli backend:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/plugin-auth-node": "^0.1.0", @@ -48,7 +51,6 @@ "express-session": "^1.17.1", "fs-extra": "9.1.0", "google-auth-library": "^7.6.1", - "helmet": "^4.0.0", "jose": "^1.27.1", "jwt-decode": "^3.1.0", "knex": "^1.0.2", @@ -65,7 +67,7 @@ "passport-gitlab2": "^5.0.0", "passport-google-oauth20": "^2.0.0", "passport-microsoft": "^0.1.0", - "passport-oauth2": "^1.5.0", + "passport-oauth2": "^1.6.1", "passport-okta-oauth": "^0.0.1", "passport-onelogin-oauth": "^0.0.1", "passport-saml": "^3.1.2", diff --git a/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.test.ts b/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.test.ts index 897233294f..83ebb5de73 100644 --- a/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.test.ts +++ b/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.test.ts @@ -30,8 +30,7 @@ describe('CatalogIdentityClient', () => { getEntities: jest.fn(), addLocation: jest.fn(), removeLocationById: jest.fn(), - getOriginLocationByEntity: jest.fn(), - getLocationByEntity: jest.fn(), + getLocationByRef: jest.fn(), removeEntityByUid: jest.fn(), refreshEntity: jest.fn(), getEntityAncestors: jest.fn(), diff --git a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts index 75a3605483..07611ddb9c 100644 --- a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts +++ b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts @@ -18,7 +18,7 @@ import express, { CookieOptions } from 'express'; import crypto from 'crypto'; import { URL } from 'url'; import { - ENTITY_DEFAULT_NAMESPACE, + DEFAULT_NAMESPACE, parseEntityRef, stringifyEntityRef, } from '@backstage/catalog-model'; @@ -271,7 +271,7 @@ export class OAuthAdapter implements AuthProviderRouteHandlers { const userEntityRef = stringifyEntityRef( parseEntityRef(identity.id, { defaultKind: 'user', - defaultNamespace: ENTITY_DEFAULT_NAMESPACE, + defaultNamespace: DEFAULT_NAMESPACE, }), ); const token = await this.options.tokenIssuer.issueToken({ diff --git a/plugins/auth-backend/src/providers/prepareBackstageIdentityResponse.ts b/plugins/auth-backend/src/providers/prepareBackstageIdentityResponse.ts index f3b234c08e..5a4e0895d9 100644 --- a/plugins/auth-backend/src/providers/prepareBackstageIdentityResponse.ts +++ b/plugins/auth-backend/src/providers/prepareBackstageIdentityResponse.ts @@ -15,7 +15,7 @@ */ import { - ENTITY_DEFAULT_NAMESPACE, + DEFAULT_NAMESPACE, parseEntityRef, stringifyEntityRef, } from '@backstage/catalog-model'; @@ -44,7 +44,7 @@ export function prepareBackstageIdentityResponse( const userEntityRef = stringifyEntityRef( parseEntityRef(sub, { defaultKind: 'user', - defaultNamespace: ENTITY_DEFAULT_NAMESPACE, + defaultNamespace: DEFAULT_NAMESPACE, }), ); return { diff --git a/plugins/auth-node/package.json b/plugins/auth-node/package.json index 4e059c5e19..83b4a45d71 100644 --- a/plugins/auth-node/package.json +++ b/plugins/auth-node/package.json @@ -10,13 +10,17 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "node-library" + }, "scripts": { - "build": "backstage-cli backend:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean", + "start": "backstage-cli package start" }, "dependencies": { "@backstage/backend-common": "^0.10.7", diff --git a/plugins/azure-devops-backend/package.json b/plugins/azure-devops-backend/package.json index a87a48046e..1264cbe069 100644 --- a/plugins/azure-devops-backend/package.json +++ b/plugins/azure-devops-backend/package.json @@ -10,14 +10,17 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "backend-plugin" + }, "scripts": { - "start": "backstage-cli backend:dev", - "build": "backstage-cli backend:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/backend-common": "^0.10.7", diff --git a/plugins/azure-devops-common/package.json b/plugins/azure-devops-common/package.json index 02faebca61..fa1bb87d16 100644 --- a/plugins/azure-devops-common/package.json +++ b/plugins/azure-devops-common/package.json @@ -11,6 +11,9 @@ "module": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "common-library" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -21,12 +24,12 @@ "backstage" ], "scripts": { - "build": "backstage-cli build", - "lint": "backstage-cli lint", - "test": "backstage-cli test --passWithNoTests", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "devDependencies": { "@backstage/cli": "^0.13.2-next.0" diff --git a/plugins/azure-devops/package.json b/plugins/azure-devops/package.json index a34686d856..8aa97a85ab 100644 --- a/plugins/azure-devops/package.json +++ b/plugins/azure-devops/package.json @@ -10,6 +10,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -17,14 +20,14 @@ "directory": "plugins/azure-devops" }, "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/catalog-model": "^0.9.10", diff --git a/plugins/badges-backend/package.json b/plugins/badges-backend/package.json index b5fc38f289..f8b2a75a3a 100644 --- a/plugins/badges-backend/package.json +++ b/plugins/badges-backend/package.json @@ -11,6 +11,9 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "backend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -22,13 +25,13 @@ "badges" ], "scripts": { - "start": "backstage-cli backend:dev", - "build": "backstage-cli backend:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/backend-common": "^0.10.7", diff --git a/plugins/badges-backend/src/badges.ts b/plugins/badges-backend/src/badges.ts index 9e4087e334..78108de080 100644 --- a/plugins/badges-backend/src/badges.ts +++ b/plugins/badges-backend/src/badges.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { ENTITY_DEFAULT_NAMESPACE } from '@backstage/catalog-model'; +import { DEFAULT_NAMESPACE } from '@backstage/catalog-model'; import { InputError } from '@backstage/errors'; import { Badge, BadgeContext, BadgeFactories } from './types'; @@ -24,9 +24,9 @@ function appTitle(context: BadgeContext): string { function entityUrl(context: BadgeContext): string { const e = context.entity!; - const entityUri = `${e.metadata.namespace || ENTITY_DEFAULT_NAMESPACE}/${ - e.kind - }/${e.metadata.name}`; + const entityUri = `${e.metadata.namespace || DEFAULT_NAMESPACE}/${e.kind}/${ + e.metadata.name + }`; const catalogUrl = `${context.config.getString('app.baseUrl')}/catalog`; return `${catalogUrl}/${entityUri}`.toLowerCase(); } diff --git a/plugins/badges-backend/src/service/router.test.ts b/plugins/badges-backend/src/service/router.test.ts index 286a2335f1..4b0ae2a44a 100644 --- a/plugins/badges-backend/src/service/router.test.ts +++ b/plugins/badges-backend/src/service/router.test.ts @@ -61,8 +61,7 @@ describe('createRouter', () => { addLocation: jest.fn(), getEntities: jest.fn(), getEntityByName: jest.fn(), - getOriginLocationByEntity: jest.fn(), - getLocationByEntity: jest.fn(), + getLocationByRef: jest.fn(), getLocationById: jest.fn(), removeLocationById: jest.fn(), removeEntityByUid: jest.fn(), diff --git a/plugins/badges/package.json b/plugins/badges/package.json index 5250318164..5fe0eb14b8 100644 --- a/plugins/badges/package.json +++ b/plugins/badges/package.json @@ -10,6 +10,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -17,14 +20,14 @@ "directory": "plugins/badges" }, "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/catalog-model": "^0.9.10", diff --git a/plugins/badges/src/api/BadgesClient.ts b/plugins/badges/src/api/BadgesClient.ts index 68714b2fa4..f63003dc90 100644 --- a/plugins/badges/src/api/BadgesClient.ts +++ b/plugins/badges/src/api/BadgesClient.ts @@ -16,7 +16,7 @@ import { generatePath } from 'react-router'; import { ResponseError } from '@backstage/errors'; -import { Entity, ENTITY_DEFAULT_NAMESPACE } from '@backstage/catalog-model'; +import { Entity, DEFAULT_NAMESPACE } from '@backstage/catalog-model'; import { BadgesApi, BadgeSpec } from './types'; import { DiscoveryApi, IdentityApi } from '@backstage/core-plugin-api'; @@ -63,7 +63,7 @@ export class BadgesClient implements BadgesApi { kind: entity.kind.toLocaleLowerCase('en-US'), namespace: entity.metadata.namespace?.toLocaleLowerCase('en-US') ?? - ENTITY_DEFAULT_NAMESPACE, + DEFAULT_NAMESPACE, name: entity.metadata.name, }; } diff --git a/plugins/bazaar-backend/package.json b/plugins/bazaar-backend/package.json index 71980acea4..728a1a3ac6 100644 --- a/plugins/bazaar-backend/package.json +++ b/plugins/bazaar-backend/package.json @@ -10,14 +10,17 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "backend-plugin" + }, "scripts": { - "start": "backstage-cli backend:dev", - "build": "backstage-cli backend:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/backend-common": "^0.10.7", diff --git a/plugins/bazaar/package.json b/plugins/bazaar/package.json index bfdcb18ca3..4cc3d72db7 100644 --- a/plugins/bazaar/package.json +++ b/plugins/bazaar/package.json @@ -10,15 +10,18 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/catalog-client": "^0.6.0", diff --git a/plugins/bitrise/package.json b/plugins/bitrise/package.json index 8b50459a84..2ddada7f6b 100644 --- a/plugins/bitrise/package.json +++ b/plugins/bitrise/package.json @@ -10,15 +10,18 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/catalog-model": "^0.9.10", diff --git a/plugins/catalog-backend-module-ldap/package.json b/plugins/catalog-backend-module-ldap/package.json index a499049265..315d04252a 100644 --- a/plugins/catalog-backend-module-ldap/package.json +++ b/plugins/catalog-backend-module-ldap/package.json @@ -11,6 +11,9 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "backend-plugin-module" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -21,12 +24,13 @@ "backstage" ], "scripts": { - "build": "backstage-cli backend:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean", + "start": "backstage-cli package start" }, "dependencies": { "@backstage/catalog-model": "^0.9.10", diff --git a/plugins/catalog-backend-module-ldap/src/processors/LdapOrgEntityProvider.ts b/plugins/catalog-backend-module-ldap/src/processors/LdapOrgEntityProvider.ts index c74e5b3aee..4c5bd2e3bd 100644 --- a/plugins/catalog-backend-module-ldap/src/processors/LdapOrgEntityProvider.ts +++ b/plugins/catalog-backend-module-ldap/src/processors/LdapOrgEntityProvider.ts @@ -15,9 +15,9 @@ */ import { + ANNOTATION_LOCATION, + ANNOTATION_ORIGIN_LOCATION, Entity, - LOCATION_ANNOTATION, - ORIGIN_LOCATION_ANNOTATION, } from '@backstage/catalog-model'; import { Config } from '@backstage/config'; import { @@ -207,8 +207,8 @@ function withLocations(providerId: string, entity: Entity): Entity { { metadata: { annotations: { - [LOCATION_ANNOTATION]: location, - [ORIGIN_LOCATION_ANNOTATION]: location, + [ANNOTATION_LOCATION]: location, + [ANNOTATION_ORIGIN_LOCATION]: location, }, }, }, diff --git a/plugins/catalog-backend-module-msgraph/package.json b/plugins/catalog-backend-module-msgraph/package.json index 7fd0a2d319..84bdb9599a 100644 --- a/plugins/catalog-backend-module-msgraph/package.json +++ b/plugins/catalog-backend-module-msgraph/package.json @@ -11,6 +11,9 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "backend-plugin-module" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -21,12 +24,13 @@ "backstage" ], "scripts": { - "build": "backstage-cli backend:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean", + "start": "backstage-cli package start" }, "dependencies": { "@azure/msal-node": "^1.1.0", diff --git a/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgEntityProvider.test.ts b/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgEntityProvider.test.ts index eab2d93526..456afda550 100644 --- a/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgEntityProvider.test.ts +++ b/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgEntityProvider.test.ts @@ -15,9 +15,9 @@ */ import { getVoidLogger } from '@backstage/backend-common'; import { + ANNOTATION_LOCATION, + ANNOTATION_ORIGIN_LOCATION, GroupEntity, - LOCATION_ANNOTATION, - ORIGIN_LOCATION_ANNOTATION, UserEntity, } from '@backstage/catalog-model'; import { EntityProviderConnection } from '@backstage/plugin-catalog-backend'; @@ -162,8 +162,8 @@ describe('withLocations', () => { name: 'u1', annotations: { [MICROSOFT_GRAPH_USER_ID_ANNOTATION]: 'uid', - [LOCATION_ANNOTATION]: 'msgraph:test/uid', - [ORIGIN_LOCATION_ANNOTATION]: 'msgraph:test/uid', + [ANNOTATION_LOCATION]: 'msgraph:test/uid', + [ANNOTATION_ORIGIN_LOCATION]: 'msgraph:test/uid', }, }, spec: { diff --git a/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgEntityProvider.ts b/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgEntityProvider.ts index 6d66723970..92836893f0 100644 --- a/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgEntityProvider.ts +++ b/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgEntityProvider.ts @@ -15,9 +15,9 @@ */ import { + ANNOTATION_LOCATION, + ANNOTATION_ORIGIN_LOCATION, Entity, - LOCATION_ANNOTATION, - ORIGIN_LOCATION_ANNOTATION, } from '@backstage/catalog-model'; import { Config } from '@backstage/config'; import { @@ -180,8 +180,8 @@ export function withLocations(providerId: string, entity: Entity): Entity { { metadata: { annotations: { - [LOCATION_ANNOTATION]: location, - [ORIGIN_LOCATION_ANNOTATION]: location, + [ANNOTATION_LOCATION]: location, + [ANNOTATION_ORIGIN_LOCATION]: location, }, }, }, diff --git a/plugins/catalog-backend/api-report.md b/plugins/catalog-backend/api-report.md index deed3e2d8b..d97df9967c 100644 --- a/plugins/catalog-backend/api-report.md +++ b/plugins/catalog-backend/api-report.md @@ -8,7 +8,6 @@ import { Account } from 'aws-sdk/clients/organizations'; import { BitbucketIntegration } from '@backstage/integration'; import { CatalogApi } from '@backstage/catalog-client'; -import { CatalogEntitiesRequest } from '@backstage/catalog-client'; import { ConditionalPolicyDecision } from '@backstage/plugin-permission-node'; import { Conditions } from '@backstage/plugin-permission-node'; import { Config } from '@backstage/config'; @@ -17,12 +16,13 @@ import { Entity } from '@backstage/catalog-model'; import { EntityPolicy } from '@backstage/catalog-model'; import { EntityRelationSpec } from '@backstage/catalog-model'; import express from 'express'; +import { GetEntitiesRequest } from '@backstage/catalog-client'; import { GithubCredentialsProvider } from '@backstage/integration'; import { GitHubIntegrationConfig } from '@backstage/integration'; import { IndexableDocument } from '@backstage/search-common'; import { JsonObject } from '@backstage/types'; import { JsonValue } from '@backstage/types'; -import { Location as Location_2 } from '@backstage/catalog-model'; +import { Location as Location_2 } from '@backstage/catalog-client'; import { LocationSpec } from '@backstage/catalog-model'; import { Logger as Logger_2 } from 'winston'; import { Organizations } from 'aws-sdk'; @@ -36,7 +36,6 @@ import { PluginEndpointDiscovery } from '@backstage/backend-common'; import { ResourceEntityV1alpha1 } from '@backstage/catalog-model'; import { Router } from 'express'; import { ScmIntegrationRegistry } from '@backstage/integration'; -import { ScmIntegrations } from '@backstage/integration'; import { TokenManager } from '@backstage/backend-common'; import { UrlReader } from '@backstage/backend-common'; import { Validators } from '@backstage/catalog-model'; @@ -177,7 +176,10 @@ export class AwsS3DiscoveryProcessor implements CatalogProcessor { // // @public export class AzureDevOpsDiscoveryProcessor implements CatalogProcessor { - constructor(options: { integrations: ScmIntegrations; logger: Logger_2 }); + constructor(options: { + integrations: ScmIntegrationRegistry; + logger: Logger_2; + }); // (undocumented) static fromConfig( config: Config, @@ -464,7 +466,7 @@ export type CatalogRulesEnforcer = { // @public (undocumented) export class CodeOwnersProcessor implements CatalogProcessor { constructor(options: { - integrations: ScmIntegrations; + integrations: ScmIntegrationRegistry; logger: Logger_2; reader: UrlReader; }); @@ -509,7 +511,7 @@ export class DefaultCatalogCollator implements DocumentCollator { discovery: PluginEndpointDiscovery; tokenManager: TokenManager; locationTemplate?: string; - filter?: CatalogEntitiesRequest['filter']; + filter?: GetEntitiesRequest['filter']; catalogClient?: CatalogApi; }); // (undocumented) @@ -524,14 +526,14 @@ export class DefaultCatalogCollator implements DocumentCollator { // (undocumented) execute(): Promise; // (undocumented) - protected filter?: CatalogEntitiesRequest['filter']; + protected filter?: GetEntitiesRequest['filter']; // (undocumented) static fromConfig( _config: Config, options: { discovery: PluginEndpointDiscovery; tokenManager: TokenManager; - filter?: CatalogEntitiesRequest['filter']; + filter?: GetEntitiesRequest['filter']; }, ): DefaultCatalogCollator; // (undocumented) @@ -750,7 +752,7 @@ function generalError( // @public export class GithubDiscoveryProcessor implements CatalogProcessor { constructor(options: { - integrations: ScmIntegrations; + integrations: ScmIntegrationRegistry; logger: Logger_2; githubCredentialsProvider?: GithubCredentialsProvider; }); @@ -773,7 +775,7 @@ export class GithubDiscoveryProcessor implements CatalogProcessor { // @alpha export class GithubMultiOrgReaderProcessor implements CatalogProcessor { constructor(options: { - integrations: ScmIntegrations; + integrations: ScmIntegrationRegistry; logger: Logger_2; orgs: GithubMultiOrgConfig; githubCredentialsProvider?: GithubCredentialsProvider; @@ -828,7 +830,7 @@ export class GitHubOrgEntityProvider implements EntityProvider { // @public export class GithubOrgReaderProcessor implements CatalogProcessor { constructor(options: { - integrations: ScmIntegrations; + integrations: ScmIntegrationRegistry; logger: Logger_2; githubCredentialsProvider?: GithubCredentialsProvider; }); diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index 40d514bb2f..e4718afcd0 100644 --- a/plugins/catalog-backend/package.json +++ b/plugins/catalog-backend/package.json @@ -11,6 +11,9 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "backend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -21,13 +24,13 @@ "backstage" ], "scripts": { - "start": "backstage-cli backend:dev", - "build": "backstage-cli backend:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/backend-common": "^0.10.7", @@ -39,6 +42,7 @@ "@backstage/plugin-catalog-common": "^0.1.2", "@backstage/plugin-permission-common": "^0.4.0", "@backstage/plugin-permission-node": "^0.4.3", + "@backstage/plugin-scaffolder-common": "^0.1.3", "@backstage/search-common": "^0.2.2", "@backstage/types": "^0.1.1", "@octokit/graphql": "^4.5.8", @@ -62,7 +66,7 @@ "winston": "^3.2.1", "yaml": "^1.9.2", "yn": "^4.0.0", - "yup": "^0.32.9" + "zod": "^3.11.6" }, "devDependencies": { "@backstage/backend-test-utils": "^0.1.17", @@ -74,7 +78,6 @@ "@types/lodash": "^4.14.151", "@types/supertest": "^2.0.8", "@types/uuid": "^8.0.0", - "@types/yup": "^0.29.13", "@vscode/sqlite3": "^5.0.7", "aws-sdk-mock": "^5.2.1", "msw": "^0.35.0", diff --git a/plugins/catalog-backend/src/database/DefaultProcessingDatabase.test.ts b/plugins/catalog-backend/src/database/DefaultProcessingDatabase.test.ts index 905339af17..729be442aa 100644 --- a/plugins/catalog-backend/src/database/DefaultProcessingDatabase.test.ts +++ b/plugins/catalog-backend/src/database/DefaultProcessingDatabase.test.ts @@ -832,7 +832,7 @@ describe('Default Processing Database', () => { /* config-1 -> location:default/root config-2 -> location:default/root - */ + */ await createLocations(knex, ['location:default/root']); await insertRefRow(knex, { @@ -1092,6 +1092,61 @@ describe('Default Processing Database', () => { }, 60_000, ); + + it.each(databases.eachSupportedId())( + 'should successfully fall back from batch to individual mode on conflicts, %p', + async databaseId => { + const fakeLogger = { + debug: jest.fn(), + }; + const { knex, db } = await createDatabase( + databaseId, + fakeLogger as any, + ); + + await createLocations(knex, ['component:default/a']); + + await insertRefRow(knex, { + source_key: undefined, + target_entity_ref: 'component:default/a', + }); + + await db.transaction(async tx => { + await db.replaceUnprocessedEntities(tx, { + type: 'full', + sourceKey: 'lols', + items: [ + { + entity: { + apiVersion: '1', + kind: 'Component', + metadata: { name: 'a' }, + spec: { marker: 'WILL_CHANGE' }, + } as Entity, + locationKey: 'file:///tmp/a', + }, + ], + }); + }); + expect(fakeLogger.debug).toBeCalledWith( + expect.stringMatching( + /Fast insert path failed, falling back to slow path/, + ), + ); + + const state = await knex('refresh_state').select(); + expect(state).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + entity_ref: 'component:default/a', + location_key: 'file:///tmp/a', + unprocessed_entity: expect.stringContaining('WILL_CHANGE'), + }), + ]), + ); + }, + 60_000, + ); }); describe('getProcessableEntities', () => { diff --git a/plugins/catalog-backend/src/database/DefaultProcessingDatabase.ts b/plugins/catalog-backend/src/database/DefaultProcessingDatabase.ts index f2f478c481..55f04c289c 100644 --- a/plugins/catalog-backend/src/database/DefaultProcessingDatabase.ts +++ b/plugins/catalog-backend/src/database/DefaultProcessingDatabase.ts @@ -45,6 +45,7 @@ import { } from './tables'; import { generateStableHash } from './util'; +import { isDatabaseConflictError } from '@backstage/backend-common'; // The number of items that are sent per batch to the database layer, when // doing .batchInsert calls to knex. This needs to be low enough to not cause @@ -160,7 +161,7 @@ export class DefaultProcessingDatabase implements ProcessingDatabase { ): Promise { const tx = txOpaque as Knex.Transaction; - const { toUpsert, toRemove } = await this.createDelta(tx, options); + const { toAdd, toUpsert, toRemove } = await this.createDelta(tx, options); if (toRemove.length) { // TODO(freben): Batch split, to not hit variable limits? @@ -277,6 +278,53 @@ export class DefaultProcessingDatabase implements ProcessingDatabase { ); } + if (toAdd.length) { + // The reason for this chunking, rather than just massively batch + // inserting the entire payload, is that we fall back to the individual + // upsert mechanism below on conflicts. That path is massively slower than + // the fast batch path, so we don't want to end up accidentally having to + // for example item-by-item upsert tens of thousands of entities in a + // large initial delivery dump. The implication is that the size of these + // chunks needs to weigh the benefit of fast successful inserts, against + // the drawback of super slow but more rare fallbacks. There's quickly + // diminishing returns though with turning up this value way high. + for (const chunk of lodash.chunk(toAdd, 50)) { + try { + await tx.batchInsert( + 'refresh_state', + chunk.map(item => ({ + entity_id: uuid(), + entity_ref: stringifyEntityRef(item.deferred.entity), + unprocessed_entity: JSON.stringify(item.deferred.entity), + unprocessed_hash: item.hash, + errors: '', + location_key: item.deferred.locationKey, + next_update_at: tx.fn.now(), + last_discovery_at: tx.fn.now(), + })), + BATCH_SIZE, + ); + await tx.batchInsert( + 'refresh_state_references', + chunk.map(item => ({ + source_key: options.sourceKey, + target_entity_ref: stringifyEntityRef(item.deferred.entity), + })), + BATCH_SIZE, + ); + } catch (error) { + if (!isDatabaseConflictError(error)) { + throw error; + } else { + this.options.logger.debug( + `Fast insert path failed, falling back to slow path, ${error}`, + ); + toUpsert.push(...chunk); + } + } + } + } + if (toUpsert.length) { for (const { deferred: { entity, locationKey }, @@ -600,11 +648,13 @@ export class DefaultProcessingDatabase implements ProcessingDatabase { tx: Knex.Transaction, options: ReplaceUnprocessedEntitiesOptions, ): Promise<{ + toAdd: { deferred: DeferredEntity; hash: string }[]; toUpsert: { deferred: DeferredEntity; hash: string }[]; toRemove: string[]; }> { if (options.type === 'delta') { return { + toAdd: [], toUpsert: options.added.map(e => ({ deferred: e, hash: generateStableHash(e.entity), @@ -644,6 +694,7 @@ export class DefaultProcessingDatabase implements ProcessingDatabase { ); const newRefsSet = new Set(items.map(item => item.ref)); + const toAdd = new Array<{ deferred: DeferredEntity; hash: string }>(); const toUpsert = new Array<{ deferred: DeferredEntity; hash: string }>(); const toRemove = oldRefs .map(row => row.target_entity_ref) @@ -654,18 +705,18 @@ export class DefaultProcessingDatabase implements ProcessingDatabase { const upsertItem = { deferred: item.deferred, hash: item.hash }; if (!oldRef) { // Add any entity that does not exist in the database - toUpsert.push(upsertItem); + toAdd.push(upsertItem); } else if (oldRef.locationKey !== item.deferred.locationKey) { // Remove and then re-add any entity that exists, but with a different location key toRemove.push(item.ref); - toUpsert.push(upsertItem); + toAdd.push(upsertItem); } else if (oldRef.oldEntityHash !== item.hash) { // Entities with modifications should be pushed through too toUpsert.push(upsertItem); } } - return { toUpsert, toRemove }; + return { toAdd, toUpsert, toRemove }; } /** diff --git a/plugins/catalog-backend/src/ingestion/processors/AnnotateLocationEntityProcessor.ts b/plugins/catalog-backend/src/ingestion/processors/AnnotateLocationEntityProcessor.ts index 54079e13ff..8adbaec628 100644 --- a/plugins/catalog-backend/src/ingestion/processors/AnnotateLocationEntityProcessor.ts +++ b/plugins/catalog-backend/src/ingestion/processors/AnnotateLocationEntityProcessor.ts @@ -15,14 +15,14 @@ */ import { - EDIT_URL_ANNOTATION, + ANNOTATION_EDIT_URL, + ANNOTATION_LOCATION, + ANNOTATION_ORIGIN_LOCATION, + ANNOTATION_SOURCE_LOCATION, + ANNOTATION_VIEW_URL, Entity, LocationSpec, - LOCATION_ANNOTATION, - ORIGIN_LOCATION_ANNOTATION, - SOURCE_LOCATION_ANNOTATION, - stringifyLocationReference, - VIEW_URL_ANNOTATION, + stringifyLocationRef, } from '@backstage/catalog-model'; import { ScmIntegrationRegistry } from '@backstage/integration'; import { identity, merge, pickBy } from 'lodash'; @@ -58,7 +58,7 @@ export class AnnotateLocationEntityProcessor implements CatalogProcessor { }); if (sourceUrl) { - sourceLocation = stringifyLocationReference({ + sourceLocation = stringifyLocationRef({ type: 'url', target: sourceUrl, }); @@ -70,12 +70,12 @@ export class AnnotateLocationEntityProcessor implements CatalogProcessor { metadata: { annotations: pickBy( { - [LOCATION_ANNOTATION]: stringifyLocationReference(location), - [ORIGIN_LOCATION_ANNOTATION]: - stringifyLocationReference(originLocation), - [VIEW_URL_ANNOTATION]: viewUrl, - [EDIT_URL_ANNOTATION]: editUrl, - [SOURCE_LOCATION_ANNOTATION]: sourceLocation, + [ANNOTATION_LOCATION]: stringifyLocationRef(location), + [ANNOTATION_ORIGIN_LOCATION]: + stringifyLocationRef(originLocation), + [ANNOTATION_VIEW_URL]: viewUrl, + [ANNOTATION_EDIT_URL]: editUrl, + [ANNOTATION_SOURCE_LOCATION]: sourceLocation, }, identity, ), diff --git a/plugins/catalog-backend/src/ingestion/processors/AzureDevOpsDiscoveryProcessor.ts b/plugins/catalog-backend/src/ingestion/processors/AzureDevOpsDiscoveryProcessor.ts index aeac64f54d..4f5df6f656 100644 --- a/plugins/catalog-backend/src/ingestion/processors/AzureDevOpsDiscoveryProcessor.ts +++ b/plugins/catalog-backend/src/ingestion/processors/AzureDevOpsDiscoveryProcessor.ts @@ -16,7 +16,10 @@ import { LocationSpec } from '@backstage/catalog-model'; import { Config } from '@backstage/config'; -import { ScmIntegrations } from '@backstage/integration'; +import { + ScmIntegrationRegistry, + ScmIntegrations, +} from '@backstage/integration'; import { Logger } from 'winston'; import * as results from './results'; import { CatalogProcessor, CatalogProcessorEmit } from './types'; @@ -37,7 +40,7 @@ import { codeSearch } from './azure'; * target: https://dev.azure.com/org/project/_git/repo **/ export class AzureDevOpsDiscoveryProcessor implements CatalogProcessor { - private readonly integrations: ScmIntegrations; + private readonly integrations: ScmIntegrationRegistry; private readonly logger: Logger; static fromConfig(config: Config, options: { logger: Logger }) { @@ -49,7 +52,10 @@ export class AzureDevOpsDiscoveryProcessor implements CatalogProcessor { }); } - constructor(options: { integrations: ScmIntegrations; logger: Logger }) { + constructor(options: { + integrations: ScmIntegrationRegistry; + logger: Logger; + }) { this.integrations = options.integrations; this.logger = options.logger; } diff --git a/plugins/catalog-backend/src/ingestion/processors/BuiltinKindsEntityProcessor.test.ts b/plugins/catalog-backend/src/ingestion/processors/BuiltinKindsEntityProcessor.test.ts index c42980d97b..1b7739a772 100644 --- a/plugins/catalog-backend/src/ingestion/processors/BuiltinKindsEntityProcessor.test.ts +++ b/plugins/catalog-backend/src/ingestion/processors/BuiltinKindsEntityProcessor.test.ts @@ -21,9 +21,9 @@ import { GroupEntity, ResourceEntity, SystemEntity, - TemplateEntityV1beta2, UserEntity, } from '@backstage/catalog-model'; +import { TemplateEntityV1beta2 } from '@backstage/plugin-scaffolder-common'; import { BuiltinKindsEntityProcessor } from './BuiltinKindsEntityProcessor'; describe('BuiltinKindsEntityProcessor', () => { diff --git a/plugins/catalog-backend/src/ingestion/processors/BuiltinKindsEntityProcessor.ts b/plugins/catalog-backend/src/ingestion/processors/BuiltinKindsEntityProcessor.ts index 5999be9793..62e71e8b9b 100644 --- a/plugins/catalog-backend/src/ingestion/processors/BuiltinKindsEntityProcessor.ts +++ b/plugins/catalog-backend/src/ingestion/processors/BuiltinKindsEntityProcessor.ts @@ -46,11 +46,13 @@ import { resourceEntityV1alpha1Validator, SystemEntity, systemEntityV1alpha1Validator, - TemplateEntityV1beta2, - templateEntityV1beta2Validator, UserEntity, userEntityV1alpha1Validator, } from '@backstage/catalog-model'; +import { + TemplateEntityV1beta2, + templateEntityV1beta2Validator, +} from '@backstage/plugin-scaffolder-common'; import * as result from './results'; import { CatalogProcessor, CatalogProcessorEmit } from './types'; diff --git a/plugins/catalog-backend/src/ingestion/processors/CodeOwnersProcessor.ts b/plugins/catalog-backend/src/ingestion/processors/CodeOwnersProcessor.ts index a70aa6d1a9..f358abf7e9 100644 --- a/plugins/catalog-backend/src/ingestion/processors/CodeOwnersProcessor.ts +++ b/plugins/catalog-backend/src/ingestion/processors/CodeOwnersProcessor.ts @@ -17,7 +17,10 @@ import { UrlReader } from '@backstage/backend-common'; import { Entity, LocationSpec } from '@backstage/catalog-model'; import { Config } from '@backstage/config'; -import { ScmIntegrations } from '@backstage/integration'; +import { + ScmIntegrationRegistry, + ScmIntegrations, +} from '@backstage/integration'; import { Logger } from 'winston'; import { findCodeOwnerByTarget } from './codeowners'; import { CatalogProcessor } from './types'; @@ -35,7 +38,7 @@ const ALLOWED_LOCATION_TYPES = [ ]; export class CodeOwnersProcessor implements CatalogProcessor { - private readonly integrations: ScmIntegrations; + private readonly integrations: ScmIntegrationRegistry; private readonly logger: Logger; private readonly reader: UrlReader; @@ -52,7 +55,7 @@ export class CodeOwnersProcessor implements CatalogProcessor { } constructor(options: { - integrations: ScmIntegrations; + integrations: ScmIntegrationRegistry; logger: Logger; reader: UrlReader; }) { diff --git a/plugins/catalog-backend/src/ingestion/processors/GitLabDiscoveryProcessor.ts b/plugins/catalog-backend/src/ingestion/processors/GitLabDiscoveryProcessor.ts index fabf3a1136..cc0113bfbe 100644 --- a/plugins/catalog-backend/src/ingestion/processors/GitLabDiscoveryProcessor.ts +++ b/plugins/catalog-backend/src/ingestion/processors/GitLabDiscoveryProcessor.ts @@ -16,7 +16,10 @@ import { LocationSpec } from '@backstage/catalog-model'; import { Config } from '@backstage/config'; -import { ScmIntegrations } from '@backstage/integration'; +import { + ScmIntegrationRegistry, + ScmIntegrations, +} from '@backstage/integration'; import { Logger } from 'winston'; import * as results from './results'; import { CatalogProcessor, CatalogProcessorEmit } from './types'; @@ -31,7 +34,7 @@ import { * Extracts repositories out of an GitLab instance. */ export class GitLabDiscoveryProcessor implements CatalogProcessor { - private readonly integrations: ScmIntegrations; + private readonly integrations: ScmIntegrationRegistry; private readonly logger: Logger; private readonly cache: CacheClient; @@ -48,7 +51,7 @@ export class GitLabDiscoveryProcessor implements CatalogProcessor { } private constructor(options: { - integrations: ScmIntegrations; + integrations: ScmIntegrationRegistry; pluginCache: PluginCacheManager; logger: Logger; }) { diff --git a/plugins/catalog-backend/src/ingestion/processors/GithubDiscoveryProcessor.ts b/plugins/catalog-backend/src/ingestion/processors/GithubDiscoveryProcessor.ts index 3196c4e161..3cb73f0181 100644 --- a/plugins/catalog-backend/src/ingestion/processors/GithubDiscoveryProcessor.ts +++ b/plugins/catalog-backend/src/ingestion/processors/GithubDiscoveryProcessor.ts @@ -19,6 +19,7 @@ import { Config } from '@backstage/config'; import { DefaultGithubCredentialsProvider, GithubCredentialsProvider, + ScmIntegrationRegistry, ScmIntegrations, } from '@backstage/integration'; import { graphql } from '@octokit/graphql'; @@ -42,7 +43,7 @@ import { CatalogProcessor, CatalogProcessorEmit } from './types'; * target: https://github.com/backstage/*\/blob/main/catalog-info.yaml **/ export class GithubDiscoveryProcessor implements CatalogProcessor { - private readonly integrations: ScmIntegrations; + private readonly integrations: ScmIntegrationRegistry; private readonly logger: Logger; private readonly githubCredentialsProvider: GithubCredentialsProvider; @@ -62,7 +63,7 @@ export class GithubDiscoveryProcessor implements CatalogProcessor { } constructor(options: { - integrations: ScmIntegrations; + integrations: ScmIntegrationRegistry; logger: Logger; githubCredentialsProvider?: GithubCredentialsProvider; }) { diff --git a/plugins/catalog-backend/src/ingestion/processors/GithubMultiOrgReaderProcessor.ts b/plugins/catalog-backend/src/ingestion/processors/GithubMultiOrgReaderProcessor.ts index dd705ad691..7d10428494 100644 --- a/plugins/catalog-backend/src/ingestion/processors/GithubMultiOrgReaderProcessor.ts +++ b/plugins/catalog-backend/src/ingestion/processors/GithubMultiOrgReaderProcessor.ts @@ -21,6 +21,7 @@ import { GithubAppCredentialsMux, GithubCredentialsProvider, GitHubIntegrationConfig, + ScmIntegrationRegistry, ScmIntegrations, } from '@backstage/integration'; import { graphql } from '@octokit/graphql'; @@ -42,7 +43,7 @@ import { buildOrgHierarchy } from './util/org'; * Be aware that this processor may not be compatible with future org structures in the catalog. */ export class GithubMultiOrgReaderProcessor implements CatalogProcessor { - private readonly integrations: ScmIntegrations; + private readonly integrations: ScmIntegrationRegistry; private readonly orgs: GithubMultiOrgConfig; private readonly logger: Logger; private readonly githubCredentialsProvider: GithubCredentialsProvider; @@ -65,7 +66,7 @@ export class GithubMultiOrgReaderProcessor implements CatalogProcessor { } constructor(options: { - integrations: ScmIntegrations; + integrations: ScmIntegrationRegistry; logger: Logger; orgs: GithubMultiOrgConfig; githubCredentialsProvider?: GithubCredentialsProvider; diff --git a/plugins/catalog-backend/src/ingestion/processors/GithubOrgReaderProcessor.ts b/plugins/catalog-backend/src/ingestion/processors/GithubOrgReaderProcessor.ts index 474d08feee..dbb7b98e87 100644 --- a/plugins/catalog-backend/src/ingestion/processors/GithubOrgReaderProcessor.ts +++ b/plugins/catalog-backend/src/ingestion/processors/GithubOrgReaderProcessor.ts @@ -18,6 +18,7 @@ import { LocationSpec } from '@backstage/catalog-model'; import { Config } from '@backstage/config'; import { GithubCredentialType, + ScmIntegrationRegistry, ScmIntegrations, GithubCredentialsProvider, DefaultGithubCredentialsProvider, @@ -39,7 +40,7 @@ type GraphQL = typeof graphql; * Extracts teams and users out of a GitHub org. */ export class GithubOrgReaderProcessor implements CatalogProcessor { - private readonly integrations: ScmIntegrations; + private readonly integrations: ScmIntegrationRegistry; private readonly logger: Logger; private readonly githubCredentialsProvider: GithubCredentialsProvider; @@ -59,7 +60,7 @@ export class GithubOrgReaderProcessor implements CatalogProcessor { } constructor(options: { - integrations: ScmIntegrations; + integrations: ScmIntegrationRegistry; logger: Logger; githubCredentialsProvider?: GithubCredentialsProvider; }) { diff --git a/plugins/catalog-backend/src/ingestion/processors/util/parse.ts b/plugins/catalog-backend/src/ingestion/processors/util/parse.ts index c9c6c79311..a6aba7e1f9 100644 --- a/plugins/catalog-backend/src/ingestion/processors/util/parse.ts +++ b/plugins/catalog-backend/src/ingestion/processors/util/parse.ts @@ -17,7 +17,7 @@ import { Entity, LocationSpec, - stringifyLocationReference, + stringifyLocationRef, } from '@backstage/catalog-model'; import lodash from 'lodash'; import yaml from 'yaml'; @@ -32,7 +32,7 @@ export function* parseEntityYaml( try { documents = yaml.parseAllDocuments(data.toString('utf8')).filter(d => d); } catch (e) { - const loc = stringifyLocationReference(location); + const loc = stringifyLocationRef(location); const message = `Failed to parse YAML at ${loc}, ${e}`; yield result.generalError(location, message); return; @@ -40,7 +40,7 @@ export function* parseEntityYaml( for (const document of documents) { if (document.errors?.length) { - const loc = stringifyLocationReference(location); + const loc = stringifyLocationRef(location); const message = `YAML error at ${loc}, ${document.errors[0]}`; yield result.generalError(location, message); } else { diff --git a/plugins/catalog-backend/src/ingestion/providers/GitHubOrgEntityProvider.ts b/plugins/catalog-backend/src/ingestion/providers/GitHubOrgEntityProvider.ts index b1d44a55b5..20e9966bd1 100644 --- a/plugins/catalog-backend/src/ingestion/providers/GitHubOrgEntityProvider.ts +++ b/plugins/catalog-backend/src/ingestion/providers/GitHubOrgEntityProvider.ts @@ -14,9 +14,9 @@ * limitations under the License. */ import { + ANNOTATION_LOCATION, + ANNOTATION_ORIGIN_LOCATION, Entity, - LOCATION_ANNOTATION, - ORIGIN_LOCATION_ANNOTATION, } from '@backstage/catalog-model'; import { Config } from '@backstage/config'; import { @@ -178,8 +178,8 @@ export function withLocations( { metadata: { annotations: { - [LOCATION_ANNOTATION]: location, - [ORIGIN_LOCATION_ANNOTATION]: location, + [ANNOTATION_LOCATION]: location, + [ANNOTATION_ORIGIN_LOCATION]: location, }, }, }, diff --git a/plugins/catalog-backend/src/processing/DefaultCatalogProcessingOrchestrator.test.ts b/plugins/catalog-backend/src/processing/DefaultCatalogProcessingOrchestrator.test.ts index 5ae4d58ec7..cc77f6a17b 100644 --- a/plugins/catalog-backend/src/processing/DefaultCatalogProcessingOrchestrator.test.ts +++ b/plugins/catalog-backend/src/processing/DefaultCatalogProcessingOrchestrator.test.ts @@ -16,12 +16,12 @@ import { getVoidLogger } from '@backstage/backend-common'; import { + ANNOTATION_LOCATION, + ANNOTATION_ORIGIN_LOCATION, Entity, EntityPolicies, LocationEntity, LocationSpec, - LOCATION_ANNOTATION, - ORIGIN_LOCATION_ANNOTATION, } from '@backstage/catalog-model'; import { ScmIntegrations } from '@backstage/integration'; import { @@ -82,8 +82,8 @@ describe('DefaultCatalogProcessingOrchestrator', () => { metadata: { name: 'my-foo-bar', annotations: { - [LOCATION_ANNOTATION]: 'url:./here', - [ORIGIN_LOCATION_ANNOTATION]: 'url:./there', + [ANNOTATION_LOCATION]: 'url:./here', + [ANNOTATION_ORIGIN_LOCATION]: 'url:./there', }, }, }; @@ -128,8 +128,8 @@ describe('DefaultCatalogProcessingOrchestrator', () => { metadata: { name: 'my-new-foo-bar', annotations: { - [LOCATION_ANNOTATION]: 'url:./new-place', - [ORIGIN_LOCATION_ANNOTATION]: 'url:./there', + [ANNOTATION_LOCATION]: 'url:./new-place', + [ANNOTATION_ORIGIN_LOCATION]: 'url:./there', }, }, }, @@ -196,8 +196,8 @@ describe('DefaultCatalogProcessingOrchestrator', () => { metadata: { name: 'l', annotations: { - [ORIGIN_LOCATION_ANNOTATION]: 'url:https://example.com/origin.yaml', - [LOCATION_ANNOTATION]: 'url:https://example.com/origin.yaml', + [ANNOTATION_ORIGIN_LOCATION]: 'url:https://example.com/origin.yaml', + [ANNOTATION_LOCATION]: 'url:https://example.com/origin.yaml', }, }, spec: { diff --git a/plugins/catalog-backend/src/processing/DefaultCatalogProcessingOrchestrator.ts b/plugins/catalog-backend/src/processing/DefaultCatalogProcessingOrchestrator.ts index 756b6a3639..105121ae2a 100644 --- a/plugins/catalog-backend/src/processing/DefaultCatalogProcessingOrchestrator.ts +++ b/plugins/catalog-backend/src/processing/DefaultCatalogProcessingOrchestrator.ts @@ -19,9 +19,9 @@ import { EntityPolicy, LocationEntity, LocationSpec, - parseLocationReference, + parseLocationRef, stringifyEntityRef, - stringifyLocationReference, + stringifyLocationRef, } from '@backstage/catalog-model'; import { assertError, @@ -119,10 +119,8 @@ export class DefaultCatalogProcessingOrchestrator // source-location? - maybe probably doesn't exist yet? const context: Context = { entityRef: stringifyEntityRef(entity), - location: parseLocationReference(getEntityLocationRef(entity)), - originLocation: parseLocationReference( - getEntityOriginLocationRef(entity), - ), + location: parseLocationRef(getEntityLocationRef(entity)), + originLocation: parseLocationRef(getEntityOriginLocationRef(entity)), cache, collector, }; @@ -149,9 +147,9 @@ export class DefaultCatalogProcessingOrchestrator throw new NotAllowedError( `Entity ${stringifyEntityRef( deferredEntity.entity, - )} at ${stringifyLocationReference( + )} at ${stringifyLocationRef( context.location, - )}, originated at ${stringifyLocationReference( + )}, originated at ${stringifyLocationRef( context.originLocation, )}, is not of an allowed kind for that location`, ); diff --git a/plugins/catalog-backend/src/processing/ProcessorOutputCollector.ts b/plugins/catalog-backend/src/processing/ProcessorOutputCollector.ts index 4ac356f706..832c5b41bf 100644 --- a/plugins/catalog-backend/src/processing/ProcessorOutputCollector.ts +++ b/plugins/catalog-backend/src/processing/ProcessorOutputCollector.ts @@ -17,9 +17,9 @@ import { Entity, EntityRelationSpec, - LOCATION_ANNOTATION, - ORIGIN_LOCATION_ANNOTATION, - stringifyLocationReference, + ANNOTATION_LOCATION, + ANNOTATION_ORIGIN_LOCATION, + stringifyLocationRef, } from '@backstage/catalog-model'; import { assertError } from '@backstage/errors'; import { Logger } from 'winston'; @@ -82,7 +82,7 @@ export class ProcessorOutputCollector { return; } - const location = stringifyLocationReference(i.location); + const location = stringifyLocationRef(i.location); // Note that at this point, we have only validated the envelope part of // the entity data. Annotations are not part of that, so we have to be @@ -98,8 +98,8 @@ export class ProcessorOutputCollector { ...entity.metadata, annotations: { ...annotations, - [ORIGIN_LOCATION_ANNOTATION]: originLocation, - [LOCATION_ANNOTATION]: location, + [ANNOTATION_ORIGIN_LOCATION]: originLocation, + [ANNOTATION_LOCATION]: location, }, }, }; diff --git a/plugins/catalog-backend/src/processing/util.ts b/plugins/catalog-backend/src/processing/util.ts index 9f5f23ed09..a4fa984dc1 100644 --- a/plugins/catalog-backend/src/processing/util.ts +++ b/plugins/catalog-backend/src/processing/util.ts @@ -20,8 +20,8 @@ import { entitySchemaValidator, LocationEntity, LocationSpec, - LOCATION_ANNOTATION, - ORIGIN_LOCATION_ANNOTATION, + ANNOTATION_LOCATION, + ANNOTATION_ORIGIN_LOCATION, stringifyEntityRef, } from '@backstage/catalog-model'; import { JsonObject, JsonValue } from '@backstage/types'; @@ -34,7 +34,7 @@ export function isLocationEntity(entity: Entity): entity is LocationEntity { } export function getEntityLocationRef(entity: Entity): string { - const ref = entity.metadata.annotations?.[LOCATION_ANNOTATION]; + const ref = entity.metadata.annotations?.[ANNOTATION_LOCATION]; if (!ref) { const entityRef = stringifyEntityRef(entity); throw new InputError(`Entity '${entityRef}' does not have a location`); @@ -43,7 +43,7 @@ export function getEntityLocationRef(entity: Entity): string { } export function getEntityOriginLocationRef(entity: Entity): string { - const ref = entity.metadata.annotations?.[ORIGIN_LOCATION_ANNOTATION]; + const ref = entity.metadata.annotations?.[ANNOTATION_ORIGIN_LOCATION]; if (!ref) { const entityRef = stringifyEntityRef(entity); throw new InputError( diff --git a/plugins/catalog-backend/src/providers/DefaultLocationStore.ts b/plugins/catalog-backend/src/providers/DefaultLocationStore.ts index 9214cd0bc1..f93afedbaa 100644 --- a/plugins/catalog-backend/src/providers/DefaultLocationStore.ts +++ b/plugins/catalog-backend/src/providers/DefaultLocationStore.ts @@ -14,7 +14,8 @@ * limitations under the License. */ -import { Location, LocationSpec } from '@backstage/catalog-model'; +import { LocationSpec } from '@backstage/catalog-model'; +import { Location } from '@backstage/catalog-client'; import { ConflictError, NotFoundError } from '@backstage/errors'; import { Knex } from 'knex'; import { v4 as uuid } from 'uuid'; diff --git a/plugins/catalog-backend/src/search/DefaultCatalogCollator.ts b/plugins/catalog-backend/src/search/DefaultCatalogCollator.ts index 93ef6968d1..8e72a265af 100644 --- a/plugins/catalog-backend/src/search/DefaultCatalogCollator.ts +++ b/plugins/catalog-backend/src/search/DefaultCatalogCollator.ts @@ -28,7 +28,7 @@ import { Config } from '@backstage/config'; import { CatalogApi, CatalogClient, - CatalogEntitiesRequest, + GetEntitiesRequest, } from '@backstage/catalog-client'; import { catalogEntityReadPermission } from '@backstage/plugin-catalog-common'; @@ -43,7 +43,7 @@ export interface CatalogEntityDocument extends IndexableDocument { export class DefaultCatalogCollator implements DocumentCollator { protected discovery: PluginEndpointDiscovery; protected locationTemplate: string; - protected filter?: CatalogEntitiesRequest['filter']; + protected filter?: GetEntitiesRequest['filter']; protected readonly catalogClient: CatalogApi; public readonly type: string = 'software-catalog'; public readonly visibilityPermission = catalogEntityReadPermission; @@ -54,7 +54,7 @@ export class DefaultCatalogCollator implements DocumentCollator { options: { discovery: PluginEndpointDiscovery; tokenManager: TokenManager; - filter?: CatalogEntitiesRequest['filter']; + filter?: GetEntitiesRequest['filter']; }, ) { return new DefaultCatalogCollator({ @@ -66,7 +66,7 @@ export class DefaultCatalogCollator implements DocumentCollator { discovery: PluginEndpointDiscovery; tokenManager: TokenManager; locationTemplate?: string; - filter?: CatalogEntitiesRequest['filter']; + filter?: GetEntitiesRequest['filter']; catalogClient?: CatalogApi; }) { const { discovery, locationTemplate, filter, catalogClient, tokenManager } = diff --git a/plugins/catalog-backend/src/service/AuthorizedLocationService.ts b/plugins/catalog-backend/src/service/AuthorizedLocationService.ts index 1ae2833cd0..13557102c9 100644 --- a/plugins/catalog-backend/src/service/AuthorizedLocationService.ts +++ b/plugins/catalog-backend/src/service/AuthorizedLocationService.ts @@ -14,7 +14,8 @@ * limitations under the License. */ -import { LocationSpec, Location, Entity } from '@backstage/catalog-model'; +import { Location } from '@backstage/catalog-client'; +import { LocationSpec, Entity } from '@backstage/catalog-model'; import { NotAllowedError, NotFoundError } from '@backstage/errors'; import { catalogLocationCreatePermission, diff --git a/plugins/catalog-backend/src/service/DefaultLocationService.ts b/plugins/catalog-backend/src/service/DefaultLocationService.ts index 8dd2274842..8bc02e24f6 100644 --- a/plugins/catalog-backend/src/service/DefaultLocationService.ts +++ b/plugins/catalog-backend/src/service/DefaultLocationService.ts @@ -15,12 +15,12 @@ */ import { Entity, - Location, LocationSpec, - LOCATION_ANNOTATION, - ORIGIN_LOCATION_ANNOTATION, + ANNOTATION_LOCATION, + ANNOTATION_ORIGIN_LOCATION, stringifyEntityRef, } from '@backstage/catalog-model'; +import { Location } from '@backstage/catalog-client'; import { CatalogProcessingOrchestrator, DeferredEntity, @@ -112,8 +112,8 @@ export class DefaultLocationService implements LocationService { }), namespace: 'default', annotations: { - [LOCATION_ANNOTATION]: `${spec.type}:${spec.target}`, - [ORIGIN_LOCATION_ANNOTATION]: `${spec.type}:${spec.target}`, + [ANNOTATION_LOCATION]: `${spec.type}:${spec.target}`, + [ANNOTATION_ORIGIN_LOCATION]: `${spec.type}:${spec.target}`, }, }, spec: { diff --git a/plugins/catalog-backend/src/service/DefaultRefreshService.test.ts b/plugins/catalog-backend/src/service/DefaultRefreshService.test.ts index 1876e59f95..84bfde1259 100644 --- a/plugins/catalog-backend/src/service/DefaultRefreshService.test.ts +++ b/plugins/catalog-backend/src/service/DefaultRefreshService.test.ts @@ -213,6 +213,7 @@ describe('Refresh integration', () => { await engine.stop(); }, + 60_000, ); it.each(databases.eachSupportedId())( @@ -264,6 +265,7 @@ describe('Refresh integration', () => { await engine.stop(); }, + 60_000, ); it.each(databases.eachSupportedId())( @@ -323,5 +325,6 @@ describe('Refresh integration', () => { await engine.stop(); }, + 60_000, ); }); diff --git a/plugins/catalog-backend/src/service/createRouter.test.ts b/plugins/catalog-backend/src/service/createRouter.test.ts index 205be01b42..6ae24ecd27 100644 --- a/plugins/catalog-backend/src/service/createRouter.test.ts +++ b/plugins/catalog-backend/src/service/createRouter.test.ts @@ -17,7 +17,8 @@ import { getVoidLogger } from '@backstage/backend-common'; import { ConfigReader } from '@backstage/config'; import { NotFoundError } from '@backstage/errors'; -import type { Entity, LocationSpec, Location } from '@backstage/catalog-model'; +import type { Location } from '@backstage/catalog-client'; +import type { Entity, LocationSpec } from '@backstage/catalog-model'; import express from 'express'; import request from 'supertest'; import { EntitiesCatalog } from '../catalog'; diff --git a/plugins/catalog-backend/src/service/createRouter.ts b/plugins/catalog-backend/src/service/createRouter.ts index ab123238c7..0dce765507 100644 --- a/plugins/catalog-backend/src/service/createRouter.ts +++ b/plugins/catalog-backend/src/service/createRouter.ts @@ -15,11 +15,7 @@ */ import { errorHandler } from '@backstage/backend-common'; -import { - analyzeLocationSchema, - locationSpecSchema, - stringifyEntityRef, -} from '@backstage/catalog-model'; +import { stringifyEntityRef } from '@backstage/catalog-model'; import { Config } from '@backstage/config'; import { NotFoundError } from '@backstage/errors'; import express from 'express'; @@ -34,8 +30,13 @@ import { parseEntityPaginationParams, parseEntityTransformParams, } from './request'; -import { disallowReadonlyMode, validateRequestBody } from './util'; +import { + disallowReadonlyMode, + locationSpec, + validateRequestBody, +} from './util'; import { RefreshOptions, LocationService, RefreshService } from './types'; +import { z } from 'zod'; /** * Options used by {@link createRouter}. @@ -165,7 +166,7 @@ export async function createRouter( if (locationService) { router .post('/locations', async (req, res) => { - const input = await validateRequestBody(req, locationSpecSchema); + const location = await validateRequestBody(req, locationSpec); const dryRun = yn(req.query.dryRun, { default: false }); // when in dryRun addLocation is effectively a read operation so we don't @@ -174,7 +175,7 @@ export async function createRouter( disallowReadonlyMode(readonlyEnabled); } - const output = await locationService.createLocation(input, dryRun, { + const output = await locationService.createLocation(location, dryRun, { authorizationToken: getBearerToken(req.header('authorization')), }); res.status(201).json(output); @@ -206,8 +207,12 @@ export async function createRouter( if (locationAnalyzer) { router.post('/analyze-location', async (req, res) => { - const input = await validateRequestBody(req, analyzeLocationSchema); - const output = await locationAnalyzer.analyzeLocation(input); + const body = await validateRequestBody( + req, + z.object({ location: locationSpec }), + ); + const schema = z.object({ location: locationSpec }); + const output = await locationAnalyzer.analyzeLocation(schema.parse(body)); res.status(200).json(output); }); } diff --git a/plugins/catalog-backend/src/service/types.ts b/plugins/catalog-backend/src/service/types.ts index 02d234b6a8..c923949a04 100644 --- a/plugins/catalog-backend/src/service/types.ts +++ b/plugins/catalog-backend/src/service/types.ts @@ -14,7 +14,8 @@ * limitations under the License. */ -import { Entity, LocationSpec, Location } from '@backstage/catalog-model'; +import { Entity, LocationSpec } from '@backstage/catalog-model'; +import { Location } from '@backstage/catalog-client'; export interface LocationService { createLocation( diff --git a/plugins/catalog-backend/src/service/util.ts b/plugins/catalog-backend/src/service/util.ts index 7cc2d6618a..09f1c2d8cf 100644 --- a/plugins/catalog-backend/src/service/util.ts +++ b/plugins/catalog-backend/src/service/util.ts @@ -17,7 +17,7 @@ import { InputError, NotAllowedError } from '@backstage/errors'; import { Request } from 'express'; import lodash from 'lodash'; -import yup from 'yup'; +import { z } from 'zod'; export async function requireRequestBody(req: Request): Promise { const contentType = req.header('content-type'); @@ -40,19 +40,24 @@ export async function requireRequestBody(req: Request): Promise { return body; } +export const locationSpec = z + .object({ + type: z.string(), + target: z.string(), + presence: z.literal('required').or(z.literal('optional')).optional(), + }) + .strict(); // no unknown keys; + export async function validateRequestBody( req: Request, - schema: yup.AnySchema, + schema: z.Schema, ): Promise { const body = await requireRequestBody(req); - try { - await schema.validate(body, { strict: true }); + return await schema.parse(body); } catch (e) { throw new InputError(`Malformed request: ${e}`); } - - return body as unknown as T; } export function disallowReadonlyMode(readonly: boolean) { diff --git a/plugins/catalog-backend/src/stitching/buildEntitySearch.test.ts b/plugins/catalog-backend/src/stitching/buildEntitySearch.test.ts index 58551a461f..173538f18f 100644 --- a/plugins/catalog-backend/src/stitching/buildEntitySearch.test.ts +++ b/plugins/catalog-backend/src/stitching/buildEntitySearch.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { Entity, ENTITY_DEFAULT_NAMESPACE } from '@backstage/catalog-model'; +import { Entity, DEFAULT_NAMESPACE } from '@backstage/catalog-model'; import { buildEntitySearch, mapToRows, traverse } from './buildEntitySearch'; describe('buildEntitySearch', () => { @@ -133,7 +133,7 @@ describe('buildEntitySearch', () => { { entity_id: 'eid', key: 'metadata.namespace', - value: ENTITY_DEFAULT_NAMESPACE, + value: DEFAULT_NAMESPACE, }, ]); }); @@ -157,7 +157,7 @@ describe('buildEntitySearch', () => { { entity_id: 'eid', key: 'metadata.namespace', - value: ENTITY_DEFAULT_NAMESPACE, + value: DEFAULT_NAMESPACE, }, { entity_id: 'eid', key: 'relations.t1', value: 'k:ns/a' }, { entity_id: 'eid', key: 'relations.t2', value: 'k:ns/b' }, diff --git a/plugins/catalog-backend/src/stitching/buildEntitySearch.ts b/plugins/catalog-backend/src/stitching/buildEntitySearch.ts index 84c6036013..d0506e8998 100644 --- a/plugins/catalog-backend/src/stitching/buildEntitySearch.ts +++ b/plugins/catalog-backend/src/stitching/buildEntitySearch.ts @@ -16,7 +16,7 @@ import { Entity, - ENTITY_DEFAULT_NAMESPACE, + DEFAULT_NAMESPACE, stringifyEntityRef, } from '@backstage/catalog-model'; import { InputError } from '@backstage/errors'; @@ -174,7 +174,7 @@ export function buildEntitySearch( // Namespace not specified has the default value "default", so we want to // match on that as well if (!entity.metadata.namespace) { - raw.push({ key: 'metadata.namespace', value: ENTITY_DEFAULT_NAMESPACE }); + raw.push({ key: 'metadata.namespace', value: DEFAULT_NAMESPACE }); } // Visit relations diff --git a/plugins/catalog-backend/src/util/conversion.ts b/plugins/catalog-backend/src/util/conversion.ts index 559a472c25..9dd5ce7986 100644 --- a/plugins/catalog-backend/src/util/conversion.ts +++ b/plugins/catalog-backend/src/util/conversion.ts @@ -18,10 +18,10 @@ import { Entity, LocationEntityV1alpha1, LocationSpec, - LOCATION_ANNOTATION, - ORIGIN_LOCATION_ANNOTATION, + ANNOTATION_LOCATION, + ANNOTATION_ORIGIN_LOCATION, stringifyEntityRef, - stringifyLocationReference, + stringifyLocationRef, } from '@backstage/catalog-model'; import { createHash } from 'crypto'; @@ -40,31 +40,31 @@ export function locationSpecToLocationEntity( let originLocation: string; if (parentEntity) { const maybeOwnLocation = - parentEntity.metadata.annotations?.[LOCATION_ANNOTATION]; + parentEntity.metadata.annotations?.[ANNOTATION_LOCATION]; if (!maybeOwnLocation) { throw new Error( `Parent entity '${stringifyEntityRef( parentEntity, - )}' of location '${stringifyLocationReference( + )}' of location '${stringifyLocationRef( location, )}' does not have a location annotation`, ); } ownLocation = maybeOwnLocation; const maybeOriginLocation = - parentEntity.metadata.annotations?.[ORIGIN_LOCATION_ANNOTATION]; + parentEntity.metadata.annotations?.[ANNOTATION_ORIGIN_LOCATION]; if (!maybeOriginLocation) { throw new Error( `Parent entity '${stringifyEntityRef( parentEntity, - )}' of location '${stringifyLocationReference( + )}' of location '${stringifyLocationRef( location, )}' does not have an origin location annotation`, ); } originLocation = maybeOriginLocation; } else { - ownLocation = stringifyLocationReference(location); + ownLocation = stringifyLocationRef(location); originLocation = ownLocation; } @@ -74,8 +74,8 @@ export function locationSpecToLocationEntity( metadata: { name: locationSpecToMetadataName(location), annotations: { - [LOCATION_ANNOTATION]: ownLocation, - [ORIGIN_LOCATION_ANNOTATION]: originLocation, + [ANNOTATION_LOCATION]: ownLocation, + [ANNOTATION_ORIGIN_LOCATION]: originLocation, }, }, spec: { diff --git a/plugins/catalog-common/package.json b/plugins/catalog-common/package.json index 4b94809ed5..5f77133215 100644 --- a/plugins/catalog-common/package.json +++ b/plugins/catalog-common/package.json @@ -12,6 +12,9 @@ "module": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "common-library" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -22,12 +25,12 @@ "backstage" ], "scripts": { - "build": "backstage-cli build", - "lint": "backstage-cli lint", - "test": "backstage-cli test --passWithNoTests", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/plugin-permission-common": "^0.4.0" diff --git a/plugins/catalog-graph/dev/index.tsx b/plugins/catalog-graph/dev/index.tsx index ed14e5fce9..3ff9285a81 100644 --- a/plugins/catalog-graph/dev/index.tsx +++ b/plugins/catalog-graph/dev/index.tsx @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { CatalogListResponse } from '@backstage/catalog-client'; +import { GetEntitiesResponse } from '@backstage/catalog-client'; import { Entity, EntityName, - ENTITY_DEFAULT_NAMESPACE, + DEFAULT_NAMESPACE, RELATION_API_CONSUMED_BY, RELATION_API_PROVIDED_BY, RELATION_CONSUMES_API, @@ -117,7 +117,7 @@ const entities = ( name, }, relations: relations.map(([type, k, n]) => ({ - target: { kind: k, name: n, namespace: ENTITY_DEFAULT_NAMESPACE }, + target: { kind: k, name: n, namespace: DEFAULT_NAMESPACE }, type, })), }; @@ -136,7 +136,7 @@ createDevApp() async getEntityByName(name: EntityName): Promise { return entities[stringifyEntityRef(name)]; }, - async getEntities(): Promise> { + async getEntities(): Promise { return { items: Object.values(entities) }; }, } as Partial as unknown as CatalogApi; diff --git a/plugins/catalog-graph/package.json b/plugins/catalog-graph/package.json index 541d21f319..ad7161eb93 100644 --- a/plugins/catalog-graph/package.json +++ b/plugins/catalog-graph/package.json @@ -10,15 +10,18 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/catalog-client": "^0.6.0", diff --git a/plugins/catalog-graph/src/components/CatalogGraphCard/CatalogGraphCard.test.tsx b/plugins/catalog-graph/src/components/CatalogGraphCard/CatalogGraphCard.test.tsx index 7209a516a5..0e2fa723dc 100644 --- a/plugins/catalog-graph/src/components/CatalogGraphCard/CatalogGraphCard.test.tsx +++ b/plugins/catalog-graph/src/components/CatalogGraphCard/CatalogGraphCard.test.tsx @@ -60,8 +60,7 @@ describe('', () => { getEntityByName: jest.fn(async _ => ({ ...entity, relations: [] })), removeEntityByUid: jest.fn(), getLocationById: jest.fn(), - getOriginLocationByEntity: jest.fn(), - getLocationByEntity: jest.fn(), + getLocationByRef: jest.fn(), addLocation: jest.fn(), removeLocationById: jest.fn(), refreshEntity: jest.fn(), diff --git a/plugins/catalog-graph/src/components/CatalogGraphPage/CatalogGraphPage.test.tsx b/plugins/catalog-graph/src/components/CatalogGraphPage/CatalogGraphPage.test.tsx index 4c7a64a7ce..c509abd712 100644 --- a/plugins/catalog-graph/src/components/CatalogGraphPage/CatalogGraphPage.test.tsx +++ b/plugins/catalog-graph/src/components/CatalogGraphPage/CatalogGraphPage.test.tsx @@ -89,8 +89,7 @@ describe('', () => { getEntityByName: jest.fn(async n => (n.name === 'e' ? entityE : entityC)), removeEntityByUid: jest.fn(), getLocationById: jest.fn(), - getOriginLocationByEntity: jest.fn(), - getLocationByEntity: jest.fn(), + getLocationByRef: jest.fn(), addLocation: jest.fn(), removeLocationById: jest.fn(), refreshEntity: jest.fn(), diff --git a/plugins/catalog-graph/src/components/EntityRelationsGraph/EntityRelationsGraph.test.tsx b/plugins/catalog-graph/src/components/EntityRelationsGraph/EntityRelationsGraph.test.tsx index be0c4dc5e5..715f30e8c9 100644 --- a/plugins/catalog-graph/src/components/EntityRelationsGraph/EntityRelationsGraph.test.tsx +++ b/plugins/catalog-graph/src/components/EntityRelationsGraph/EntityRelationsGraph.test.tsx @@ -150,8 +150,7 @@ describe('', () => { getEntityByName: jest.fn(async n => entities[stringifyEntityRef(n)]), removeEntityByUid: jest.fn(), getLocationById: jest.fn(), - getOriginLocationByEntity: jest.fn(), - getLocationByEntity: jest.fn(), + getLocationByRef: jest.fn(), addLocation: jest.fn(), removeLocationById: jest.fn(), refreshEntity: jest.fn(), diff --git a/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityRelationNodesAndEdges.ts b/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityRelationNodesAndEdges.ts index 2f78fd9c17..b272abc654 100644 --- a/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityRelationNodesAndEdges.ts +++ b/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityRelationNodesAndEdges.ts @@ -14,7 +14,7 @@ * limitations under the License. */ import { - ENTITY_DEFAULT_NAMESPACE, + DEFAULT_NAMESPACE, stringifyEntityRef, } from '@backstage/catalog-model'; import { MouseEvent, useState } from 'react'; @@ -77,7 +77,7 @@ export function useEntityRelationNodesAndEdges({ title: entity.metadata?.title ?? undefined, kind: entity.kind, name: entity.metadata.name, - namespace: entity.metadata.namespace ?? ENTITY_DEFAULT_NAMESPACE, + namespace: entity.metadata.namespace ?? DEFAULT_NAMESPACE, focused, color: focused ? 'secondary' : 'primary', }; diff --git a/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityStore.test.ts b/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityStore.test.ts index a60750bab5..214f1a8fb9 100644 --- a/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityStore.test.ts +++ b/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityStore.test.ts @@ -32,8 +32,7 @@ describe('useEntityStore', () => { getEntityByName: jest.fn(), removeEntityByUid: jest.fn(), getLocationById: jest.fn(), - getOriginLocationByEntity: jest.fn(), - getLocationByEntity: jest.fn(), + getLocationByRef: jest.fn(), addLocation: jest.fn(), removeLocationById: jest.fn(), refreshEntity: jest.fn(), diff --git a/plugins/catalog-graphql/package.json b/plugins/catalog-graphql/package.json index b757790275..a1920b76a3 100644 --- a/plugins/catalog-graphql/package.json +++ b/plugins/catalog-graphql/package.json @@ -10,6 +10,9 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "backend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -21,14 +24,14 @@ "graphql" ], "scripts": { - "start": "backstage-cli backend:dev", - "build": "backstage-cli backend:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", "generate:types": "graphql-codegen", - "clean": "backstage-cli clean" + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/catalog-model": "^0.9.10", diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json index 7ce6f8524f..1e62395e64 100644 --- a/plugins/catalog-import/package.json +++ b/plugins/catalog-import/package.json @@ -11,6 +11,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -21,14 +24,14 @@ "backstage" ], "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/catalog-client": "^0.6.0", diff --git a/plugins/catalog-import/src/api/CatalogImportClient.test.ts b/plugins/catalog-import/src/api/CatalogImportClient.test.ts index fa63825af1..d2c7771804 100644 --- a/plugins/catalog-import/src/api/CatalogImportClient.test.ts +++ b/plugins/catalog-import/src/api/CatalogImportClient.test.ts @@ -94,8 +94,7 @@ describe('CatalogImportClient', () => { addLocation: jest.fn(), removeLocationById: jest.fn(), getEntityByName: jest.fn(), - getOriginLocationByEntity: jest.fn(), - getLocationByEntity: jest.fn(), + getLocationByRef: jest.fn(), getLocationById: jest.fn(), removeEntityByUid: jest.fn(), refreshEntity: jest.fn(), diff --git a/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/StepPrepareCreatePullRequest.test.tsx b/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/StepPrepareCreatePullRequest.test.tsx index 8d26657bb3..40c1152fe8 100644 --- a/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/StepPrepareCreatePullRequest.test.tsx +++ b/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/StepPrepareCreatePullRequest.test.tsx @@ -39,8 +39,7 @@ describe('', () => { getEntities: jest.fn(), addLocation: jest.fn(), getEntityByName: jest.fn(), - getOriginLocationByEntity: jest.fn(), - getLocationByEntity: jest.fn(), + getLocationByRef: jest.fn(), getLocationById: jest.fn(), removeLocationById: jest.fn(), removeEntityByUid: jest.fn(), diff --git a/plugins/catalog-react/api-report.md b/plugins/catalog-react/api-report.md index 056f10f135..5ab3f20d76 100644 --- a/plugins/catalog-react/api-report.md +++ b/plugins/catalog-react/api-report.md @@ -9,12 +9,12 @@ import { ApiRef } from '@backstage/core-plugin-api'; import { AsyncState } from 'react-use/lib/useAsync'; import { CATALOG_FILTER_EXISTS } from '@backstage/catalog-client'; import { CatalogApi } from '@backstage/catalog-client'; -import { CatalogListResponse } from '@backstage/catalog-client'; import { ComponentEntity } from '@backstage/catalog-model'; import { ComponentProps } from 'react'; import { Context } from 'react'; import { Entity } from '@backstage/catalog-model'; import { EntityName } from '@backstage/catalog-model'; +import { GetEntitiesResponse } from '@backstage/catalog-client'; import { IconButton } from '@material-ui/core'; import { IdentityApi } from '@backstage/core-plugin-api'; import { LinkProps } from '@backstage/core-components'; @@ -612,7 +612,7 @@ export function useEntityTypeFilter(): EntityTypeReturn; // @public export function useOwnedEntities(allowedKinds?: string[]): { loading: boolean; - ownedEntities: CatalogListResponse | undefined; + ownedEntities: GetEntitiesResponse | undefined; }; // Warning: (ae-missing-release-tag) "useOwnUser" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) diff --git a/plugins/catalog-react/package.json b/plugins/catalog-react/package.json index d995fdf848..967ad8ba0b 100644 --- a/plugins/catalog-react/package.json +++ b/plugins/catalog-react/package.json @@ -11,6 +11,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "web-library" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -21,12 +24,13 @@ "backstage" ], "scripts": { - "build": "backstage-cli build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean", + "start": "backstage-cli package start" }, "dependencies": { "@backstage/catalog-client": "^0.6.0", @@ -59,6 +63,7 @@ "@backstage/cli": "^0.13.2", "@backstage/core-app-api": "^0.5.2", "@backstage/plugin-catalog-common": "^0.1.2", + "@backstage/plugin-scaffolder-common": "^0.1.3", "@backstage/test-utils": "^0.2.4", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", diff --git a/plugins/catalog-react/src/components/EntityRefLink/EntityRefLink.tsx b/plugins/catalog-react/src/components/EntityRefLink/EntityRefLink.tsx index 8120ececd2..f2c67f1087 100644 --- a/plugins/catalog-react/src/components/EntityRefLink/EntityRefLink.tsx +++ b/plugins/catalog-react/src/components/EntityRefLink/EntityRefLink.tsx @@ -17,7 +17,7 @@ import { Entity, EntityName, - ENTITY_DEFAULT_NAMESPACE, + DEFAULT_NAMESPACE, } from '@backstage/catalog-model'; import React, { forwardRef } from 'react'; import { entityRouteRef } from '../../routes'; @@ -66,8 +66,7 @@ export const EntityRefLink = forwardRef( const routeParams = { kind, - namespace: - namespace?.toLocaleLowerCase('en-US') ?? ENTITY_DEFAULT_NAMESPACE, + namespace: namespace?.toLocaleLowerCase('en-US') ?? DEFAULT_NAMESPACE, name, }; const formattedEntityRefTitle = formatEntityRefTitle(entityRef, { diff --git a/plugins/catalog-react/src/components/EntityRefLink/format.ts b/plugins/catalog-react/src/components/EntityRefLink/format.ts index f3977ccc95..50e018c7ab 100644 --- a/plugins/catalog-react/src/components/EntityRefLink/format.ts +++ b/plugins/catalog-react/src/components/EntityRefLink/format.ts @@ -17,8 +17,7 @@ import { Entity, EntityName, - ENTITY_DEFAULT_NAMESPACE, - serializeEntityRef, + DEFAULT_NAMESPACE, } from '@backstage/catalog-model'; export function formatEntityRefTitle( @@ -40,18 +39,14 @@ export function formatEntityRefTitle( name = entityRef.name; } - if (namespace === ENTITY_DEFAULT_NAMESPACE) { + if (namespace === DEFAULT_NAMESPACE) { namespace = undefined; } kind = kind.toLocaleLowerCase('en-US'); - - return `${serializeEntityRef({ - kind: - defaultKind && defaultKind.toLocaleLowerCase('en-US') === kind - ? undefined - : kind, - name, - namespace, - })}`; + kind = + defaultKind && defaultKind.toLocaleLowerCase('en-US') === kind + ? undefined + : kind; + return `${kind ? `${kind}:` : ''}${namespace ? `${namespace}/` : ''}${name}`; } diff --git a/plugins/catalog-react/src/components/InspectEntityDialog/components/AncestryPage.tsx b/plugins/catalog-react/src/components/InspectEntityDialog/components/AncestryPage.tsx index b27bbe3948..bf6c8971b0 100644 --- a/plugins/catalog-react/src/components/InspectEntityDialog/components/AncestryPage.tsx +++ b/plugins/catalog-react/src/components/InspectEntityDialog/components/AncestryPage.tsx @@ -16,7 +16,7 @@ import { Entity, - ENTITY_DEFAULT_NAMESPACE, + DEFAULT_NAMESPACE, stringifyEntityRef, } from '@backstage/catalog-model'; import { @@ -143,7 +143,7 @@ function CustomNode({ node }: DependencyGraphTypes.RenderNodeProps) { navigate( entityRoute({ kind: node.kind, - namespace: node.metadata.namespace || ENTITY_DEFAULT_NAMESPACE, + namespace: node.metadata.namespace || DEFAULT_NAMESPACE, name: node.metadata.name, }), ); diff --git a/plugins/catalog-react/src/components/InspectEntityDialog/components/ColocatedPage.tsx b/plugins/catalog-react/src/components/InspectEntityDialog/components/ColocatedPage.tsx index 96d3900a59..d5a98f434c 100644 --- a/plugins/catalog-react/src/components/InspectEntityDialog/components/ColocatedPage.tsx +++ b/plugins/catalog-react/src/components/InspectEntityDialog/components/ColocatedPage.tsx @@ -16,8 +16,8 @@ import { Entity, - LOCATION_ANNOTATION, - ORIGIN_LOCATION_ANNOTATION, + ANNOTATION_LOCATION, + ANNOTATION_ORIGIN_LOCATION, stringifyEntityRef, } from '@backstage/catalog-model'; import { Progress, ResponseErrorPanel } from '@backstage/core-components'; @@ -53,8 +53,8 @@ function useColocated(entity: Entity): { } { const catalogApi = useApi(catalogApiRef); const currentEntityRef = stringifyEntityRef(entity); - const location = entity.metadata.annotations?.[LOCATION_ANNOTATION]; - const origin = entity.metadata.annotations?.[ORIGIN_LOCATION_ANNOTATION]; + const location = entity.metadata.annotations?.[ANNOTATION_LOCATION]; + const origin = entity.metadata.annotations?.[ANNOTATION_ORIGIN_LOCATION]; const { loading, error, value } = useAsync(async () => { if (!location && !origin) { @@ -63,10 +63,10 @@ function useColocated(entity: Entity): { const response = await catalogApi.getEntities({ filter: [ ...(location - ? [{ [`metadata.annotations.${LOCATION_ANNOTATION}`]: location }] + ? [{ [`metadata.annotations.${ANNOTATION_LOCATION}`]: location }] : []), ...(origin - ? [{ [`metadata.annotations.${ORIGIN_LOCATION_ANNOTATION}`]: origin }] + ? [{ [`metadata.annotations.${ANNOTATION_ORIGIN_LOCATION}`]: origin }] : []), ], }); @@ -128,11 +128,11 @@ function Contents(props: { entity: Entity }) { } const atLocation = colocatedEntities.filter( - e => e.metadata.annotations?.[LOCATION_ANNOTATION] === location, + e => e.metadata.annotations?.[ANNOTATION_LOCATION] === location, ); const atOrigin = colocatedEntities.filter( e => - e.metadata.annotations?.[ORIGIN_LOCATION_ANNOTATION] === originLocation, + e.metadata.annotations?.[ANNOTATION_ORIGIN_LOCATION] === originLocation, ); return ( diff --git a/plugins/catalog-react/src/components/UnregisterEntityDialog/UnregisterEntityDialog.test.tsx b/plugins/catalog-react/src/components/UnregisterEntityDialog/UnregisterEntityDialog.test.tsx index 2b29bba4fd..68cb5f2bdf 100644 --- a/plugins/catalog-react/src/components/UnregisterEntityDialog/UnregisterEntityDialog.test.tsx +++ b/plugins/catalog-react/src/components/UnregisterEntityDialog/UnregisterEntityDialog.test.tsx @@ -19,7 +19,7 @@ jest.mock('./useUnregisterEntityDialogState'); import userEvent from '@testing-library/user-event'; import React from 'react'; import { UnregisterEntityDialog } from './UnregisterEntityDialog'; -import { ORIGIN_LOCATION_ANNOTATION } from '@backstage/catalog-model'; +import { ANNOTATION_ORIGIN_LOCATION } from '@backstage/catalog-model'; import { CatalogClient } from '@backstage/catalog-client'; import { catalogApiRef } from '../../api'; import { entityRouteRef } from '../../routes'; @@ -55,7 +55,7 @@ describe('UnregisterEntityDialog', () => { name: 'n', namespace: 'ns', annotations: { - [ORIGIN_LOCATION_ANNOTATION]: 'url:http://example.com', + [ANNOTATION_ORIGIN_LOCATION]: 'url:http://example.com', }, }, spec: {}, diff --git a/plugins/catalog-react/src/components/UnregisterEntityDialog/useUnregisterEntityDialogState.test.tsx b/plugins/catalog-react/src/components/UnregisterEntityDialog/useUnregisterEntityDialogState.test.tsx index 8d6083f111..25af7564d1 100644 --- a/plugins/catalog-react/src/components/UnregisterEntityDialog/useUnregisterEntityDialogState.test.tsx +++ b/plugins/catalog-react/src/components/UnregisterEntityDialog/useUnregisterEntityDialogState.test.tsx @@ -14,12 +14,8 @@ * limitations under the License. */ -import { - Entity, - Location, - ORIGIN_LOCATION_ANNOTATION, -} from '@backstage/catalog-model'; -import { CatalogApi } from '@backstage/catalog-client'; +import { CatalogApi, Location } from '@backstage/catalog-client'; +import { Entity, ANNOTATION_ORIGIN_LOCATION } from '@backstage/catalog-model'; import { catalogApiRef } from '../../api'; import { act, @@ -43,7 +39,7 @@ function defer(): { promise: Promise; resolve: (value: T) => void } { describe('useUnregisterEntityDialogState', () => { const catalogApiMock = { - getOriginLocationByEntity: jest.fn(), + getLocationByRef: jest.fn(), getEntities: jest.fn(), removeLocationById: jest.fn(), removeEntityByUid: jest.fn(), @@ -69,9 +65,7 @@ describe('useUnregisterEntityDialogState', () => { resolveLocation = deferredLocation.resolve; resolveColocatedEntities = deferredColocatedEntities.resolve; - catalogApiMock.getOriginLocationByEntity.mockReturnValue( - deferredLocation.promise, - ); + catalogApiMock.getLocationByRef.mockReturnValue(deferredLocation.promise); catalogApiMock.getEntities.mockReturnValue( deferredColocatedEntities.promise.then(items => ({ items })), ); @@ -83,7 +77,7 @@ describe('useUnregisterEntityDialogState', () => { name: 'n', namespace: 'ns', annotations: { - [ORIGIN_LOCATION_ANNOTATION]: 'url:https://example.com', + [ANNOTATION_ORIGIN_LOCATION]: 'url:https://example.com', }, }, spec: {}, @@ -117,7 +111,7 @@ describe('useUnregisterEntityDialogState', () => { }); it('chooses the bootstrap path when necessary', async () => { - entity.metadata.annotations![ORIGIN_LOCATION_ANNOTATION] = + entity.metadata.annotations![ANNOTATION_ORIGIN_LOCATION] = 'bootstrap:bootstrap'; let rendered: RenderHookResult; @@ -141,7 +135,7 @@ describe('useUnregisterEntityDialogState', () => { }); it('chooses only-delete when there was no location annotation', async () => { - delete entity.metadata.annotations![ORIGIN_LOCATION_ANNOTATION]; + delete entity.metadata.annotations![ANNOTATION_ORIGIN_LOCATION]; let rendered: RenderHookResult; act(() => { diff --git a/plugins/catalog-react/src/components/UnregisterEntityDialog/useUnregisterEntityDialogState.ts b/plugins/catalog-react/src/components/UnregisterEntityDialog/useUnregisterEntityDialogState.ts index 7f75016e16..6420ebd5ae 100644 --- a/plugins/catalog-react/src/components/UnregisterEntityDialog/useUnregisterEntityDialogState.ts +++ b/plugins/catalog-react/src/components/UnregisterEntityDialog/useUnregisterEntityDialogState.ts @@ -18,7 +18,7 @@ import { Entity, EntityName, getEntityName, - ORIGIN_LOCATION_ANNOTATION, + ANNOTATION_ORIGIN_LOCATION, } from '@backstage/catalog-model'; import { catalogApiRef } from '../../api'; import { useCallback } from 'react'; @@ -60,20 +60,20 @@ export function useUnregisterEntityDialogState( entity: Entity, ): UseUnregisterEntityDialogState { const catalogApi = useApi(catalogApiRef); - const locationRef = entity.metadata.annotations?.[ORIGIN_LOCATION_ANNOTATION]; + const locationRef = entity.metadata.annotations?.[ANNOTATION_ORIGIN_LOCATION]; const uid = entity.metadata.uid; const isBootstrap = locationRef === 'bootstrap:bootstrap'; // Load the prerequisite data: what entities that are colocated with us, and // what location that spawned us const prerequisites = useAsync(async () => { - const locationPromise = catalogApi.getOriginLocationByEntity(entity); + const locationPromise = catalogApi.getLocationByRef(locationRef!); let colocatedEntitiesPromise: Promise; if (!locationRef) { colocatedEntitiesPromise = Promise.resolve([]); } else { - const locationAnnotationFilter = `metadata.annotations.${ORIGIN_LOCATION_ANNOTATION}`; + const locationAnnotationFilter = `metadata.annotations.${ANNOTATION_ORIGIN_LOCATION}`; colocatedEntitiesPromise = catalogApi .getEntities({ filter: { [locationAnnotationFilter]: locationRef }, diff --git a/plugins/catalog-react/src/components/UserListPicker/UserListPicker.test.tsx b/plugins/catalog-react/src/components/UserListPicker/UserListPicker.test.tsx index d4cfedecbf..630a995bbe 100644 --- a/plugins/catalog-react/src/components/UserListPicker/UserListPicker.test.tsx +++ b/plugins/catalog-react/src/components/UserListPicker/UserListPicker.test.tsx @@ -36,6 +36,7 @@ import { identityApiRef, storageApiRef, } from '@backstage/core-plugin-api'; +import { useEntityOwnership } from '../../hooks'; const mockUser: UserEntity = { apiVersion: 'backstage.io/v1alpha1', @@ -81,9 +82,9 @@ jest.mock('../../hooks', () => { const actual = jest.requireActual('../../hooks'); return { ...actual, - useEntityOwnership: () => ({ + useEntityOwnership: jest.fn(() => ({ isOwnedEntity: mockIsOwnedEntity, - }), + })), useStarredEntities: () => ({ isStarredEntity: mockIsStarredEntity, }), @@ -327,6 +328,19 @@ describe('', () => { }); }); + it('does not reset the filter while owned entities are loading', () => { + const isOwnedEntity = jest.fn(() => false); + (useEntityOwnership as jest.Mock).mockReturnValueOnce({ + loading: true, + isOwnedEntity, + }); + + render(picker({ loading: false })); + expect(updateFilters).not.toHaveBeenCalledWith({ + user: new UserListFilter('all', isOwnedEntity, mockIsStarredEntity), + }); + }); + it('resets the filter to "all" when entities are loaded', () => { render(picker({ loading: false })); diff --git a/plugins/catalog-react/src/components/UserListPicker/UserListPicker.tsx b/plugins/catalog-react/src/components/UserListPicker/UserListPicker.tsx index cbf6089f2e..de23f75e47 100644 --- a/plugins/catalog-react/src/components/UserListPicker/UserListPicker.tsx +++ b/plugins/catalog-react/src/components/UserListPicker/UserListPicker.tsx @@ -130,8 +130,13 @@ export const UserListPicker = ({ const classes = useStyles(); const configApi = useApi(configApiRef); const orgName = configApi.getOptionalString('organization.name') ?? 'Company'; - const { filters, updateFilters, backendEntities, queryParameters, loading } = - useEntityListProvider(); + const { + filters, + updateFilters, + backendEntities, + queryParameters, + loading: loadingBackendEntities, + } = useEntityListProvider(); // Remove group items that aren't in availableFilters and exclude // any now-empty groups. @@ -149,7 +154,10 @@ export const UserListPicker = ({ .filter(({ items }) => !!items.length); const { isStarredEntity } = useStarredEntities(); - const { isOwnedEntity } = useEntityOwnership(); + const { isOwnedEntity, loading: loadingEntityOwnership } = + useEntityOwnership(); + + const loading = loadingBackendEntities || loadingEntityOwnership; // Static filters; used for generating counts of potentially unselected kinds const ownedFilter = useMemo( diff --git a/plugins/catalog-react/src/filters.test.ts b/plugins/catalog-react/src/filters.test.ts index 668e3b4bc3..cdc2ce2150 100644 --- a/plugins/catalog-react/src/filters.test.ts +++ b/plugins/catalog-react/src/filters.test.ts @@ -14,7 +14,8 @@ * limitations under the License. */ -import { Entity, TemplateEntityV1beta2 } from '@backstage/catalog-model'; +import { Entity } from '@backstage/catalog-model'; +import { TemplateEntityV1beta2 } from '@backstage/plugin-scaffolder-common'; import { EntityTextFilter } from './filters'; const entities: Entity[] = [ diff --git a/plugins/catalog-react/src/hooks/useOwnUser.ts b/plugins/catalog-react/src/hooks/useOwnUser.ts index f49eb768d0..497f065f04 100644 --- a/plugins/catalog-react/src/hooks/useOwnUser.ts +++ b/plugins/catalog-react/src/hooks/useOwnUser.ts @@ -15,7 +15,7 @@ */ import { - ENTITY_DEFAULT_NAMESPACE, + DEFAULT_NAMESPACE, parseEntityRef, UserEntity, } from '@backstage/catalog-model'; @@ -35,7 +35,7 @@ export function useOwnUser(): AsyncState { return catalogApi.getEntityByName( parseEntityRef(identity.userEntityRef, { defaultKind: 'User', - defaultNamespace: ENTITY_DEFAULT_NAMESPACE, + defaultNamespace: DEFAULT_NAMESPACE, }), ) as Promise; }, [catalogApi, identityApi]); diff --git a/plugins/catalog-react/src/hooks/useOwnedEntities.ts b/plugins/catalog-react/src/hooks/useOwnedEntities.ts index ffe64830f4..dad73740c1 100644 --- a/plugins/catalog-react/src/hooks/useOwnedEntities.ts +++ b/plugins/catalog-react/src/hooks/useOwnedEntities.ts @@ -19,8 +19,8 @@ import { loadIdentityOwnerRefs, } from './useEntityOwnership'; import { identityApiRef, useApi } from '@backstage/core-plugin-api'; -import { Entity, RELATION_OWNED_BY } from '@backstage/catalog-model'; -import { CatalogListResponse } from '@backstage/catalog-client'; +import { RELATION_OWNED_BY } from '@backstage/catalog-model'; +import { GetEntitiesResponse } from '@backstage/catalog-client'; import useAsync from 'react-use/lib/useAsync'; import { useMemo } from 'react'; @@ -32,11 +32,10 @@ import { useMemo } from 'react'; * @public * * @param allowedKinds - Array of allowed kinds to filter the entities - * @returns CatalogListResponse */ export function useOwnedEntities(allowedKinds?: string[]): { loading: boolean; - ownedEntities: CatalogListResponse | undefined; + ownedEntities: GetEntitiesResponse | undefined; } { const identityApi = useApi(identityApiRef); const catalogApi = useApi(catalogApiRef); diff --git a/plugins/catalog-react/src/routes.ts b/plugins/catalog-react/src/routes.ts index 1fcbd14866..57801fab4a 100644 --- a/plugins/catalog-react/src/routes.ts +++ b/plugins/catalog-react/src/routes.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { Entity, ENTITY_DEFAULT_NAMESPACE } from '@backstage/catalog-model'; +import { Entity, DEFAULT_NAMESPACE } from '@backstage/catalog-model'; import { createRouteRef } from '@backstage/core-plugin-api'; import { getOrCreateGlobalSingleton } from '@backstage/version-bridge'; @@ -61,7 +61,7 @@ export function entityRouteParams(entity: Entity) { kind: entity.kind.toLocaleLowerCase('en-US'), namespace: entity.metadata.namespace?.toLocaleLowerCase('en-US') ?? - ENTITY_DEFAULT_NAMESPACE, + DEFAULT_NAMESPACE, name: entity.metadata.name, } as const; } diff --git a/plugins/catalog-react/src/utils/getEntityMetadataUrl.ts b/plugins/catalog-react/src/utils/getEntityMetadataUrl.ts index 996f928ecf..3b44816ac1 100644 --- a/plugins/catalog-react/src/utils/getEntityMetadataUrl.ts +++ b/plugins/catalog-react/src/utils/getEntityMetadataUrl.ts @@ -15,15 +15,15 @@ */ import { - EDIT_URL_ANNOTATION, + ANNOTATION_EDIT_URL, + ANNOTATION_VIEW_URL, Entity, - VIEW_URL_ANNOTATION, } from '@backstage/catalog-model'; export function getEntityMetadataViewUrl(entity: Entity): string | undefined { - return entity.metadata.annotations?.[VIEW_URL_ANNOTATION]; + return entity.metadata.annotations?.[ANNOTATION_VIEW_URL]; } export function getEntityMetadataEditUrl(entity: Entity): string | undefined { - return entity.metadata.annotations?.[EDIT_URL_ANNOTATION]; + return entity.metadata.annotations?.[ANNOTATION_EDIT_URL]; } diff --git a/plugins/catalog-react/src/utils/getEntitySourceLocation.ts b/plugins/catalog-react/src/utils/getEntitySourceLocation.ts index 59c3b5ab95..dd4d5c07f6 100644 --- a/plugins/catalog-react/src/utils/getEntitySourceLocation.ts +++ b/plugins/catalog-react/src/utils/getEntitySourceLocation.ts @@ -15,9 +15,9 @@ */ import { + ANNOTATION_SOURCE_LOCATION, Entity, - parseLocationReference, - SOURCE_LOCATION_ANNOTATION, + parseLocationRef, } from '@backstage/catalog-model'; import { ScmIntegrationRegistry } from '@backstage/integration'; @@ -31,14 +31,14 @@ export function getEntitySourceLocation( scmIntegrationsApi: ScmIntegrationRegistry, ): EntitySourceLocation | undefined { const sourceLocation = - entity.metadata.annotations?.[SOURCE_LOCATION_ANNOTATION]; + entity.metadata.annotations?.[ANNOTATION_SOURCE_LOCATION]; if (!sourceLocation) { return undefined; } try { - const sourceLocationRef = parseLocationReference(sourceLocation); + const sourceLocationRef = parseLocationRef(sourceLocation); const integration = scmIntegrationsApi.byUrl(sourceLocationRef.target); return { locationTargetUrl: sourceLocationRef.target, diff --git a/plugins/catalog/api-report.md b/plugins/catalog/api-report.md index e7825127a6..99bd727961 100644 --- a/plugins/catalog/api-report.md +++ b/plugins/catalog/api-report.md @@ -5,24 +5,13 @@ ```ts /// -import { AddLocationRequest } from '@backstage/catalog-client'; -import { AddLocationResponse } from '@backstage/catalog-client'; import { ApiHolder } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/core-plugin-api'; -import { CatalogApi } from '@backstage/catalog-client'; -import { CatalogClient } from '@backstage/catalog-client'; -import { CatalogEntitiesRequest } from '@backstage/catalog-client'; -import { CatalogEntityAncestorsRequest } from '@backstage/catalog-client'; -import { CatalogEntityAncestorsResponse } from '@backstage/catalog-client'; -import { CatalogListResponse } from '@backstage/catalog-client'; -import { CatalogRequestOptions } from '@backstage/catalog-client'; import { Entity } from '@backstage/catalog-model'; import { EntityName } from '@backstage/catalog-model'; import { ExternalRouteRef } from '@backstage/core-plugin-api'; import { IconComponent } from '@backstage/core-plugin-api'; -import { IdentityApi } from '@backstage/core-plugin-api'; import { InfoCardVariants } from '@backstage/core-components'; -import { Location as Location_2 } from '@backstage/catalog-model'; import { Overrides } from '@material-ui/core/styles/overrides'; import { PropsWithChildren } from 'react'; import { default as React_2 } from 'react'; @@ -64,63 +53,6 @@ export type BackstageOverrides = Overrides & { >; }; -// Warning: (ae-missing-release-tag) "CatalogClientWrapper" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public @deprecated -export class CatalogClientWrapper implements CatalogApi { - constructor(options: { client: CatalogClient; identityApi: IdentityApi }); - // (undocumented) - addLocation( - request: AddLocationRequest, - options?: CatalogRequestOptions, - ): Promise; - // (undocumented) - getEntities( - request?: CatalogEntitiesRequest, - options?: CatalogRequestOptions, - ): Promise>; - // (undocumented) - getEntityAncestors( - request: CatalogEntityAncestorsRequest, - options?: CatalogRequestOptions, - ): Promise; - // (undocumented) - getEntityByName( - compoundName: EntityName, - options?: CatalogRequestOptions, - ): Promise; - // (undocumented) - getLocationByEntity( - entity: Entity, - options?: CatalogRequestOptions, - ): Promise; - // (undocumented) - getLocationById( - id: string, - options?: CatalogRequestOptions, - ): Promise; - // (undocumented) - getOriginLocationByEntity( - entity: Entity, - options?: CatalogRequestOptions, - ): Promise; - // (undocumented) - refreshEntity( - entityRef: string, - options?: CatalogRequestOptions, - ): Promise; - // (undocumented) - removeEntityByUid( - uid: string, - options?: CatalogRequestOptions, - ): Promise; - // (undocumented) - removeLocationById( - id: string, - options?: CatalogRequestOptions, - ): Promise; -} - // Warning: (ae-missing-release-tag) "CatalogEntityPage" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -349,22 +281,6 @@ export const EntityListContainer: ({ // @public export const EntityOrphanWarning: () => JSX.Element; -// Warning: (ae-missing-release-tag) "EntityPageLayout" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public @deprecated -export const EntityPageLayout: { - ({ - children, - UNSTABLE_extraContextMenuItems, - UNSTABLE_contextMenuOptions, - }: EntityPageLayoutProps): JSX.Element; - Content: (_props: { - path: string; - title: string; - element: JSX.Element; - }) => null; -}; - // Warning: (ae-missing-release-tag) "EntityProcessingErrorsPanel" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public @@ -388,12 +304,6 @@ export const EntitySwitch: { }) => null; }; -// Warning: (ae-forgotten-export) The symbol "SystemDiagramCard" needs to be exported by the entry point index.d.ts -// Warning: (ae-missing-release-tag) "EntitySystemDiagramCard" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public @deprecated (undocumented) -export const EntitySystemDiagramCard: SystemDiagramCard; - // Warning: (ae-missing-release-tag) "FilterContainer" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -458,15 +368,6 @@ export const RelatedEntitiesCard: (props: { asRenderableEntities: (entities: Entity[]) => T[]; }) => JSX.Element; -// Warning: (ae-missing-release-tag) "Router" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public @deprecated (undocumented) -export const Router: ({ - EntityPage, -}: { - EntityPage?: React_2.ComponentType<{}> | undefined; -}) => JSX.Element; - // @public (undocumented) export type SystemDiagramCardClassKey = | 'domainNode' @@ -481,6 +382,5 @@ export type SystemDiagramCardClassKey = // src/components/CatalogTable/CatalogTable.d.ts:11:5 - (ae-forgotten-export) The symbol "columnFactories" needs to be exported by the entry point index.d.ts // src/components/EntityLayout/EntityLayout.d.ts:43:5 - (ae-forgotten-export) The symbol "EntityLayoutProps" needs to be exported by the entry point index.d.ts // src/components/EntityLayout/EntityLayout.d.ts:44:5 - (ae-forgotten-export) The symbol "SubRoute" needs to be exported by the entry point index.d.ts -// src/components/EntityPageLayout/EntityPageLayout.d.ts:22:5 - (ae-forgotten-export) The symbol "EntityPageLayoutProps" needs to be exported by the entry point index.d.ts // src/plugin.d.ts:22:5 - (ae-forgotten-export) The symbol "ColumnBreakpoints" needs to be exported by the entry point index.d.ts ``` diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index a2492aaba7..5f6caf65d7 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -11,6 +11,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -21,14 +24,14 @@ "backstage" ], "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/catalog-client": "^0.6.0", diff --git a/plugins/catalog/src/CatalogClientWrapper.test.ts b/plugins/catalog/src/CatalogClientWrapper.test.ts deleted file mode 100644 index e1bba9e60f..0000000000 --- a/plugins/catalog/src/CatalogClientWrapper.test.ts +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { CatalogClient } from '@backstage/catalog-client'; -import { CatalogClientWrapper } from './CatalogClientWrapper'; -import { DiscoveryApi, IdentityApi } from '@backstage/core-plugin-api'; - -jest.mock('@backstage/catalog-client'); -const MockedCatalogClient = CatalogClient as jest.Mock; - -const mockBaseUrl = 'http://backstage:9191/i-am-a-mock-base'; -const discoveryApi: DiscoveryApi = { - async getBaseUrl(_pluginId) { - return mockBaseUrl; - }, -}; -const identityApi: IdentityApi = { - signOut: jest.fn(), - getProfileInfo: jest.fn(), - getBackstageIdentity: jest.fn(), - getCredentials: jest.fn().mockResolvedValue({ token: 'fake-id-token' }), -}; -const guestIdentityApi: IdentityApi = { - signOut: jest.fn(), - getProfileInfo: jest.fn(), - getBackstageIdentity: jest.fn(), - getCredentials: jest.fn().mockResolvedValue({ token: undefined }), -}; - -describe('CatalogClientWrapper', () => { - beforeEach(() => { - MockedCatalogClient.mockClear(); - }); - - describe('getEntities', () => { - it('injects authorization token', async () => { - const client = new CatalogClientWrapper({ - client: new MockedCatalogClient({ discoveryApi }), - identityApi, - }); - await client.getEntities(); - const getEntities = MockedCatalogClient.mock.instances[0].getEntities; - expect(getEntities).toHaveBeenCalledWith(undefined, { - token: 'fake-id-token', - }); - expect(getEntities).toHaveBeenCalledTimes(1); - }); - }); - - describe('getLocationById', () => { - it('omits authorization token when guest', async () => { - const client = new CatalogClientWrapper({ - client: new MockedCatalogClient({ discoveryApi }), - identityApi: guestIdentityApi, - }); - await client.getLocationById('42'); - const getLocationById = - MockedCatalogClient.mock.instances[0].getLocationById; - expect(getLocationById).toHaveBeenCalledWith('42', {}); - expect(getLocationById).toHaveBeenCalledTimes(1); - }); - }); - - describe('getEntityByName', () => { - const name = { - kind: 'kind', - namespace: 'namespace', - name: 'name', - }; - it('injects authorization token', async () => { - const client = new CatalogClientWrapper({ - client: new MockedCatalogClient({ discoveryApi }), - identityApi, - }); - await client.getEntityByName(name); - const getEntityByName = - MockedCatalogClient.mock.instances[0].getEntityByName; - expect(getEntityByName).toHaveBeenCalledWith(name, { - token: 'fake-id-token', - }); - expect(getEntityByName).toHaveBeenCalledTimes(1); - }); - }); - - describe('addLocation', () => { - const location = { target: 'target' }; - it('injects authorization token', async () => { - const client = new CatalogClientWrapper({ - client: new MockedCatalogClient({ discoveryApi }), - identityApi, - }); - await client.addLocation(location); - const addLocation = MockedCatalogClient.mock.instances[0].addLocation; - expect(addLocation).toHaveBeenCalledWith(location, { - token: 'fake-id-token', - }); - expect(addLocation).toHaveBeenCalledTimes(1); - }); - }); - - describe('getLocationByEntity', () => { - const entity = { - apiVersion: 'apiVersion', - kind: 'kind', - metadata: { - name: 'name', - }, - }; - it('injects authorization token', async () => { - const client = new CatalogClientWrapper({ - client: new MockedCatalogClient({ discoveryApi }), - identityApi, - }); - await client.getLocationByEntity(entity); - const getLocationByEntity = - MockedCatalogClient.mock.instances[0].getLocationByEntity; - expect(getLocationByEntity).toHaveBeenCalledWith(entity, { - token: 'fake-id-token', - }); - expect(getLocationByEntity).toHaveBeenCalledTimes(1); - }); - }); - - describe('removeEntityByUid', () => { - it('injects authorization token', async () => { - const uid = 'uid'; - const client = new CatalogClientWrapper({ - client: new MockedCatalogClient({ discoveryApi }), - identityApi, - }); - await client.removeEntityByUid(uid); - const removeEntityByUid = - MockedCatalogClient.mock.instances[0].removeEntityByUid; - expect(removeEntityByUid).toHaveBeenCalledWith(uid, { - token: 'fake-id-token', - }); - expect(removeEntityByUid).toHaveBeenCalledTimes(1); - }); - }); -}); diff --git a/plugins/catalog/src/CatalogClientWrapper.ts b/plugins/catalog/src/CatalogClientWrapper.ts deleted file mode 100644 index 939c4f095b..0000000000 --- a/plugins/catalog/src/CatalogClientWrapper.ts +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Entity, EntityName, Location } from '@backstage/catalog-model'; -import { - AddLocationRequest, - AddLocationResponse, - CatalogApi, - CatalogClient, - CatalogEntitiesRequest, - CatalogListResponse, - CatalogRequestOptions, - CatalogEntityAncestorsRequest, - CatalogEntityAncestorsResponse, -} from '@backstage/catalog-client'; -import { IdentityApi } from '@backstage/core-plugin-api'; - -/** - * CatalogClient wrapper that injects identity token for all requests - * - * @deprecated The default catalog client now uses the `fetchApiRef` - * implementation, which in turn by default issues tokens just the same as this - * class used to assist in doing. If you use a custom `fetchApiRef` - * implementation that does NOT issue tokens, or use a custom `catalogApiRef` - * implementation which does not use the default `fetchApiRef`, you can wrap - * your catalog API in this class to get back the old behavior. - */ -export class CatalogClientWrapper implements CatalogApi { - private readonly identityApi: IdentityApi; - private readonly client: CatalogClient; - - constructor(options: { client: CatalogClient; identityApi: IdentityApi }) { - this.client = options.client; - this.identityApi = options.identityApi; - } - - async getLocationById( - id: string, - options?: CatalogRequestOptions, - ): Promise { - return await this.client.getLocationById( - id, - await this.getCredentials(options), - ); - } - - async getEntities( - request?: CatalogEntitiesRequest, - options?: CatalogRequestOptions, - ): Promise> { - return await this.client.getEntities( - request, - await this.getCredentials(options), - ); - } - - async getEntityByName( - compoundName: EntityName, - options?: CatalogRequestOptions, - ): Promise { - return await this.client.getEntityByName( - compoundName, - await this.getCredentials(options), - ); - } - - async addLocation( - request: AddLocationRequest, - options?: CatalogRequestOptions, - ): Promise { - return await this.client.addLocation( - request, - await this.getCredentials(options), - ); - } - - async getOriginLocationByEntity( - entity: Entity, - options?: CatalogRequestOptions, - ): Promise { - return await this.client.getOriginLocationByEntity( - entity, - await this.getCredentials(options), - ); - } - - async getLocationByEntity( - entity: Entity, - options?: CatalogRequestOptions, - ): Promise { - return await this.client.getLocationByEntity( - entity, - await this.getCredentials(options), - ); - } - - async removeLocationById( - id: string, - options?: CatalogRequestOptions, - ): Promise { - return await this.client.removeLocationById( - id, - await this.getCredentials(options), - ); - } - - async removeEntityByUid( - uid: string, - options?: CatalogRequestOptions, - ): Promise { - return await this.client.removeEntityByUid( - uid, - await this.getCredentials(options), - ); - } - - async refreshEntity( - entityRef: string, - options?: CatalogRequestOptions, - ): Promise { - return await this.client.refreshEntity( - entityRef, - await this.getCredentials(options), - ); - } - - async getEntityAncestors( - request: CatalogEntityAncestorsRequest, - options?: CatalogRequestOptions, - ): Promise { - return await this.client.getEntityAncestors( - request, - await this.getCredentials(options), - ); - } - - private async getCredentials( - options?: CatalogRequestOptions, - ): Promise<{ token?: string }> { - if (options?.token) { - return { token: options?.token }; - } - return this.identityApi.getCredentials(); - } -} diff --git a/plugins/catalog/src/components/AboutCard/AboutCard.test.tsx b/plugins/catalog/src/components/AboutCard/AboutCard.test.tsx index 4ef97b3d46..74c6490534 100644 --- a/plugins/catalog/src/components/AboutCard/AboutCard.test.tsx +++ b/plugins/catalog/src/components/AboutCard/AboutCard.test.tsx @@ -38,7 +38,7 @@ describe('', () => { getEntityByName: jest.fn(), getEntities: jest.fn(), addLocation: jest.fn(), - getLocationByEntity: jest.fn(), + getLocationByRef: jest.fn(), removeEntityByUid: jest.fn(), refreshEntity: jest.fn(), } as any; diff --git a/plugins/catalog/src/components/AboutCard/AboutCard.tsx b/plugins/catalog/src/components/AboutCard/AboutCard.tsx index a6c9635db2..f552d50a68 100644 --- a/plugins/catalog/src/components/AboutCard/AboutCard.tsx +++ b/plugins/catalog/src/components/AboutCard/AboutCard.tsx @@ -16,8 +16,8 @@ import { Entity, - ENTITY_DEFAULT_NAMESPACE, - LOCATION_ANNOTATION, + ANNOTATION_LOCATION, + DEFAULT_NAMESPACE, stringifyEntityRef, } from '@backstage/catalog-model'; import { @@ -107,7 +107,7 @@ export function AboutCard({ variant }: AboutCardProps) { href: viewTechdocLink && viewTechdocLink({ - namespace: entity.metadata.namespace || ENTITY_DEFAULT_NAMESPACE, + namespace: entity.metadata.namespace || DEFAULT_NAMESPACE, kind: entity.kind, name: entity.metadata.name, }), @@ -127,7 +127,7 @@ export function AboutCard({ variant }: AboutCardProps) { cardContentClass = classes.fullHeightCardContent; } - const entityLocation = entity.metadata.annotations?.[LOCATION_ANNOTATION]; + const entityLocation = entity.metadata.annotations?.[ANNOTATION_LOCATION]; // Limiting the ability to manually refresh to the less expensive locations const allowRefresh = entityLocation?.startsWith('url:') || entityLocation?.startsWith('file:'); diff --git a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx index 20acff3c50..c6a108ffc1 100644 --- a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx +++ b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx @@ -100,7 +100,7 @@ describe('DefaultCatalogPage', () => { }, ] as Entity[], }), - getLocationByEntity: () => + getLocationByRef: () => Promise.resolve({ id: 'id', type: 'github', target: 'url' }), getEntityByName: async entityName => { return { diff --git a/plugins/catalog/src/components/CatalogTable/CatalogTable.test.tsx b/plugins/catalog/src/components/CatalogTable/CatalogTable.test.tsx index 4c6adcf400..db9835e3a3 100644 --- a/plugins/catalog/src/components/CatalogTable/CatalogTable.test.tsx +++ b/plugins/catalog/src/components/CatalogTable/CatalogTable.test.tsx @@ -15,9 +15,9 @@ */ import { - EDIT_URL_ANNOTATION, + ANNOTATION_EDIT_URL, + ANNOTATION_VIEW_URL, Entity, - VIEW_URL_ANNOTATION, } from '@backstage/catalog-model'; import { ApiProvider } from '@backstage/core-app-api'; import { @@ -123,7 +123,7 @@ describe('CatalogTable component', () => { kind: 'Component', metadata: { name: 'component1', - annotations: { [EDIT_URL_ANNOTATION]: 'https://other.place' }, + annotations: { [ANNOTATION_EDIT_URL]: 'https://other.place' }, }, }; @@ -155,7 +155,7 @@ describe('CatalogTable component', () => { kind: 'Component', metadata: { name: 'component1', - annotations: { [VIEW_URL_ANNOTATION]: 'https://other.place' }, + annotations: { [ANNOTATION_VIEW_URL]: 'https://other.place' }, }, }; diff --git a/plugins/catalog/src/components/EntityLayout/EntityLayout.tsx b/plugins/catalog/src/components/EntityLayout/EntityLayout.tsx index 144e5d01a8..0e93e74f2d 100644 --- a/plugins/catalog/src/components/EntityLayout/EntityLayout.tsx +++ b/plugins/catalog/src/components/EntityLayout/EntityLayout.tsx @@ -16,7 +16,7 @@ import { Entity, - ENTITY_DEFAULT_NAMESPACE, + DEFAULT_NAMESPACE, RELATION_OWNED_BY, } from '@backstage/catalog-model'; import { @@ -99,9 +99,7 @@ const headerProps = ( entity?.metadata.title ?? paramName ?? entity?.metadata.name ?? ''; return { headerTitle: `${name}${ - namespace && namespace !== ENTITY_DEFAULT_NAMESPACE - ? ` in ${namespace}` - : '' + namespace && namespace !== DEFAULT_NAMESPACE ? ` in ${namespace}` : '' }`, headerType: (() => { let t = kind.toLocaleLowerCase('en-US'); diff --git a/plugins/catalog/src/components/EntityOrphanWarning/DeleteEntityDialog.test.tsx b/plugins/catalog/src/components/EntityOrphanWarning/DeleteEntityDialog.test.tsx index f58e6b9b66..75155aa075 100644 --- a/plugins/catalog/src/components/EntityOrphanWarning/DeleteEntityDialog.test.tsx +++ b/plugins/catalog/src/components/EntityOrphanWarning/DeleteEntityDialog.test.tsx @@ -16,7 +16,7 @@ import userEvent from '@testing-library/user-event'; import React from 'react'; import { DeleteEntityDialog } from './DeleteEntityDialog'; -import { ORIGIN_LOCATION_ANNOTATION } from '@backstage/catalog-model'; +import { ANNOTATION_ORIGIN_LOCATION } from '@backstage/catalog-model'; import { CatalogApi } from '@backstage/catalog-client'; import { catalogApiRef } from '@backstage/plugin-catalog-react'; import { screen, waitFor } from '@testing-library/react'; @@ -42,7 +42,7 @@ describe('DeleteEntityDialog', () => { name: 'n', namespace: 'ns', annotations: { - [ORIGIN_LOCATION_ANNOTATION]: 'url:http://example.com', + [ANNOTATION_ORIGIN_LOCATION]: 'url:http://example.com', }, }, spec: {}, diff --git a/plugins/catalog/src/components/EntityPageLayout/EntityPageLayout.tsx b/plugins/catalog/src/components/EntityPageLayout/EntityPageLayout.tsx deleted file mode 100644 index 82a980afcb..0000000000 --- a/plugins/catalog/src/components/EntityPageLayout/EntityPageLayout.tsx +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import { - Entity, - ENTITY_DEFAULT_NAMESPACE, - RELATION_OWNED_BY, -} from '@backstage/catalog-model'; -import { - EntityContext, - EntityRefLinks, - FavoriteEntity, - getEntityRelations, - InspectEntityDialog, - UnregisterEntityDialog, - useEntityCompoundName, -} from '@backstage/plugin-catalog-react'; -import { Box } from '@material-ui/core'; -import React, { useContext, useState } from 'react'; -import { useNavigate } from 'react-router'; -import { EntityContextMenu } from '../EntityContextMenu/EntityContextMenu'; -import { Tabbed } from './Tabbed'; - -import { - Content, - Header, - HeaderLabel, - Link, - Page, - Progress, - ResponseErrorPanel, - WarningPanel, -} from '@backstage/core-components'; - -import { IconComponent } from '@backstage/core-plugin-api'; - -const EntityPageTitle = ({ - entity, - title, -}: { - title: string; - entity: Entity | undefined; -}) => ( - - {title} - {entity && } - -); - -const EntityLabels = ({ entity }: { entity: Entity }) => { - const ownedByRelations = getEntityRelations(entity, RELATION_OWNED_BY); - return ( - <> - {ownedByRelations.length > 0 && ( - - } - /> - )} - {entity.spec?.lifecycle && ( - - )} - - ); -}; - -const headerProps = ( - kind: string, - namespace: string | undefined, - name: string, - entity: Entity | undefined, -): { headerTitle: string; headerType: string } => { - return { - headerTitle: `${name}${ - namespace && namespace !== ENTITY_DEFAULT_NAMESPACE - ? ` in ${namespace}` - : '' - }`, - headerType: (() => { - let t = kind.toLocaleLowerCase('en-US'); - if (entity && entity.spec && 'type' in entity.spec) { - t += ' — '; - t += (entity.spec as { type: string }).type.toLocaleLowerCase('en-US'); - } - return t; - })(), - }; -}; - -// NOTE(freben): Intentionally not exported at this point, since it's part of -// the unstable extra context menu items concept below -type ExtraContextMenuItem = { - title: string; - Icon: IconComponent; - onClick: () => void; -}; - -// unstable context menu option, eg: disable the unregister entity menu -type contextMenuOptions = { - disableUnregister: boolean; -}; - -type EntityPageLayoutProps = { - UNSTABLE_extraContextMenuItems?: ExtraContextMenuItem[]; - UNSTABLE_contextMenuOptions?: contextMenuOptions; - children?: React.ReactNode; -}; - -/** - * Old entity page, only used by the old router based hierarchies. - * - * @deprecated Please use CatalogEntityPage instead - */ -export const EntityPageLayout = ({ - children, - UNSTABLE_extraContextMenuItems, - UNSTABLE_contextMenuOptions, -}: EntityPageLayoutProps) => { - const { kind, namespace, name } = useEntityCompoundName(); - const { entity, loading, error } = useContext(EntityContext); - const { headerTitle, headerType } = headerProps( - kind, - namespace, - name, - entity!, - ); - - const [confirmationDialogOpen, setConfirmationDialogOpen] = useState(false); - const [inspectionDialogOpen, setInspectionDialogOpen] = useState(false); - const navigate = useNavigate(); - const cleanUpAfterRemoval = async () => { - setConfirmationDialogOpen(false); - navigate('/'); - }; - - return ( - -
} - pageTitleOverride={headerTitle} - type={headerType} - > - {/* TODO: Make entity labels configurable for entity kind / type */} - {entity && ( - <> - - setConfirmationDialogOpen(true)} - onInspectEntity={() => setInspectionDialogOpen(true)} - /> - - )} -
- - {loading && ( - - - - )} - - {entity && {children}} - - {error && ( - - - - )} - - {!loading && !error && !entity && ( - - - There is no {kind} with the requested{' '} - - kind, namespace, and name - - . - - - )} - - setConfirmationDialogOpen(false)} - /> - setInspectionDialogOpen(false)} - /> -
- ); -}; - -EntityPageLayout.Content = Tabbed.Content; diff --git a/plugins/catalog/src/components/EntityPageLayout/Tabbed/Tabbed.test.tsx b/plugins/catalog/src/components/EntityPageLayout/Tabbed/Tabbed.test.tsx deleted file mode 100644 index ad111380f8..0000000000 --- a/plugins/catalog/src/components/EntityPageLayout/Tabbed/Tabbed.test.tsx +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import React from 'react'; -import { Tabbed } from './Tabbed'; -import { renderInTestApp } from '@backstage/test-utils'; -import { act, fireEvent } from '@testing-library/react'; -import { Routes, Route } from 'react-router'; - -describe('Tabbed layout', () => { - it('renders simplest case', async () => { - const rendered = await renderInTestApp( - - tabbed-test-content} - /> - , - ); - - expect(rendered.getByText('tabbed-test-title')).toBeInTheDocument(); - expect(rendered.getByText('tabbed-test-content')).toBeInTheDocument(); - }); - - it('throws if any other component is a child of Tabbed.Layout', async () => { - await expect( - renderInTestApp( - - tabbed-test-content} - /> -
This will cause app to throw
-
, - ), - ).rejects.toThrow(/This component only accepts/); - }); - - it('navigates when user clicks different tab', async () => { - const rendered = await renderInTestApp( - - - tabbed-test-content} - /> - tabbed-test-content-2} - /> - - } - /> - , - ); - - const secondTab = rendered.queryAllByRole('tab')[1]; - act(() => { - fireEvent.click(secondTab); - }); - - expect(rendered.getByText('tabbed-test-title')).toBeInTheDocument(); - expect(rendered.queryByText('tabbed-test-content')).not.toBeInTheDocument(); - - expect(rendered.getByText('tabbed-test-title-2')).toBeInTheDocument(); - expect(rendered.queryByText('tabbed-test-content-2')).toBeInTheDocument(); - }); - - describe('correctly delegates nested links', () => { - const renderRoute = (route: string) => - renderInTestApp( - - - tabbed-test-content} - /> - - tabbed-test-content-2 - - tabbed-test-nested-content-2} - /> - - - } - /> - - } - /> - , - { routeEntries: [route] }, - ); - - it('works for nested content', async () => { - const rendered = await renderRoute('/some-other-path/nested'); - - expect( - rendered.queryByText('tabbed-test-content'), - ).not.toBeInTheDocument(); - expect(rendered.queryByText('tabbed-test-content-2')).toBeInTheDocument(); - expect( - rendered.queryByText('tabbed-test-nested-content-2'), - ).toBeInTheDocument(); - }); - - it('works for non-nested content', async () => { - const rendered = await renderRoute('/some-other-path/'); - - expect( - rendered.queryByText('tabbed-test-content'), - ).not.toBeInTheDocument(); - expect(rendered.queryByText('tabbed-test-content-2')).toBeInTheDocument(); - expect( - rendered.queryByText('tabbed-test-nested-content-2'), - ).not.toBeInTheDocument(); - }); - }); - - it('shows only one tab contents at a time', async () => { - const rendered = await renderInTestApp( - - tabbed-test-content} - /> - tabbed-test-content-2} - /> - , - { routeEntries: ['/some-other-path'] }, - ); - - expect(rendered.getByText('tabbed-test-title')).toBeInTheDocument(); - expect(rendered.queryByText('tabbed-test-content')).not.toBeInTheDocument(); - - expect(rendered.getByText('tabbed-test-title-2')).toBeInTheDocument(); - expect(rendered.queryByText('tabbed-test-content-2')).toBeInTheDocument(); - }); - - it('redirects to the top level when no route is matching the url', async () => { - const rendered = await renderInTestApp( - - tabbed-test-content} - /> - tabbed-test-content-2} - /> - , - { routeEntries: ['/non-existing-path'] }, - ); - - expect(rendered.getByText('tabbed-test-title')).toBeInTheDocument(); - expect(rendered.getByText('tabbed-test-content')).toBeInTheDocument(); - expect(rendered.getByText('tabbed-test-title-2')).toBeInTheDocument(); - - expect( - rendered.queryByText('tabbed-test-content-2'), - ).not.toBeInTheDocument(); - }); -}); diff --git a/plugins/catalog/src/components/EntityPageLayout/Tabbed/Tabbed.tsx b/plugins/catalog/src/components/EntityPageLayout/Tabbed/Tabbed.tsx deleted file mode 100644 index 59271d2c60..0000000000 --- a/plugins/catalog/src/components/EntityPageLayout/Tabbed/Tabbed.tsx +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import React from 'react'; -import { - useParams, - useNavigate, - PartialRouteObject, - matchRoutes, - RouteObject, - useRoutes, - Navigate, - RouteMatch, -} from 'react-router'; -import { Helmet } from 'react-helmet'; -import { Tab, HeaderTabs, Content } from '@backstage/core-components'; - -const getSelectedIndexOrDefault = ( - matchedRoute: RouteMatch, - tabs: Tab[], - defaultIndex = 0, -) => { - if (!matchedRoute) return defaultIndex; - const tabIndex = tabs.findIndex(t => t.id === matchedRoute.route.path); - return ~tabIndex ? tabIndex : defaultIndex; -}; - -/** - * Compound component, which allows you to define layout - * for EntityPage using Tabs as a sub-navigation mechanism - * Consists of 2 parts: Tabbed.Layout and Tabbed.Content. - * Takes care of: tabs, routes, document titles, spacing around content - * - * @example - * ```jsx - * - * This is rendered under /example/anything-here route} - * /> - * - * ``` - */ -export const Tabbed = { - Layout: ({ children }: { children: React.ReactNode }) => { - const routes: PartialRouteObject[] = []; - const tabs: Tab[] = []; - const params = useParams(); - const navigate = useNavigate(); - - React.Children.forEach(children, child => { - if (!React.isValidElement(child)) { - // Skip conditionals resolved to falses/nulls/undefineds etc - return; - } - if (child.type !== Tabbed.Content) { - throw new Error( - 'This component only accepts Content elements as direct children. Check the code of the EntityPage.', - ); - } - const pathAndId = (child as JSX.Element).props.path; - - // Child here must be then always a functional component without any wrappers - tabs.push({ - id: pathAndId, - label: (child as JSX.Element).props.title, - }); - - routes.push({ - path: pathAndId, - element: child.props.element, - }); - }); - - // Add catch-all for incorrect sub-routes - if ((routes?.[0]?.path ?? '') !== '') - routes.push({ - path: '/*', - element: , - }); - - const [matchedRoute] = - matchRoutes(routes as RouteObject[], `/${params['*']}`) ?? []; - const selectedIndex = getSelectedIndexOrDefault(matchedRoute, tabs); - const currentTab = tabs[selectedIndex]; - const title = currentTab?.label; - - const onTabChange = (index: number) => - // Remove trailing /* - // And remove leading / for relative navigation - // Note! route resolves relative to the position in the React tree, - // not relative to current location - navigate(tabs[index].id.replace(/\/\*$/, '').replace(/^\//, '')); - - const currentRouteElement = useRoutes(routes); - - if (!currentTab) return null; - return ( - <> - - - - {currentRouteElement} - - - ); - }, - Content: (_props: { path: string; title: string; element: JSX.Element }) => - null, -}; diff --git a/plugins/catalog/src/components/EntityPageLayout/Tabbed/index.ts b/plugins/catalog/src/components/EntityPageLayout/Tabbed/index.ts deleted file mode 100644 index ff14fe3b2c..0000000000 --- a/plugins/catalog/src/components/EntityPageLayout/Tabbed/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -export { Tabbed } from './Tabbed'; diff --git a/plugins/catalog/src/components/EntityPageLayout/index.ts b/plugins/catalog/src/components/EntityPageLayout/index.ts deleted file mode 100644 index 549d3d8454..0000000000 --- a/plugins/catalog/src/components/EntityPageLayout/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -export { EntityPageLayout } from './EntityPageLayout'; diff --git a/plugins/catalog/src/components/EntityProcessingErrorsPanel/EntityProcessingErrorsPanel.tsx b/plugins/catalog/src/components/EntityProcessingErrorsPanel/EntityProcessingErrorsPanel.tsx index e4df011b38..d73685655c 100644 --- a/plugins/catalog/src/components/EntityProcessingErrorsPanel/EntityProcessingErrorsPanel.tsx +++ b/plugins/catalog/src/components/EntityProcessingErrorsPanel/EntityProcessingErrorsPanel.tsx @@ -19,7 +19,6 @@ import { AlphaEntity, stringifyEntityRef, EntityStatusItem, - compareEntityToRef, } from '@backstage/catalog-model'; import { catalogApiRef, @@ -110,10 +109,8 @@ export const EntityProcessingErrorsPanel = () => { <> {value.items.map((ancestorError, index) => ( - {!compareEntityToRef( - entity, - stringifyEntityRef(ancestorError.entity), - ) && ( + {stringifyEntityRef(entity) !== + stringifyEntityRef(ancestorError.entity) && ( The error below originates from{' '} diff --git a/plugins/catalog/src/components/Router.tsx b/plugins/catalog/src/components/Router.tsx deleted file mode 100644 index e8b00d8513..0000000000 --- a/plugins/catalog/src/components/Router.tsx +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import { ENTITY_DEFAULT_NAMESPACE } from '@backstage/catalog-model'; -import { - AsyncEntityProvider, - useEntity, - useEntityFromUrl, -} from '@backstage/plugin-catalog-react'; -import { Typography } from '@material-ui/core'; -import React, { ComponentType, ReactNode } from 'react'; -import { Navigate, Route, Routes, useParams } from 'react-router'; -import { CatalogPage } from './CatalogPage'; -import { EntityNotFound } from './EntityNotFound'; -import { EntityPageLayout } from './EntityPageLayout'; -import { Content, Link } from '@backstage/core-components'; - -const DefaultEntityPage = () => ( - - - This is the default entity page. - - To override this component with your custom implementation, read - docs on{' '} - backstage.io/docs - - - } - /> - -); - -const EntityPageSwitch = ({ EntityPage }: { EntityPage: ComponentType }) => { - const { entity, loading, error } = useEntity(); - // Loading and error states - if (loading) return ; - if (error || !entity) return ; - - // Otherwise EntityPage provided from the App - // Note that EntityPage will include EntityPageLayout already - return ; -}; - -const OldEntityRouteRedirect = () => { - const { optionalNamespaceAndName, '*': rest } = useParams() as any; - const [name, namespace] = optionalNamespaceAndName.split(':').reverse(); - const namespaceLower = - namespace?.toLocaleLowerCase('en-US') ?? ENTITY_DEFAULT_NAMESPACE; - const restWithSlash = rest ? `/${rest}` : ''; - return ( - - ); -}; - -export const EntityLoader = (props: { children: ReactNode }) => ( - -); - -/** - * @deprecated Use plugin extensions instead - * */ -export const Router = ({ - EntityPage = DefaultEntityPage, -}: { - EntityPage?: ComponentType; -}) => ( - - } /> - - - - } - /> - } - /> - -); diff --git a/plugins/catalog/src/components/SystemDiagramCard/SystemDiagramCard.tsx b/plugins/catalog/src/components/SystemDiagramCard/SystemDiagramCard.tsx index 6c17e4ee67..ec4d13a2f2 100644 --- a/plugins/catalog/src/components/SystemDiagramCard/SystemDiagramCard.tsx +++ b/plugins/catalog/src/components/SystemDiagramCard/SystemDiagramCard.tsx @@ -20,7 +20,7 @@ import { RELATION_PROVIDES_API, RELATION_PART_OF, stringifyEntityRef, - ENTITY_DEFAULT_NAMESPACE, + DEFAULT_NAMESPACE, parseEntityRef, } from '@backstage/catalog-model'; import { @@ -92,7 +92,7 @@ function readableEntityName( ): string { return stringifyEntityRef(ref) .toLocaleLowerCase('en-US') - .replace(`:${ENTITY_DEFAULT_NAMESPACE}/`, ':') + .replace(`:${DEFAULT_NAMESPACE}/`, ':') .split(':')[1]; } @@ -180,7 +180,7 @@ export function SystemDiagramCard() { 'spec.system': [ currentSystemName, `${ - entity.metadata.namespace || ENTITY_DEFAULT_NAMESPACE + entity.metadata.namespace || DEFAULT_NAMESPACE }/${currentSystemName}`, ], }, diff --git a/plugins/catalog/src/index.ts b/plugins/catalog/src/index.ts index 57dd911b2d..b7756024ac 100644 --- a/plugins/catalog/src/index.ts +++ b/plugins/catalog/src/index.ts @@ -20,7 +20,6 @@ * @packageDocumentation */ -export { CatalogClientWrapper } from './CatalogClientWrapper'; export * from './components/AboutCard'; export * from './components/CatalogKindHeader'; export * from './components/CatalogResultListItem'; @@ -30,11 +29,9 @@ export * from './components/CatalogTable/columns'; export * from './components/EntityLayout'; export * from './components/EntityOrphanWarning'; export * from './components/EntityProcessingErrorsPanel'; -export * from './components/EntityPageLayout'; export * from './components/EntitySwitch'; export * from './components/FilteredEntityLayout'; export * from './overridableComponents'; -export { Router } from './components/Router'; export { CatalogEntityPage, CatalogIndexPage, @@ -49,7 +46,6 @@ export { EntityHasSubcomponentsCard, EntityHasSystemsCard, EntityLinksCard, - EntitySystemDiagramCard, RelatedEntitiesCard, } from './plugin'; diff --git a/plugins/catalog/src/plugin.ts b/plugins/catalog/src/plugin.ts index 5a94cd2a09..2e4ebe9570 100644 --- a/plugins/catalog/src/plugin.ts +++ b/plugins/catalog/src/plugin.ts @@ -177,20 +177,6 @@ export const EntityDependsOnResourcesCard = catalogPlugin.provide( }), ); -/** - * @deprecated This component is replaced by EntityCatalogGraphCard which is imported from `@backstage/plugin-catalog-graph`. This component will be removed in an - * upcoming release - */ -export const EntitySystemDiagramCard = catalogPlugin.provide( - createComponentExtension({ - name: 'EntitySystemDiagramCard', - component: { - lazy: () => - import('./components/SystemDiagramCard').then(m => m.SystemDiagramCard), - }, - }), -); - export const RelatedEntitiesCard = catalogPlugin.provide( createComponentExtension({ name: 'RelatedEntitiesCard', diff --git a/plugins/cicd-statistics/package.json b/plugins/cicd-statistics/package.json index de221887c8..6b9d21753d 100644 --- a/plugins/cicd-statistics/package.json +++ b/plugins/cicd-statistics/package.json @@ -11,6 +11,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -21,12 +24,13 @@ "backstage" ], "scripts": { - "build": "backstage-cli build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean", + "start": "backstage-cli package start" }, "devDependencies": { "@types/react": "^16.13.1 || ^17.0.0", @@ -34,7 +38,7 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.8", - "@backstage/core-plugin-api": "^0.4.1", + "@backstage/core-plugin-api": "^0.6.0", "@backstage/plugin-catalog-react": "^0.6.14", "@date-io/luxon": "^1.3.13", "@material-ui/core": "^4.9.13", diff --git a/plugins/circleci/package.json b/plugins/circleci/package.json index 58df662e68..12a313219b 100644 --- a/plugins/circleci/package.json +++ b/plugins/circleci/package.json @@ -11,6 +11,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -22,14 +25,14 @@ "circleci" ], "scripts": { - "build": "backstage-cli plugin:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "clean": "backstage-cli clean", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", "diff": "backstage-cli plugin:diff", - "start": "backstage-cli plugin:serve", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack" + "start": "backstage-cli package start", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" }, "dependencies": { "@backstage/catalog-model": "^0.9.10", diff --git a/plugins/cloudbuild/package.json b/plugins/cloudbuild/package.json index 7ed6f48f71..6f57c0a0a7 100644 --- a/plugins/cloudbuild/package.json +++ b/plugins/cloudbuild/package.json @@ -10,6 +10,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -21,14 +24,14 @@ "google cloud" ], "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/catalog-model": "^0.9.10", diff --git a/plugins/code-coverage-backend/package.json b/plugins/code-coverage-backend/package.json index c5c77f9873..2148c3cddb 100644 --- a/plugins/code-coverage-backend/package.json +++ b/plugins/code-coverage-backend/package.json @@ -10,14 +10,17 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "backend-plugin" + }, "scripts": { - "start": "backstage-cli backend:dev", - "build": "backstage-cli backend:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/backend-common": "^0.10.7", diff --git a/plugins/code-coverage/package.json b/plugins/code-coverage/package.json index 49f092bf25..213e64cb3b 100644 --- a/plugins/code-coverage/package.json +++ b/plugins/code-coverage/package.json @@ -10,15 +10,18 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/catalog-model": "^0.9.10", diff --git a/plugins/config-schema/package.json b/plugins/config-schema/package.json index 46e030dbc8..8cfe6b2a6f 100644 --- a/plugins/config-schema/package.json +++ b/plugins/config-schema/package.json @@ -10,15 +10,18 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/config": "^0.1.13", diff --git a/plugins/cost-insights/package.json b/plugins/cost-insights/package.json index 45178cb475..4b3c93d2a8 100644 --- a/plugins/cost-insights/package.json +++ b/plugins/cost-insights/package.json @@ -11,6 +11,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -21,14 +24,14 @@ "backstage" ], "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/catalog-model": "^0.9.10", diff --git a/plugins/cost-insights/src/hooks/useGroups.tsx b/plugins/cost-insights/src/hooks/useGroups.tsx index 6d20f435b3..de0e253763 100644 --- a/plugins/cost-insights/src/hooks/useGroups.tsx +++ b/plugins/cost-insights/src/hooks/useGroups.tsx @@ -26,10 +26,7 @@ import { MapLoadingToProps, useLoading } from './useLoading'; import { Group, Maybe } from '../types'; import { DefaultLoadingAction } from '../utils/loading'; import { useApi, identityApiRef } from '@backstage/core-plugin-api'; -import { - ENTITY_DEFAULT_NAMESPACE, - parseEntityRef, -} from '@backstage/catalog-model'; +import { DEFAULT_NAMESPACE, parseEntityRef } from '@backstage/catalog-model'; type GroupsProviderLoadingProps = { dispatchLoadingGroups: (isLoading: boolean) => void; @@ -66,7 +63,7 @@ export const GroupsProvider = ({ children }: PropsWithChildren<{}>) => { const { userEntityRef } = await identityApi.getBackstageIdentity(); const { name: userId } = parseEntityRef(userEntityRef, { defaultKind: 'User', - defaultNamespace: ENTITY_DEFAULT_NAMESPACE, + defaultNamespace: DEFAULT_NAMESPACE, }); const g = await client.getUserGroups(userId); setGroups(g); diff --git a/plugins/explore-react/package.json b/plugins/explore-react/package.json index 3da9de5e08..714474ce06 100644 --- a/plugins/explore-react/package.json +++ b/plugins/explore-react/package.json @@ -11,6 +11,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "web-library" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -21,12 +24,13 @@ "backstage" ], "scripts": { - "build": "backstage-cli plugin:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "clean": "backstage-cli clean", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack" + "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", + "start": "backstage-cli package start" }, "dependencies": { "@backstage/core-plugin-api": "^0.6.0" diff --git a/plugins/explore/package.json b/plugins/explore/package.json index 7cb22f5782..7c76e88a59 100644 --- a/plugins/explore/package.json +++ b/plugins/explore/package.json @@ -11,6 +11,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -21,14 +24,14 @@ "backstage" ], "scripts": { - "build": "backstage-cli plugin:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "clean": "backstage-cli clean", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "start": "backstage-cli plugin:serve" + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "start": "backstage-cli package start" }, "dependencies": { "@backstage/catalog-model": "^0.9.10", diff --git a/plugins/explore/src/components/DefaultExplorePage/DefaultExplorePage.test.tsx b/plugins/explore/src/components/DefaultExplorePage/DefaultExplorePage.test.tsx index d10c262357..db59e28f40 100644 --- a/plugins/explore/src/components/DefaultExplorePage/DefaultExplorePage.test.tsx +++ b/plugins/explore/src/components/DefaultExplorePage/DefaultExplorePage.test.tsx @@ -24,8 +24,7 @@ describe('', () => { const catalogApi: jest.Mocked = { addLocation: jest.fn(_a => new Promise(() => {})), getEntities: jest.fn(), - getOriginLocationByEntity: jest.fn(), - getLocationByEntity: jest.fn(), + getLocationByRef: jest.fn(), getLocationById: jest.fn(), removeLocationById: jest.fn(), removeEntityByUid: jest.fn(), diff --git a/plugins/explore/src/components/DomainExplorerContent/DomainExplorerContent.test.tsx b/plugins/explore/src/components/DomainExplorerContent/DomainExplorerContent.test.tsx index e36bd4ddb9..c431bd0c6c 100644 --- a/plugins/explore/src/components/DomainExplorerContent/DomainExplorerContent.test.tsx +++ b/plugins/explore/src/components/DomainExplorerContent/DomainExplorerContent.test.tsx @@ -25,8 +25,7 @@ describe('', () => { const catalogApi: jest.Mocked = { addLocation: jest.fn(_a => new Promise(() => {})), getEntities: jest.fn(), - getOriginLocationByEntity: jest.fn(), - getLocationByEntity: jest.fn(), + getLocationByRef: jest.fn(), getLocationById: jest.fn(), removeLocationById: jest.fn(), removeEntityByUid: jest.fn(), diff --git a/plugins/explore/src/components/GroupsExplorerContent/GroupsExplorerContent.test.tsx b/plugins/explore/src/components/GroupsExplorerContent/GroupsExplorerContent.test.tsx index 5d3f7c358b..23ae2a3e6d 100644 --- a/plugins/explore/src/components/GroupsExplorerContent/GroupsExplorerContent.test.tsx +++ b/plugins/explore/src/components/GroupsExplorerContent/GroupsExplorerContent.test.tsx @@ -25,8 +25,7 @@ describe('', () => { const catalogApi: jest.Mocked = { addLocation: jest.fn(_a => new Promise(() => {})), getEntities: jest.fn(), - getOriginLocationByEntity: jest.fn(), - getLocationByEntity: jest.fn(), + getLocationByRef: jest.fn(), getLocationById: jest.fn(), removeLocationById: jest.fn(), removeEntityByUid: jest.fn(), diff --git a/plugins/firehydrant/package.json b/plugins/firehydrant/package.json index 81272e2b6d..974e3cc9e7 100644 --- a/plugins/firehydrant/package.json +++ b/plugins/firehydrant/package.json @@ -11,15 +11,18 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/core-components": "^0.8.8", diff --git a/plugins/fossa/package.json b/plugins/fossa/package.json index 53e40aae96..2d9674f0f7 100644 --- a/plugins/fossa/package.json +++ b/plugins/fossa/package.json @@ -11,6 +11,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -22,14 +25,14 @@ "fossa" ], "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/catalog-model": "^0.9.10", diff --git a/plugins/fossa/src/components/FossaPage/FossaPage.test.tsx b/plugins/fossa/src/components/FossaPage/FossaPage.test.tsx index 421ff4431f..df376895bc 100644 --- a/plugins/fossa/src/components/FossaPage/FossaPage.test.tsx +++ b/plugins/fossa/src/components/FossaPage/FossaPage.test.tsx @@ -30,9 +30,8 @@ describe('', () => { addLocation: jest.fn(), getEntities: jest.fn(), getEntityByName: jest.fn(), - getLocationByEntity: jest.fn(), + getLocationByRef: jest.fn(), getLocationById: jest.fn(), - getOriginLocationByEntity: jest.fn(), removeEntityByUid: jest.fn(), removeLocationById: jest.fn(), refreshEntity: jest.fn(), diff --git a/plugins/gcp-projects/package.json b/plugins/gcp-projects/package.json index 992336300f..d8b23960fe 100644 --- a/plugins/gcp-projects/package.json +++ b/plugins/gcp-projects/package.json @@ -10,6 +10,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -21,14 +24,14 @@ "google cloud" ], "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/core-components": "^0.8.8", @@ -38,7 +41,7 @@ "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", "react-router-dom": "6.0.0-beta.0", - "react-use": "^17.2.4" + "@react-hookz/web": "^12.3.0" }, "peerDependencies": { "react": "^16.13.1 || ^17.0.0" diff --git a/plugins/gcp-projects/src/components/ProjectDetailsPage/ProjectDetailsPage.tsx b/plugins/gcp-projects/src/components/ProjectDetailsPage/ProjectDetailsPage.tsx index 36247ac492..b900b81695 100644 --- a/plugins/gcp-projects/src/components/ProjectDetailsPage/ProjectDetailsPage.tsx +++ b/plugins/gcp-projects/src/components/ProjectDetailsPage/ProjectDetailsPage.tsx @@ -27,7 +27,7 @@ import { Typography, } from '@material-ui/core'; import React from 'react'; -import useAsync from 'react-use/lib/useAsync'; +import { useAsync, useMountEffect } from '@react-hookz/web'; import { gcpApiRef } from '../../api'; import { @@ -60,19 +60,13 @@ const DetailsPage = () => { const api = useApi(gcpApiRef); const classes = useStyles(); - const { - loading, - error, - value: details, - } = useAsync( - async () => - api.getProject( - decodeURIComponent(location.search.split('projectId=')[1]), - ), - [location.search], + const [{ status, result: details, error }, { execute }] = useAsync(async () => + api.getProject(decodeURIComponent(location.search.split('projectId=')[1])), ); - if (loading) { + useMountEffect(execute); + + if (status === 'loading') { return ; } else if (error) { return ( diff --git a/plugins/gcp-projects/src/components/ProjectListPage/ProjectListPage.tsx b/plugins/gcp-projects/src/components/ProjectListPage/ProjectListPage.tsx index d5a57432b3..dea12f4b60 100644 --- a/plugins/gcp-projects/src/components/ProjectListPage/ProjectListPage.tsx +++ b/plugins/gcp-projects/src/components/ProjectListPage/ProjectListPage.tsx @@ -18,7 +18,7 @@ import { Button, LinearProgress, Tooltip, Typography } from '@material-ui/core'; import React from 'react'; -import useAsync from 'react-use/lib/useAsync'; +import { useAsync, useMountEffect } from '@react-hookz/web'; import { gcpApiRef, Project } from '../../api'; import { @@ -58,9 +58,12 @@ const labels = ( const PageContents = () => { const api = useApi(gcpApiRef); - const { loading, error, value } = useAsync(() => api.listProjects()); + const [{ status, result, error }, { execute }] = useAsync(() => + api.listProjects(), + ); + useMountEffect(execute); - if (loading) { + if (status === 'loading') { return ; } else if (error) { return ( @@ -108,7 +111,7 @@ const PageContents = () => { }, ]} data={ - value?.map((project: Project) => ({ + result?.map((project: Project) => ({ id: project.projectId, name: project.name, projectNumber: project?.projectNumber || 'Error', diff --git a/plugins/git-release-manager/package.json b/plugins/git-release-manager/package.json index 381ca0dd24..19e71b3bb8 100644 --- a/plugins/git-release-manager/package.json +++ b/plugins/git-release-manager/package.json @@ -10,15 +10,18 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/core-components": "^0.8.8", diff --git a/plugins/github-actions/package.json b/plugins/github-actions/package.json index cb112fedb1..a383771924 100644 --- a/plugins/github-actions/package.json +++ b/plugins/github-actions/package.json @@ -11,6 +11,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -23,14 +26,14 @@ "github actions" ], "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/catalog-model": "^0.9.10", diff --git a/plugins/github-actions/src/components/Cards/Cards.tsx b/plugins/github-actions/src/components/Cards/Cards.tsx index cb4b2190fc..c3df91bca6 100644 --- a/plugins/github-actions/src/components/Cards/Cards.tsx +++ b/plugins/github-actions/src/components/Cards/Cards.tsx @@ -24,7 +24,7 @@ import { } from '@material-ui/core'; import ExternalLinkIcon from '@material-ui/icons/Launch'; import React, { useEffect } from 'react'; -import { GITHUB_ACTIONS_ANNOTATION } from '../useProjectName'; +import { GITHUB_ACTIONS_ANNOTATION } from '../getProjectNameFromEntity'; import { useWorkflowRuns, WorkflowRun } from '../useWorkflowRuns'; import { WorkflowRunsTable } from '../WorkflowRunsTable'; import { WorkflowRunStatus } from '../WorkflowRunStatus'; diff --git a/plugins/github-actions/src/components/Cards/RecentWorkflowRunsCard.tsx b/plugins/github-actions/src/components/Cards/RecentWorkflowRunsCard.tsx index 3423bea84d..12c3223d83 100644 --- a/plugins/github-actions/src/components/Cards/RecentWorkflowRunsCard.tsx +++ b/plugins/github-actions/src/components/Cards/RecentWorkflowRunsCard.tsx @@ -18,7 +18,7 @@ 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 { GITHUB_ACTIONS_ANNOTATION } from '../useProjectName'; +import { GITHUB_ACTIONS_ANNOTATION } from '../getProjectNameFromEntity'; import { useWorkflowRuns } from '../useWorkflowRuns'; import { WorkflowRunStatus } from '../WorkflowRunStatus'; import { Typography } from '@material-ui/core'; diff --git a/plugins/github-actions/src/components/Router.tsx b/plugins/github-actions/src/components/Router.tsx index ea07213c45..251ecb169a 100644 --- a/plugins/github-actions/src/components/Router.tsx +++ b/plugins/github-actions/src/components/Router.tsx @@ -20,7 +20,7 @@ import { Routes, Route } from 'react-router'; import { buildRouteRef } from '../routes'; import { WorkflowRunDetails } from './WorkflowRunDetails'; import { WorkflowRunsTable } from './WorkflowRunsTable'; -import { GITHUB_ACTIONS_ANNOTATION } from './useProjectName'; +import { GITHUB_ACTIONS_ANNOTATION } from './getProjectNameFromEntity'; import { MissingAnnotationEmptyState } from '@backstage/core-components'; export const isGithubActionsAvailable = (entity: Entity) => diff --git a/plugins/github-actions/src/components/WorkflowRunDetails/WorkflowRunDetails.tsx b/plugins/github-actions/src/components/WorkflowRunDetails/WorkflowRunDetails.tsx index aebf7dfa01..989ab27800 100644 --- a/plugins/github-actions/src/components/WorkflowRunDetails/WorkflowRunDetails.tsx +++ b/plugins/github-actions/src/components/WorkflowRunDetails/WorkflowRunDetails.tsx @@ -39,7 +39,7 @@ import ExternalLinkIcon from '@material-ui/icons/Launch'; import { DateTime } from 'luxon'; import React from 'react'; import { Job, Jobs, Step } from '../../api'; -import { useProjectName } from '../useProjectName'; +import { getProjectNameFromEntity } from '../getProjectNameFromEntity'; import { WorkflowRunStatus } from '../WorkflowRunStatus'; import { useWorkflowRunJobs } from './useWorkflowRunJobs'; import { useWorkflowRunsDetails } from './useWorkflowRunsDetails'; @@ -164,25 +164,25 @@ const JobsList = ({ jobs, entity }: { jobs?: Jobs; entity: Entity }) => { export const WorkflowRunDetails = ({ entity }: { entity: Entity }) => { const config = useApi(configApiRef); - const projectName = useProjectName(entity); + const projectName = getProjectNameFromEntity(entity); // TODO: Get github hostname from metadata annotation const hostname = readGitHubIntegrationConfigs( config.getOptionalConfigArray('integrations.github') ?? [], )[0].host; - const [owner, repo] = projectName.value ? projectName.value.split('/') : []; + const [owner, repo] = (projectName && projectName.split('/')) || []; const details = useWorkflowRunsDetails({ hostname, owner, repo }); const jobs = useWorkflowRunJobs({ hostname, owner, repo }); - const error = projectName.error || (projectName.value && details.error); const classes = useStyles(); - if (error) { + + if (details.error && details.error.message) { return ( - Failed to load build, {error.message} + Failed to load build, {details.error.message} ); - } else if (projectName.loading || details.loading) { + } else if (details.loading) { return ; } return ( diff --git a/plugins/github-actions/src/components/WorkflowRunDetails/useWorkflowRunJobs.ts b/plugins/github-actions/src/components/WorkflowRunDetails/useWorkflowRunJobs.ts index 002d379ed1..ba0f3b6ba8 100644 --- a/plugins/github-actions/src/components/WorkflowRunDetails/useWorkflowRunJobs.ts +++ b/plugins/github-actions/src/components/WorkflowRunDetails/useWorkflowRunJobs.ts @@ -37,7 +37,7 @@ export const useWorkflowRunJobs = ({ repo, id: parseInt(id, 10), }) - : Promise.reject('No repo/owner provided'); + : Promise.reject(new Error('No repo/owner provided')); }, [repo, owner, id]); return jobs; }; diff --git a/plugins/github-actions/src/components/WorkflowRunDetails/useWorkflowRunsDetails.ts b/plugins/github-actions/src/components/WorkflowRunDetails/useWorkflowRunsDetails.ts index ef9b4f7ccf..10a043161e 100644 --- a/plugins/github-actions/src/components/WorkflowRunDetails/useWorkflowRunsDetails.ts +++ b/plugins/github-actions/src/components/WorkflowRunDetails/useWorkflowRunsDetails.ts @@ -37,7 +37,7 @@ export const useWorkflowRunsDetails = ({ repo, id: parseInt(id, 10), }) - : Promise.reject('No repo/owner provided'); + : Promise.reject(new Error('No repo/owner provided')); }, [repo, owner, id]); return details; }; diff --git a/plugins/github-actions/src/components/WorkflowRunLogs/WorkflowRunLogs.tsx b/plugins/github-actions/src/components/WorkflowRunLogs/WorkflowRunLogs.tsx index 0f1670bbbc..bf66399288 100644 --- a/plugins/github-actions/src/components/WorkflowRunLogs/WorkflowRunLogs.tsx +++ b/plugins/github-actions/src/components/WorkflowRunLogs/WorkflowRunLogs.tsx @@ -33,7 +33,7 @@ import { import DescriptionIcon from '@material-ui/icons/Description'; import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import React from 'react'; -import { useProjectName } from '../useProjectName'; +import { getProjectNameFromEntity } from '../getProjectNameFromEntity'; import { useDownloadWorkflowRunLogs } from './useDownloadWorkflowRunLogs'; const useStyles = makeStyles(theme => ({ @@ -77,13 +77,13 @@ export const WorkflowRunLogs = ({ }) => { const config = useApi(configApiRef); const classes = useStyles(); - const projectName = useProjectName(entity); + const projectName = getProjectNameFromEntity(entity); // TODO: Get github hostname from metadata annotation const hostname = readGitHubIntegrationConfigs( config.getOptionalConfigArray('integrations.github') ?? [], )[0].host; - const [owner, repo] = projectName.value ? projectName.value.split('/') : []; + const [owner, repo] = (projectName && projectName.split('/')) || []; const jobLogs = useDownloadWorkflowRunLogs({ hostname, owner, diff --git a/plugins/github-actions/src/components/WorkflowRunsTable/WorkflowRunsTable.tsx b/plugins/github-actions/src/components/WorkflowRunsTable/WorkflowRunsTable.tsx index 81fa036221..c8c42eb1bc 100644 --- a/plugins/github-actions/src/components/WorkflowRunsTable/WorkflowRunsTable.tsx +++ b/plugins/github-actions/src/components/WorkflowRunsTable/WorkflowRunsTable.tsx @@ -29,7 +29,7 @@ import { useWorkflowRuns, WorkflowRun } from '../useWorkflowRuns'; import { WorkflowRunStatus } from '../WorkflowRunStatus'; import SyncIcon from '@material-ui/icons/Sync'; import { buildRouteRef } from '../../routes'; -import { useProjectName } from '../useProjectName'; +import { getProjectNameFromEntity } from '../getProjectNameFromEntity'; import { Entity } from '@backstage/catalog-model'; import { readGitHubIntegrationConfigs } from '@backstage/integration'; @@ -157,7 +157,7 @@ export const WorkflowRunsTable = ({ branch?: string; }) => { const config = useApi(configApiRef); - const { value: projectName, loading } = useProjectName(entity); + const projectName = getProjectNameFromEntity(entity); // TODO: Get github hostname from metadata annotation const hostname = readGitHubIntegrationConfigs( config.getOptionalConfigArray('integrations.github') ?? [], @@ -172,7 +172,7 @@ export const WorkflowRunsTable = ({ }); const githubHost = hostname || 'github.com'; - const hasNoRuns = !loading && !tableProps.loading && !runs; + const hasNoRuns = !tableProps.loading && !runs; return hasNoRuns ? ( { - const { value, loading, error } = useAsync(async () => { - return entity?.metadata.annotations?.[GITHUB_ACTIONS_ANNOTATION] ?? ''; - }); - return { value, loading, error }; -}; +export const getProjectNameFromEntity = (entity: Entity) => + entity?.metadata.annotations?.[GITHUB_ACTIONS_ANNOTATION] ?? ''; diff --git a/plugins/github-actions/src/index.ts b/plugins/github-actions/src/index.ts index f520b9fbbc..ab041b4970 100644 --- a/plugins/github-actions/src/index.ts +++ b/plugins/github-actions/src/index.ts @@ -35,4 +35,4 @@ export { isGithubActionsAvailable as isPluginApplicableToEntity, } from './components/Router'; export * from './components/Cards'; -export { GITHUB_ACTIONS_ANNOTATION } from './components/useProjectName'; +export { GITHUB_ACTIONS_ANNOTATION } from './components/getProjectNameFromEntity'; diff --git a/plugins/github-deployments/package.json b/plugins/github-deployments/package.json index e4c3e4917c..c8f37f5121 100644 --- a/plugins/github-deployments/package.json +++ b/plugins/github-deployments/package.json @@ -10,15 +10,18 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/catalog-model": "^0.9.10", diff --git a/plugins/github-deployments/src/api/index.ts b/plugins/github-deployments/src/api/index.ts index b64d914612..e0eef7cc1d 100644 --- a/plugins/github-deployments/src/api/index.ts +++ b/plugins/github-deployments/src/api/index.ts @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { parseLocationReference } from '@backstage/catalog-model'; +import { parseLocationRef } from '@backstage/catalog-model'; import { InputError } from '@backstage/errors'; import { ScmIntegrationRegistry } from '@backstage/integration'; import { graphql } from '@octokit/graphql'; @@ -27,7 +27,7 @@ const getBaseUrl = ( return 'https://api.github.com'; } - const location = parseLocationReference(host); + const location = parseLocationRef(host); if (location.type !== 'github' && location.type !== 'url') { return 'https://api.github.com'; } diff --git a/plugins/github-deployments/src/components/GithubDeploymentsCard.tsx b/plugins/github-deployments/src/components/GithubDeploymentsCard.tsx index 901e20a899..68881617f4 100644 --- a/plugins/github-deployments/src/components/GithubDeploymentsCard.tsx +++ b/plugins/github-deployments/src/components/GithubDeploymentsCard.tsx @@ -23,8 +23,8 @@ import { } from '../Router'; import { GithubDeploymentsTable } from './GithubDeploymentsTable/GithubDeploymentsTable'; import { - LOCATION_ANNOTATION, - SOURCE_LOCATION_ANNOTATION, + ANNOTATION_LOCATION, + ANNOTATION_SOURCE_LOCATION, } from '@backstage/catalog-model'; import { @@ -88,8 +88,8 @@ export const GithubDeploymentsCard = (props: { const { last, lastStatuses, columns } = props; const { entity } = useEntity(); const [host] = [ - entity?.metadata.annotations?.[SOURCE_LOCATION_ANNOTATION], - entity?.metadata.annotations?.[LOCATION_ANNOTATION], + entity?.metadata.annotations?.[ANNOTATION_SOURCE_LOCATION], + entity?.metadata.annotations?.[ANNOTATION_LOCATION], ].filter(Boolean); return !isGithubDeploymentsAvailable(entity) ? ( diff --git a/plugins/gitops-profiles/package.json b/plugins/gitops-profiles/package.json index 1cadbc8d65..851bc2501e 100644 --- a/plugins/gitops-profiles/package.json +++ b/plugins/gitops-profiles/package.json @@ -11,6 +11,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -22,14 +25,14 @@ "gitops" ], "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/core-components": "^0.8.8", diff --git a/plugins/gocd/package.json b/plugins/gocd/package.json index 86802a43f2..3cefcd9a82 100644 --- a/plugins/gocd/package.json +++ b/plugins/gocd/package.json @@ -11,6 +11,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -18,14 +21,14 @@ "directory": "plugins/gocd" }, "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/catalog-model": "^0.9.10", diff --git a/plugins/graphiql/package.json b/plugins/graphiql/package.json index 185e273c3f..269302f1bb 100644 --- a/plugins/graphiql/package.json +++ b/plugins/graphiql/package.json @@ -8,6 +8,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "homepage": "https://github.com/backstage/backstage/tree/master/plugins/graphiql#readme", "repository": { "type": "git", @@ -21,14 +24,14 @@ "main": "src/index.ts", "types": "src/index.ts", "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/core-components": "^0.8.8", diff --git a/plugins/graphql-backend/package.json b/plugins/graphql-backend/package.json index a13a901646..acc9749da6 100644 --- a/plugins/graphql-backend/package.json +++ b/plugins/graphql-backend/package.json @@ -11,6 +11,9 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "backend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -22,13 +25,13 @@ "graphql" ], "scripts": { - "start": "backstage-cli backend:dev", - "build": "backstage-cli backend:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/backend-common": "^0.10.7", @@ -42,7 +45,7 @@ "express": "^4.17.1", "express-promise-router": "^4.1.0", "graphql": "^16.0.0", - "helmet": "^4.0.0", + "helmet": "^5.0.2", "reflect-metadata": "^0.1.13", "winston": "^3.2.1", "yn": "^4.0.0" diff --git a/plugins/home/api-report.md b/plugins/home/api-report.md index 264189ee07..6fae50151c 100644 --- a/plugins/home/api-report.md +++ b/plugins/home/api-report.md @@ -24,6 +24,7 @@ export type ClockConfig = { // @public (undocumented) export const ComponentAccordion: ({ title, + expanded, Content, Actions, Settings, @@ -31,6 +32,7 @@ export const ComponentAccordion: ({ ...childProps }: { title: string; + expanded?: boolean | undefined; Content: () => JSX.Element; Actions?: (() => JSX.Element) | undefined; Settings?: (() => JSX.Element) | undefined; diff --git a/plugins/home/package.json b/plugins/home/package.json index f57b0bb83e..204faa57bd 100644 --- a/plugins/home/package.json +++ b/plugins/home/package.json @@ -10,15 +10,28 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, + "homepage": "https://github.com/backstage/backstage/tree/master/plugins/home#readme", + "repository": { + "type": "git", + "url": "https://github.com/backstage/backstage", + "directory": "plugins/home" + }, + "keywords": [ + "backstage", + "homepage" + ], "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/catalog-model": "^0.9.10", diff --git a/plugins/home/src/componentRenderers/ComponentAccordion.tsx b/plugins/home/src/componentRenderers/ComponentAccordion.tsx index 5cf54d7a0c..ef44f7f292 100644 --- a/plugins/home/src/componentRenderers/ComponentAccordion.tsx +++ b/plugins/home/src/componentRenderers/ComponentAccordion.tsx @@ -33,10 +33,14 @@ const useStyles = makeStyles((theme: Theme) => ({ settingsIconButton: { padding: theme.spacing(0, 1, 0, 0), }, + contentContainer: { + width: '100%', + }, })); export const ComponentAccordion = ({ title, + expanded = false, Content, Actions, Settings, @@ -44,6 +48,7 @@ export const ComponentAccordion = ({ ...childProps }: { title: string; + expanded?: boolean; Content: () => JSX.Element; Actions?: () => JSX.Element; Settings?: () => JSX.Element; @@ -51,7 +56,7 @@ export const ComponentAccordion = ({ }) => { const classes = useStyles(); const [settingsIsExpanded, setSettingsIsExpanded] = React.useState(false); - const [isExpanded, setIsExpanded] = React.useState(false); + const [isExpanded, setIsExpanded] = React.useState(expanded); const handleOpenSettings = (e: any) => { e.stopPropagation(); @@ -71,7 +76,9 @@ export const ComponentAccordion = ({ )} setIsExpanded(expanded)} + onChange={(_e: any, expandedValue: boolean) => + setIsExpanded(expandedValue) + } > }> {Settings && ( @@ -85,7 +92,7 @@ export const ComponentAccordion = ({ {title} -
+
{Actions && }
diff --git a/plugins/home/src/homePageComponents/Toolkit/Content.test.tsx b/plugins/home/src/homePageComponents/Toolkit/Content.test.tsx index 7fbaff08f9..1955019a4a 100644 --- a/plugins/home/src/homePageComponents/Toolkit/Content.test.tsx +++ b/plugins/home/src/homePageComponents/Toolkit/Content.test.tsx @@ -13,19 +13,32 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { renderInTestApp } from '@backstage/test-utils'; import React from 'react'; import { Content } from './Content'; +import { ContextProvider } from './Context'; describe('', () => { + const tools = [ + { label: 'tool', url: '/url', icon:
icon
}, + { label: 'tool 2', url: '/url-2', icon:
icon 2
}, + ]; + test('should render list of tools', async () => { + const { getByText } = await renderInTestApp(); + + expect(getByText('tool')).toBeInTheDocument(); + expect(getByText('tool 2')).toBeInTheDocument(); + expect(getByText('tool').closest('a')).toHaveAttribute('href', '/url'); + expect(getByText('tool 2').closest('a')).toHaveAttribute('href', '/url-2'); + }); + + test('should render list of tools using context', async () => { const { getByText } = await renderInTestApp( - icon
}, - { label: 'tool 2', url: '/url-2', icon:
icon 2
}, - ]} - />, + + + , ); expect(getByText('tool')).toBeInTheDocument(); diff --git a/plugins/home/src/homePageComponents/Toolkit/Content.tsx b/plugins/home/src/homePageComponents/Toolkit/Content.tsx index 4ee1884bd0..21affc57f1 100644 --- a/plugins/home/src/homePageComponents/Toolkit/Content.tsx +++ b/plugins/home/src/homePageComponents/Toolkit/Content.tsx @@ -22,6 +22,7 @@ import { ListItemText, } from '@material-ui/core'; import React from 'react'; +import { useToolkit, Tool } from './Context'; const useStyles = makeStyles(theme => ({ toolkit: { @@ -49,12 +50,6 @@ const useStyles = makeStyles(theme => ({ }, })); -type Tool = { - label: string; - url: string; - icon: React.ReactNode; -}; - /** * Props for Toolkit content component {@link Content}. * @@ -71,10 +66,12 @@ export type ToolkitContentProps = { */ export const Content = (props: ToolkitContentProps) => { const classes = useStyles(); + const toolkit = useToolkit(); + const tools = toolkit?.tools ?? props.tools; return ( - {props.tools.map((tool: Tool) => ( + {tools.map((tool: Tool) => ( {tool.icon} (undefined); + +export const ContextProvider = ({ + children, + tools, +}: { + children: JSX.Element; + tools: Tool[]; +}) => { + const [toolsValue, _setTools] = React.useState(tools); + + const value: ToolkitContextValue = { + tools: toolsValue, + }; + + return {children}; +}; + +export const useToolkit = () => { + const value = React.useContext(Context); + return value; +}; + +export default Context; diff --git a/plugins/home/src/homePageComponents/Toolkit/Toolkit.stories.tsx b/plugins/home/src/homePageComponents/Toolkit/Toolkit.stories.tsx index 0a8e6fffbe..cad188c5d6 100644 --- a/plugins/home/src/homePageComponents/Toolkit/Toolkit.stories.tsx +++ b/plugins/home/src/homePageComponents/Toolkit/Toolkit.stories.tsx @@ -14,11 +14,13 @@ * limitations under the License. */ -import { TemplateBackstageLogoIcon } from '../../templates'; -import { HomePageToolkit } from '../../plugin'; +import { InfoCard } from '@backstage/core-components'; import { wrapInTestApp } from '@backstage/test-utils'; import { Grid } from '@material-ui/core'; import React, { ComponentType } from 'react'; +import { ComponentAccordion } from '../../componentRenderers'; +import { HomePageToolkit } from '../../plugin'; +import { TemplateBackstageLogoIcon } from '../../templates'; export default { title: 'Plugins/Home/Components/Toolkit', @@ -38,3 +40,43 @@ export const Default = () => { ); }; + +export const InAccordian = () => { + const ExpandedComponentAccordion = (props: any) => ( + + ); + + return ( + + + , + })} + Renderer={ExpandedComponentAccordion} + /> + , + })} + Renderer={ComponentAccordion} + /> + , + })} + Renderer={ComponentAccordion} + /> + + + ); +}; diff --git a/plugins/home/src/homePageComponents/Toolkit/index.ts b/plugins/home/src/homePageComponents/Toolkit/index.ts index 98e0869825..67ea1f3c84 100644 --- a/plugins/home/src/homePageComponents/Toolkit/index.ts +++ b/plugins/home/src/homePageComponents/Toolkit/index.ts @@ -16,3 +16,4 @@ export { Content } from './Content'; export type { ToolkitContentProps } from './Content'; +export { ContextProvider } from './Context'; diff --git a/plugins/ilert/package.json b/plugins/ilert/package.json index 4c6581553c..5f741b5a49 100644 --- a/plugins/ilert/package.json +++ b/plugins/ilert/package.json @@ -10,15 +10,18 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/catalog-model": "^0.9.10", diff --git a/plugins/ilert/src/components/Incident/IncidentActionsMenu.tsx b/plugins/ilert/src/components/Incident/IncidentActionsMenu.tsx index d58fa91108..909e4dc362 100644 --- a/plugins/ilert/src/components/Incident/IncidentActionsMenu.tsx +++ b/plugins/ilert/src/components/Incident/IncidentActionsMenu.tsx @@ -27,10 +27,7 @@ import { identityApiRef, } from '@backstage/core-plugin-api'; import { Progress, Link } from '@backstage/core-components'; -import { - ENTITY_DEFAULT_NAMESPACE, - parseEntityRef, -} from '@backstage/catalog-model'; +import { DEFAULT_NAMESPACE, parseEntityRef } from '@backstage/catalog-model'; export const IncidentActionsMenu = ({ incident, @@ -71,7 +68,7 @@ export const IncidentActionsMenu = ({ const { userEntityRef } = await identityApi.getBackstageIdentity(); const { name: userName } = parseEntityRef(userEntityRef, { defaultKind: 'User', - defaultNamespace: ENTITY_DEFAULT_NAMESPACE, + defaultNamespace: DEFAULT_NAMESPACE, }); const newIncident = await ilertApi.acceptIncident(incident, userName); alertApi.post({ message: 'Incident accepted.' }); @@ -91,7 +88,7 @@ export const IncidentActionsMenu = ({ const { userEntityRef } = await identityApi.getBackstageIdentity(); const { name: userName } = parseEntityRef(userEntityRef, { defaultKind: 'User', - defaultNamespace: ENTITY_DEFAULT_NAMESPACE, + defaultNamespace: DEFAULT_NAMESPACE, }); const newIncident = await ilertApi.resolveIncident(incident, userName); alertApi.post({ message: 'Incident resolved.' }); diff --git a/plugins/ilert/src/components/Incident/IncidentNewModal.tsx b/plugins/ilert/src/components/Incident/IncidentNewModal.tsx index c8f63c6073..561047d45e 100644 --- a/plugins/ilert/src/components/Incident/IncidentNewModal.tsx +++ b/plugins/ilert/src/components/Incident/IncidentNewModal.tsx @@ -14,10 +14,7 @@ * limitations under the License. */ import React from 'react'; -import { - ENTITY_DEFAULT_NAMESPACE, - parseEntityRef, -} from '@backstage/catalog-model'; +import { DEFAULT_NAMESPACE, parseEntityRef } from '@backstage/catalog-model'; import { makeStyles } from '@material-ui/core/styles'; import Alert from '@material-ui/lab/Alert'; import Button from '@material-ui/core/Button'; @@ -108,7 +105,7 @@ export const IncidentNewModal = ({ const { userEntityRef } = await identityApi.getBackstageIdentity(); const { name: userName } = parseEntityRef(userEntityRef, { defaultKind: 'User', - defaultNamespace: ENTITY_DEFAULT_NAMESPACE, + defaultNamespace: DEFAULT_NAMESPACE, }); await ilertApi.createIncident({ integrationKey, diff --git a/plugins/jenkins-backend/api-report.md b/plugins/jenkins-backend/api-report.md index b8d171f9c1..d437a5dd75 100644 --- a/plugins/jenkins-backend/api-report.md +++ b/plugins/jenkins-backend/api-report.md @@ -3,7 +3,7 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts -import { CatalogClient } from '@backstage/catalog-client'; +import { CatalogApi } from '@backstage/catalog-client'; import { Config } from '@backstage/config'; import { EntityName } from '@backstage/catalog-model'; import express from 'express'; @@ -21,7 +21,7 @@ export class DefaultJenkinsInfoProvider implements JenkinsInfoProvider { // (undocumented) static fromConfig(options: { config: Config; - catalog: CatalogClient; + catalog: CatalogApi; }): DefaultJenkinsInfoProvider; // (undocumented) getInstance(opt: { diff --git a/plugins/jenkins-backend/package.json b/plugins/jenkins-backend/package.json index 52e8862fae..b21fdc794f 100644 --- a/plugins/jenkins-backend/package.json +++ b/plugins/jenkins-backend/package.json @@ -11,15 +11,18 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "backend-plugin" + }, "configSchema": "config.d.ts", "scripts": { - "start": "backstage-cli backend:dev", - "build": "backstage-cli backend:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/backend-common": "^0.10.7", diff --git a/plugins/jenkins-backend/src/service/jenkinsInfoProvider.test.ts b/plugins/jenkins-backend/src/service/jenkinsInfoProvider.test.ts index 496fe535e3..62299926df 100644 --- a/plugins/jenkins-backend/src/service/jenkinsInfoProvider.test.ts +++ b/plugins/jenkins-backend/src/service/jenkinsInfoProvider.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { CatalogClient } from '@backstage/catalog-client'; +import { CatalogApi } from '@backstage/catalog-client'; import { Entity, EntityName } from '@backstage/catalog-model'; import { ConfigReader } from '@backstage/config'; import { @@ -159,9 +159,9 @@ describe('JenkinsConfig', () => { }); describe('DefaultJenkinsInfoProvider', () => { - const mockCatalog: jest.Mocked = { + const mockCatalog: jest.Mocked = { getEntityByName: jest.fn(), - } as any as jest.Mocked; + } as any as jest.Mocked; const entityRef: EntityName = { kind: 'Component', diff --git a/plugins/jenkins-backend/src/service/jenkinsInfoProvider.ts b/plugins/jenkins-backend/src/service/jenkinsInfoProvider.ts index 7dbc94dacf..f822f475f1 100644 --- a/plugins/jenkins-backend/src/service/jenkinsInfoProvider.ts +++ b/plugins/jenkins-backend/src/service/jenkinsInfoProvider.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { CatalogClient } from '@backstage/catalog-client'; +import { CatalogApi } from '@backstage/catalog-client'; import { Entity, EntityName, @@ -168,12 +168,12 @@ export class DefaultJenkinsInfoProvider implements JenkinsInfoProvider { private constructor( private readonly config: JenkinsConfig, - private readonly catalog: CatalogClient, + private readonly catalog: CatalogApi, ) {} static fromConfig(options: { config: Config; - catalog: CatalogClient; + catalog: CatalogApi; }): DefaultJenkinsInfoProvider { return new DefaultJenkinsInfoProvider( JenkinsConfig.fromConfig(options.config), diff --git a/plugins/jenkins/package.json b/plugins/jenkins/package.json index 7b1283cd23..719ed70615 100644 --- a/plugins/jenkins/package.json +++ b/plugins/jenkins/package.json @@ -11,6 +11,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -22,14 +25,14 @@ "jenkins" ], "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/catalog-model": "^0.9.10", diff --git a/plugins/kafka-backend/package.json b/plugins/kafka-backend/package.json index 01b23ba696..8a35006feb 100644 --- a/plugins/kafka-backend/package.json +++ b/plugins/kafka-backend/package.json @@ -11,6 +11,9 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "backend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -23,13 +26,13 @@ ], "configSchema": "config.d.ts", "scripts": { - "start": "backstage-cli backend:dev", - "build": "backstage-cli backend:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/backend-common": "^0.10.7", diff --git a/plugins/kafka/package.json b/plugins/kafka/package.json index 12dd578daa..eb0ab12232 100644 --- a/plugins/kafka/package.json +++ b/plugins/kafka/package.json @@ -10,15 +10,18 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/catalog-model": "^0.9.10", diff --git a/plugins/kubernetes-backend/package.json b/plugins/kubernetes-backend/package.json index feb6a4defd..bf3915bd2a 100644 --- a/plugins/kubernetes-backend/package.json +++ b/plugins/kubernetes-backend/package.json @@ -11,6 +11,9 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "backend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -23,13 +26,13 @@ ], "configSchema": "schema.d.ts", "scripts": { - "start": "backstage-cli backend:dev", - "build": "backstage-cli backend:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/backend-common": "^0.10.7", @@ -47,7 +50,7 @@ "express": "^4.17.1", "express-promise-router": "^4.1.0", "fs-extra": "9.1.0", - "helmet": "^4.0.0", + "helmet": "^5.0.2", "lodash": "^4.17.21", "morgan": "^1.10.0", "stream-buffers": "^3.0.2", diff --git a/plugins/kubernetes-backend/src/kubernetes-auth-translator/AwsIamKubernetesAuthTranslator.ts b/plugins/kubernetes-backend/src/kubernetes-auth-translator/AwsIamKubernetesAuthTranslator.ts index 4af39d4f26..9f1353ca5c 100644 --- a/plugins/kubernetes-backend/src/kubernetes-auth-translator/AwsIamKubernetesAuthTranslator.ts +++ b/plugins/kubernetes-backend/src/kubernetes-auth-translator/AwsIamKubernetesAuthTranslator.ts @@ -18,19 +18,6 @@ import { sign } from 'aws4'; import { AWSClusterDetails } from '../types/types'; import { KubernetesAuthTranslator } from './types'; -const base64 = (str: string) => - Buffer.from(str.toString(), 'binary').toString('base64'); -const prepend = (prep: string) => (str: string) => prep + str; -const replace = - (search: string | RegExp, substitution: string) => (str: string) => - str.replace(search, substitution); -const pipe = - (fns: ReadonlyArray) => - (thing: string): string => - fns.reduce((val, fn) => fn(val), thing); -const removePadding = replace(/=+$/, ''); -const makeUrlSafe = pipe([replace('+', '-'), replace('/', '_')]); - type SigningCreds = { accessKeyId: string | undefined; secretAccessKey: string | undefined; @@ -117,15 +104,15 @@ export class AwsIamKubernetesAuthTranslator signQuery: true, }; - const signedRequest = sign(request, credentials); + const signed = sign(request, credentials); + const url = `https://${signed.host}${signed.path}`; + const base64Url = Buffer.from(url, 'binary').toString('base64'); + const urlSafeBase64Url = base64Url + .replace(/\+/g, '-') + .replace(/\//g, '_') + .replace(/=+$/, ''); - return pipe([ - (signed: any) => `https://${signed.host}${signed.path}`, - base64, - removePadding, - makeUrlSafe, - prepend('k8s-aws-v1.'), - ])(signedRequest); + return `k8s-aws-v1.${urlSafeBase64Url}`; } async decorateClusterDetailsWithAuth( diff --git a/plugins/kubernetes-common/package.json b/plugins/kubernetes-common/package.json index cd12eb3519..041032f0e1 100644 --- a/plugins/kubernetes-common/package.json +++ b/plugins/kubernetes-common/package.json @@ -11,6 +11,9 @@ "module": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "common-library" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -24,12 +27,12 @@ "dist" ], "scripts": { - "build": "backstage-cli build", - "lint": "backstage-cli lint", - "test": "backstage-cli test --passWithNoTests", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "bugs": { "url": "https://github.com/backstage/backstage/issues" diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index 1a60997405..1d9f9c1821 100644 --- a/plugins/kubernetes/package.json +++ b/plugins/kubernetes/package.json @@ -10,6 +10,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -21,14 +24,14 @@ "kubernetes" ], "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/catalog-model": "^0.9.10", diff --git a/plugins/lighthouse/package.json b/plugins/lighthouse/package.json index 618202b54c..3bb06ac0cf 100644 --- a/plugins/lighthouse/package.json +++ b/plugins/lighthouse/package.json @@ -11,6 +11,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -22,14 +25,14 @@ "lighthouse" ], "scripts": { - "build": "backstage-cli plugin:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "clean": "backstage-cli clean", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "start": "backstage-cli plugin:serve" + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "start": "backstage-cli package start" }, "dependencies": { "@backstage/catalog-model": "^0.9.10", diff --git a/plugins/newrelic-dashboard/package.json b/plugins/newrelic-dashboard/package.json index dba9cc1148..f0b3d29680 100644 --- a/plugins/newrelic-dashboard/package.json +++ b/plugins/newrelic-dashboard/package.json @@ -9,15 +9,18 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/catalog-model": "^0.9.10", diff --git a/plugins/newrelic/package.json b/plugins/newrelic/package.json index 9f9d51eae3..7f0b2e6c26 100644 --- a/plugins/newrelic/package.json +++ b/plugins/newrelic/package.json @@ -11,6 +11,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -22,14 +25,14 @@ "newrelic" ], "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/core-components": "^0.8.8", diff --git a/plugins/org/CHANGELOG.md b/plugins/org/CHANGELOG.md index 76b3945a5d..e9dfbce07d 100644 --- a/plugins/org/CHANGELOG.md +++ b/plugins/org/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-org +## 0.4.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.8.8 + - @backstage/plugin-catalog-react@0.6.14 + ## 0.4.2-next.0 ### Patch Changes diff --git a/plugins/org/package.json b/plugins/org/package.json index 58f293fa8c..c5a52e14e5 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.4.2-next.0", + "version": "0.4.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -10,15 +10,18 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/catalog-model": "^0.9.10", diff --git a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx index 9a107f2d8f..74a4f6fc90 100644 --- a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx +++ b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ import { - ENTITY_DEFAULT_NAMESPACE, + DEFAULT_NAMESPACE, GroupEntity, UserEntity, stringifyEntityRef, @@ -124,7 +124,7 @@ export const MembersListCard = (_props: { const displayName = profile?.displayName ?? groupName; - const groupNamespace = grpNamespace || ENTITY_DEFAULT_NAMESPACE; + const groupNamespace = grpNamespace || DEFAULT_NAMESPACE; const [page, setPage] = React.useState(1); const pageChange = (_: React.ChangeEvent, pageIndex: number) => { diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx index 26a79dfaee..2030f4c100 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx @@ -15,8 +15,8 @@ */ import { - CatalogEntitiesRequest, - CatalogListResponse, + GetEntitiesRequest, + GetEntitiesResponse, } from '@backstage/catalog-client'; import { Entity, GroupEntity, UserEntity } from '@backstage/catalog-model'; import { @@ -110,15 +110,15 @@ const items = [ ] as Entity[]; const getEntitiesMock = ( - request?: CatalogEntitiesRequest, -): Promise> => { + request?: GetEntitiesRequest, +): Promise => { const filterKinds = !Array.isArray(request?.filter) && Array.isArray(request?.filter?.kind) ? request?.filter?.kind ?? [] : []; // we expect the request to be like { filter: { kind: ['API','System'], .... }. If changed in OwnerShipCard, let's change in also here return Promise.resolve({ items: items.filter(item => filterKinds.find(k => k === item.kind)), - } as CatalogListResponse); + } as GetEntitiesResponse); }; describe('OwnershipCard', () => { diff --git a/plugins/pagerduty/package.json b/plugins/pagerduty/package.json index 7912a32f15..2c9e0bc79d 100644 --- a/plugins/pagerduty/package.json +++ b/plugins/pagerduty/package.json @@ -10,6 +10,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -21,14 +24,14 @@ "pagerduty" ], "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/catalog-model": "^0.9.10", diff --git a/plugins/pagerduty/src/components/TriggerDialog/TriggerDialog.tsx b/plugins/pagerduty/src/components/TriggerDialog/TriggerDialog.tsx index ef0659becb..171238cdd3 100644 --- a/plugins/pagerduty/src/components/TriggerDialog/TriggerDialog.tsx +++ b/plugins/pagerduty/src/components/TriggerDialog/TriggerDialog.tsx @@ -34,10 +34,7 @@ import { alertApiRef, identityApiRef, } from '@backstage/core-plugin-api'; -import { - ENTITY_DEFAULT_NAMESPACE, - parseEntityRef, -} from '@backstage/catalog-model'; +import { DEFAULT_NAMESPACE, parseEntityRef } from '@backstage/catalog-model'; type Props = { showDialog: boolean; @@ -61,7 +58,7 @@ export const TriggerDialog = ({ const { userEntityRef } = await identityApi.getBackstageIdentity(); const { name: userName } = parseEntityRef(userEntityRef, { defaultKind: 'User', - defaultNamespace: ENTITY_DEFAULT_NAMESPACE, + defaultNamespace: DEFAULT_NAMESPACE, }); await api.triggerAlarm({ integrationKey: integrationKey as string, diff --git a/plugins/permission-backend/api-report.md b/plugins/permission-backend/api-report.md index 843c9a315c..2b59113535 100644 --- a/plugins/permission-backend/api-report.md +++ b/plugins/permission-backend/api-report.md @@ -3,6 +3,7 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { Config } from '@backstage/config'; import express from 'express'; import { IdentityClient } from '@backstage/plugin-auth-node'; import { Logger as Logger_2 } from 'winston'; @@ -14,6 +15,8 @@ export function createRouter(options: RouterOptions): Promise; // @public export interface RouterOptions { + // (undocumented) + config: Config; // (undocumented) discovery: PluginEndpointDiscovery; // (undocumented) diff --git a/plugins/permission-backend/package.json b/plugins/permission-backend/package.json index e1a4e10c5c..6b7817f10b 100644 --- a/plugins/permission-backend/package.json +++ b/plugins/permission-backend/package.json @@ -9,14 +9,17 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "backend-plugin" + }, "scripts": { - "start": "backstage-cli backend:dev", - "build": "backstage-cli backend:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/backend-common": "^0.10.7", diff --git a/plugins/permission-backend/src/service/PermissionIntegrationClient.test.ts b/plugins/permission-backend/src/service/PermissionIntegrationClient.test.ts index 4be1b55379..9981496658 100644 --- a/plugins/permission-backend/src/service/PermissionIntegrationClient.test.ts +++ b/plugins/permission-backend/src/service/PermissionIntegrationClient.test.ts @@ -20,7 +20,11 @@ import express, { Router, RequestHandler } from 'express'; import { RestContext, rest } from 'msw'; import { setupServer, SetupServerApi } from 'msw/node'; import { PluginEndpointDiscovery } from '@backstage/backend-common'; -import { AuthorizeResult } from '@backstage/plugin-permission-common'; +import { + AuthorizeResult, + PermissionCondition, + PermissionCriteria, +} from '@backstage/plugin-permission-common'; import { createPermissionIntegrationRouter } from '@backstage/plugin-permission-node'; import { PermissionIntegrationClient } from './PermissionIntegrationClient'; @@ -28,7 +32,7 @@ describe('PermissionIntegrationClient', () => { describe('applyConditions', () => { let server: SetupServerApi; - const mockConditions = { + const mockConditions: PermissionCriteria = { not: { allOf: [ { rule: 'RULE_1', params: [] }, diff --git a/plugins/permission-backend/src/service/router.test.ts b/plugins/permission-backend/src/service/router.test.ts index 498fcb748b..b98b32b01c 100644 --- a/plugins/permission-backend/src/service/router.test.ts +++ b/plugins/permission-backend/src/service/router.test.ts @@ -26,6 +26,7 @@ import { import { PermissionIntegrationClient } from './PermissionIntegrationClient'; import { createRouter } from './router'; +import { ConfigReader } from '@backstage/config'; const mockApplyConditions: jest.MockedFunction< InstanceType['applyConditions'] @@ -63,6 +64,7 @@ describe('createRouter', () => { beforeAll(async () => { const router = await createRouter({ + config: new ConfigReader({ permission: { enabled: true } }), logger: getVoidLogger(), discovery: { getBaseUrl: jest.fn(), diff --git a/plugins/permission-backend/src/service/router.ts b/plugins/permission-backend/src/service/router.ts index 413f3e6b45..48f7b1a2e5 100644 --- a/plugins/permission-backend/src/service/router.ts +++ b/plugins/permission-backend/src/service/router.ts @@ -44,6 +44,7 @@ import { import { PermissionIntegrationClient } from './PermissionIntegrationClient'; import { memoize } from 'lodash'; import DataLoader from 'dataloader'; +import { Config } from '@backstage/config'; const querySchema: z.ZodSchema> = z.object({ id: z.string(), @@ -79,6 +80,7 @@ export interface RouterOptions { discovery: PluginEndpointDiscovery; policy: PermissionPolicy; identity: IdentityClient; + config: Config; } const handleRequest = async ( @@ -139,7 +141,13 @@ const handleRequest = async ( export async function createRouter( options: RouterOptions, ): Promise { - const { policy, discovery, identity } = options; + const { policy, discovery, identity, config, logger } = options; + + if (!config.getOptionalBoolean('permission.enabled')) { + logger.warn( + 'Permission backend started with permissions disabled. Enable permissions by setting permission.enabled=true.', + ); + } const permissionIntegrationClient = new PermissionIntegrationClient({ discovery, diff --git a/plugins/permission-common/api-report.md b/plugins/permission-common/api-report.md index 30a67e8c8b..db05766dc0 100644 --- a/plugins/permission-common/api-report.md +++ b/plugins/permission-common/api-report.md @@ -5,6 +5,16 @@ ```ts import { Config } from '@backstage/config'; +// @public +export type AllOfCriteria = { + allOf: NonEmptyArray>; +}; + +// @public +export type AnyOfCriteria = { + anyOf: NonEmptyArray>; +}; + // @public export type AuthorizeDecision = | { @@ -65,6 +75,11 @@ export function isReadPermission(permission: Permission): boolean; // @public export function isUpdatePermission(permission: Permission): boolean; +// @public +export type NotCriteria = { + not: PermissionCriteria; +}; + // @public export type Permission = { name: string; @@ -103,14 +118,8 @@ export type PermissionCondition = { // @public export type PermissionCriteria = - | { - allOf: PermissionCriteria[]; - } - | { - anyOf: PermissionCriteria[]; - } - | { - not: PermissionCriteria; - } + | AllOfCriteria + | AnyOfCriteria + | NotCriteria | TQuery; ``` diff --git a/plugins/permission-common/package.json b/plugins/permission-common/package.json index d3054fe9fe..a3d099d1a8 100644 --- a/plugins/permission-common/package.json +++ b/plugins/permission-common/package.json @@ -10,6 +10,9 @@ "module": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "common-library" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -27,12 +30,12 @@ ], "configSchema": "config.d.ts", "scripts": { - "build": "backstage-cli build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "bugs": { "url": "https://github.com/backstage/backstage/issues" diff --git a/plugins/permission-common/src/PermissionClient.ts b/plugins/permission-common/src/PermissionClient.ts index 58f4d44d20..9431050690 100644 --- a/plugins/permission-common/src/PermissionClient.ts +++ b/plugins/permission-common/src/PermissionClient.ts @@ -43,9 +43,18 @@ const permissionCriteriaSchema: z.ZodSchema< rule: z.string(), params: z.array(z.unknown()), }) - .or(z.object({ anyOf: z.array(permissionCriteriaSchema) })) - .or(z.object({ allOf: z.array(permissionCriteriaSchema) })) - .or(z.object({ not: permissionCriteriaSchema })), + .strict() + .or( + z + .object({ anyOf: z.array(permissionCriteriaSchema).nonempty() }) + .strict(), + ) + .or( + z + .object({ allOf: z.array(permissionCriteriaSchema).nonempty() }) + .strict(), + ) + .or(z.object({ not: permissionCriteriaSchema }).strict()), ); const responseSchema = z.object({ diff --git a/plugins/permission-common/src/types/api.ts b/plugins/permission-common/src/types/api.ts index 287c7ffe83..e0ab1f1642 100644 --- a/plugins/permission-common/src/types/api.ts +++ b/plugins/permission-common/src/types/api.ts @@ -72,14 +72,44 @@ export type PermissionCondition = { params: TParams; }; +/** + * Utility type to represent an array with 1 or more elements. + * @ignore + */ +type NonEmptyArray = [T, ...T[]]; + +/** + * Represnts a logical AND for the provided criteria. + * @public + */ +export type AllOfCriteria = { + allOf: NonEmptyArray>; +}; + +/** + * Represnts a logical OR for the provided criteria. + * @public + */ +export type AnyOfCriteria = { + anyOf: NonEmptyArray>; +}; + +/** + * Represents a negation of the provided criteria. + * @public + */ +export type NotCriteria = { + not: PermissionCriteria; +}; + /** * Composes several {@link PermissionCondition}s as criteria with a nested AND/OR structure. * @public */ export type PermissionCriteria = - | { allOf: PermissionCriteria[] } - | { anyOf: PermissionCriteria[] } - | { not: PermissionCriteria } + | AllOfCriteria + | AnyOfCriteria + | NotCriteria | TQuery; /** diff --git a/plugins/permission-common/src/types/index.ts b/plugins/permission-common/src/types/index.ts index b4453fcc63..fa98de73f1 100644 --- a/plugins/permission-common/src/types/index.ts +++ b/plugins/permission-common/src/types/index.ts @@ -23,6 +23,9 @@ export type { Identified, PermissionCondition, PermissionCriteria, + AllOfCriteria, + AnyOfCriteria, + NotCriteria, } from './api'; export type { DiscoveryApi } from './discovery'; export type { diff --git a/plugins/permission-node/package.json b/plugins/permission-node/package.json index 04a567f16b..1c3e711dfc 100644 --- a/plugins/permission-node/package.json +++ b/plugins/permission-node/package.json @@ -10,6 +10,9 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "node-library" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -21,12 +24,13 @@ "permissions" ], "scripts": { - "build": "backstage-cli backend:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean", + "start": "backstage-cli package start" }, "dependencies": { "@backstage/backend-common": "^0.10.7", diff --git a/plugins/permission-node/src/integration/createConditionTransformer.ts b/plugins/permission-node/src/integration/createConditionTransformer.ts index 0e736b832c..ee4224b8bd 100644 --- a/plugins/permission-node/src/integration/createConditionTransformer.ts +++ b/plugins/permission-node/src/integration/createConditionTransformer.ts @@ -14,6 +14,8 @@ * limitations under the License. */ import { + AllOfCriteria, + AnyOfCriteria, PermissionCondition, PermissionCriteria, } from '@backstage/plugin-permission-common'; @@ -32,11 +34,11 @@ const mapConditions = ( if (isAndCriteria(criteria)) { return { allOf: criteria.allOf.map(child => mapConditions(child, getRule)), - }; + } as AllOfCriteria; } else if (isOrCriteria(criteria)) { return { anyOf: criteria.anyOf.map(child => mapConditions(child, getRule)), - }; + } as AnyOfCriteria; } else if (isNotCriteria(criteria)) { return { not: mapConditions(criteria.not, getRule), diff --git a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts index 065c30a978..6408de46a1 100644 --- a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts +++ b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts @@ -247,7 +247,8 @@ describe('createPermissionIntegrationRouter', () => { resourceRef: 'default:test/resource-1', resourceType: 'test-incorrect-resource-1', conditions: { - anyOf: [], + rule: 'test-rule-1', + params: [{}], }, }, { @@ -255,7 +256,8 @@ describe('createPermissionIntegrationRouter', () => { resourceRef: 'default:test/resource-2', resourceType: 'test-resource', conditions: { - anyOf: [], + rule: 'test-rule-1', + params: [{}], }, }, { @@ -263,7 +265,8 @@ describe('createPermissionIntegrationRouter', () => { resourceRef: 'default:test/resource-3', resourceType: 'test-incorrect-resource-2', conditions: { - anyOf: [], + rule: 'test-rule-1', + params: [{}], }, }, ], diff --git a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts index 1b01660fb0..efb5d7c3a6 100644 --- a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts +++ b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts @@ -38,13 +38,15 @@ const permissionCriteriaSchema: z.ZodSchema< PermissionCriteria > = z.lazy(() => z.union([ - z.object({ anyOf: z.array(permissionCriteriaSchema) }), - z.object({ allOf: z.array(permissionCriteriaSchema) }), - z.object({ not: permissionCriteriaSchema }), - z.object({ - rule: z.string(), - params: z.array(z.unknown()), - }), + z.object({ anyOf: z.array(permissionCriteriaSchema).nonempty() }).strict(), + z.object({ allOf: z.array(permissionCriteriaSchema).nonempty() }).strict(), + z.object({ not: permissionCriteriaSchema }).strict(), + z + .object({ + rule: z.string(), + params: z.array(z.unknown()), + }) + .strict(), ]), ); diff --git a/plugins/permission-node/src/integration/util.ts b/plugins/permission-node/src/integration/util.ts index d9457cfefc..3878e18895 100644 --- a/plugins/permission-node/src/integration/util.ts +++ b/plugins/permission-node/src/integration/util.ts @@ -14,22 +14,27 @@ * limitations under the License. */ -import { PermissionCriteria } from '@backstage/plugin-permission-common'; +import { + AllOfCriteria, + AnyOfCriteria, + NotCriteria, + PermissionCriteria, +} from '@backstage/plugin-permission-common'; import { PermissionRule } from '../types'; export const isAndCriteria = ( filter: PermissionCriteria, -): filter is { allOf: PermissionCriteria[] } => +): filter is AllOfCriteria => Object.prototype.hasOwnProperty.call(filter, 'allOf'); export const isOrCriteria = ( filter: PermissionCriteria, -): filter is { anyOf: PermissionCriteria[] } => +): filter is AnyOfCriteria => Object.prototype.hasOwnProperty.call(filter, 'anyOf'); export const isNotCriteria = ( filter: PermissionCriteria, -): filter is { not: PermissionCriteria } => +): filter is NotCriteria => Object.prototype.hasOwnProperty.call(filter, 'not'); export const createGetRule = ( diff --git a/plugins/permission-react/package.json b/plugins/permission-react/package.json index ce6e2dbf54..b62a681c06 100644 --- a/plugins/permission-react/package.json +++ b/plugins/permission-react/package.json @@ -9,6 +9,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "web-library" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -19,12 +22,13 @@ "backstage" ], "scripts": { - "build": "backstage-cli build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean", + "start": "backstage-cli package start" }, "dependencies": { "@backstage/config": "^0.1.13", diff --git a/plugins/proxy-backend/package.json b/plugins/proxy-backend/package.json index 5336bbb098..5b2e9a5713 100644 --- a/plugins/proxy-backend/package.json +++ b/plugins/proxy-backend/package.json @@ -10,6 +10,9 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "backend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -20,13 +23,13 @@ "backstage" ], "scripts": { - "start": "backstage-cli backend:dev", - "build": "backstage-cli backend:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/backend-common": "^0.10.7", diff --git a/plugins/rollbar-backend/package.json b/plugins/rollbar-backend/package.json index 36683ef66a..91a4d38c31 100644 --- a/plugins/rollbar-backend/package.json +++ b/plugins/rollbar-backend/package.json @@ -11,6 +11,9 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "backend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -22,13 +25,13 @@ "rollbar" ], "scripts": { - "start": "backstage-cli backend:dev", - "build": "backstage-cli backend:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/backend-common": "^0.10.7", @@ -40,7 +43,6 @@ "express": "^4.17.1", "express-promise-router": "^4.1.0", "fs-extra": "9.1.0", - "helmet": "^4.0.0", "lodash": "^4.17.21", "morgan": "^1.10.0", "node-fetch": "^2.6.7", diff --git a/plugins/rollbar/package.json b/plugins/rollbar/package.json index 5767f26c5e..764a4dc036 100644 --- a/plugins/rollbar/package.json +++ b/plugins/rollbar/package.json @@ -11,6 +11,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -22,14 +25,14 @@ "rollbar" ], "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/catalog-model": "^0.9.10", diff --git a/plugins/scaffolder-backend-module-cookiecutter/api-report.md b/plugins/scaffolder-backend-module-cookiecutter/api-report.md index 132d3d4225..e55c6368c4 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/api-report.md +++ b/plugins/scaffolder-backend-module-cookiecutter/api-report.md @@ -6,6 +6,7 @@ /// import { ContainerRunner } from '@backstage/backend-common'; +import { JsonObject } from '@backstage/types'; import { ScmIntegrations } from '@backstage/integration'; import { TemplateAction } from '@backstage/plugin-scaffolder-backend'; import { UrlReader } from '@backstage/backend-common'; @@ -15,5 +16,12 @@ export function createFetchCookiecutterAction(options: { reader: UrlReader; integrations: ScmIntegrations; containerRunner: ContainerRunner; -}): TemplateAction; +}): TemplateAction<{ + url: string; + targetPath?: string | undefined; + values: JsonObject; + copyWithoutRender?: string[] | undefined; + extensions?: string[] | undefined; + imageName?: string | undefined; +}>; ``` diff --git a/plugins/scaffolder-backend-module-cookiecutter/package.json b/plugins/scaffolder-backend-module-cookiecutter/package.json index cee138b576..e3386ee7a4 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/package.json +++ b/plugins/scaffolder-backend-module-cookiecutter/package.json @@ -10,14 +10,17 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "backend-plugin-module" + }, "scripts": { - "start": "backstage-cli backend:dev", - "build": "backstage-cli backend:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/backend-common": "^0.10.7", diff --git a/plugins/scaffolder-backend-module-rails/api-report.md b/plugins/scaffolder-backend-module-rails/api-report.md index 9c0610d4f2..aa631c5333 100644 --- a/plugins/scaffolder-backend-module-rails/api-report.md +++ b/plugins/scaffolder-backend-module-rails/api-report.md @@ -4,6 +4,7 @@ ```ts import { ContainerRunner } from '@backstage/backend-common'; +import { JsonObject } from '@backstage/types'; import { ScmIntegrations } from '@backstage/integration'; import { TemplateAction } from '@backstage/plugin-scaffolder-backend'; import { UrlReader } from '@backstage/backend-common'; @@ -13,5 +14,10 @@ export function createFetchRailsAction(options: { reader: UrlReader; integrations: ScmIntegrations; containerRunner: ContainerRunner; -}): TemplateAction; +}): TemplateAction<{ + url: string; + targetPath?: string | undefined; + values: JsonObject; + imageName?: string | undefined; +}>; ``` diff --git a/plugins/scaffolder-backend-module-rails/package.json b/plugins/scaffolder-backend-module-rails/package.json index 5f32dbadd8..edf8c1cc84 100644 --- a/plugins/scaffolder-backend-module-rails/package.json +++ b/plugins/scaffolder-backend-module-rails/package.json @@ -11,14 +11,17 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "backend-plugin-module" + }, "scripts": { - "build": "backstage-cli backend:build", - "start": "backstage-cli backend:dev", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/backend-common": "^0.10.7", diff --git a/plugins/scaffolder-backend-module-yeoman/api-report.md b/plugins/scaffolder-backend-module-yeoman/api-report.md index fc18814faa..0f8747e592 100644 --- a/plugins/scaffolder-backend-module-yeoman/api-report.md +++ b/plugins/scaffolder-backend-module-yeoman/api-report.md @@ -3,8 +3,13 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { JsonObject } from '@backstage/types'; import { TemplateAction } from '@backstage/plugin-scaffolder-backend'; // @public -export function createRunYeomanAction(): TemplateAction; +export function createRunYeomanAction(): TemplateAction<{ + namespace: string; + args?: string[] | undefined; + options?: JsonObject | undefined; +}>; ``` diff --git a/plugins/scaffolder-backend-module-yeoman/package.json b/plugins/scaffolder-backend-module-yeoman/package.json index a49898be1c..5a82f2df32 100644 --- a/plugins/scaffolder-backend-module-yeoman/package.json +++ b/plugins/scaffolder-backend-module-yeoman/package.json @@ -10,21 +10,24 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "backend-plugin-module" + }, "scripts": { - "start": "backstage-cli backend:dev", - "build": "backstage-cli backend:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/config": "^0.1.13", "@backstage/plugin-scaffolder-backend": "^0.15.24", "@backstage/types": "^0.1.1", "winston": "^3.2.1", - "yeoman-environment": "^3.6.0" + "yeoman-environment": "^3.9.1" }, "devDependencies": { "@backstage/backend-common": "^0.10.7", diff --git a/plugins/scaffolder-backend/api-report.md b/plugins/scaffolder-backend/api-report.md index 5e7b5a428b..ba16b5d4f0 100644 --- a/plugins/scaffolder-backend/api-report.md +++ b/plugins/scaffolder-backend/api-report.md @@ -29,20 +29,17 @@ import { SpawnOptionsWithoutStdio } from 'child_process'; import { TaskSpec } from '@backstage/plugin-scaffolder-common'; import { TaskSpecV1beta2 } from '@backstage/plugin-scaffolder-common'; import { TaskSpecV1beta3 } from '@backstage/plugin-scaffolder-common'; -import { TemplateEntityV1beta2 } from '@backstage/catalog-model'; import { TemplateMetadata } from '@backstage/plugin-scaffolder-common'; import { UrlReader } from '@backstage/backend-common'; import { Writable } from 'stream'; -// Warning: (ae-forgotten-export) The symbol "InputBase" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "ActionContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export type ActionContext = { +export type ActionContext = { baseUrl?: string; logger: Logger_2; logStream: Writable; - token?: string | undefined; secrets?: TaskSecrets; workspacePath: string; input: Input; @@ -51,19 +48,6 @@ export type ActionContext = { metadata?: TemplateMetadata; }; -// Warning: (ae-missing-release-tag) "CatalogEntityClient" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public -export class CatalogEntityClient { - constructor(catalogClient: CatalogApi); - findTemplate( - templateName: string, - options?: { - token?: string; - }, - ): Promise; -} - // @public export type CompletedTaskState = 'failed' | 'completed'; @@ -77,7 +61,7 @@ export const createBuiltinActions: (options: { containerRunner?: ContainerRunner; config: Config; additionalTemplateFilters?: Record; -}) => TemplateAction[]; +}) => TemplateAction[]; // Warning: (ae-missing-release-tag) "createCatalogRegisterAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -85,17 +69,33 @@ export const createBuiltinActions: (options: { export function createCatalogRegisterAction(options: { catalogClient: CatalogApi; integrations: ScmIntegrations; -}): TemplateAction; +}): TemplateAction< + | { + catalogInfoUrl: string; + optional?: boolean | undefined; + } + | { + repoContentsUrl: string; + catalogInfoPath?: string | undefined; + optional?: boolean | undefined; + } +>; // Warning: (ae-missing-release-tag) "createCatalogWriteAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export function createCatalogWriteAction(): TemplateAction; +export function createCatalogWriteAction(): TemplateAction<{ + filePath?: string | undefined; + entity: Entity; +}>; // Warning: (ae-missing-release-tag) "createDebugLogAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public -export function createDebugLogAction(): TemplateAction; +export function createDebugLogAction(): TemplateAction<{ + message?: string | undefined; + listWorkspace?: boolean | undefined; +}>; export { createFetchCookiecutterAction }; @@ -105,7 +105,10 @@ export { createFetchCookiecutterAction }; export function createFetchPlainAction(options: { reader: UrlReader; integrations: ScmIntegrations; -}): TemplateAction; +}): TemplateAction<{ + url: string; + targetPath?: string | undefined; +}>; // Warning: (ae-missing-release-tag) "createFetchTemplateAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -114,17 +117,32 @@ export function createFetchTemplateAction(options: { reader: UrlReader; integrations: ScmIntegrations; additionalTemplateFilters?: Record; -}): TemplateAction; +}): TemplateAction<{ + url: string; + targetPath?: string | undefined; + values: any; + templateFileExtension?: string | boolean | undefined; + copyWithoutRender?: string[] | undefined; + cookiecutterCompat?: boolean | undefined; +}>; // Warning: (ae-missing-release-tag) "createFilesystemDeleteAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const createFilesystemDeleteAction: () => TemplateAction; +export const createFilesystemDeleteAction: () => TemplateAction<{ + files: string[]; +}>; // Warning: (ae-missing-release-tag) "createFilesystemRenameAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const createFilesystemRenameAction: () => TemplateAction; +export const createFilesystemRenameAction: () => TemplateAction<{ + files: Array<{ + from: string; + to: string; + overwrite?: boolean; + }>; +}>; // Warning: (ae-missing-release-tag) "createGithubActionsDispatchAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -132,7 +150,17 @@ export const createFilesystemRenameAction: () => TemplateAction; export function createGithubActionsDispatchAction(options: { integrations: ScmIntegrations; githubCredentialsProvider?: GithubCredentialsProvider; -}): TemplateAction; +}): TemplateAction<{ + repoUrl: string; + workflowId: string; + branchOrTagName: string; + workflowInputs?: + | { + [key: string]: string; + } + | undefined; + token?: string | undefined; +}>; // Warning: (ae-missing-release-tag) "createGithubWebhookAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -141,7 +169,16 @@ export function createGithubWebhookAction(options: { integrations: ScmIntegrationRegistry; defaultWebhookSecret?: string; githubCredentialsProvider?: GithubCredentialsProvider; -}): TemplateAction; +}): TemplateAction<{ + repoUrl: string; + webhookUrl: string; + webhookSecret?: string | undefined; + events?: string[] | undefined; + active?: boolean | undefined; + contentType?: 'form' | 'json' | undefined; + insecureSsl?: boolean | undefined; + token?: string | undefined; +}>; // Warning: (ae-missing-release-tag) "createPublishAzureAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -149,7 +186,13 @@ export function createGithubWebhookAction(options: { export function createPublishAzureAction(options: { integrations: ScmIntegrationRegistry; config: Config; -}): TemplateAction; +}): TemplateAction<{ + repoUrl: string; + description?: string | undefined; + defaultBranch?: string | undefined; + sourcePath?: string | undefined; + token?: string | undefined; +}>; // Warning: (ae-missing-release-tag) "createPublishBitbucketAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -157,12 +200,22 @@ export function createPublishAzureAction(options: { export function createPublishBitbucketAction(options: { integrations: ScmIntegrationRegistry; config: Config; -}): TemplateAction; +}): TemplateAction<{ + repoUrl: string; + description?: string | undefined; + defaultBranch?: string | undefined; + repoVisibility?: 'private' | 'public' | undefined; + sourcePath?: string | undefined; + enableLFS?: boolean | undefined; + token?: string | undefined; +}>; // Warning: (ae-missing-release-tag) "createPublishFileAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public -export function createPublishFileAction(): TemplateAction; +export function createPublishFileAction(): TemplateAction<{ + path: string; +}>; // Warning: (ae-missing-release-tag) "createPublishGithubAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -171,7 +224,23 @@ export function createPublishGithubAction(options: { integrations: ScmIntegrationRegistry; config: Config; githubCredentialsProvider?: GithubCredentialsProvider; -}): TemplateAction; +}): TemplateAction<{ + repoUrl: string; + description?: string | undefined; + access?: string | undefined; + defaultBranch?: string | undefined; + sourcePath?: string | undefined; + requireCodeOwnerReviews?: boolean | undefined; + repoVisibility?: 'internal' | 'private' | 'public' | undefined; + collaborators?: + | { + username: string; + access: 'pull' | 'push' | 'admin' | 'maintain' | 'triage'; + }[] + | undefined; + token?: string | undefined; + topics?: string[] | undefined; +}>; // Warning: (ae-forgotten-export) The symbol "CreateGithubPullRequestActionOptions" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "createPublishGithubPullRequestAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -181,7 +250,15 @@ export const createPublishGithubPullRequestAction: ({ integrations, githubCredentialsProvider, clientFactory, -}: CreateGithubPullRequestActionOptions) => TemplateAction; +}: CreateGithubPullRequestActionOptions) => TemplateAction<{ + title: string; + branchName: string; + description: string; + repoUrl: string; + targetPath?: string | undefined; + sourcePath?: string | undefined; + token?: string | undefined; +}>; // Warning: (ae-missing-release-tag) "createPublishGitlabAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -189,14 +266,28 @@ export const createPublishGithubPullRequestAction: ({ export function createPublishGitlabAction(options: { integrations: ScmIntegrationRegistry; config: Config; -}): TemplateAction; +}): TemplateAction<{ + repoUrl: string; + defaultBranch?: string | undefined; + repoVisibility?: 'internal' | 'private' | 'public' | undefined; + sourcePath?: string | undefined; + token?: string | undefined; +}>; // Warning: (ae-missing-release-tag) "createPublishGitlabMergeRequestAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) export const createPublishGitlabMergeRequestAction: (options: { integrations: ScmIntegrationRegistry; -}) => TemplateAction; +}) => TemplateAction<{ + projectid: string; + repoUrl: string; + title: string; + description: string; + branchName: string; + targetPath: string; + token?: string | undefined; +}>; // Warning: (ae-missing-release-tag) "createRouter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -206,13 +297,9 @@ export function createRouter(options: RouterOptions): Promise; // Warning: (ae-missing-release-tag) "createTemplateAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const createTemplateAction: < - Input extends Partial<{ - [name: string]: JsonValue | Partial | undefined; - }>, ->( - templateAction: TemplateAction, -) => TemplateAction; +export const createTemplateAction: ( + templateAction: TemplateAction, +) => TemplateAction; // @public export type CreateWorkerOptions = { @@ -451,7 +538,6 @@ export class TaskManager implements TaskContext { // @public export type TaskSecrets = Record & { - token?: string; backstageToken?: string; }; @@ -531,7 +617,7 @@ export class TaskWorker { // Warning: (ae-missing-release-tag) "TemplateAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export type TemplateAction = { +export type TemplateAction = { id: string; description?: string; schema?: { @@ -546,13 +632,11 @@ export type TemplateAction = { // @public (undocumented) export class TemplateActionRegistry { // (undocumented) - get(actionId: string): TemplateAction; + get(actionId: string): TemplateAction; // (undocumented) - list(): TemplateAction[]; + list(): TemplateAction[]; // (undocumented) - register( - action: TemplateAction, - ): void; + register(action: TemplateAction): void; } // Warning: (ae-missing-release-tag) "TemplateFilter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) diff --git a/plugins/scaffolder-backend/config.d.ts b/plugins/scaffolder-backend/config.d.ts index aa4ecf8053..7883284165 100644 --- a/plugins/scaffolder-backend/config.d.ts +++ b/plugins/scaffolder-backend/config.d.ts @@ -28,30 +28,5 @@ export interface Config { * The commit message used when new components are created. */ defaultCommitMessage?: string; - /** - * @deprecated Replaced by parameters for the publish:github action - */ - github?: { - [key: string]: string; - }; - /** - * @deprecated Use the Gitlab integration instead - */ - gitlab?: { - api: { [key: string]: string }; - }; - /** - * @deprecated Use the Azure integration instead - */ - azure?: { - baseUrl: string; - api: { [key: string]: string }; - }; - /** - * @deprecated Use the Bitbucket integration instead - */ - bitbucket?: { - api: { [key: string]: string }; - }; }; } diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index 3161448562..69e3e16f5d 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -11,6 +11,9 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "backend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -21,13 +24,13 @@ "backstage" ], "scripts": { - "start": "backstage-cli backend:dev", - "build": "backstage-cli backend:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean", + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean", "build:assets": "node scripts/build-nunjucks.js" }, "dependencies": { @@ -55,7 +58,6 @@ "git-url-parse": "^11.6.0", "globby": "^11.0.0", "handlebars": "^4.7.6", - "helmet": "^4.0.0", "isbinaryfile": "^4.0.8", "isomorphic-git": "^1.8.0", "jsonschema": "^1.2.6", diff --git a/plugins/scaffolder-backend/src/lib/catalog/CatalogEntityClient.ts b/plugins/scaffolder-backend/src/lib/catalog/CatalogEntityClient.ts deleted file mode 100644 index 430afa5b5d..0000000000 --- a/plugins/scaffolder-backend/src/lib/catalog/CatalogEntityClient.ts +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { TemplateEntityV1beta2 } from '@backstage/catalog-model'; -import { CatalogApi } from '@backstage/catalog-client'; -import { ConflictError, NotFoundError } from '@backstage/errors'; - -/** - * A catalog client tailored for reading out entity data from the catalog. - */ -export class CatalogEntityClient { - constructor(private readonly catalogClient: CatalogApi) {} - - /** - * Looks up a single template using a template name. - * - * Throws a NotFoundError or ConflictError if 0 or multiple templates are found. - */ - async findTemplate( - templateName: string, - options?: { token?: string }, - ): Promise { - const { items: templates } = (await this.catalogClient.getEntities( - { - filter: { - kind: 'template', - 'metadata.name': templateName, - }, - }, - options, - )) as { items: TemplateEntityV1beta2[] }; - - if (templates.length !== 1) { - if (templates.length > 1) { - throw new ConflictError( - 'Templates lookup resulted in multiple matches', - ); - } else { - throw new NotFoundError('Template not found'); - } - } - - return templates[0]; - } -} diff --git a/plugins/scaffolder-backend/src/lib/catalog/index.ts b/plugins/scaffolder-backend/src/lib/catalog/index.ts deleted file mode 100644 index ea693b00b3..0000000000 --- a/plugins/scaffolder-backend/src/lib/catalog/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -export { CatalogEntityClient } from './CatalogEntityClient'; diff --git a/plugins/scaffolder-backend/src/lib/index.ts b/plugins/scaffolder-backend/src/lib/index.ts index dbb4348a2c..20096f9c03 100644 --- a/plugins/scaffolder-backend/src/lib/index.ts +++ b/plugins/scaffolder-backend/src/lib/index.ts @@ -14,5 +14,4 @@ * limitations under the License. */ -export * from './catalog'; export * from './templating'; diff --git a/plugins/scaffolder-backend/src/processor/ScaffolderEntitiesProcessor.ts b/plugins/scaffolder-backend/src/processor/ScaffolderEntitiesProcessor.ts index 4f3c13f342..b90f3498c0 100644 --- a/plugins/scaffolder-backend/src/processor/ScaffolderEntitiesProcessor.ts +++ b/plugins/scaffolder-backend/src/processor/ScaffolderEntitiesProcessor.ts @@ -21,7 +21,6 @@ import { parseEntityRef, RELATION_OWNED_BY, RELATION_OWNER_OF, - entityKindSchemaValidator, } from '@backstage/catalog-model'; import { CatalogProcessor, @@ -30,18 +29,16 @@ import { } from '@backstage/plugin-catalog-backend'; import { TemplateEntityV1beta3, - templateEntityV1beta3Schema, + templateEntityV1beta3Validator, } from '@backstage/plugin-scaffolder-common'; /** @public */ export class ScaffolderEntitiesProcessor implements CatalogProcessor { - private readonly validators = [ - entityKindSchemaValidator(templateEntityV1beta3Schema), - ]; + private readonly validators = [templateEntityV1beta3Validator]; async validateEntityKind(entity: Entity): Promise { for (const validator of this.validators) { - if (validator(entity)) { + if (await validator.check(entity)) { return true; } } diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/TemplateActionRegistry.ts b/plugins/scaffolder-backend/src/scaffolder/actions/TemplateActionRegistry.ts index cd31db49eb..e546d5bf9a 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/TemplateActionRegistry.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/TemplateActionRegistry.ts @@ -14,13 +14,14 @@ * limitations under the License. */ -import { InputBase, TemplateAction } from './types'; +import { JsonObject } from '@backstage/types'; import { ConflictError, NotFoundError } from '@backstage/errors'; +import { TemplateAction } from './types'; export class TemplateActionRegistry { private readonly actions = new Map>(); - register(action: TemplateAction) { + register(action: TemplateAction) { if (this.actions.has(action.id)) { throw new ConflictError( `Template action with ID '${action.id}' has already been registered`, @@ -29,7 +30,7 @@ export class TemplateActionRegistry { this.actions.set(action.id, action); } - get(actionId: string): TemplateAction { + get(actionId: string): TemplateAction { const action = this.actions.get(actionId); if (!action) { throw new NotFoundError( @@ -39,7 +40,7 @@ export class TemplateActionRegistry { return action; } - list(): TemplateAction[] { + list(): TemplateAction[] { return [...this.actions.values()]; } } diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/catalog/write.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/catalog/write.test.ts index 9612780b12..dd6f29f99b 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/catalog/write.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/catalog/write.test.ts @@ -23,7 +23,7 @@ const fsMock = fs as jest.Mocked; import { PassThrough } from 'stream'; import os from 'os'; import { getVoidLogger } from '@backstage/backend-common'; -import { ORIGIN_LOCATION_ANNOTATION } from '@backstage/catalog-model'; +import { ANNOTATION_ORIGIN_LOCATION } from '@backstage/catalog-model'; import { createCatalogWriteAction } from './write'; import { resolve as resolvePath } from 'path'; import * as yaml from 'yaml'; @@ -51,7 +51,7 @@ describe('catalog:write', () => { name: 'n', namespace: 'ns', annotations: { - [ORIGIN_LOCATION_ANNOTATION]: 'url:https://example.com', + [ANNOTATION_ORIGIN_LOCATION]: 'url:https://example.com', }, }, spec: {}, @@ -79,7 +79,7 @@ describe('catalog:write', () => { name: 'n', namespace: 'ns', annotations: { - [ORIGIN_LOCATION_ANNOTATION]: 'url:https://example.com', + [ANNOTATION_ORIGIN_LOCATION]: 'url:https://example.com', }, }, spec: {}, diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts index 481ab894ec..9df2b7146e 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts @@ -15,6 +15,7 @@ */ import { ContainerRunner, UrlReader } from '@backstage/backend-common'; +import { JsonObject } from '@backstage/types'; import { CatalogApi } from '@backstage/catalog-client'; import { GithubCredentialsProvider, @@ -47,6 +48,7 @@ import { createGithubWebhookAction, } from './github'; import { TemplateFilter } from '../../../lib'; +import { TemplateAction } from '../types'; export const createBuiltinActions = (options: { reader: UrlReader; @@ -55,7 +57,7 @@ export const createBuiltinActions = (options: { containerRunner?: ContainerRunner; config: Config; additionalTemplateFilters?: Record; -}) => { +}): TemplateAction[] => { const { reader, integrations, @@ -126,5 +128,5 @@ export const createBuiltinActions = (options: { ); } - return actions; + return actions as TemplateAction[]; }; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/debug/log.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/debug/log.test.ts index 38c50afecc..ecd0f33e21 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/debug/log.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/debug/log.test.ts @@ -61,7 +61,7 @@ describe('debug:log', () => { const context = { ...mockContext, input: { - listWorkspace: 'true', + listWorkspace: true, }, }; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/template.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/template.test.ts index 6ee8f8ce01..2f9bfd3796 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/template.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/template.test.ts @@ -27,12 +27,18 @@ import { ScmIntegrations } from '@backstage/integration'; import { PassThrough } from 'stream'; import { fetchContents } from './helpers'; import { ActionContext, TemplateAction } from '../../types'; -import { createFetchTemplateAction, FetchTemplateInput } from './template'; +import { createFetchTemplateAction } from './template'; jest.mock('./helpers', () => ({ fetchContents: jest.fn(), })); +type FetchTemplateInput = ReturnType< + typeof createFetchTemplateAction +> extends TemplateAction + ? U + : never; + const realFiles = Object.fromEntries( [ resolvePackagePath( diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/template.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/template.ts index 32a3a84070..08dfc46caf 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/template.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/template.ts @@ -28,22 +28,6 @@ import { SecureTemplater, } from '../../../../lib/templating/SecureTemplater'; -type CookieCompatInput = { - copyWithoutRender?: string[]; - cookiecutterCompat?: boolean; -}; - -type ExtensionInput = { - templateFileExtension?: string | boolean; -}; - -export type FetchTemplateInput = { - url: string; - targetPath?: string; - values: any; -} & CookieCompatInput & - ExtensionInput; - export function createFetchTemplateAction(options: { reader: UrlReader; integrations: ScmIntegrations; @@ -51,7 +35,16 @@ export function createFetchTemplateAction(options: { }) { const { reader, integrations, additionalTemplateFilters } = options; - return createTemplateAction({ + return createTemplateAction<{ + url: string; + targetPath?: string; + values: any; + templateFileExtension?: string | boolean; + + // Cookiecutter compat options + copyWithoutRender?: string[]; + cookiecutterCompat?: boolean; + }>({ id: 'fetch:template', description: "Downloads a skeleton, templates variables into file and directory names and content, and places the result in the workspace, or optionally in a subdirectory specified by the 'targetPath' input option.", diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/filesystem/delete.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/filesystem/delete.test.ts index ba8a145721..713de5b0ad 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/filesystem/delete.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/filesystem/delete.test.ts @@ -61,28 +61,28 @@ describe('fs:delete', () => { await expect( action.handler({ ...mockContext, - input: { files: undefined }, + input: { files: undefined } as any, }), ).rejects.toThrow(/files must be an Array/); await expect( action.handler({ ...mockContext, - input: { files: {} }, + input: { files: {} } as any, }), ).rejects.toThrow(/files must be an Array/); await expect( action.handler({ ...mockContext, - input: { files: '' }, + input: { files: '' } as any, }), ).rejects.toThrow(/files must be an Array/); await expect( action.handler({ ...mockContext, - input: { files: null }, + input: { files: null } as any, }), ).rejects.toThrow(/files must be an Array/); }); diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/filesystem/rename.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/filesystem/rename.test.ts index 8452735083..b12e4269c2 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/filesystem/rename.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/filesystem/rename.test.ts @@ -76,28 +76,28 @@ describe('fs:rename', () => { await expect( action.handler({ ...mockContext, - input: { files: undefined }, + input: { files: undefined } as any, }), ).rejects.toThrow(/files must be an Array/); await expect( action.handler({ ...mockContext, - input: { files: {} }, + input: { files: {} } as any, }), ).rejects.toThrow(/files must be an Array/); await expect( action.handler({ ...mockContext, - input: { files: '' }, + input: { files: '' } as any, }), ).rejects.toThrow(/files must be an Array/); await expect( action.handler({ ...mockContext, - input: { files: null }, + input: { files: null } as any, }), ).rejects.toThrow(/files must be an Array/); }); @@ -106,21 +106,21 @@ describe('fs:rename', () => { await expect( action.handler({ ...mockContext, - input: { files: ['old.md'] }, + input: { files: ['old.md'] } as any, }), ).rejects.toThrow(/each file must have a from and to property/); await expect( action.handler({ ...mockContext, - input: { files: [{ from: 'old.md' }] }, + input: { files: [{ from: 'old.md' }] } as any, }), ).rejects.toThrow(/each file must have a from and to property/); await expect( action.handler({ ...mockContext, - input: { files: [{ to: 'new.md' }] }, + input: { files: [{ to: 'new.md' }] } as any, }), ).rejects.toThrow(/each file must have a from and to property/); }); diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/filesystem/rename.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/filesystem/rename.ts index 4bdba96750..c3e128cec5 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/filesystem/rename.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/filesystem/rename.ts @@ -17,16 +17,16 @@ import { createTemplateAction } from '../../createTemplateAction'; import { resolveSafeChildPath } from '@backstage/backend-common'; import { InputError } from '@backstage/errors'; -import { JsonObject } from '@backstage/types'; import fs from 'fs-extra'; -interface FilesToRename extends JsonObject { - from: string; - to: string; -} - export const createFilesystemRenameAction = () => { - return createTemplateAction<{ files: FilesToRename }>({ + return createTemplateAction<{ + files: Array<{ + from: string; + to: string; + overwrite?: boolean; + }>; + }>({ id: 'fs:rename', description: 'Renames files and directories within the workspace', schema: { diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubWebhook.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubWebhook.ts index 660c7793f2..0c93ae1dd5 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubWebhook.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubWebhook.ts @@ -23,8 +23,6 @@ import { OctokitProvider } from './OctokitProvider'; import { emitterEventNames } from '@octokit/webhooks'; import { assertError } from '@backstage/errors'; -type ContentType = 'form' | 'json'; - export function createGithubWebhookAction(options: { integrations: ScmIntegrationRegistry; defaultWebhookSecret?: string; @@ -45,7 +43,7 @@ export function createGithubWebhookAction(options: { webhookSecret?: string; events?: string[]; active?: boolean; - contentType?: ContentType; + contentType?: 'form' | 'json'; insecureSsl?: boolean; token?: string; }>({ diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/helpers.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/helpers.ts index 92b578d385..9303b5e487 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/helpers.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/helpers.ts @@ -58,7 +58,9 @@ export const runCommand = async ({ process.on('close', code => { if (code !== 0) { - return reject(`Command ${command} failed, exit code: ${code}`); + return reject( + new Error(`Command ${command} failed, exit code: ${code}`), + ); } return resolve(); }); diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.test.ts index 3d14710f3e..5493219d57 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.test.ts @@ -51,7 +51,7 @@ describe('publish:bitbucket', () => { const mockContext = { input: { repoUrl: 'bitbucket.org?workspace=workspace&project=project&repo=repo', - repoVisibility: 'private', + repoVisibility: 'private' as const, }, workspacePath: 'lol', logger: getVoidLogger(), diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.ts index 8ba8592642..47ebce0550 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.ts @@ -29,7 +29,7 @@ const createBitbucketCloudRepository = async (opts: { workspace: string; project: string; repo: string; - description: string; + description?: string; repoVisibility: 'private' | 'public'; authorization: string; }) => { @@ -91,7 +91,7 @@ const createBitbucketServerRepository = async (opts: { host: string; project: string; repo: string; - description: string; + description?: string; repoVisibility: 'private' | 'public'; authorization: string; apiBaseUrl?: string; @@ -200,11 +200,11 @@ export function createPublishBitbucketAction(options: { return createTemplateAction<{ repoUrl: string; - description: string; + description?: string; defaultBranch?: string; - repoVisibility: 'private' | 'public'; + repoVisibility?: 'private' | 'public'; sourcePath?: string; - enableLFS: boolean; + enableLFS?: boolean; token?: string; }>({ id: 'publish:bitbucket', diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.test.ts index 5467ca651c..1e58635bbe 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.test.ts @@ -52,7 +52,7 @@ describe('publish:github', () => { input: { repoUrl: 'github.com?repo=repo&owner=owner', description: 'description', - repoVisibility: 'private', + repoVisibility: 'private' as const, access: 'owner/blam', }, workspacePath: 'lol', diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts index 139fad04d4..cabe40986f 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts @@ -28,9 +28,6 @@ import { Config } from '@backstage/config'; import { OctokitProvider } from '../github/OctokitProvider'; import { assertError } from '@backstage/errors'; -type Permission = 'pull' | 'push' | 'admin' | 'maintain' | 'triage'; -type Collaborator = { access: Permission; username: string }; - export function createPublishGithubAction(options: { integrations: ScmIntegrationRegistry; config: Config; @@ -50,8 +47,11 @@ export function createPublishGithubAction(options: { defaultBranch?: string; sourcePath?: string; requireCodeOwnerReviews?: boolean; - repoVisibility: 'private' | 'internal' | 'public'; - collaborators: Collaborator[]; + repoVisibility?: 'private' | 'internal' | 'public'; + collaborators?: Array<{ + username: string; + access: 'pull' | 'push' | 'admin' | 'maintain' | 'triage'; + }>; token?: string; topics?: string[]; }>({ diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/githubPullRequest.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/githubPullRequest.test.ts index 20ea4b03da..64d3bc41de 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/githubPullRequest.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/githubPullRequest.test.ts @@ -28,13 +28,18 @@ import { ActionContext, TemplateAction } from '../../types'; import { ClientFactoryInput, createPublishGithubPullRequestAction, - GithubPullRequestActionInput, PullRequestCreator, } from './githubPullRequest'; const root = os.platform() === 'win32' ? 'C:\\root' : '/root'; const workspacePath = resolvePath(root, 'my-workspace'); +type GithubPullRequestActionInput = ReturnType< + typeof createPublishGithubPullRequestAction +> extends TemplateAction + ? U + : never; + describe('createPublishGithubPullRequestAction', () => { let instance: TemplateAction; let fakeClient: PullRequestCreator; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/githubPullRequest.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/githubPullRequest.ts index 80333c4966..c329b6b6f3 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/githubPullRequest.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/githubPullRequest.ts @@ -48,16 +48,6 @@ export type PullRequestCreatorConstructor = ( octokit: Octokit, ) => PullRequestCreator; -export type GithubPullRequestActionInput = { - title: string; - branchName: string; - description: string; - repoUrl: string; - targetPath?: string; - sourcePath?: string; - token?: string; -}; - export type ClientFactoryInput = { integrations: ScmIntegrationRegistry; githubCredentialsProvider?: GithubCredentialsProvider; @@ -122,7 +112,15 @@ export const createPublishGithubPullRequestAction = ({ githubCredentialsProvider, clientFactory = defaultClientFactory, }: CreateGithubPullRequestActionOptions) => { - return createTemplateAction({ + return createTemplateAction<{ + title: string; + branchName: string; + description: string; + repoUrl: string; + targetPath?: string; + sourcePath?: string; + token?: string; + }>({ id: 'publish:github:pull-request', schema: { input: { diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.test.ts index a32fea8830..db4ad5a019 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.test.ts @@ -45,7 +45,7 @@ describe('publish:gitlab', () => { const mockContext = { input: { repoUrl: 'gitlab.com?repo=repo&owner=owner', - repoVisibility: 'private', + repoVisibility: 'private' as const, }, workspacePath: 'lol', logger: getVoidLogger(), diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.ts index 48979306b1..a3c1919b63 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.ts @@ -31,7 +31,7 @@ export function createPublishGitlabAction(options: { return createTemplateAction<{ repoUrl: string; defaultBranch?: string; - repoVisibility: 'private' | 'internal' | 'public'; + repoVisibility?: 'private' | 'internal' | 'public'; sourcePath?: string; token?: string; }>({ diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts index bf687268c3..e04eb5cdb5 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts @@ -24,22 +24,20 @@ import { InputError } from '@backstage/errors'; import { parseRepoUrl } from './util'; import { resolveSafeChildPath } from '@backstage/backend-common'; -export type GitlabMergeRequestActionInput = { - projectid: string; - repoUrl: string; - title: string; - description: string; - branchName: string; - targetPath: string; - token?: string; -}; - export const createPublishGitlabMergeRequestAction = (options: { integrations: ScmIntegrationRegistry; }) => { const { integrations } = options; - return createTemplateAction({ + return createTemplateAction<{ + projectid: string; + repoUrl: string; + title: string; + description: string; + branchName: string; + targetPath: string; + token?: string; + }>({ id: 'publish:gitlab:merge-request', schema: { input: { diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/createTemplateAction.ts b/plugins/scaffolder-backend/src/scaffolder/actions/createTemplateAction.ts index a741900f9d..243f39e070 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/createTemplateAction.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/createTemplateAction.ts @@ -14,11 +14,12 @@ * limitations under the License. */ -import { InputBase, TemplateAction } from './types'; +import { JsonObject } from '@backstage/types'; +import { TemplateAction } from './types'; -export const createTemplateAction = ( - templateAction: TemplateAction, -): TemplateAction => { +export const createTemplateAction = ( + templateAction: TemplateAction, +): TemplateAction => { // TODO(blam): Can add some more validation here to validate the action later on return templateAction; }; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/types.ts b/plugins/scaffolder-backend/src/scaffolder/actions/types.ts index 4b842e8c5c..6008e8183f 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/types.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/types.ts @@ -20,11 +20,7 @@ import { JsonValue, JsonObject } from '@backstage/types'; import { Schema } from 'jsonschema'; import { TaskSecrets, TemplateMetadata } from '../tasks/types'; -type PartialJsonObject = Partial; -type PartialJsonValue = PartialJsonObject | JsonValue | undefined; -export type InputBase = Partial<{ [name: string]: PartialJsonValue }>; - -export type ActionContext = { +export type ActionContext = { /** * Base URL for the location of the task spec, typically the url of the source entity file. */ @@ -32,12 +28,6 @@ export type ActionContext = { logger: Logger; logStream: Writable; - - /** - * User token forwarded from initial request, for use in subsequent api requests - * @deprecated use `secrets.backstageToken` instead - */ - token?: string | undefined; secrets?: TaskSecrets; workspacePath: string; input: Input; @@ -51,7 +41,7 @@ export type ActionContext = { metadata?: TemplateMetadata; }; -export type TemplateAction = { +export type TemplateAction = { id: string; description?: string; schema?: { diff --git a/plugins/scaffolder-backend/src/scaffolder/index.ts b/plugins/scaffolder-backend/src/scaffolder/index.ts index e055223d8c..0c6b5e01cc 100644 --- a/plugins/scaffolder-backend/src/scaffolder/index.ts +++ b/plugins/scaffolder-backend/src/scaffolder/index.ts @@ -13,5 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + export * from './actions'; export * from './tasks'; diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/HandlebarsWorkflowRunner.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/HandlebarsWorkflowRunner.ts index 91c82edebb..86e719c828 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/HandlebarsWorkflowRunner.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/HandlebarsWorkflowRunner.ts @@ -236,8 +236,6 @@ export class HandlebarsWorkflowRunner implements WorkflowRunner { logger: taskLogger, logStream: stream, input, - // this token is deprecated, and will be removed in favour of secrets.backstageToken instead. - token: task.secrets?.token, secrets: task.secrets ?? {}, workspacePath, async createTemporaryDirectory() { diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.test.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.test.ts index 1597c575ac..f46d969eb8 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.test.ts @@ -203,13 +203,15 @@ describe('DefaultWorkflowRunner', () => { ], }, { - token: fakeToken, + backstageToken: fakeToken, }, ); await runner.execute(task); - expect(fakeActionHandler.mock.calls[0][0].token).toEqual(fakeToken); + expect(fakeActionHandler.mock.calls[0][0].secrets).toEqual( + expect.objectContaining({ backstageToken: fakeToken }), + ); }); }); diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts index 889e94d000..5d39d0bc00 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts @@ -258,17 +258,9 @@ export class NunjucksWorkflowRunner implements WorkflowRunner { const tmpDirs = new Array(); const stepOutput: { [outputName: string]: JsonValue } = {}; - if (!task.spec.metadata) { - console.warn( - 'DEPRECATION NOTICE: metadata is undefined. metadata will be required in the future.', - ); - } - await action.handler({ baseUrl: task.spec.baseUrl, input, - // this token is deprecated, and will be removed in favour of secrets.backstageToken instead. - token: task.secrets?.token, secrets: task.secrets ?? {}, logger: taskLogger, logStream: streamLogger, diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.test.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.test.ts index 130f6ced13..93285a4ab3 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.test.ts @@ -38,7 +38,7 @@ async function createStore(): Promise { describe('StorageTaskBroker', () => { let storage: DatabaseTaskStore; - const fakeSecrets = { token: 'secret' } as TaskSecrets; + const fakeSecrets = { backstageToken: 'secret' } as TaskSecrets; beforeAll(async () => { storage = await createStore(); diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/types.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/types.ts index 8caee87f57..8b28fe562c 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/types.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/types.ts @@ -90,8 +90,6 @@ export type SerializedTaskEvent = { * @public */ export type TaskSecrets = Record & { - /** @deprecated Use `backstageToken` instead */ - token?: string; backstageToken?: string; }; diff --git a/plugins/scaffolder-backend/src/service/helpers.ts b/plugins/scaffolder-backend/src/service/helpers.ts index 6741ab3379..5cfc58d586 100644 --- a/plugins/scaffolder-backend/src/service/helpers.ts +++ b/plugins/scaffolder-backend/src/service/helpers.ts @@ -14,14 +14,21 @@ * limitations under the License. */ +import { CatalogApi } from '@backstage/catalog-client'; import { Entity, - LOCATION_ANNOTATION, - parseLocationReference, - SOURCE_LOCATION_ANNOTATION, + ANNOTATION_LOCATION, + parseLocationRef, + ANNOTATION_SOURCE_LOCATION, + EntityRef, + parseEntityRef, } from '@backstage/catalog-model'; import { Config } from '@backstage/config'; -import { assertError } from '@backstage/errors'; +import { assertError, ConflictError, NotFoundError } from '@backstage/errors'; +import { + TemplateEntityV1beta2, + TemplateEntityV1beta3, +} from '@backstage/plugin-scaffolder-common'; import fs from 'fs-extra'; import os from 'os'; import { Logger } from 'winston'; @@ -59,15 +66,15 @@ export async function getWorkingDirectory( * For file locations this will return a `file://` URL. */ export function getEntityBaseUrl(entity: Entity): string | undefined { - let location = entity.metadata.annotations?.[SOURCE_LOCATION_ANNOTATION]; + let location = entity.metadata.annotations?.[ANNOTATION_SOURCE_LOCATION]; if (!location) { - location = entity.metadata.annotations?.[LOCATION_ANNOTATION]; + location = entity.metadata.annotations?.[ANNOTATION_LOCATION]; } if (!location) { return undefined; } - const { type, target } = parseLocationReference(location); + const { type, target } = parseLocationRef(location); if (type === 'url') { return target; } else if (type === 'file') { @@ -78,3 +85,49 @@ export function getEntityBaseUrl(entity: Entity): string | undefined { // what the url is pointing to makes sense to use as a baseUrl return undefined; } + +/** + * Will use the provided CatalogApi to go find the template entity ref that is provided with and additional token + * Returns the first matching template, throws a NotFoundError or ConflictError if 0 or multiple templates are found. + */ +export async function findTemplate({ + entityRef, + token, + catalogApi, +}: { + entityRef: EntityRef; + token?: string; + catalogApi: CatalogApi; +}): Promise { + const parsedEntityRef = parseEntityRef(entityRef, { + defaultKind: 'template', + defaultNamespace: 'default', + }); + const { items } = await catalogApi.getEntities( + { + filter: { + kind: 'template', + 'metadata.name': parsedEntityRef.name, + 'metadata.namespace': parsedEntityRef.namespace, + }, + }, + { + token, + }, + ); + + const templates = items.filter( + (entity): entity is TemplateEntityV1beta3 | TemplateEntityV1beta2 => + entity.kind === 'Template', + ); + + if (templates.length !== 1) { + if (templates.length > 1) { + throw new ConflictError('Templates lookup resulted in multiple matches'); + } else { + throw new NotFoundError('Template not found'); + } + } + + return templates[0]; +} diff --git a/plugins/scaffolder-backend/src/service/router.test.ts b/plugins/scaffolder-backend/src/service/router.test.ts index d8ba15279f..b20dfa5d24 100644 --- a/plugins/scaffolder-backend/src/service/router.test.ts +++ b/plugins/scaffolder-backend/src/service/router.test.ts @@ -36,7 +36,7 @@ import { UrlReaders, } from '@backstage/backend-common'; import { CatalogApi } from '@backstage/catalog-client'; -import { TemplateEntityV1beta2 } from '@backstage/catalog-model'; +import { TemplateEntityV1beta2 } from '@backstage/plugin-scaffolder-common'; import { ConfigReader } from '@backstage/config'; import express from 'express'; import request from 'supertest'; @@ -182,7 +182,7 @@ describe('createRouter', () => { spec: {} as any, status: 'completed', createdAt: '', - secrets: { token: 'secret' }, + secrets: { backstageToken: 'secret' }, }); const response = await request(app).get(`/v2/tasks/a-random-id`); diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index 85ed8a60ab..b2978441bd 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -20,16 +20,20 @@ import { UrlReader, } from '@backstage/backend-common'; import { CatalogApi } from '@backstage/catalog-client'; -import { Entity, TemplateEntityV1beta2 } from '@backstage/catalog-model'; +import { stringifyEntityRef } from '@backstage/catalog-model'; +import { Entity } from '@backstage/catalog-model'; import { Config } from '@backstage/config'; import { InputError, NotFoundError } from '@backstage/errors'; import { ScmIntegrations } from '@backstage/integration'; -import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; +import { + TemplateEntityV1beta2, + TemplateEntityV1beta3, +} from '@backstage/plugin-scaffolder-common'; import express from 'express'; import Router from 'express-promise-router'; import { validate } from 'jsonschema'; import { Logger } from 'winston'; -import { CatalogEntityClient, TemplateFilter } from '../lib'; +import { TemplateFilter } from '../lib'; import { createBuiltinActions, DatabaseTaskStore, @@ -40,7 +44,7 @@ import { TemplateActionRegistry, } from '../scaffolder'; import { StorageTaskBroker } from '../scaffolder/tasks/StorageTaskBroker'; -import { getEntityBaseUrl, getWorkingDirectory } from './helpers'; +import { getEntityBaseUrl, getWorkingDirectory, findTemplate } from './helpers'; /** * RouterOptions @@ -89,7 +93,6 @@ export async function createRouter( const logger = parentLogger.child({ plugin: 'scaffolder' }); const workingDirectory = await getWorkingDirectory(config, logger); - const entityClient = new CatalogEntityClient(catalogClient); const integrations = ScmIntegrations.fromConfig(config); let taskBroker: TaskBroker; @@ -148,7 +151,9 @@ export async function createRouter( ); } - const template = await entityClient.findTemplate(name, { + const template = await findTemplate({ + catalogApi: catalogClient, + entityRef: { kind, namespace, name }, token: getBearerToken(req.headers.authorization), }); if (isSupportedTemplate(template)) { @@ -183,16 +188,29 @@ export async function createRouter( const templateName: string = req.body.templateName; const values = req.body.values; const token = getBearerToken(req.headers.authorization); - const template = await entityClient.findTemplate(templateName, { - token, + const template = await findTemplate({ + catalogApi: catalogClient, + entityRef: { + name: templateName, + }, + token: getBearerToken(req.headers.authorization), }); let taskSpec: TaskSpec; if (isSupportedTemplate(template)) { + if (template.apiVersion === 'backstage.io/v1beta2') { + logger.warn( + `Scaffolding ${stringifyEntityRef( + template, + )} with deprecated apiVersion ${ + template.apiVersion + }. Please migrate the template to backstage.io/v1beta3. https://backstage.io/docs/features/software-templates/migrating-from-v1beta2-to-v1beta3`, + ); + } + for (const parameters of [template.spec.parameters ?? []].flat()) { const result = validate(values, parameters); - if (!result.valid) { res.status(400).json({ errors: result.errors }); return; diff --git a/plugins/scaffolder-common/api-report.md b/plugins/scaffolder-common/api-report.md index 3bca8e74ed..8d2324a2dd 100644 --- a/plugins/scaffolder-common/api-report.md +++ b/plugins/scaffolder-common/api-report.md @@ -5,13 +5,13 @@ ```ts import { Entity } from '@backstage/catalog-model'; import { JsonObject } from '@backstage/types'; -import { JSONSchema } from '@backstage/catalog-model'; import { JsonValue } from '@backstage/types'; +import { KindValidator } from '@backstage/catalog-model'; // @public export type TaskSpec = TaskSpecV1beta2 | TaskSpecV1beta3; -// @public +// @public @deprecated export interface TaskSpecV1beta2 { // (undocumented) apiVersion: 'backstage.io/v1beta2'; @@ -61,7 +61,34 @@ export interface TaskStep { name: string; } -// @public (undocumented) +// @public @deprecated +export interface TemplateEntityV1beta2 extends Entity { + // (undocumented) + apiVersion: 'backstage.io/v1beta2'; + // (undocumented) + kind: 'Template'; + // (undocumented) + spec: { + type: string; + parameters?: JsonObject | JsonObject[]; + steps: Array<{ + id?: string; + name?: string; + action: string; + input?: JsonObject; + if?: string | boolean; + }>; + output?: { + [name: string]: string; + }; + owner?: string; + }; +} + +// @public @deprecated +export const templateEntityV1beta2Validator: KindValidator; + +// @public export interface TemplateEntityV1beta3 extends Entity { // (undocumented) apiVersion: 'scaffolder.backstage.io/v1beta3'; @@ -85,8 +112,8 @@ export interface TemplateEntityV1beta3 extends Entity { }; } -// @public (undocumented) -export const templateEntityV1beta3Schema: JSONSchema; +// @public +export const templateEntityV1beta3Validator: KindValidator; // @public export type TemplateMetadata = { diff --git a/plugins/scaffolder-common/package.json b/plugins/scaffolder-common/package.json index 6b03a7c884..92e54d87f5 100644 --- a/plugins/scaffolder-common/package.json +++ b/plugins/scaffolder-common/package.json @@ -12,6 +12,9 @@ "module": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "common-library" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -25,12 +28,12 @@ "dist" ], "scripts": { - "build": "backstage-cli build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "bugs": { "url": "https://github.com/backstage/backstage/issues" diff --git a/plugins/scaffolder-common/src/TaskSpec.ts b/plugins/scaffolder-common/src/TaskSpec.ts index 8d8ccedbad..1cbe41b28c 100644 --- a/plugins/scaffolder-common/src/TaskSpec.ts +++ b/plugins/scaffolder-common/src/TaskSpec.ts @@ -17,7 +17,8 @@ import { JsonValue, JsonObject } from '@backstage/types'; /** - * TemplateMetadata + * Metadata about the Template that was the originator of a scaffolder task, as + * stored in the database. * * @public */ @@ -26,7 +27,7 @@ export type TemplateMetadata = { }; /** - * TaskStep + * An individual step of a scaffolder task, as stored in the database. * * @public */ @@ -39,9 +40,12 @@ export interface TaskStep { } /** - * TaskSpecV1beta2 + * A scaffolder task as stored in the database, generated from a v1beta2 + * apiVersion Template. * * @public + * @deprecated Please convert your templates to TaskSpecV1beta3 on apiVersion + * scaffolder.backstage.io/v1beta3 */ export interface TaskSpecV1beta2 { apiVersion: 'backstage.io/v1beta2'; @@ -53,7 +57,8 @@ export interface TaskSpecV1beta2 { } /** - * TaskSpecV1beta3 + * A scaffolder task as stored in the database, generated from a v1beta3 + * apiVersion Template. * * @public */ @@ -67,7 +72,7 @@ export interface TaskSpecV1beta3 { } /** - * TaskSpec + * A scaffolder task as stored in the database, generated from a Template. * * @public */ diff --git a/packages/catalog-model/src/schema/kinds/Template.v1beta2.schema.json b/plugins/scaffolder-common/src/Template.v1beta2.schema.json similarity index 100% rename from packages/catalog-model/src/schema/kinds/Template.v1beta2.schema.json rename to plugins/scaffolder-common/src/Template.v1beta2.schema.json diff --git a/packages/catalog-model/src/kinds/TemplateEntityV1beta2.test.ts b/plugins/scaffolder-common/src/TemplateEntityV1beta2.test.ts similarity index 100% rename from packages/catalog-model/src/kinds/TemplateEntityV1beta2.test.ts rename to plugins/scaffolder-common/src/TemplateEntityV1beta2.test.ts diff --git a/packages/catalog-model/src/kinds/TemplateEntityV1beta2.ts b/plugins/scaffolder-common/src/TemplateEntityV1beta2.ts similarity index 58% rename from packages/catalog-model/src/kinds/TemplateEntityV1beta2.ts rename to plugins/scaffolder-common/src/TemplateEntityV1beta2.ts index f4c2dfb5bc..280caec52f 100644 --- a/packages/catalog-model/src/kinds/TemplateEntityV1beta2.ts +++ b/plugins/scaffolder-common/src/TemplateEntityV1beta2.ts @@ -14,15 +14,21 @@ * limitations under the License. */ +import { + Entity, + entityKindSchemaValidator, + KindValidator, +} from '@backstage/catalog-model'; import { JsonObject } from '@backstage/types'; -import type { Entity } from '../entity/Entity'; -import schema from '../schema/kinds/Template.v1beta2.schema.json'; -import { ajvCompiledJsonSchemaValidator } from './util'; +import schema from './Template.v1beta2.schema.json'; /** - * Backstage catalog Template kind Entity. Templates are used by the Scaffolder plugin to create new Components. + * Backstage catalog Template kind Entity. Templates are used by the Scaffolder + * plugin to create new entities, such as Components. * * @public + * @deprecated Please convert your templates to TemplateEntityV1beta3 on + * apiVersion scaffolder.backstage.io/v1beta3 */ export interface TemplateEntityV1beta2 extends Entity { apiVersion: 'backstage.io/v1beta2'; @@ -42,10 +48,18 @@ export interface TemplateEntityV1beta2 extends Entity { }; } +const validator = entityKindSchemaValidator(schema); + /** - * {@link KindValidator} for {@link TemplateEntityV1beta2}. + * Entity data validator for {@link TemplateEntityV1beta2}. * * @public + * @deprecated Please convert your templates to TemplateEntityV1beta3 on + * apiVersion scaffolder.backstage.io/v1beta3 */ -export const templateEntityV1beta2Validator = - ajvCompiledJsonSchemaValidator(schema); +export const templateEntityV1beta2Validator: KindValidator = { + // TODO(freben): Emulate the old KindValidator until we fix that type + async check(data: Entity) { + return validator(data) === data; + }, +}; diff --git a/plugins/scaffolder-common/src/TemplateEntityV1beta3.ts b/plugins/scaffolder-common/src/TemplateEntityV1beta3.ts index 2aefa5fd6b..13b699de69 100644 --- a/plugins/scaffolder-common/src/TemplateEntityV1beta3.ts +++ b/plugins/scaffolder-common/src/TemplateEntityV1beta3.ts @@ -14,10 +14,20 @@ * limitations under the License. */ +import { + Entity, + entityKindSchemaValidator, + KindValidator, +} from '@backstage/catalog-model'; import { JsonObject } from '@backstage/types'; -import { Entity } from '@backstage/catalog-model'; +import schema from './Template.v1beta3.schema.json'; -/** @public */ +/** + * Backstage catalog Template kind Entity. Templates are used by the Scaffolder + * plugin to create new entities, such as Components. + * + * @public + */ export interface TemplateEntityV1beta3 extends Entity { apiVersion: 'scaffolder.backstage.io/v1beta3'; kind: 'Template'; @@ -35,3 +45,17 @@ export interface TemplateEntityV1beta3 extends Entity { owner?: string; }; } + +const validator = entityKindSchemaValidator(schema); + +/** + * Entity data validator for {@link TemplateEntityV1beta3}. + * + * @public + */ +export const templateEntityV1beta3Validator: KindValidator = { + // TODO(freben): Emulate the old KindValidator until we fix that type + async check(data: Entity) { + return validator(data) === data; + }, +}; diff --git a/plugins/scaffolder-common/src/index.ts b/plugins/scaffolder-common/src/index.ts index 1197f48fed..e74a5f988f 100644 --- a/plugins/scaffolder-common/src/index.ts +++ b/plugins/scaffolder-common/src/index.ts @@ -20,15 +20,8 @@ * @packageDocumentation */ -import { JSONSchema } from '@backstage/catalog-model'; -import v1beta3Schema from './Template.v1beta3.schema.json'; - -export type { TemplateEntityV1beta3 } from './TemplateEntityV1beta3'; - -/** @public */ -export const templateEntityV1beta3Schema: JSONSchema = v1beta3Schema as Omit< - JSONSchema, - 'examples' ->; - export * from './TaskSpec'; +export { templateEntityV1beta2Validator } from './TemplateEntityV1beta2'; +export type { TemplateEntityV1beta2 } from './TemplateEntityV1beta2'; +export { templateEntityV1beta3Validator } from './TemplateEntityV1beta3'; +export type { TemplateEntityV1beta3 } from './TemplateEntityV1beta3'; diff --git a/plugins/scaffolder/api-report.md b/plugins/scaffolder/api-report.md index f8ae64cd82..0a9145c780 100644 --- a/plugins/scaffolder/api-report.md +++ b/plugins/scaffolder/api-report.md @@ -27,7 +27,7 @@ import { ReactNode } from 'react'; import { RouteRef } from '@backstage/core-plugin-api'; import { ScmIntegrationRegistry } from '@backstage/integration'; import { TaskSpec } from '@backstage/plugin-scaffolder-common'; -import { TemplateEntityV1beta2 } from '@backstage/catalog-model'; +import { TemplateEntityV1beta2 } from '@backstage/plugin-scaffolder-common'; // Warning: (ae-missing-release-tag) "createScaffolderFieldExtension" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index 0e31d6c4a5..1c9baafd48 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -11,6 +11,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -21,14 +24,14 @@ "backstage" ], "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/catalog-client": "^0.6.0", diff --git a/plugins/scaffolder/src/components/Router.tsx b/plugins/scaffolder/src/components/Router.tsx index 601844780d..6b0de28ea9 100644 --- a/plugins/scaffolder/src/components/Router.tsx +++ b/plugins/scaffolder/src/components/Router.tsx @@ -16,7 +16,8 @@ import React, { ComponentType } from 'react'; import { Routes, Route, useOutlet } from 'react-router'; -import { TemplateEntityV1beta2, Entity } from '@backstage/catalog-model'; +import { Entity } from '@backstage/catalog-model'; +import { TemplateEntityV1beta2 } from '@backstage/plugin-scaffolder-common'; import { ScaffolderPage } from './ScaffolderPage'; import { TemplatePage } from './TemplatePage'; import { TaskPage } from './TaskPage'; diff --git a/plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPage.tsx b/plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPage.tsx index 116b7ed82a..ec5d1272ab 100644 --- a/plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPage.tsx +++ b/plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPage.tsx @@ -23,7 +23,8 @@ import { Page, SupportButton, } from '@backstage/core-components'; -import { TemplateEntityV1beta2, Entity } from '@backstage/catalog-model'; +import { Entity } from '@backstage/catalog-model'; +import { TemplateEntityV1beta2 } from '@backstage/plugin-scaffolder-common'; import { useRouteRef } from '@backstage/core-plugin-api'; import { EntityKindPicker, diff --git a/plugins/scaffolder/src/components/TemplateCard/TemplateCard.tsx b/plugins/scaffolder/src/components/TemplateCard/TemplateCard.tsx index a02e6d3b14..3495409dd6 100644 --- a/plugins/scaffolder/src/components/TemplateCard/TemplateCard.tsx +++ b/plugins/scaffolder/src/components/TemplateCard/TemplateCard.tsx @@ -13,11 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { - Entity, - RELATION_OWNED_BY, - TemplateEntityV1beta2, -} from '@backstage/catalog-model'; +import { Entity, RELATION_OWNED_BY } from '@backstage/catalog-model'; +import { TemplateEntityV1beta2 } from '@backstage/plugin-scaffolder-common'; import { ScmIntegrationIcon, scmIntegrationsApiRef, @@ -123,7 +120,8 @@ const DeprecationWarning = () => { const Title = ( - This template syntax is deprecated. Click for more info. + This template uses a syntax that has been deprecated, and should be + migrated to a newer syntax. Click for more info. ); @@ -131,7 +129,7 @@ const DeprecationWarning = () => {
diff --git a/plugins/scaffolder/src/components/TemplateList/TemplateList.tsx b/plugins/scaffolder/src/components/TemplateList/TemplateList.tsx index 2ac0def547..a7f0b49132 100644 --- a/plugins/scaffolder/src/components/TemplateList/TemplateList.tsx +++ b/plugins/scaffolder/src/components/TemplateList/TemplateList.tsx @@ -15,11 +15,8 @@ */ import React, { ComponentType } from 'react'; -import { - Entity, - stringifyEntityRef, - TemplateEntityV1beta2, -} from '@backstage/catalog-model'; +import { Entity, stringifyEntityRef } from '@backstage/catalog-model'; +import { TemplateEntityV1beta2 } from '@backstage/plugin-scaffolder-common'; import { Content, ContentHeader, @@ -90,6 +87,7 @@ export const TemplateList = ({ ))} diff --git a/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.test.tsx b/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.test.tsx index 3dc609a63b..82f12ac0a3 100644 --- a/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.test.tsx +++ b/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.test.tsx @@ -46,7 +46,7 @@ describe('', () => { getEntityByName: jest.fn(), getEntities: jest.fn(async () => ({ items: entities })), addLocation: jest.fn(), - getLocationByEntity: jest.fn(), + getLocationByRef: jest.fn(), removeEntityByUid: jest.fn(), } as any; let Wrapper: React.ComponentType; diff --git a/plugins/scaffolder/src/components/fields/EntityTagsPicker/EntityTagsPicker.tsx b/plugins/scaffolder/src/components/fields/EntityTagsPicker/EntityTagsPicker.tsx index b0577acfeb..bf566bd616 100644 --- a/plugins/scaffolder/src/components/fields/EntityTagsPicker/EntityTagsPicker.tsx +++ b/plugins/scaffolder/src/components/fields/EntityTagsPicker/EntityTagsPicker.tsx @@ -16,7 +16,7 @@ import React, { useState } from 'react'; import useAsync from 'react-use/lib/useAsync'; import useEffectOnce from 'react-use/lib/useEffectOnce'; -import { CatalogEntitiesRequest } from '@backstage/catalog-client'; +import { GetEntitiesRequest } from '@backstage/catalog-client'; import { Entity, makeValidator } from '@backstage/catalog-model'; import { useApi } from '@backstage/core-plugin-api'; import { catalogApiRef } from '@backstage/plugin-catalog-react'; @@ -40,7 +40,7 @@ export const EntityTagsPicker = ({ const kinds = uiSchema['ui:options']?.kinds as string[]; const { loading, value: existingTags } = useAsync(async () => { - const tagsRequest: CatalogEntitiesRequest = { fields: ['metadata.tags'] }; + const tagsRequest: GetEntitiesRequest = { fields: ['metadata.tags'] }; if (kinds) { tagsRequest.filter = { kind: kinds }; } diff --git a/plugins/scaffolder/src/components/fields/OwnerPicker/OwnerPicker.test.tsx b/plugins/scaffolder/src/components/fields/OwnerPicker/OwnerPicker.test.tsx index 31992fbc8a..b78d3add9e 100644 --- a/plugins/scaffolder/src/components/fields/OwnerPicker/OwnerPicker.test.tsx +++ b/plugins/scaffolder/src/components/fields/OwnerPicker/OwnerPicker.test.tsx @@ -43,7 +43,7 @@ describe('', () => { getEntityByName: jest.fn(), getEntities: jest.fn(async () => ({ items: entities })), addLocation: jest.fn(), - getLocationByEntity: jest.fn(), + getLocationByRef: jest.fn(), removeEntityByUid: jest.fn(), } as any; let Wrapper: React.ComponentType; diff --git a/plugins/search-backend-module-elasticsearch/package.json b/plugins/search-backend-module-elasticsearch/package.json index 6b21d0d0ab..51df462b8a 100644 --- a/plugins/search-backend-module-elasticsearch/package.json +++ b/plugins/search-backend-module-elasticsearch/package.json @@ -10,14 +10,17 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "backend-plugin-module" + }, "scripts": { - "start": "backstage-cli backend:dev", - "build": "backstage-cli backend:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/config": "^0.1.13", @@ -32,7 +35,7 @@ "devDependencies": { "@backstage/backend-common": "^0.10.7-next.0", "@backstage/cli": "^0.13.2-next.0", - "@elastic/elasticsearch-mock": "^0.3.0" + "@elastic/elasticsearch-mock": "^1.0.0" }, "files": [ "dist", diff --git a/plugins/search-backend-module-pg/package.json b/plugins/search-backend-module-pg/package.json index 392b9af73a..979d60a9bc 100644 --- a/plugins/search-backend-module-pg/package.json +++ b/plugins/search-backend-module-pg/package.json @@ -10,14 +10,17 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "backend-plugin-module" + }, "scripts": { - "start": "backstage-cli backend:dev", - "build": "backstage-cli backend:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/backend-common": "^0.10.7", diff --git a/plugins/search-backend-node/package.json b/plugins/search-backend-node/package.json index e2d83d0f4f..eaa1e171cf 100644 --- a/plugins/search-backend-node/package.json +++ b/plugins/search-backend-node/package.json @@ -10,14 +10,17 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "node-library" + }, "scripts": { - "start": "backstage-cli backend:dev", - "build": "backstage-cli backend:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/search-common": "^0.2.2", diff --git a/plugins/search-backend/package.json b/plugins/search-backend/package.json index 117e484c62..db91541ccd 100644 --- a/plugins/search-backend/package.json +++ b/plugins/search-backend/package.json @@ -10,14 +10,17 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "backend-plugin" + }, "scripts": { - "start": "backstage-cli backend:dev", - "build": "backstage-cli backend:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/backend-common": "^0.10.7", diff --git a/plugins/search/api-report.md b/plugins/search/api-report.md index a45f02564f..10ce787a6c 100644 --- a/plugins/search/api-report.md +++ b/plugins/search/api-report.md @@ -145,9 +145,17 @@ export const SearchContextProvider: ({ initialState, children, }: React_2.PropsWithChildren<{ - initialState?: SettableSearchContext | undefined; + initialState?: SearchContextState | undefined; }>) => JSX.Element; +// @public +export type SearchContextState = { + term: string; + types: string[]; + filters: JsonObject; + pageCursor?: string; +}; + // Warning: (ae-missing-release-tag) "SearchFilter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -201,6 +209,7 @@ export type SearchFilterWrapperProps = SearchFilterComponentProps & { // @public (undocumented) export const SearchModal: ({ open, + hidden, toggleModal, }: SearchModalProps) => JSX.Element; @@ -208,9 +217,8 @@ export const SearchModal: ({ // // @public (undocumented) export interface SearchModalProps { - // (undocumented) + hidden?: boolean; open?: boolean; - // (undocumented) toggleModal: () => void; } @@ -320,7 +328,13 @@ export type SidebarSearchProps = { // @public (undocumented) export const useSearch: () => SearchContextValue; -// Warnings were encountered during analysis: -// -// src/components/SearchContext/SearchContext.d.ts:23:5 - (ae-forgotten-export) The symbol "SettableSearchContext" needs to be exported by the entry point index.d.ts +// @public +export function useSearchModal(initialState?: boolean): { + state: { + hidden: boolean; + open: boolean; + }; + toggleModal: () => void; + setOpen: (open: boolean) => void; +}; ``` diff --git a/plugins/search/package.json b/plugins/search/package.json index 34baf41306..8832d41332 100644 --- a/plugins/search/package.json +++ b/plugins/search/package.json @@ -10,6 +10,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -20,14 +23,14 @@ "backstage" ], "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/catalog-model": "^0.9.10", diff --git a/plugins/search/src/components/LegacySearchPage/LegacySearchResult.tsx b/plugins/search/src/components/LegacySearchPage/LegacySearchResult.tsx index f48ffb61d7..ba92dba710 100644 --- a/plugins/search/src/components/LegacySearchPage/LegacySearchResult.tsx +++ b/plugins/search/src/components/LegacySearchPage/LegacySearchResult.tsx @@ -20,7 +20,7 @@ import useAsync from 'react-use/lib/useAsync'; import { catalogApiRef } from '@backstage/plugin-catalog-react'; import { Filters, FiltersButton, FiltersState } from './Filters'; -import { Entity, ENTITY_DEFAULT_NAMESPACE } from '@backstage/catalog-model'; +import { Entity, DEFAULT_NAMESPACE } from '@backstage/catalog-model'; import { EmptyState, @@ -156,7 +156,7 @@ export const SearchResult = ({ searchQuery }: SearchResultProps) => { : undefined, url: `/catalog/${ entity.metadata.namespace?.toLocaleLowerCase('en-US') || - ENTITY_DEFAULT_NAMESPACE + DEFAULT_NAMESPACE }/${entity.kind.toLocaleLowerCase('en-US')}/${entity.metadata.name}`, })); }, []); diff --git a/plugins/search/src/components/SearchBar/SearchBar.tsx b/plugins/search/src/components/SearchBar/SearchBar.tsx index 2ddec22294..a203d27c93 100644 --- a/plugins/search/src/components/SearchBar/SearchBar.tsx +++ b/plugins/search/src/components/SearchBar/SearchBar.tsx @@ -169,13 +169,16 @@ export type SearchBarProps = Partial; export const SearchBar = ({ onChange, ...props }: SearchBarProps) => { const { term, setTerm } = useSearch(); - const handleChange = (newValue: string) => { - if (onChange) { - onChange(newValue); - } else { - setTerm(newValue); - } - }; + const handleChange = useCallback( + (newValue: string) => { + if (onChange) { + onChange(newValue); + } else { + setTerm(newValue); + } + }, + [onChange, setTerm], + ); return ; }; diff --git a/plugins/search/src/components/SearchContext/SearchContext.tsx b/plugins/search/src/components/SearchContext/SearchContext.tsx index 336041bf1f..a9f42fe5ca 100644 --- a/plugins/search/src/components/SearchContext/SearchContext.tsx +++ b/plugins/search/src/components/SearchContext/SearchContext.tsx @@ -31,45 +31,41 @@ import { searchApiRef } from '../../apis'; type SearchContextValue = { result: AsyncState; - term: string; setTerm: React.Dispatch>; - types: string[]; setTypes: React.Dispatch>; - filters: JsonObject; setFilters: React.Dispatch>; - open?: boolean; - toggleModal: () => void; - pageCursor?: string; setPageCursor: React.Dispatch>; fetchNextPage?: React.DispatchWithoutAction; fetchPreviousPage?: React.DispatchWithoutAction; -}; +} & SearchContextState; -type SettableSearchContext = Omit< - SearchContextValue, - | 'result' - | 'setTerm' - | 'setTypes' - | 'setFilters' - | 'toggleModal' - | 'setPageCursor' - | 'fetchNextPage' - | 'fetchPreviousPage' ->; +/** + * The initial state of `SearchContextProvider`. + * + * @public + */ +export type SearchContextState = { + term: string; + types: string[]; + filters: JsonObject; + pageCursor?: string; +}; export const SearchContext = createContext( undefined, ); +const searchInitialState: SearchContextState = { + term: '', + pageCursor: undefined, + filters: {}, + types: [], +}; + export const SearchContextProvider = ({ - initialState = { - term: '', - pageCursor: undefined, - filters: {}, - types: [], - }, + initialState = searchInitialState, children, -}: PropsWithChildren<{ initialState?: SettableSearchContext }>) => { +}: PropsWithChildren<{ initialState?: SearchContextState }>) => { const searchApi = useApi(searchApiRef); const [pageCursor, setPageCursor] = useState( initialState.pageCursor, @@ -77,11 +73,6 @@ export const SearchContextProvider = ({ const [filters, setFilters] = useState(initialState.filters); const [term, setTerm] = useState(initialState.term); const [types, setTypes] = useState(initialState.types); - const [open, setOpen] = useState(false); - const toggleModal = useCallback( - (): void => setOpen(prevState => !prevState), - [], - ); const prevTerm = usePrevious(term); @@ -90,7 +81,7 @@ export const SearchContextProvider = ({ searchApi.query({ term, filters, - pageCursor: pageCursor, + pageCursor, types, }), [term, filters, types, pageCursor], @@ -118,8 +109,6 @@ export const SearchContextProvider = ({ result, filters, setFilters, - open, - toggleModal, term, setTerm, types, diff --git a/plugins/search/src/components/SearchContext/SearchContextForStorybook.stories.tsx b/plugins/search/src/components/SearchContext/SearchContextForStorybook.stories.tsx index e969e0d8cc..36d670a1ed 100644 --- a/plugins/search/src/components/SearchContext/SearchContextForStorybook.stories.tsx +++ b/plugins/search/src/components/SearchContext/SearchContextForStorybook.stories.tsx @@ -16,7 +16,7 @@ import { ApiProvider } from '@backstage/core-app-api'; import { SearchResultSet } from '@backstage/search-common'; import { TestApiRegistry } from '@backstage/test-utils'; -import React, { ComponentProps } from 'react'; +import React, { ComponentProps, PropsWithChildren } from 'react'; import { searchApiRef } from '../../apis'; import { SearchContextProvider as RealSearchContextProvider } from './SearchContext'; @@ -33,13 +33,16 @@ type QueryResultProps = { export const SearchContextProvider = ( props: ComponentProps & QueryResultProps, ) => { - const { mockedResults, ...contextProps } = props; - const query: any = () => Promise.resolve(mockedResults || {}); - const apiRegistry = TestApiRegistry.from([searchApiRef, { query }]); - return ( - - - + + + ); }; + +export function SearchApiProvider(props: PropsWithChildren) { + const { mockedResults, children } = props; + const query: any = () => Promise.resolve(mockedResults || {}); + const apiRegistry = TestApiRegistry.from([searchApiRef, { query }]); + return ; +} diff --git a/plugins/search/src/components/SearchContext/index.tsx b/plugins/search/src/components/SearchContext/index.tsx index 682ade916f..8651e661c1 100644 --- a/plugins/search/src/components/SearchContext/index.tsx +++ b/plugins/search/src/components/SearchContext/index.tsx @@ -19,3 +19,5 @@ export { SearchContext, useSearch, } from './SearchContext'; + +export type { SearchContextState } from './SearchContext'; diff --git a/plugins/search/src/components/SearchModal/SearchModal.stories.tsx b/plugins/search/src/components/SearchModal/SearchModal.stories.tsx index e4b89000d5..aa0ad0479a 100644 --- a/plugins/search/src/components/SearchModal/SearchModal.stories.tsx +++ b/plugins/search/src/components/SearchModal/SearchModal.stories.tsx @@ -18,9 +18,9 @@ import { wrapInTestApp } from '@backstage/test-utils'; import { Button } from '@material-ui/core'; import React, { ComponentType } from 'react'; import { rootRouteRef } from '../../plugin'; -import { useSearch } from '../SearchContext'; -import { SearchContextProvider } from '../SearchContext/SearchContextForStorybook.stories'; +import { SearchApiProvider } from '../SearchContext/SearchContextForStorybook.stories'; import { SearchModal } from './SearchModal'; +import { useSearchModal } from './useSearchModal'; const mockResults = { results: [ @@ -57,23 +57,23 @@ export default { decorators: [ (Story: ComponentType<{}>) => wrapInTestApp( - + - , + , { mountedRoutes: { '/search': rootRouteRef } }, ), ], }; export const Default = () => { - const { open, toggleModal } = useSearch(); + const { state, toggleModal } = useSearchModal(); return ( <> - + ); }; diff --git a/plugins/search/src/components/SearchModal/SearchModal.test.tsx b/plugins/search/src/components/SearchModal/SearchModal.test.tsx index b59be710de..d3b2a825e2 100644 --- a/plugins/search/src/components/SearchModal/SearchModal.test.tsx +++ b/plugins/search/src/components/SearchModal/SearchModal.test.tsx @@ -24,7 +24,6 @@ import { rootRouteRef } from '../../plugin'; import { searchApiRef } from '../../apis'; import { SearchModal } from './SearchModal'; -import { SearchContextProvider } from '../SearchContext'; describe('SearchModal', () => { const query = jest.fn().mockResolvedValue({ results: [] }); @@ -34,14 +33,16 @@ describe('SearchModal', () => { [searchApiRef, { query }], ); + beforeEach(() => { + query.mockClear(); + }); + const toggleModal = jest.fn(); it('Should render the Modal correctly', async () => { await renderInTestApp( - - - + , { mountedRoutes: { @@ -51,14 +52,13 @@ describe('SearchModal', () => { ); expect(screen.getByRole('dialog')).toBeInTheDocument(); + expect(query).toHaveBeenCalledTimes(1); }); it('Calls toggleModal handler', async () => { await renderInTestApp( - - - + , { mountedRoutes: { @@ -66,7 +66,25 @@ describe('SearchModal', () => { }, }, ); + + expect(query).toHaveBeenCalledTimes(1); userEvent.keyboard('{esc}'); expect(toggleModal).toHaveBeenCalledTimes(1); }); + + it('should render SearchModal hiding its content', async () => { + const { getByTestId } = await renderInTestApp( + + , + { + mountedRoutes: { + '/search': rootRouteRef, + }, + }, + ); + + expect(getByTestId('search-bar-next')).toBeInTheDocument(); + expect(getByTestId('search-bar-next')).not.toBeVisible(); + }); }); diff --git a/plugins/search/src/components/SearchModal/SearchModal.tsx b/plugins/search/src/components/SearchModal/SearchModal.tsx index 1f0a879f96..2a71e53ea8 100644 --- a/plugins/search/src/components/SearchModal/SearchModal.tsx +++ b/plugins/search/src/components/SearchModal/SearchModal.tsx @@ -38,7 +38,21 @@ import { Link, useContent } from '@backstage/core-components'; import { rootRouteRef } from '../../plugin'; export interface SearchModalProps { + /** + * If true, it renders the modal. + */ open?: boolean; + /** + * This is supposed to be used together with the open prop. + * If `hidden` is true, it hides the modal. + * If `open` is false, the value of `hidden` has no effect on the modal. + * Use `open` for controlling whether the modal should be rendered or not. + */ + hidden?: boolean; + /** + * a function invoked when a search item is pressed or when the dialog + * should be closed. + */ toggleModal: () => void; } @@ -57,7 +71,7 @@ const useStyles = makeStyles(theme => ({ viewResultsLink: { verticalAlign: '0.5em' }, })); -export const Modal = ({ open = true, toggleModal }: SearchModalProps) => { +export const Modal = ({ toggleModal }: SearchModalProps) => { const getSearchLink = useRouteRef(rootRouteRef); const classes = useStyles(); @@ -75,16 +89,7 @@ export const Modal = ({ open = true, toggleModal }: SearchModalProps) => { }; return ( - + <> @@ -139,14 +144,34 @@ export const Modal = ({ open = true, toggleModal }: SearchModalProps) => { - + ); }; -export const SearchModal = ({ open = true, toggleModal }: SearchModalProps) => { +export const SearchModal = ({ + open = true, + hidden, + toggleModal, +}: SearchModalProps) => { + const classes = useStyles(); + return ( - - - + ); }; diff --git a/plugins/search/src/components/SearchModal/index.tsx b/plugins/search/src/components/SearchModal/index.tsx index ec0053951d..646dff0a62 100644 --- a/plugins/search/src/components/SearchModal/index.tsx +++ b/plugins/search/src/components/SearchModal/index.tsx @@ -15,3 +15,4 @@ */ export { SearchModal } from './SearchModal'; export type { SearchModalProps } from './SearchModal'; +export { useSearchModal } from './useSearchModal'; diff --git a/plugins/search/src/components/SearchModal/useSearchModal.test.tsx b/plugins/search/src/components/SearchModal/useSearchModal.test.tsx new file mode 100644 index 0000000000..424dffff76 --- /dev/null +++ b/plugins/search/src/components/SearchModal/useSearchModal.test.tsx @@ -0,0 +1,73 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { act, renderHook } from '@testing-library/react-hooks'; +import { useSearchModal } from './useSearchModal'; + +describe('useSearchModal', () => { + it.each([ + [true, { open: true, hidden: false }], + [false, { open: false, hidden: true }], + ])( + 'should return the correct state when initial state is %s', + (initialState, result) => { + const rendered = renderHook(() => useSearchModal(initialState)); + + expect(rendered.result.current.state).toEqual(result); + }, + ); + + it('should keep open forever to true once modal is toggled', () => { + const rendered = renderHook(() => useSearchModal()); + act(() => rendered.result.current.toggleModal()); + + expect(rendered.result.current.state).toEqual({ + open: true, + hidden: false, + }); + + act(() => rendered.result.current.toggleModal()); + expect(rendered.result.current.state).toEqual({ + open: true, + hidden: true, + }); + }); + + it('should keep open to false if setOpen(false) is invoked on an initially closed modal', () => { + const rendered = renderHook(() => useSearchModal()); + act(() => rendered.result.current.setOpen(false)); + expect(rendered.result.current.state).toEqual({ + open: false, + hidden: true, + }); + }); + + it('should keep open forever to true even when the modal transition from opened to closed', () => { + const rendered = renderHook(() => useSearchModal()); + + act(() => rendered.result.current.setOpen(true)); + expect(rendered.result.current.state).toEqual({ + open: true, + hidden: false, + }); + + act(() => rendered.result.current.setOpen(false)); + expect(rendered.result.current.state).toEqual({ + open: true, + hidden: true, + }); + }); +}); diff --git a/plugins/search/src/components/SearchModal/useSearchModal.tsx b/plugins/search/src/components/SearchModal/useSearchModal.tsx new file mode 100644 index 0000000000..3871687d1a --- /dev/null +++ b/plugins/search/src/components/SearchModal/useSearchModal.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 { useCallback, useState } from 'react'; + +/** + * Use this hook to manage the state of {@link SearchModal} + * and change its visibility. + * + * @public + * + * @param initialState - pass `true` to make the modal initially visible + * @returns an object containing the state of the modal together with + * functions for changing the visibility of the modal. + */ +export function useSearchModal(initialState = false) { + const [state, setState] = useState({ + hidden: !initialState, + open: initialState, + }); + + const toggleModal = useCallback( + () => + setState(prevState => ({ + open: true, + hidden: !prevState.hidden, + })), + [], + ); + + const setOpen = useCallback( + (open: boolean) => + setState(prevState => ({ + open: prevState.open || open, + hidden: !open, + })), + [], + ); + + return { state, toggleModal, setOpen }; +} diff --git a/plugins/search/src/components/SearchType/SearchType.Accordion.test.tsx b/plugins/search/src/components/SearchType/SearchType.Accordion.test.tsx index 6b4171a024..1aae64c463 100644 --- a/plugins/search/src/components/SearchType/SearchType.Accordion.test.tsx +++ b/plugins/search/src/components/SearchType/SearchType.Accordion.test.tsx @@ -33,7 +33,6 @@ describe('SearchType.Accordion', () => { term: '', types: [], filters: {}, - toggleModal: jest.fn(), setTerm: jest.fn(), setTypes: jest.fn(), setFilters: jest.fn(), diff --git a/plugins/search/src/components/SearchType/SearchType.Tabs.test.tsx b/plugins/search/src/components/SearchType/SearchType.Tabs.test.tsx index 54f09023bc..741ee6e83f 100644 --- a/plugins/search/src/components/SearchType/SearchType.Tabs.test.tsx +++ b/plugins/search/src/components/SearchType/SearchType.Tabs.test.tsx @@ -33,7 +33,6 @@ describe('SearchType.Tabs', () => { term: '', types: [], filters: {}, - toggleModal: jest.fn(), setTerm: jest.fn(), setTypes: jest.fn(), setFilters: jest.fn(), diff --git a/plugins/search/src/components/SidebarSearchModal/SidebarSearchModal.tsx b/plugins/search/src/components/SidebarSearchModal/SidebarSearchModal.tsx index b8f20de67d..bbf4eef4e4 100644 --- a/plugins/search/src/components/SidebarSearchModal/SidebarSearchModal.tsx +++ b/plugins/search/src/components/SidebarSearchModal/SidebarSearchModal.tsx @@ -17,15 +17,14 @@ import React from 'react'; import SearchIcon from '@material-ui/icons/Search'; import { SidebarItem } from '@backstage/core-components'; import { IconComponent } from '@backstage/core-plugin-api'; -import { SearchModal } from '../SearchModal'; -import { useSearch } from '../SearchContext'; +import { SearchModal, useSearchModal } from '../SearchModal'; export type SidebarSearchModalProps = { icon?: IconComponent; }; export const SidebarSearchModal = (props: SidebarSearchModalProps) => { - const { open, toggleModal } = useSearch(); + const { state, toggleModal } = useSearchModal(); const Icon = props.icon ? props.icon : SearchIcon; return ( @@ -36,7 +35,7 @@ export const SidebarSearchModal = (props: SidebarSearchModalProps) => { text="Search" onClick={toggleModal} /> - + ); }; diff --git a/plugins/search/src/index.ts b/plugins/search/src/index.ts index 99c3f5177b..cef0355fb4 100644 --- a/plugins/search/src/index.ts +++ b/plugins/search/src/index.ts @@ -32,13 +32,14 @@ export type { SearchBarProps, } from './components/SearchBar'; export { SearchContextProvider, useSearch } from './components/SearchContext'; +export type { SearchContextState } from './components/SearchContext'; export { SearchFilter, SearchFilterNext } from './components/SearchFilter'; export type { SearchAutocompleteFilterProps, SearchFilterComponentProps, SearchFilterWrapperProps, } from './components/SearchFilter'; -export { SearchModal } from './components/SearchModal'; +export { SearchModal, useSearchModal } from './components/SearchModal'; export type { SearchModalProps } from './components/SearchModal'; export { SearchPage as Router } from './components/SearchPage'; export { SearchResultPager } from './components/SearchResultPager'; diff --git a/plugins/sentry/package.json b/plugins/sentry/package.json index 48137dc5e1..f87f140cb4 100644 --- a/plugins/sentry/package.json +++ b/plugins/sentry/package.json @@ -11,6 +11,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -22,14 +25,14 @@ "sentry" ], "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/catalog-model": "^0.9.10", diff --git a/plugins/shortcuts/package.json b/plugins/shortcuts/package.json index d3bcb14f15..43a5da6efb 100644 --- a/plugins/shortcuts/package.json +++ b/plugins/shortcuts/package.json @@ -10,15 +10,18 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/core-components": "^0.8.8", diff --git a/plugins/shortcuts/src/ShortcutIcon.tsx b/plugins/shortcuts/src/ShortcutIcon.tsx index 94a894fcb0..be78928452 100644 --- a/plugins/shortcuts/src/ShortcutIcon.tsx +++ b/plugins/shortcuts/src/ShortcutIcon.tsx @@ -15,33 +15,28 @@ */ import React from 'react'; +import { makeStyles } from '@material-ui/core/styles'; +import Avatar from '@material-ui/core/Avatar'; type Props = { text: string; color: string; }; -export const ShortcutIcon = ({ text, color }: Props) => { - const size = 28; - return ( - - - - {text} - - - ); +const useStyles = makeStyles(theme => ({ + avatar: (props: Props) => ({ + color: theme.palette.getContrastText(props.color), + backgroundColor: props.color, + width: 28, + height: 28, + fontWeight: 'bold', + fontSize: 13, + filter: 'contrast(150%) brightness(1.4)', + }), +})); + +export const ShortcutIcon = (props: Props) => { + const classes = useStyles(props); + + return {props.text}; }; diff --git a/plugins/shortcuts/src/ShortcutItem.test.tsx b/plugins/shortcuts/src/ShortcutItem.test.tsx index e080026f00..528eb13efa 100644 --- a/plugins/shortcuts/src/ShortcutItem.test.tsx +++ b/plugins/shortcuts/src/ShortcutItem.test.tsx @@ -24,7 +24,6 @@ import { renderInTestApp, wrapInTestApp, } from '@backstage/test-utils'; -import { pageTheme } from '@backstage/theme'; import { SidebarContext } from '@backstage/core-components'; describe('ShortcutItem', () => { @@ -77,27 +76,4 @@ describe('ShortcutItem', () => { expect(screen.getByText('MT')).toBeInTheDocument(); }); }); - - it('gets the color based on the theme', async () => { - const { rerender } = await renderInTestApp( - , - ); - - expect(document.querySelector('circle')?.getAttribute('fill')).toEqual( - pageTheme.tool.colors[0], - ); - - const newShortcut: Shortcut = { - id: 'id', - url: '/catalog', - title: 'some title', - }; - rerender(wrapInTestApp()); - - await waitFor(() => { - expect(document.querySelector('circle')?.getAttribute('fill')).toEqual( - pageTheme.home.colors[0], - ); - }); - }); }); diff --git a/plugins/sonarqube/package.json b/plugins/sonarqube/package.json index fb2de64ffe..40863c7cbd 100644 --- a/plugins/sonarqube/package.json +++ b/plugins/sonarqube/package.json @@ -11,6 +11,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -23,14 +26,14 @@ "sonarcloud" ], "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/catalog-model": "^0.9.10", diff --git a/plugins/splunk-on-call/package.json b/plugins/splunk-on-call/package.json index 1bc8948d95..fe0e050209 100644 --- a/plugins/splunk-on-call/package.json +++ b/plugins/splunk-on-call/package.json @@ -10,6 +10,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -21,14 +24,14 @@ "splunk-on-call" ], "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/catalog-model": "^0.9.10", diff --git a/plugins/tech-insights-backend-module-jsonfc/package.json b/plugins/tech-insights-backend-module-jsonfc/package.json index fc2c6b7add..9dfa01769a 100644 --- a/plugins/tech-insights-backend-module-jsonfc/package.json +++ b/plugins/tech-insights-backend-module-jsonfc/package.json @@ -10,6 +10,9 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "backend-plugin-module" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -22,13 +25,13 @@ "scorecard" ], "scripts": { - "start": "backstage-cli backend:dev", - "build": "backstage-cli backend:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/backend-common": "^0.10.7", diff --git a/plugins/tech-insights-backend/package.json b/plugins/tech-insights-backend/package.json index 5a60e478d8..96f253519e 100644 --- a/plugins/tech-insights-backend/package.json +++ b/plugins/tech-insights-backend/package.json @@ -10,6 +10,9 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "backend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -22,13 +25,13 @@ "reporting" ], "scripts": { - "start": "backstage-cli backend:dev", - "build": "backstage-cli backend:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/backend-common": "^0.10.7", diff --git a/plugins/tech-insights-backend/src/service/fact/factRetrievers/entityMetadataFactRetriever.test.ts b/plugins/tech-insights-backend/src/service/fact/factRetrievers/entityMetadataFactRetriever.test.ts index b99f6a1c02..a51ce0ab83 100644 --- a/plugins/tech-insights-backend/src/service/fact/factRetrievers/entityMetadataFactRetriever.test.ts +++ b/plugins/tech-insights-backend/src/service/fact/factRetrievers/entityMetadataFactRetriever.test.ts @@ -14,13 +14,13 @@ * limitations under the License. */ -import { Entity, RELATION_OWNED_BY } from '@backstage/catalog-model'; +import { RELATION_OWNED_BY } from '@backstage/catalog-model'; import { PluginEndpointDiscovery, getVoidLogger, } from '@backstage/backend-common'; import { ConfigReader } from '@backstage/config'; -import { CatalogListResponse } from '@backstage/catalog-client'; +import { GetEntitiesResponse } from '@backstage/catalog-client'; import { entityMetadataFactRetriever } from './entityMetadataFactRetriever'; const getEntitiesMock = jest.fn(); @@ -36,7 +36,7 @@ const discovery: jest.Mocked = { getExternalBaseUrl: jest.fn(), }; -const defaultEntityListResponse: CatalogListResponse = { +const defaultEntityListResponse: GetEntitiesResponse = { items: [ { apiVersion: 'backstage.io/v1beta1', diff --git a/plugins/tech-insights-backend/src/service/fact/factRetrievers/entityOwnershipFactRetriever.test.ts b/plugins/tech-insights-backend/src/service/fact/factRetrievers/entityOwnershipFactRetriever.test.ts index ea0801f17c..2108379f06 100644 --- a/plugins/tech-insights-backend/src/service/fact/factRetrievers/entityOwnershipFactRetriever.test.ts +++ b/plugins/tech-insights-backend/src/service/fact/factRetrievers/entityOwnershipFactRetriever.test.ts @@ -15,13 +15,13 @@ */ import { entityOwnershipFactRetriever } from './entityOwnershipFactRetriever'; -import { Entity, RELATION_OWNED_BY } from '@backstage/catalog-model'; +import { RELATION_OWNED_BY } from '@backstage/catalog-model'; import { PluginEndpointDiscovery, getVoidLogger, } from '@backstage/backend-common'; import { ConfigReader } from '@backstage/config'; -import { CatalogListResponse } from '@backstage/catalog-client'; +import { GetEntitiesResponse } from '@backstage/catalog-client'; const getEntitiesMock = jest.fn(); jest.mock('@backstage/catalog-client', () => { @@ -36,7 +36,7 @@ const discovery: jest.Mocked = { getExternalBaseUrl: jest.fn(), }; -const defaultEntityListResponse: CatalogListResponse = { +const defaultEntityListResponse: GetEntitiesResponse = { items: [ { apiVersion: 'backstage.io/v1beta1', diff --git a/plugins/tech-insights-backend/src/service/fact/factRetrievers/techdocsFactRetriever.test.ts b/plugins/tech-insights-backend/src/service/fact/factRetrievers/techdocsFactRetriever.test.ts index 6ed9b12523..a3604129b7 100644 --- a/plugins/tech-insights-backend/src/service/fact/factRetrievers/techdocsFactRetriever.test.ts +++ b/plugins/tech-insights-backend/src/service/fact/factRetrievers/techdocsFactRetriever.test.ts @@ -15,13 +15,13 @@ */ import { techdocsFactRetriever } from './techdocsFactRetriever'; -import { Entity, RELATION_OWNED_BY } from '@backstage/catalog-model'; +import { RELATION_OWNED_BY } from '@backstage/catalog-model'; import { PluginEndpointDiscovery, getVoidLogger, } from '@backstage/backend-common'; import { ConfigReader } from '@backstage/config'; -import { CatalogListResponse } from '@backstage/catalog-client'; +import { GetEntitiesResponse } from '@backstage/catalog-client'; const getEntitiesMock = jest.fn(); jest.mock('@backstage/catalog-client', () => { @@ -36,7 +36,7 @@ const discovery: jest.Mocked = { getExternalBaseUrl: jest.fn(), }; -const defaultEntityListResponse: CatalogListResponse = { +const defaultEntityListResponse: GetEntitiesResponse = { items: [ { apiVersion: 'backstage.io/v1beta1', diff --git a/plugins/tech-insights-common/package.json b/plugins/tech-insights-common/package.json index a0b840da74..35e0c956e3 100644 --- a/plugins/tech-insights-common/package.json +++ b/plugins/tech-insights-common/package.json @@ -10,6 +10,9 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "common-library" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -22,12 +25,12 @@ ], "scripts": { "start": "backstage-cli backend:dev", - "build": "backstage-cli backend:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@types/luxon": "^2.0.5", diff --git a/plugins/tech-insights-node/package.json b/plugins/tech-insights-node/package.json index 05c6f10071..4290d2fc1b 100644 --- a/plugins/tech-insights-node/package.json +++ b/plugins/tech-insights-node/package.json @@ -10,6 +10,9 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "backend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -21,13 +24,13 @@ "tech-insights" ], "scripts": { - "start": "backstage-cli backend:dev", - "build": "backstage-cli backend:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/backend-common": "^0.10.7", diff --git a/plugins/tech-insights/package.json b/plugins/tech-insights/package.json index b7b1b6877c..d364fa3b40 100644 --- a/plugins/tech-insights/package.json +++ b/plugins/tech-insights/package.json @@ -9,15 +9,18 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/catalog-model": "^0.9.10", diff --git a/plugins/tech-radar/package.json b/plugins/tech-radar/package.json index 29601d1755..590c5cbd78 100644 --- a/plugins/tech-radar/package.json +++ b/plugins/tech-radar/package.json @@ -11,6 +11,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -21,14 +24,14 @@ "backstage" ], "scripts": { - "build": "backstage-cli plugin:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean", - "start": "backstage-cli plugin:serve" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean", + "start": "backstage-cli package start" }, "dependencies": { "@backstage/core-components": "^0.8.8", diff --git a/plugins/techdocs-backend/package.json b/plugins/techdocs-backend/package.json index 0beabaf719..27d2a952d9 100644 --- a/plugins/techdocs-backend/package.json +++ b/plugins/techdocs-backend/package.json @@ -11,6 +11,9 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "backend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -22,13 +25,13 @@ "techdocs" ], "scripts": { - "start": "backstage-cli backend:dev", - "build": "backstage-cli backend:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/backend-common": "^0.10.7", @@ -41,7 +44,6 @@ "@backstage/search-common": "^0.2.2", "@backstage/techdocs-common": "^0.11.7", "@types/express": "^4.17.6", - "cross-fetch": "^3.1.5", "dockerode": "^3.3.1", "express": "^4.17.1", "express-promise-router": "^4.1.0", diff --git a/plugins/techdocs-backend/src/DocsBuilder/builder.ts b/plugins/techdocs-backend/src/DocsBuilder/builder.ts index 66eb52c1aa..05e9c0ce52 100644 --- a/plugins/techdocs-backend/src/DocsBuilder/builder.ts +++ b/plugins/techdocs-backend/src/DocsBuilder/builder.ts @@ -15,7 +15,7 @@ */ import { Entity, - ENTITY_DEFAULT_NAMESPACE, + DEFAULT_NAMESPACE, stringifyEntityRef, } from '@backstage/catalog-model'; import { Config } from '@backstage/config'; @@ -111,8 +111,7 @@ export class DocsBuilder { try { storedEtag = ( await this.publisher.fetchTechDocsMetadata({ - namespace: - this.entity.metadata.namespace ?? ENTITY_DEFAULT_NAMESPACE, + namespace: this.entity.metadata.namespace ?? DEFAULT_NAMESPACE, kind: this.entity.kind, name: this.entity.metadata.name, }) diff --git a/plugins/techdocs-backend/src/search/DefaultTechDocsCollator.test.ts b/plugins/techdocs-backend/src/search/DefaultTechDocsCollator.test.ts index 7e7545ea1f..e81fc1e7a9 100644 --- a/plugins/techdocs-backend/src/search/DefaultTechDocsCollator.test.ts +++ b/plugins/techdocs-backend/src/search/DefaultTechDocsCollator.test.ts @@ -198,8 +198,8 @@ describe('DefaultTechDocsCollator', () => { componentType: entity!.spec!.type, lifecycle: entity!.spec!.lifecycle, owner: '', - kind: entity.kind, - name: entity.metadata.name, + kind: entity.kind.toLocaleLowerCase('en-US'), + name: entity.metadata.name.toLocaleLowerCase('en-US'), authorization: { resourceRef: `component:default/${entity.metadata.name}`, }, diff --git a/plugins/techdocs-backend/src/search/DefaultTechDocsCollator.ts b/plugins/techdocs-backend/src/search/DefaultTechDocsCollator.ts index 5149fe6c09..987e8c6b15 100644 --- a/plugins/techdocs-backend/src/search/DefaultTechDocsCollator.ts +++ b/plugins/techdocs-backend/src/search/DefaultTechDocsCollator.ts @@ -145,9 +145,7 @@ export class DefaultTechDocsCollator implements DocumentCollator { path: doc.location, }), path: doc.location, - kind: entity.kind, - namespace: entity.metadata.namespace || 'default', - name: entity.metadata.name, + ...entityInfo, entityTitle: entity.metadata.title, componentType: entity.spec?.type?.toString() || 'other', lifecycle: (entity.spec?.lifecycle as string) || '', diff --git a/plugins/techdocs-backend/src/service/DocsSynchronizer.test.ts b/plugins/techdocs-backend/src/service/DocsSynchronizer.test.ts index 1eb8c8f56f..1830dbfcf0 100644 --- a/plugins/techdocs-backend/src/service/DocsSynchronizer.test.ts +++ b/plugins/techdocs-backend/src/service/DocsSynchronizer.test.ts @@ -31,7 +31,7 @@ import { DocsSynchronizer, DocsSynchronizerSyncOpts } from './DocsSynchronizer'; jest.mock('../DocsBuilder'); -jest.mock('cross-fetch', () => ({ +jest.mock('node-fetch', () => ({ __esModule: true, default: async () => { return { diff --git a/plugins/techdocs-backend/src/service/DocsSynchronizer.ts b/plugins/techdocs-backend/src/service/DocsSynchronizer.ts index 4d407ab54a..2979d2efe4 100644 --- a/plugins/techdocs-backend/src/service/DocsSynchronizer.ts +++ b/plugins/techdocs-backend/src/service/DocsSynchronizer.ts @@ -15,7 +15,7 @@ */ import { PluginEndpointDiscovery } from '@backstage/backend-common'; -import { Entity, ENTITY_DEFAULT_NAMESPACE } from '@backstage/catalog-model'; +import { Entity, DEFAULT_NAMESPACE } from '@backstage/catalog-model'; import { Config } from '@backstage/config'; import { assertError, NotFoundError } from '@backstage/errors'; import { ScmIntegrationRegistry } from '@backstage/integration'; @@ -24,7 +24,7 @@ import { PreparerBuilder, PublisherBase, } from '@backstage/techdocs-common'; -import fetch from 'cross-fetch'; +import fetch from 'node-fetch'; import { PassThrough } from 'stream'; import * as winston from 'winston'; import { TechDocsCache } from '../cache'; @@ -177,7 +177,7 @@ export class DocsSynchronizer { // Fetch techdocs_metadata.json from the publisher and from cache. const baseUrl = await discovery.getBaseUrl('techdocs'); - const namespace = entity.metadata?.namespace || ENTITY_DEFAULT_NAMESPACE; + const namespace = entity.metadata?.namespace || DEFAULT_NAMESPACE; const kind = entity.kind; const name = entity.metadata.name; const legacyPathCasing = diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index 794e386136..6e8594a33b 100644 --- a/plugins/techdocs/package.json +++ b/plugins/techdocs/package.json @@ -11,6 +11,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -22,14 +25,14 @@ "techdocs" ], "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/catalog-model": "^0.9.10", diff --git a/plugins/techdocs/src/reader/components/Reader.tsx b/plugins/techdocs/src/reader/components/Reader.tsx index 7869fc1b9b..c12b17b486 100644 --- a/plugins/techdocs/src/reader/components/Reader.tsx +++ b/plugins/techdocs/src/reader/components/Reader.tsx @@ -142,6 +142,7 @@ export const useTechDocsReaderDom = (entityRef: EntityName): Element | null => { const techdocsSanitizer = useApi(configApiRef); const { namespace = '', kind = '', name = '' } = entityRef; const { state, path, content: rawPage } = useTechDocsReader(); + const isDarkTheme = theme.palette.type === 'dark'; const [sidebars, setSidebars] = useState(); const [dom, setDom] = useState(null); @@ -219,6 +220,27 @@ export const useTechDocsReaderDom = (entityRef: EntityName): Element | null => { --md-accent-fg-color: ${theme.palette.primary.main}; --md-default-fg-color--lightest: ${theme.palette.textVerySubtle}; } + .codehilite .gd, .highlight .gd { + background-color: ${isDarkTheme ? 'rgba(248,81,73,0.65)' : '#fdd'}; + } + .codehilite .gi, .highlight .gi { + background-color: ${isDarkTheme ? 'rgba(46,160,67,0.65)' : '#dfd'}; + } + .highlight .kd { + color: ${isDarkTheme ? '#4aaaf7' : '#3b78e7'}; + } + .highlight .k { + color: ${isDarkTheme ? '#4aaaf7' : '#3b78e7'}; + } + .highlight .nx { + color: ${isDarkTheme ? '#ff53a3' : '#ec407a'}; + } + .highlight .s1 { + color: ${isDarkTheme ? '#1cad46' : 'rgb(13, 144, 79)'}; + } + .highlight .kt { + color: ${isDarkTheme ? '#4aaaf7' : '#3e61a2'}; + } .md-main__inner { margin-top: 0; } .md-sidebar { position: fixed; bottom: 100px; width: 20rem; } .md-sidebar--secondary { right: 2rem; } @@ -248,7 +270,7 @@ export const useTechDocsReaderDom = (entityRef: EntityName): Element | null => { } .md-typeset table:not([class]) th { font-weight: bold; } .md-typeset .admonition, .md-typeset details { - font-size: 1rem; + font-size: inherit; } /* style the checkmarks of the task list */ @@ -351,21 +373,22 @@ export const useTechDocsReaderDom = (entityRef: EntityName): Element | null => { }), ]), [ + techdocsSanitizer, + techdocsStorageApi, kind, name, namespace, scmIntegrationsApi, - techdocsStorageApi, - techdocsSanitizer, - theme.palette.action.disabledBackground, - theme.palette.background.default, - theme.palette.background.paper, - theme.palette.primary.main, - theme.palette.success.main, - theme.palette.text.primary, - theme.palette.textSubtle, - theme.palette.textVerySubtle, theme.typography.fontFamily, + theme.palette.text.primary, + theme.palette.primary.main, + theme.palette.background.paper, + theme.palette.background.default, + theme.palette.textVerySubtle, + theme.palette.textSubtle, + theme.palette.action.disabledBackground, + theme.palette.success.main, + isDarkTheme, isPinned, ], ); diff --git a/plugins/todo-backend/package.json b/plugins/todo-backend/package.json index 3371dbbecc..90fcee6e55 100644 --- a/plugins/todo-backend/package.json +++ b/plugins/todo-backend/package.json @@ -10,6 +10,9 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "backend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -17,12 +20,13 @@ "directory": "plugins/todo-backend" }, "scripts": { - "build": "backstage-cli backend:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean", + "start": "backstage-cli package start" }, "dependencies": { "@backstage/backend-common": "^0.10.7", diff --git a/plugins/todo-backend/src/service/TodoReaderService.test.ts b/plugins/todo-backend/src/service/TodoReaderService.test.ts index 3d86a1726b..fbb1341e73 100644 --- a/plugins/todo-backend/src/service/TodoReaderService.test.ts +++ b/plugins/todo-backend/src/service/TodoReaderService.test.ts @@ -45,8 +45,7 @@ function mockCatalogClient(entity?: Entity): jest.Mocked { addLocation: jest.fn(), getEntities: jest.fn(), getEntityByName: jest.fn(), - getOriginLocationByEntity: jest.fn(), - getLocationByEntity: jest.fn(), + getLocationByRef: jest.fn(), getLocationById: jest.fn(), removeLocationById: jest.fn(), removeEntityByUid: jest.fn(), @@ -301,7 +300,7 @@ describe('TodoReaderService', () => { await expect(service.listTodos({ entity: entityName })).rejects.toEqual( expect.objectContaining({ name: 'NotFoundError', - message: 'Entity not found, Component:default/my-component', + message: 'Entity not found, component:default/my-component', }), ); expect(catalogClient.getEntityByName).toHaveBeenCalledWith(entityName, { @@ -321,7 +320,7 @@ describe('TodoReaderService', () => { expect.objectContaining({ name: 'InputError', message: - 'No entity location annotation found for Component:my-component', + 'No entity location annotation found for component:default/my-component', }), ); }); @@ -342,7 +341,7 @@ describe('TodoReaderService', () => { await expect(service.listTodos({ entity: entityName })).rejects.toEqual( expect.objectContaining({ name: 'InputError', - message: `Invalid entity location type for Component:my-component, got 'file'`, + message: `Invalid entity location type for component:default/my-component, got 'file'`, }), ); }); @@ -363,7 +362,7 @@ describe('TodoReaderService', () => { await expect(service.listTodos({ entity: entityName })).rejects.toEqual( expect.objectContaining({ name: 'InputError', - message: `Invalid entity source location type for Component:my-component, got 'file'`, + message: `Invalid entity source location type for component:default/my-component, got 'file'`, }), ); }); diff --git a/plugins/todo-backend/src/service/TodoReaderService.ts b/plugins/todo-backend/src/service/TodoReaderService.ts index 54957d89c4..86f53057da 100644 --- a/plugins/todo-backend/src/service/TodoReaderService.ts +++ b/plugins/todo-backend/src/service/TodoReaderService.ts @@ -17,11 +17,11 @@ import { InputError, NotFoundError } from '@backstage/errors'; import { CatalogApi } from '@backstage/catalog-client'; import { - LOCATION_ANNOTATION, - SOURCE_LOCATION_ANNOTATION, - serializeEntityRef, + ANNOTATION_LOCATION, + ANNOTATION_SOURCE_LOCATION, Entity, - parseLocationReference, + parseLocationRef, + stringifyEntityRef, } from '@backstage/catalog-model'; import { TodoReader } from '../lib'; import { ListTodosRequest, ListTodosResponse, TodoService } from './types'; @@ -71,7 +71,7 @@ export class TodoReaderService implements TodoService { }); if (!entity) { throw new NotFoundError( - `Entity not found, ${serializeEntityRef(req.entity)}`, + `Entity not found, ${stringifyEntityRef(req.entity)}`, ); } @@ -128,12 +128,12 @@ export class TodoReaderService implements TodoService { private getEntitySourceUrl(entity: Entity) { const sourceLocation = - entity.metadata.annotations?.[SOURCE_LOCATION_ANNOTATION]; + entity.metadata.annotations?.[ANNOTATION_SOURCE_LOCATION]; if (sourceLocation) { - const parsed = parseLocationReference(sourceLocation); + const parsed = parseLocationRef(sourceLocation); if (parsed.type !== 'url') { throw new InputError( - `Invalid entity source location type for ${serializeEntityRef( + `Invalid entity source location type for ${stringifyEntityRef( entity, )}, got '${parsed.type}'`, ); @@ -141,12 +141,12 @@ export class TodoReaderService implements TodoService { return parsed.target; } - const location = entity.metadata.annotations?.[LOCATION_ANNOTATION]; + const location = entity.metadata.annotations?.[ANNOTATION_LOCATION]; if (location) { - const parsed = parseLocationReference(location); + const parsed = parseLocationRef(location); if (parsed.type !== 'url') { throw new InputError( - `Invalid entity location type for ${serializeEntityRef( + `Invalid entity location type for ${stringifyEntityRef( entity, )}, got '${parsed.type}'`, ); @@ -154,7 +154,7 @@ export class TodoReaderService implements TodoService { return parsed.target; } throw new InputError( - `No entity location annotation found for ${serializeEntityRef(entity)}`, + `No entity location annotation found for ${stringifyEntityRef(entity)}`, ); } } diff --git a/plugins/todo/dev/index.tsx b/plugins/todo/dev/index.tsx index fe547812ec..375c89e4a4 100644 --- a/plugins/todo/dev/index.tsx +++ b/plugins/todo/dev/index.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { Entity, LOCATION_ANNOTATION } from '@backstage/catalog-model'; +import { Entity, ANNOTATION_LOCATION } from '@backstage/catalog-model'; import { createDevApp } from '@backstage/dev-utils'; import { EntityProvider } from '@backstage/plugin-catalog-react'; import OnlineIcon from '@material-ui/icons/Cloud'; @@ -31,7 +31,7 @@ const entity: Entity = { metadata: { name: 'backstage', annotations: { - [LOCATION_ANNOTATION]: + [ANNOTATION_LOCATION]: 'https://github.com/backstage/backstage/blob/master/catalog-info.yaml', }, }, diff --git a/plugins/todo/package.json b/plugins/todo/package.json index 8282772d90..274ada538f 100644 --- a/plugins/todo/package.json +++ b/plugins/todo/package.json @@ -10,6 +10,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -17,14 +20,14 @@ "directory": "plugins/todo" }, "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/catalog-model": "^0.9.10", diff --git a/plugins/user-settings/package.json b/plugins/user-settings/package.json index 4c33a1ac50..ad8fa2142d 100644 --- a/plugins/user-settings/package.json +++ b/plugins/user-settings/package.json @@ -11,6 +11,9 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "homepage": "https://backstage.io", "repository": { "type": "git", @@ -21,14 +24,14 @@ "backstage" ], "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/core-components": "^0.8.8", diff --git a/plugins/user-settings/src/components/FeatureFlags/EmptyFlags.tsx b/plugins/user-settings/src/components/FeatureFlags/EmptyFlags.tsx index 785f398d6f..0e2b911978 100644 --- a/plugins/user-settings/src/components/FeatureFlags/EmptyFlags.tsx +++ b/plugins/user-settings/src/components/FeatureFlags/EmptyFlags.tsx @@ -22,9 +22,7 @@ const EXAMPLE = `import { createPlugin } from '@backstage/core-plugin-api'; export default createPlugin({ id: 'plugin-name', - register({ router, featureFlags }) { - featureFlags.register('enable-example-feature'); - }, + featureFlags: [{ name: 'enable-example-feature' }], }); `; diff --git a/plugins/xcmetrics/package.json b/plugins/xcmetrics/package.json index b765a1be2d..e9cf5d80ea 100644 --- a/plugins/xcmetrics/package.json +++ b/plugins/xcmetrics/package.json @@ -10,15 +10,18 @@ "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "frontend-plugin" + }, "scripts": { - "build": "backstage-cli plugin:build", - "start": "backstage-cli plugin:serve", - "lint": "backstage-cli lint", - "test": "backstage-cli test", + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", "diff": "backstage-cli plugin:diff", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" }, "dependencies": { "@backstage/core-components": "^0.8.8", diff --git a/storybook/package.json b/storybook/package.json index ea488e94ac..5a3437f697 100644 --- a/storybook/package.json +++ b/storybook/package.json @@ -15,12 +15,12 @@ "react-dom": "^17.0.2" }, "devDependencies": { - "@storybook/addon-a11y": "^6.4.18", - "@storybook/addon-actions": "^6.4.18", - "@storybook/addon-links": "^6.4.18", - "@storybook/addon-storysource": "^6.4.18", - "@storybook/addons": "^6.4.14", - "@storybook/react": "^6.4.18", + "@storybook/addon-a11y": "^6.4.19", + "@storybook/addon-actions": "^6.4.19", + "@storybook/addon-links": "^6.4.19", + "@storybook/addon-storysource": "^6.4.19", + "@storybook/addons": "^6.4.19", + "@storybook/react": "^6.4.19", "storybook-dark-mode": "^1.0.8" }, "peerDependencies": { diff --git a/storybook/yarn.lock b/storybook/yarn.lock index 284ada1cb2..94f7e109ae 100644 --- a/storybook/yarn.lock +++ b/storybook/yarn.lock @@ -1310,19 +1310,19 @@ resolved "https://registry.npmjs.org/@popperjs/core/-/core-2.11.2.tgz#830beaec4b4091a9e9398ac50f865ddea52186b9" integrity sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA== -"@storybook/addon-a11y@^6.4.18": - version "6.4.18" - resolved "https://registry.npmjs.org/@storybook/addon-a11y/-/addon-a11y-6.4.18.tgz#c61f71cd7b17aff408835ee35e29bf4a0716ece7" - integrity sha512-sqsA5pXXKKDsquSXu5KC8WxQ1gg5ZoNIltWRgmJCEt4a0bkGUzn2iz+uW/gbt4NOVWGPXKvmMBLT/q4Q9gb+og== +"@storybook/addon-a11y@^6.4.19": + version "6.4.19" + resolved "https://registry.npmjs.org/@storybook/addon-a11y/-/addon-a11y-6.4.19.tgz#fb92840b5559b429afe2f28211440a5b5d1b6fcb" + integrity sha512-dG6easap6W4AqyggVZPq8lBrhza8StA8J4eYz/GVdoXINSGtq/casV0rkmY3+SUXhPYux5oGavHo86j5I4Q/0Q== dependencies: - "@storybook/addons" "6.4.18" - "@storybook/api" "6.4.18" - "@storybook/channels" "6.4.18" - "@storybook/client-logger" "6.4.18" - "@storybook/components" "6.4.18" - "@storybook/core-events" "6.4.18" + "@storybook/addons" "6.4.19" + "@storybook/api" "6.4.19" + "@storybook/channels" "6.4.19" + "@storybook/client-logger" "6.4.19" + "@storybook/components" "6.4.19" + "@storybook/core-events" "6.4.19" "@storybook/csf" "0.0.2--canary.87bc651.0" - "@storybook/theming" "6.4.18" + "@storybook/theming" "6.4.19" axe-core "^4.2.0" core-js "^3.8.2" global "^4.4.0" @@ -1332,17 +1332,17 @@ ts-dedent "^2.0.0" util-deprecate "^1.0.2" -"@storybook/addon-actions@^6.4.18": - version "6.4.18" - resolved "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-6.4.18.tgz#e997060e1b0af62f9f831301a56a3addfc1f1365" - integrity sha512-qPw5qfbWPmyOdaXxAVAbdVLVVE31gRrkH0ESUps+FXVNypRz1/0lJ6M2VrtOHMrFbGBl94SALdqsHOx6OYZKwg== +"@storybook/addon-actions@^6.4.19": + version "6.4.19" + resolved "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-6.4.19.tgz#10631d9c0a6669810264ea7fac3bff7201553084" + integrity sha512-GpSvP8xV8GfNkmtGJjfCgaOx6mbjtyTK0aT9FqX9pU0s+KVMmoCTrBh43b7dWrwxxas01yleBK9VpYggzhi/Fw== dependencies: - "@storybook/addons" "6.4.18" - "@storybook/api" "6.4.18" - "@storybook/components" "6.4.18" - "@storybook/core-events" "6.4.18" + "@storybook/addons" "6.4.19" + "@storybook/api" "6.4.19" + "@storybook/components" "6.4.19" + "@storybook/core-events" "6.4.19" "@storybook/csf" "0.0.2--canary.87bc651.0" - "@storybook/theming" "6.4.18" + "@storybook/theming" "6.4.19" core-js "^3.8.2" fast-deep-equal "^3.1.3" global "^4.4.0" @@ -1356,16 +1356,16 @@ util-deprecate "^1.0.2" uuid-browser "^3.1.0" -"@storybook/addon-links@^6.4.18": - version "6.4.18" - resolved "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-6.4.18.tgz#edb61db6c291056f7d3c64566aea436a6796c50a" - integrity sha512-yIbL57+tV1Ei2b7zTGU/T7muBFByTPm/8IN5SA5tSFYRTR9VtFuvBXco6I9Wz9GLN/REyVa4+AoDahokk7+vPQ== +"@storybook/addon-links@^6.4.19": + version "6.4.19" + resolved "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-6.4.19.tgz#001f26c4ffc7d36fd6018b8a137449948b337869" + integrity sha512-ebFHYlGDQkHSmI5QEJb1NxGNToVOLgjKkxXUe+JXX7AfHvrWiXVrN/57aOtBPZzj4h2jRPRTZgwR5glhPIlfEQ== dependencies: - "@storybook/addons" "6.4.18" - "@storybook/client-logger" "6.4.18" - "@storybook/core-events" "6.4.18" + "@storybook/addons" "6.4.19" + "@storybook/client-logger" "6.4.19" + "@storybook/core-events" "6.4.19" "@storybook/csf" "0.0.2--canary.87bc651.0" - "@storybook/router" "6.4.18" + "@storybook/router" "6.4.19" "@types/qs" "^6.9.5" core-js "^3.8.2" global "^4.4.0" @@ -1374,18 +1374,18 @@ regenerator-runtime "^0.13.7" ts-dedent "^2.0.0" -"@storybook/addon-storysource@^6.4.18": - version "6.4.18" - resolved "https://registry.npmjs.org/@storybook/addon-storysource/-/addon-storysource-6.4.18.tgz#00f0fb919b6224bfa8379b7c4c66e0b32b443921" - integrity sha512-02hs9dnfJs5lihQ0c/Cv4+lQNmkR0Fd+isEL+oVNcWTE9g0LVSLzC3evzeQCJv0SDzei7T0N+G7pF1P2dmc5PQ== +"@storybook/addon-storysource@^6.4.19": + version "6.4.19" + resolved "https://registry.npmjs.org/@storybook/addon-storysource/-/addon-storysource-6.4.19.tgz#09ec47b0c9f68ba9590edfcc7bd72984c048d272" + integrity sha512-WcjPgd0/m9rGMQbf6H2/wvXUhW5lSELWdXeCCK1taQHQUjhs8tq83fa7OkI9kE25drPiUJuPzObbCoYr94hftQ== dependencies: - "@storybook/addons" "6.4.18" - "@storybook/api" "6.4.18" - "@storybook/client-logger" "6.4.18" - "@storybook/components" "6.4.18" - "@storybook/router" "6.4.18" - "@storybook/source-loader" "6.4.18" - "@storybook/theming" "6.4.18" + "@storybook/addons" "6.4.19" + "@storybook/api" "6.4.19" + "@storybook/client-logger" "6.4.19" + "@storybook/components" "6.4.19" + "@storybook/router" "6.4.19" + "@storybook/source-loader" "6.4.19" + "@storybook/theming" "6.4.19" core-js "^3.8.2" estraverse "^5.2.0" loader-utils "^2.0.0" @@ -1394,35 +1394,35 @@ react-syntax-highlighter "^13.5.3" regenerator-runtime "^0.13.7" -"@storybook/addons@6.4.18", "@storybook/addons@^6.4.14": - version "6.4.18" - resolved "https://registry.npmjs.org/@storybook/addons/-/addons-6.4.18.tgz#fc92a4a608680f2e182a5e896ed382792f6b774e" - integrity sha512-fd3S79P4jJCYZNA2JxA1Xnkj0UlHGQ4Vg72aroWy4OQFlgGQor1LgPfM6RaJ9rh/4k4BXYPXsS7wzI0UWKG3Lw== +"@storybook/addons@6.4.19", "@storybook/addons@^6.4.19": + version "6.4.19" + resolved "https://registry.npmjs.org/@storybook/addons/-/addons-6.4.19.tgz#797d912b8b5a86cd6e0d31fa4c42d1f80808a432" + integrity sha512-QNyRYhpqmHV8oJxxTBdkRlLSbDFhpBvfvMfIrIT1UXb/eemdBZTaCGVvXZ9UixoEEI7f8VwAQ44IvkU5B1509w== dependencies: - "@storybook/api" "6.4.18" - "@storybook/channels" "6.4.18" - "@storybook/client-logger" "6.4.18" - "@storybook/core-events" "6.4.18" + "@storybook/api" "6.4.19" + "@storybook/channels" "6.4.19" + "@storybook/client-logger" "6.4.19" + "@storybook/core-events" "6.4.19" "@storybook/csf" "0.0.2--canary.87bc651.0" - "@storybook/router" "6.4.18" - "@storybook/theming" "6.4.18" + "@storybook/router" "6.4.19" + "@storybook/theming" "6.4.19" "@types/webpack-env" "^1.16.0" core-js "^3.8.2" global "^4.4.0" regenerator-runtime "^0.13.7" -"@storybook/api@6.4.18": - version "6.4.18" - resolved "https://registry.npmjs.org/@storybook/api/-/api-6.4.18.tgz#92da2b69aeec712419bec9bab5c8434ff1776e97" - integrity sha512-tSbsHKklBysuSmw4T+cKzMj6mQh/42m9F8+2iJns2XG/IUKpMAzFg/9dlgCTW+ay6dJwsR79JGIc9ccIe4SMgQ== +"@storybook/api@6.4.19": + version "6.4.19" + resolved "https://registry.npmjs.org/@storybook/api/-/api-6.4.19.tgz#8000a0e4c52c39b910b4ccc6731419e8e71800ef" + integrity sha512-aDvea+NpQCBjpNp9YidO1Pr7fzzCp15FSdkG+2ihGQfv5raxrN+IIJnGUXecpe71nvlYiB+29UXBVK7AL0j51Q== dependencies: - "@storybook/channels" "6.4.18" - "@storybook/client-logger" "6.4.18" - "@storybook/core-events" "6.4.18" + "@storybook/channels" "6.4.19" + "@storybook/client-logger" "6.4.19" + "@storybook/core-events" "6.4.19" "@storybook/csf" "0.0.2--canary.87bc651.0" - "@storybook/router" "6.4.18" + "@storybook/router" "6.4.19" "@storybook/semver" "^7.3.2" - "@storybook/theming" "6.4.18" + "@storybook/theming" "6.4.19" core-js "^3.8.2" fast-deep-equal "^3.1.3" global "^4.4.0" @@ -1434,10 +1434,10 @@ ts-dedent "^2.0.0" util-deprecate "^1.0.2" -"@storybook/builder-webpack4@6.4.18": - version "6.4.18" - resolved "https://registry.npmjs.org/@storybook/builder-webpack4/-/builder-webpack4-6.4.18.tgz#8bae72b9e982d35a5a9f2b7f9af9d85a9c2dc966" - integrity sha512-N/OGjTnc7CpVoDnfoI49uMjAIpGqh2lWHFYNIWaUoG1DNnTt1nCc49hw9awjFc5KgaYOwJmVg1SYYE8Afssu+Q== +"@storybook/builder-webpack4@6.4.19": + version "6.4.19" + resolved "https://registry.npmjs.org/@storybook/builder-webpack4/-/builder-webpack4-6.4.19.tgz#ca8228639be06e50d5f1555b844dd4177e5068ad" + integrity sha512-wxA6SMH11duc9D53aeVVBwrVRemFIoxHp/dOugkkg6ZZFAb4ZmWzf/ENc3vQIZdZpfNRi7IZIZEOfoHc994cmw== dependencies: "@babel/core" "^7.12.10" "@babel/plugin-proposal-class-properties" "^7.12.1" @@ -1460,22 +1460,22 @@ "@babel/preset-env" "^7.12.11" "@babel/preset-react" "^7.12.10" "@babel/preset-typescript" "^7.12.7" - "@storybook/addons" "6.4.18" - "@storybook/api" "6.4.18" - "@storybook/channel-postmessage" "6.4.18" - "@storybook/channels" "6.4.18" - "@storybook/client-api" "6.4.18" - "@storybook/client-logger" "6.4.18" - "@storybook/components" "6.4.18" - "@storybook/core-common" "6.4.18" - "@storybook/core-events" "6.4.18" - "@storybook/node-logger" "6.4.18" - "@storybook/preview-web" "6.4.18" - "@storybook/router" "6.4.18" + "@storybook/addons" "6.4.19" + "@storybook/api" "6.4.19" + "@storybook/channel-postmessage" "6.4.19" + "@storybook/channels" "6.4.19" + "@storybook/client-api" "6.4.19" + "@storybook/client-logger" "6.4.19" + "@storybook/components" "6.4.19" + "@storybook/core-common" "6.4.19" + "@storybook/core-events" "6.4.19" + "@storybook/node-logger" "6.4.19" + "@storybook/preview-web" "6.4.19" + "@storybook/router" "6.4.19" "@storybook/semver" "^7.3.2" - "@storybook/store" "6.4.18" - "@storybook/theming" "6.4.18" - "@storybook/ui" "6.4.18" + "@storybook/store" "6.4.19" + "@storybook/theming" "6.4.19" + "@storybook/ui" "6.4.19" "@types/node" "^14.0.10" "@types/webpack" "^4.41.26" autoprefixer "^9.8.6" @@ -1509,51 +1509,51 @@ webpack-hot-middleware "^2.25.1" webpack-virtual-modules "^0.2.2" -"@storybook/channel-postmessage@6.4.18": - version "6.4.18" - resolved "https://registry.npmjs.org/@storybook/channel-postmessage/-/channel-postmessage-6.4.18.tgz#24547fe7cee599969fd62df22142ba7046099a8e" - integrity sha512-SKapUREPkqzKoBMpOJrZddE9PCR8CJkPTcDpjDqcRsTvToRWsux3pvzmuW4iGYnHNh+GQml7Rz9x85WfMIpfyQ== +"@storybook/channel-postmessage@6.4.19": + version "6.4.19" + resolved "https://registry.npmjs.org/@storybook/channel-postmessage/-/channel-postmessage-6.4.19.tgz#5db4e1188aaa9de05fee3ba6a6b7f3b988cade03" + integrity sha512-E5h/itFzQ/6M08LR4kqlgqqmeO3tmavI+nUAlZrkCrotpJFNMHE2i0PQHg0TkFJrRDpYcrwD+AjUW4IwdqrisQ== dependencies: - "@storybook/channels" "6.4.18" - "@storybook/client-logger" "6.4.18" - "@storybook/core-events" "6.4.18" + "@storybook/channels" "6.4.19" + "@storybook/client-logger" "6.4.19" + "@storybook/core-events" "6.4.19" core-js "^3.8.2" global "^4.4.0" qs "^6.10.0" telejson "^5.3.2" -"@storybook/channel-websocket@6.4.18": - version "6.4.18" - resolved "https://registry.npmjs.org/@storybook/channel-websocket/-/channel-websocket-6.4.18.tgz#cf3a03e88b983c2953cb76a40a964806790567c4" - integrity sha512-ROqNZAFB1gP9u8dmlM4KxykXHsd1ifunBgFY3ncQKeRi2Oh30OMVB2ZhNdoIF8i8X5ZBwSpId1o6nQhL2e/EJA== +"@storybook/channel-websocket@6.4.19": + version "6.4.19" + resolved "https://registry.npmjs.org/@storybook/channel-websocket/-/channel-websocket-6.4.19.tgz#5b2f34f9089966bab66c55721766d3d1803edf2e" + integrity sha512-cXKwQjIXttfdUyZlcHORelUmJ5nUKswsnCA/qy7IRWpZjD8yQJcNk1dYC+tTHDVqFgdRT89pL0hRRB1rlaaR8Q== dependencies: - "@storybook/channels" "6.4.18" - "@storybook/client-logger" "6.4.18" + "@storybook/channels" "6.4.19" + "@storybook/client-logger" "6.4.19" core-js "^3.8.2" global "^4.4.0" telejson "^5.3.2" -"@storybook/channels@6.4.18": - version "6.4.18" - resolved "https://registry.npmjs.org/@storybook/channels/-/channels-6.4.18.tgz#2907aca0039b5eb9ae305112f14c488c2621c2f6" - integrity sha512-Bh4l7VKKR2ImLbZ9XgL/DzT3lFv9+SLiCu1ozfpBZGHUCOLyHRnkG/h8wYvRkF9s3tpNwOtaCaqD1vkkZfr3uw== +"@storybook/channels@6.4.19": + version "6.4.19" + resolved "https://registry.npmjs.org/@storybook/channels/-/channels-6.4.19.tgz#095bbaee494bf5b03f7cb92d34626f2f5063cb31" + integrity sha512-EwyoncFvTfmIlfsy8jTfayCxo2XchPkZk/9txipugWSmc057HdklMKPLOHWP0z5hLH0IbVIKXzdNISABm36jwQ== dependencies: core-js "^3.8.2" ts-dedent "^2.0.0" util-deprecate "^1.0.2" -"@storybook/client-api@6.4.18": - version "6.4.18" - resolved "https://registry.npmjs.org/@storybook/client-api/-/client-api-6.4.18.tgz#61c7c90f3f099e4d3bcc36576d2adbe2e5ef6eee" - integrity sha512-ua2Q692Fz2b3q5M/Qzjixg2LArwrcHGBmht06bNw/jrRfyFeTUHOhh5BT7LxSEetUgHATH/Y1GW40xza9rXFNw== +"@storybook/client-api@6.4.19": + version "6.4.19" + resolved "https://registry.npmjs.org/@storybook/client-api/-/client-api-6.4.19.tgz#131597e160f112f51240a4e407191053e5ed972f" + integrity sha512-OCrT5Um3FDvZnimQKwWtwsaI+5agPwq2i8YiqlofrI/NPMKp0I7DEkCGwE5IRD1Q8BIKqHcMo5tTmfYi0AxyOg== dependencies: - "@storybook/addons" "6.4.18" - "@storybook/channel-postmessage" "6.4.18" - "@storybook/channels" "6.4.18" - "@storybook/client-logger" "6.4.18" - "@storybook/core-events" "6.4.18" + "@storybook/addons" "6.4.19" + "@storybook/channel-postmessage" "6.4.19" + "@storybook/channels" "6.4.19" + "@storybook/client-logger" "6.4.19" + "@storybook/core-events" "6.4.19" "@storybook/csf" "0.0.2--canary.87bc651.0" - "@storybook/store" "6.4.18" + "@storybook/store" "6.4.19" "@types/qs" "^6.9.5" "@types/webpack-env" "^1.16.0" core-js "^3.8.2" @@ -1568,23 +1568,23 @@ ts-dedent "^2.0.0" util-deprecate "^1.0.2" -"@storybook/client-logger@6.4.18": - version "6.4.18" - resolved "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-6.4.18.tgz#4ad8ea7d67b17e5db8f15cffcc2f984df3479462" - integrity sha512-ciBaASMaB2ZPksbuyDbp3++5SZxbhcihEpl+RQcAVV8g+TUyBZKIcHt8HNHicTczz5my1EydZovMh1IkSBMICA== +"@storybook/client-logger@6.4.19": + version "6.4.19" + resolved "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-6.4.19.tgz#b2011ad2fa446cce4a9afdb41974b2a576e9fad2" + integrity sha512-zmg/2wyc9W3uZrvxaW4BfHcr40J0v7AGslqYXk9H+ERLVwIvrR4NhxQFaS6uITjBENyRDxwzfU3Va634WcmdDQ== dependencies: core-js "^3.8.2" global "^4.4.0" -"@storybook/components@6.4.18": - version "6.4.18" - resolved "https://registry.npmjs.org/@storybook/components/-/components-6.4.18.tgz#1f3eba9ab69a09b9468af0126d6e7ab040655ca4" - integrity sha512-LAPKYWgB6S10Vzt0IWa1Ihf9EAuQOGxlqehTuxYLOwMOKbto8iEbGRse/XaQfxdZf/RbmOL4u+7nVRROWgOEjg== +"@storybook/components@6.4.19": + version "6.4.19" + resolved "https://registry.npmjs.org/@storybook/components/-/components-6.4.19.tgz#084ba21f26a3eeab82f45178de6899688eecb2fc" + integrity sha512-q/0V37YAJA7CNc+wSiiefeM9+3XVk8ixBNylY36QCGJgIeGQ5/79vPyUe6K4lLmsQwpmZsIq1s1Ad5+VbboeOA== dependencies: "@popperjs/core" "^2.6.0" - "@storybook/client-logger" "6.4.18" + "@storybook/client-logger" "6.4.19" "@storybook/csf" "0.0.2--canary.87bc651.0" - "@storybook/theming" "6.4.18" + "@storybook/theming" "6.4.19" "@types/color-convert" "^2.0.0" "@types/overlayscrollbars" "^1.12.0" "@types/react-syntax-highlighter" "11.0.5" @@ -1606,21 +1606,21 @@ ts-dedent "^2.0.0" util-deprecate "^1.0.2" -"@storybook/core-client@6.4.18": - version "6.4.18" - resolved "https://registry.npmjs.org/@storybook/core-client/-/core-client-6.4.18.tgz#7f2feb961864dcf6de501a94a41900fd36b43657" - integrity sha512-F9CqW31Mr9Qde90uqPorpkiS+P7UteKYmdHlV0o0czeWaL+MEhpY+3pRJuRIIjX5C7Vc89TvljMqs37Khakmdg== +"@storybook/core-client@6.4.19": + version "6.4.19" + resolved "https://registry.npmjs.org/@storybook/core-client/-/core-client-6.4.19.tgz#fc6902c4321ae9e7c2858126172bc0752a84321c" + integrity sha512-rQHRZjhArPleE7/S8ZUolgzwY+hC0smSKX/3PQxO2GcebDjnJj6+iSV3h+aSMHMmTdoCQvjYw9aBpT8scuRe+A== dependencies: - "@storybook/addons" "6.4.18" - "@storybook/channel-postmessage" "6.4.18" - "@storybook/channel-websocket" "6.4.18" - "@storybook/client-api" "6.4.18" - "@storybook/client-logger" "6.4.18" - "@storybook/core-events" "6.4.18" + "@storybook/addons" "6.4.19" + "@storybook/channel-postmessage" "6.4.19" + "@storybook/channel-websocket" "6.4.19" + "@storybook/client-api" "6.4.19" + "@storybook/client-logger" "6.4.19" + "@storybook/core-events" "6.4.19" "@storybook/csf" "0.0.2--canary.87bc651.0" - "@storybook/preview-web" "6.4.18" - "@storybook/store" "6.4.18" - "@storybook/ui" "6.4.18" + "@storybook/preview-web" "6.4.19" + "@storybook/store" "6.4.19" + "@storybook/ui" "6.4.19" airbnb-js-shims "^2.2.1" ansi-to-html "^0.6.11" core-js "^3.8.2" @@ -1632,10 +1632,10 @@ unfetch "^4.2.0" util-deprecate "^1.0.2" -"@storybook/core-common@6.4.18": - version "6.4.18" - resolved "https://registry.npmjs.org/@storybook/core-common/-/core-common-6.4.18.tgz#0688a0a4a80cdbc161966c5a7ff49e755d64bbab" - integrity sha512-y4e43trNyQ3/v0Wpi240on7yVooUQvJBhJxOGEfcxAMRtcDa0ZCxHO4vAFX3k3voQOSmiXItXfJ1eGo/K+u0Fw== +"@storybook/core-common@6.4.19": + version "6.4.19" + resolved "https://registry.npmjs.org/@storybook/core-common/-/core-common-6.4.19.tgz#18e6c6095ebd9a94b074529917c693084921d3ca" + integrity sha512-X1pJJkO48DFxl6iyEemIKqRkJ7j9/cBh3BRBUr+xZHXBvnD0GKDXIocwh0PjSxSC6XSu3UCQnqtKi3PbjRl8Dg== dependencies: "@babel/core" "^7.12.10" "@babel/plugin-proposal-class-properties" "^7.12.1" @@ -1658,7 +1658,7 @@ "@babel/preset-react" "^7.12.10" "@babel/preset-typescript" "^7.12.7" "@babel/register" "^7.12.1" - "@storybook/node-logger" "6.4.18" + "@storybook/node-logger" "6.4.19" "@storybook/semver" "^7.3.2" "@types/node" "^14.0.10" "@types/pretty-hrtime" "^1.0.0" @@ -1687,29 +1687,29 @@ util-deprecate "^1.0.2" webpack "4" -"@storybook/core-events@6.4.18": - version "6.4.18" - resolved "https://registry.npmjs.org/@storybook/core-events/-/core-events-6.4.18.tgz#630a19425eb387c6134f29b967c30458c65f7ea8" - integrity sha512-lCT3l0rFs6CuVpD8+mwmj1lUTomGErySTxi0KmVd2AWQj8kJL90EfS0jHSU5JIXScDvuwXDXLLmvMfqNU+zHdg== +"@storybook/core-events@6.4.19": + version "6.4.19" + resolved "https://registry.npmjs.org/@storybook/core-events/-/core-events-6.4.19.tgz#d2a03156783a3cb9bd9f7ba81a06a798a5c296ae" + integrity sha512-KICzUw6XVQUJzFSCXfvhfHAuyhn4Q5J4IZEfuZkcGJS4ODkrO6tmpdYE5Cfr+so95Nfp0ErWiLUuodBsW9/rtA== dependencies: core-js "^3.8.2" -"@storybook/core-server@6.4.18": - version "6.4.18" - resolved "https://registry.npmjs.org/@storybook/core-server/-/core-server-6.4.18.tgz#520935f7f330a734488e733ad4cf15a9556679b5" - integrity sha512-7e2QUtD8/TE14P9X/xsBDMBbNVi/etTtMKKhsG2TG25daRz+6qadbM9tNP0YwvIDk452cNYJkjflV48mf5+ZEA== +"@storybook/core-server@6.4.19": + version "6.4.19" + resolved "https://registry.npmjs.org/@storybook/core-server/-/core-server-6.4.19.tgz#0d1b4b2094749b8bce03e3d01422e14e5fef8e66" + integrity sha512-bKsUB9f7hl5ya2JXxpIrErmbDQjoH39FVbzYZWjMo4t/b7+Xyi6vYadwyWcqlpUQmis09ZaSMv8L/Tw0TuwLAA== dependencies: "@discoveryjs/json-ext" "^0.5.3" - "@storybook/builder-webpack4" "6.4.18" - "@storybook/core-client" "6.4.18" - "@storybook/core-common" "6.4.18" - "@storybook/core-events" "6.4.18" + "@storybook/builder-webpack4" "6.4.19" + "@storybook/core-client" "6.4.19" + "@storybook/core-common" "6.4.19" + "@storybook/core-events" "6.4.19" "@storybook/csf" "0.0.2--canary.87bc651.0" - "@storybook/csf-tools" "6.4.18" - "@storybook/manager-webpack4" "6.4.18" - "@storybook/node-logger" "6.4.18" + "@storybook/csf-tools" "6.4.19" + "@storybook/manager-webpack4" "6.4.19" + "@storybook/node-logger" "6.4.19" "@storybook/semver" "^7.3.2" - "@storybook/store" "6.4.18" + "@storybook/store" "6.4.19" "@types/node" "^14.0.10" "@types/node-fetch" "^2.5.7" "@types/pretty-hrtime" "^1.0.0" @@ -1742,18 +1742,18 @@ webpack "4" ws "^8.2.3" -"@storybook/core@6.4.18": - version "6.4.18" - resolved "https://registry.npmjs.org/@storybook/core/-/core-6.4.18.tgz#56f7bb0f20dbcfa205d860022b7bf30bf42fd472" - integrity sha512-7DTMAEXiBIwd1jgalbsZiXCiS2Be9MKKsr6GQdf3WaBm0WYV067oN9jcUY5IgNtJX06arT4Ykp+CGG/TR+sLlw== +"@storybook/core@6.4.19": + version "6.4.19" + resolved "https://registry.npmjs.org/@storybook/core/-/core-6.4.19.tgz#58dd055bcc0ef335e0e0d3f6eca74b4d4d49eba1" + integrity sha512-55LOQ/h/kf1jMhjN85t/pIEdIwWEG9yV7bdwv3niVvmoypCxyyjn9/QNK0RKYAeDSUtdm6FVoJ6k5CpxWz2d8w== dependencies: - "@storybook/core-client" "6.4.18" - "@storybook/core-server" "6.4.18" + "@storybook/core-client" "6.4.19" + "@storybook/core-server" "6.4.19" -"@storybook/csf-tools@6.4.18": - version "6.4.18" - resolved "https://registry.npmjs.org/@storybook/csf-tools/-/csf-tools-6.4.18.tgz#cdd40b543f9bea79c1481c236868b8ea04af6bd7" - integrity sha512-KtwxKrkndEyvyAiBliI6m4yMFMvnyI4fOjU8t1qCit/0gjutOF5JxmmZ+H8FSI5dIyibEOzQmzHe0MyStAjCEQ== +"@storybook/csf-tools@6.4.19": + version "6.4.19" + resolved "https://registry.npmjs.org/@storybook/csf-tools/-/csf-tools-6.4.19.tgz#28bdea11da17501a8bc4e761b821d7721880eaf6" + integrity sha512-gf/zRhGoAVsFwSyV2tc+jeJfZQkxF6QsaZgbUSe24/IUvGFCT/PS/jZq1qy7dECAwrTOfykgu8juyBtj6WhWyw== dependencies: "@babel/core" "^7.12.10" "@babel/generator" "^7.12.11" @@ -1780,20 +1780,20 @@ dependencies: lodash "^4.17.15" -"@storybook/manager-webpack4@6.4.18": - version "6.4.18" - resolved "https://registry.npmjs.org/@storybook/manager-webpack4/-/manager-webpack4-6.4.18.tgz#5317c917dbdaf4cf8721647551a785eb13c04146" - integrity sha512-6oX1KrIJBoY4vdZiMftJNusv+Bm8pegVjdJ+aZcbr/41x7ufP3tu5UKebEXDH0UURXtLw0ffl+OgojewGdpC1Q== +"@storybook/manager-webpack4@6.4.19": + version "6.4.19" + resolved "https://registry.npmjs.org/@storybook/manager-webpack4/-/manager-webpack4-6.4.19.tgz#999577afb9b9a57fc478f7c5e5d95d785ea69da3" + integrity sha512-R8ugZjTYqXvlc6gDOcw909L65sIleOmIJLZR+N6/H85MivGXHu39jOwONqB7tVACufRty4FNecn8tEiQL2SAKA== dependencies: "@babel/core" "^7.12.10" "@babel/plugin-transform-template-literals" "^7.12.1" "@babel/preset-react" "^7.12.10" - "@storybook/addons" "6.4.18" - "@storybook/core-client" "6.4.18" - "@storybook/core-common" "6.4.18" - "@storybook/node-logger" "6.4.18" - "@storybook/theming" "6.4.18" - "@storybook/ui" "6.4.18" + "@storybook/addons" "6.4.19" + "@storybook/core-client" "6.4.19" + "@storybook/core-common" "6.4.19" + "@storybook/node-logger" "6.4.19" + "@storybook/theming" "6.4.19" + "@storybook/ui" "6.4.19" "@types/node" "^14.0.10" "@types/webpack" "^4.41.26" babel-loader "^8.0.0" @@ -1822,10 +1822,10 @@ webpack-dev-middleware "^3.7.3" webpack-virtual-modules "^0.2.2" -"@storybook/node-logger@6.4.18": - version "6.4.18" - resolved "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-6.4.18.tgz#8759761ba7526b2fa03a1a08fe82d6d892d7a072" - integrity sha512-wY1qt4XOXtJJdQ+DrO3RijtiwVFqWuWetvCY4RV4lge5yk0FP5Q+MTpmjazYodAvGPUIP0LK9bvEDLwXa0JUfw== +"@storybook/node-logger@6.4.19": + version "6.4.19" + resolved "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-6.4.19.tgz#554f9efad4e95ce6fa63222d026f43258293c896" + integrity sha512-hO2Aar3PgPnPtNq2fVgiuGlqo3EEVR6TKVBXMq7foL3tN2k4BQFKLDHbm5qZQQntyYKurKsRUGKPJFPuI1ov/w== dependencies: "@types/npmlog" "^4.1.2" chalk "^4.1.0" @@ -1833,17 +1833,17 @@ npmlog "^5.0.1" pretty-hrtime "^1.0.3" -"@storybook/preview-web@6.4.18": - version "6.4.18" - resolved "https://registry.npmjs.org/@storybook/preview-web/-/preview-web-6.4.18.tgz#47c908bf27d2089ccf3296c376a6f5b1e8674b5a" - integrity sha512-0x64uLdGhIOk9hIuRKTHFdP7+iEHyjAOi5U4jtwqFfDtG4n4zxEGSsUWij7pTR2rAYf7g2NWIbAM7qb1AqqcLQ== +"@storybook/preview-web@6.4.19": + version "6.4.19" + resolved "https://registry.npmjs.org/@storybook/preview-web/-/preview-web-6.4.19.tgz#bdfab7b2f760caf72140229dd64fd57617ad000b" + integrity sha512-jqltoBv5j7lvnxEfV9w8dLX9ASWGuvgz97yg8Yo5FqkftEwrHJenyvMGcTgDJKJPorF+wiz/9aIqnmd3LCAcZQ== dependencies: - "@storybook/addons" "6.4.18" - "@storybook/channel-postmessage" "6.4.18" - "@storybook/client-logger" "6.4.18" - "@storybook/core-events" "6.4.18" + "@storybook/addons" "6.4.19" + "@storybook/channel-postmessage" "6.4.19" + "@storybook/client-logger" "6.4.19" + "@storybook/core-events" "6.4.19" "@storybook/csf" "0.0.2--canary.87bc651.0" - "@storybook/store" "6.4.18" + "@storybook/store" "6.4.19" ansi-to-html "^0.6.11" core-js "^3.8.2" global "^4.4.0" @@ -1868,22 +1868,22 @@ react-docgen-typescript "^2.0.0" tslib "^2.0.0" -"@storybook/react@^6.4.18": - version "6.4.18" - resolved "https://registry.npmjs.org/@storybook/react/-/react-6.4.18.tgz#22624af56a9873c6616b5dc6a1e30c968bac95d2" - integrity sha512-dKxwsvJEGTm/aNIJSJMI4MImsI4EhmBa42FtwVvtFkrokuMf2CsmTJsaaAh+1or9SKGTiFuGsYDGhX5joE3XUQ== +"@storybook/react@^6.4.19": + version "6.4.19" + resolved "https://registry.npmjs.org/@storybook/react/-/react-6.4.19.tgz#1707b785b5a65c867e291ede12113e7fd55f8998" + integrity sha512-5b3i8jkVrjQGmcxxxXwCduHPIh+cluWkfeweKeQOe+lW4BR8fuUICo3AMLrYPAtB/UcaJyYkIYmTvF2mkfepFA== dependencies: "@babel/preset-flow" "^7.12.1" "@babel/preset-react" "^7.12.10" "@pmmmwh/react-refresh-webpack-plugin" "^0.5.1" - "@storybook/addons" "6.4.18" - "@storybook/core" "6.4.18" - "@storybook/core-common" "6.4.18" + "@storybook/addons" "6.4.19" + "@storybook/core" "6.4.19" + "@storybook/core-common" "6.4.19" "@storybook/csf" "0.0.2--canary.87bc651.0" - "@storybook/node-logger" "6.4.18" + "@storybook/node-logger" "6.4.19" "@storybook/react-docgen-typescript-plugin" "1.0.2-canary.253f8c1.0" "@storybook/semver" "^7.3.2" - "@storybook/store" "6.4.18" + "@storybook/store" "6.4.19" "@types/webpack-env" "^1.16.0" babel-plugin-add-react-displayname "^0.0.5" babel-plugin-named-asset-import "^0.3.1" @@ -1898,12 +1898,12 @@ ts-dedent "^2.0.0" webpack "4" -"@storybook/router@6.4.18": - version "6.4.18" - resolved "https://registry.npmjs.org/@storybook/router/-/router-6.4.18.tgz#8803dd78277f8602d6c11dae56f6229474dfa54c" - integrity sha512-itvSWHhG1X/NV1sMlwP1qKtF0HfiIaAHImr0LwQ2K2F6/CI11W68dJAs4WBUdwzA0+H0Joyu/2a/6mCQHcee1A== +"@storybook/router@6.4.19": + version "6.4.19" + resolved "https://registry.npmjs.org/@storybook/router/-/router-6.4.19.tgz#e653224dd9a521836bbd2610f604f609a2c77af2" + integrity sha512-KWWwIzuyeEIWVezkCihwY2A76Il9tUNg0I410g9qT7NrEsKyqXGRYOijWub7c1GGyNjLqz0jtrrehtixMcJkuA== dependencies: - "@storybook/client-logger" "6.4.18" + "@storybook/client-logger" "6.4.19" core-js "^3.8.2" fast-deep-equal "^3.1.3" global "^4.4.0" @@ -1923,13 +1923,13 @@ core-js "^3.6.5" find-up "^4.1.0" -"@storybook/source-loader@6.4.18": - version "6.4.18" - resolved "https://registry.npmjs.org/@storybook/source-loader/-/source-loader-6.4.18.tgz#205423e56f7da752d64a0695f2b22ed94378e5d0" - integrity sha512-sjKvngCCYDbBwjjFTjAXO6VsAzKkjy+UctseeULXxEN3cKIsz/R3y7MrrN9yBrwyYcn0k3pqa9d9e3gE+Jv2Tw== +"@storybook/source-loader@6.4.19": + version "6.4.19" + resolved "https://registry.npmjs.org/@storybook/source-loader/-/source-loader-6.4.19.tgz#24d134750bc41a13255b2b4a545f2d82613f004f" + integrity sha512-XqTsqddRglvfW7mhyjwoqd/B8L6samcBehhO0OEbsFp6FPWa9eXuObCxtRYIcjcSIe+ksbW3D/54ppEs1L/g1Q== dependencies: - "@storybook/addons" "6.4.18" - "@storybook/client-logger" "6.4.18" + "@storybook/addons" "6.4.19" + "@storybook/client-logger" "6.4.19" "@storybook/csf" "0.0.2--canary.87bc651.0" core-js "^3.8.2" estraverse "^5.2.0" @@ -1939,14 +1939,14 @@ prettier ">=2.2.1 <=2.3.0" regenerator-runtime "^0.13.7" -"@storybook/store@6.4.18": - version "6.4.18" - resolved "https://registry.npmjs.org/@storybook/store/-/store-6.4.18.tgz#3b693c9d5555d5cfc04e2318e104746d9d55ad66" - integrity sha512-Vl5oCs/9fP1gUgfgMHTBsnYbwAAoaR93/bzDBeOHI3eo5x9uzzJtA4zcRmEiKahR/wgwGacpWy90JrIX469PDQ== +"@storybook/store@6.4.19": + version "6.4.19" + resolved "https://registry.npmjs.org/@storybook/store/-/store-6.4.19.tgz#bf4031499f4d49909d7b691c03cc5ef1ec00ad74" + integrity sha512-N9/ZjemRHGfT3InPIbqQqc6snkcfnf3Qh9oOr0smbfaVGJol//KOX65kzzobtzFcid0WxtTDZ3HmgFVH+GvuhQ== dependencies: - "@storybook/addons" "6.4.18" - "@storybook/client-logger" "6.4.18" - "@storybook/core-events" "6.4.18" + "@storybook/addons" "6.4.19" + "@storybook/client-logger" "6.4.19" + "@storybook/core-events" "6.4.19" "@storybook/csf" "0.0.2--canary.87bc651.0" core-js "^3.8.2" fast-deep-equal "^3.1.3" @@ -1960,15 +1960,15 @@ ts-dedent "^2.0.0" util-deprecate "^1.0.2" -"@storybook/theming@6.4.18": - version "6.4.18" - resolved "https://registry.npmjs.org/@storybook/theming/-/theming-6.4.18.tgz#05365cc1d3dab5d71b80a82928fc5188106a0ed6" - integrity sha512-1o0w2eP+8sXUesdtXpZR4Yvayp1h3xvK7l9+wuHh+1uCy+EvD5UI9d1HvU5kt5fw7XAJJcInaVAmyAbpwct0TQ== +"@storybook/theming@6.4.19": + version "6.4.19" + resolved "https://registry.npmjs.org/@storybook/theming/-/theming-6.4.19.tgz#0a6834d91e0b0eadbb10282e7fb2947e2bbf9e9e" + integrity sha512-V4pWmTvAxmbHR6B3jA4hPkaxZPyExHvCToy7b76DpUTpuHihijNDMAn85KhOQYIeL9q14zP/aiz899tOHsOidg== dependencies: "@emotion/core" "^10.1.1" "@emotion/is-prop-valid" "^0.8.6" "@emotion/styled" "^10.0.27" - "@storybook/client-logger" "6.4.18" + "@storybook/client-logger" "6.4.19" core-js "^3.8.2" deep-object-diff "^1.1.0" emotion-theming "^10.0.27" @@ -1978,21 +1978,21 @@ resolve-from "^5.0.0" ts-dedent "^2.0.0" -"@storybook/ui@6.4.18": - version "6.4.18" - resolved "https://registry.npmjs.org/@storybook/ui/-/ui-6.4.18.tgz#3ceaf6b317f8f2c1d7d1cdc49daaac7eaf10af6b" - integrity sha512-f2ckcLvEyA9CRcu6W2I2CyEbUnU4j3h5Nz0N40YZ2uRMVNQY2xPywAFZVySZIJAaum/5phDfnOD0Feap/Q6zVQ== +"@storybook/ui@6.4.19": + version "6.4.19" + resolved "https://registry.npmjs.org/@storybook/ui/-/ui-6.4.19.tgz#1fb9f6cd875ee4937cf9d81ca45d5156800176d1" + integrity sha512-gFwdn5LA2U6oQ4bfUFLyHZnNasGQ01YVdwjbi+l6yjmnckBNtZfJoVTZ1rzGUbxSE9rK48InJRU+latTsr7xAg== dependencies: "@emotion/core" "^10.1.1" - "@storybook/addons" "6.4.18" - "@storybook/api" "6.4.18" - "@storybook/channels" "6.4.18" - "@storybook/client-logger" "6.4.18" - "@storybook/components" "6.4.18" - "@storybook/core-events" "6.4.18" - "@storybook/router" "6.4.18" + "@storybook/addons" "6.4.19" + "@storybook/api" "6.4.19" + "@storybook/channels" "6.4.19" + "@storybook/client-logger" "6.4.19" + "@storybook/components" "6.4.19" + "@storybook/core-events" "6.4.19" + "@storybook/router" "6.4.19" "@storybook/semver" "^7.3.2" - "@storybook/theming" "6.4.18" + "@storybook/theming" "6.4.19" copy-to-clipboard "^3.3.1" core-js "^3.8.2" core-js-pure "^3.8.2" diff --git a/yarn.lock b/yarn.lock index e2f1514ba2..0aeb9b2821 100644 --- a/yarn.lock +++ b/yarn.lock @@ -122,16 +122,17 @@ "@azure/abort-controller" "^1.0.0" tslib "^2.2.0" -"@azure/core-client@^1.0.0": - version "1.2.2" - resolved "https://registry.npmjs.org/@azure/core-client/-/core-client-1.2.2.tgz#29c781e5ccd4da968cea89d3b909ab573a3a7bec" - integrity sha512-VYFR2qiczjBrSfpQSbo5s8FJhXaJFz2tP01MOrpNJaOqnSNEKcY35I79b1Ty7s8qHGvc5/YMJ745l3B7abncFQ== +"@azure/core-client@^1.4.0": + version "1.5.0" + resolved "https://registry.npmjs.org/@azure/core-client/-/core-client-1.5.0.tgz#7aabb87d20e08db3683a117191c844bc19adb74e" + integrity sha512-YNk8i9LT6YcFdFO+RRU0E4Ef+A8Y5lhXo6lz61rwbG8Uo7kSqh0YqK04OexiilM43xd6n3Y9yBhLnb1NFNI9dA== dependencies: "@azure/abort-controller" "^1.0.0" "@azure/core-asynciterator-polyfill" "^1.0.0" "@azure/core-auth" "^1.3.0" - "@azure/core-rest-pipeline" "^1.1.0" - "@azure/core-tracing" "1.0.0-preview.12" + "@azure/core-rest-pipeline" "^1.5.0" + "@azure/core-tracing" "1.0.0-preview.13" + "@azure/logger" "^1.0.0" tslib "^2.2.0" "@azure/core-http@^1.2.0": @@ -172,16 +173,16 @@ dependencies: "@azure/core-asynciterator-polyfill" "^1.0.0" -"@azure/core-rest-pipeline@^1.1.0": - version "1.1.1" - resolved "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.1.1.tgz#53b4278f5c417c3da9f133511064375362b68a12" - integrity sha512-ObF8iTEDXIG7/NlL28ni9bR3XLJwgm2S3GWO4aNW6CsTCFVoY9HMdbBtN7xOB+pUQwifehifXNnootbzzuwJnw== +"@azure/core-rest-pipeline@^1.1.0", "@azure/core-rest-pipeline@^1.5.0": + version "1.5.0" + resolved "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.5.0.tgz#6f3989bd2cad581adb982885f836c00dacd78336" + integrity sha512-Lofjl3mu1TULhjxoPKY4IqXt6mC8Q+r3xMF1dOz0D/aElKfrbqtO2fts36PCClAq+DJzQM/kbnrNTf3X601I5w== dependencies: "@azure/abort-controller" "^1.0.0" "@azure/core-auth" "^1.3.0" - "@azure/core-tracing" "1.0.0-preview.12" + "@azure/core-tracing" "1.0.0-preview.13" "@azure/logger" "^1.0.0" - form-data "^3.0.0" + form-data "^4.0.0" http-proxy-agent "^4.0.1" https-proxy-agent "^5.0.0" tslib "^2.2.0" @@ -196,14 +197,6 @@ "@opentelemetry/api" "^0.10.2" tslib "^2.0.0" -"@azure/core-tracing@1.0.0-preview.12": - version "1.0.0-preview.12" - resolved "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.0.0-preview.12.tgz#f53ff452c0742ad981c244f97d93d37ca2b5e139" - integrity sha512-nvo2Wc4EKZGN6eFu9n3U7OXmASmL8VxoPIH7xaD6OlQqi44bouF0YIi9ID5rEsKLiAU59IYx6M297nqWVMWPDg== - dependencies: - "@opentelemetry/api" "^1.0.0" - tslib "^2.2.0" - "@azure/core-tracing@1.0.0-preview.13": version "1.0.0-preview.13" resolved "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.0.0-preview.13.tgz#55883d40ae2042f6f1e12b17dd0c0d34c536d644" @@ -229,13 +222,13 @@ tslib "^2.0.0" "@azure/identity@^2.0.1": - version "2.0.1" - resolved "https://registry.npmjs.org/@azure/identity/-/identity-2.0.1.tgz#31107506371e520bc874647a9e4384cfd2f85103" - integrity sha512-gdGGuLKlKIQaf2RefA84keoBfmWfiAntbW2SzcdKvwLSGzsio/qkyY3sYUpXRz/sqLDxguuimgZukp7TPgwIlg== + version "2.0.3" + resolved "https://registry.npmjs.org/@azure/identity/-/identity-2.0.3.tgz#286e7b145b29bee009ef10f3c2900122dcc1c947" + integrity sha512-MFW2QS5dWm2U8MDTSm0sHo7pcAQtQtJhKVVcN5wA2ownHzmHluXTGFK4WdFiXzUInhZtqYA5CH+OGHTGs6DTBA== dependencies: "@azure/abort-controller" "^1.0.0" "@azure/core-auth" "^1.3.0" - "@azure/core-client" "^1.0.0" + "@azure/core-client" "^1.4.0" "@azure/core-rest-pipeline" "^1.1.0" "@azure/core-tracing" "1.0.0-preview.13" "@azure/core-util" "^1.0.0-beta.1" @@ -243,7 +236,6 @@ "@azure/msal-browser" "^2.16.0" "@azure/msal-common" "^4.5.1" "@azure/msal-node" "^1.3.0" - "@types/stoppable" "^1.1.0" events "^3.0.0" jws "^4.0.0" open "^8.0.0" @@ -323,7 +315,7 @@ resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.16.8.tgz#31560f9f29fdf1868de8cb55049538a1b9732a60" integrity sha512-m7OkX0IdKLKPpBlJtF561YJal5y/jyI5fNfWbPxh2D/nbzzGI4qRyrD8xO2jB24u7l+5I2a43scCG2IrfjC50Q== -"@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.13.16", "@babel/core@^7.14.0", "@babel/core@^7.15.5", "@babel/core@^7.7.5": +"@babel/core@^7.1.0", "@babel/core@^7.13.16", "@babel/core@^7.14.0", "@babel/core@^7.15.5", "@babel/core@^7.7.5": version "7.16.12" resolved "https://registry.npmjs.org/@babel/core/-/core-7.16.12.tgz#5edc53c1b71e54881315923ae2aedea2522bb784" integrity sha512-dK5PtG1uiN2ikk++5OzSYsitZKny4wOCD0nrO4TqnW4BVBTQ2NGS3NgilvT/TEyxTST7LNyWV/T4tXDoD3fOgg== @@ -1049,7 +1041,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-transform-react-constant-elements@^7.12.1": +"@babel/plugin-transform-react-constant-elements@^7.14.5": version "7.16.7" resolved "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.16.7.tgz#19e9e4c2df2f6c3e6b3aea11778297d81db8df62" integrity sha512-lF+cfsyTgwWkcw715J88JhMYJ5GpysYNLhLP1PkvkhTRN7B3e74R/1KsDxFxhRpSn0UUD3IWM4GvdBR2PEbbQQ== @@ -1163,7 +1155,7 @@ "@babel/helper-create-regexp-features-plugin" "^7.16.7" "@babel/helper-plugin-utils" "^7.16.7" -"@babel/preset-env@^7.12.1": +"@babel/preset-env@^7.15.6": version "7.16.11" resolved "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.11.tgz#5dd88fd885fae36f88fd7c8342475c9f0abe2982" integrity sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g== @@ -1263,7 +1255,7 @@ "@babel/types" "^7.4.4" esutils "^2.0.2" -"@babel/preset-react@^7.12.5": +"@babel/preset-react@^7.14.5": version "7.16.7" resolved "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.16.7.tgz#4c18150491edc69c183ff818f9f2aecbe5d93852" integrity sha512-fWpyI8UM/HE6DfPBzD8LnhQ/OcH8AgTaqcqP2nGOXEUV+VKBR5JRN9hCk9ai+zQQ57vtm9oWeXguBCPNUjytgA== @@ -1275,7 +1267,7 @@ "@babel/plugin-transform-react-jsx-development" "^7.16.7" "@babel/plugin-transform-react-pure-annotations" "^7.16.7" -"@babel/preset-typescript@^7.13.0": +"@babel/preset-typescript@^7.13.0", "@babel/preset-typescript@^7.15.0", "@babel/preset-typescript@^7.16.0": version "7.16.7" resolved "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.16.7.tgz#ab114d68bb2020afc069cd51b37ff98a046a70b9" integrity sha512-WbVEmgXdIyvzB77AQjGBEyYPZx+8tTsO50XtfozQrkW8QB2rLJpH2lgx0TRw5EJrBxOZQ+wCcyPVQvS8tjEHpQ== @@ -1358,7 +1350,7 @@ "@babel/helper-validator-identifier" "^7.15.7" to-fast-properties "^2.0.0" -"@babel/types@^7.0.0", "@babel/types@^7.12.6", "@babel/types@^7.15.6", "@babel/types@^7.16.0", "@babel/types@^7.16.7", "@babel/types@^7.16.8", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4": +"@babel/types@^7.0.0", "@babel/types@^7.15.6", "@babel/types@^7.16.0", "@babel/types@^7.16.7", "@babel/types@^7.16.8", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4": version "7.16.8" resolved "https://registry.npmjs.org/@babel/types/-/types-7.16.8.tgz#0ba5da91dd71e0a4e7781a30f22770831062e3c1" integrity sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg== @@ -1366,22 +1358,6 @@ "@babel/helper-validator-identifier" "^7.16.7" to-fast-properties "^2.0.0" -"@backstage/core-plugin-api@^0.4.0", "@backstage/core-plugin-api@^0.4.1": - version "0.4.1" - resolved "https://registry.npmjs.org/@backstage/core-plugin-api/-/core-plugin-api-0.4.1.tgz#c0a13504bdfa61ae3d0db96934cd6c32a7574446" - integrity sha512-IIb7XTcquTPaSIlamMKUgeTs5uLqkKN0Nw32QdTZhKgFkFFVzWC0AwN+henkaMNBZFdGb0ttPzrvNXGj5E6dGg== - dependencies: - "@backstage/config" "^0.1.11" - "@backstage/theme" "^0.2.14" - "@backstage/types" "^0.1.1" - "@backstage/version-bridge" "^0.1.1" - "@material-ui/core" "^4.12.2" - history "^5.0.0" - prop-types "^15.7.2" - react-router-dom "6.0.0-beta.0" - react-use "^17.2.4" - zen-observable "^0.8.15" - "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" @@ -1736,14 +1712,14 @@ dependencies: "@date-io/core" "^1.3.13" -"@elastic/elasticsearch-mock@^0.3.0": - version "0.3.0" - resolved "https://registry.npmjs.org/@elastic/elasticsearch-mock/-/elasticsearch-mock-0.3.0.tgz#6b1d8448aad3ca20f760fa01c0206b733c9c1e54" - integrity sha512-hZYRjPgRE1M0wCqdsgaDtwxrgQEXDZya1gQ3gnpc8pB8mHUfPoO+9ye7GbDPUkWbuGGGZ4/p6OKmAbt/ME+CDQ== +"@elastic/elasticsearch-mock@^1.0.0": + version "1.0.0" + resolved "https://registry.npmjs.org/@elastic/elasticsearch-mock/-/elasticsearch-mock-1.0.0.tgz#1fbaf6bf220cd74a34494ff3a8673551d9dfc66f" + integrity sha512-MajkXUZ1xMYJilZc4f6KxZ9fbOp3VkUgjshZOm3Z4dbzEpRz7FinOfo6/Om7qdFyzhCJ9GgPQz4b0zp+3QMeqQ== dependencies: - fast-deep-equal "^3.1.1" - find-my-way "^2.2.2" - into-stream "^5.1.1" + fast-deep-equal "^3.1.3" + find-my-way "^4.3.3" + into-stream "^6.0.0" "@elastic/elasticsearch@7.13.0": version "7.13.0" @@ -1809,12 +1785,12 @@ query-string "^7.0.0" xcase "^2.0.1" -"@gitbeaker/core@^35.1.0": - version "35.1.0" - resolved "https://registry.npmjs.org/@gitbeaker/core/-/core-35.1.0.tgz#57f294886451b5ab2bccf0fc5fd8f6507473cd3a" - integrity sha512-DM9w3wgrS8GoXMLJb0DL2VSxTvP3yoaGDfX2d8n3wMGSjZbCknh3YnbVG/OfnaPbh9PH71kGll3SY5rJgz7XJg== +"@gitbeaker/core@^35.4.0": + version "35.4.0" + resolved "https://registry.npmjs.org/@gitbeaker/core/-/core-35.4.0.tgz#ebc3e46f9d8e17f85f81ccfe163cffdcd429545a" + integrity sha512-VjRmC/j1umhn0+f+DbrbxXDAc0uvGd32tJ4MCFQYkxw9ndr/0Rlg8iYvYN/zWyqtgr3SeTxMyS3Z9MtbWWhjBA== dependencies: - "@gitbeaker/requester-utils" "^35.1.0" + "@gitbeaker/requester-utils" "^35.4.0" form-data "^4.0.0" li "^1.3.0" mime "^3.0.0" @@ -1822,14 +1798,14 @@ xcase "^2.0.1" "@gitbeaker/node@^35.1.0": - version "35.1.0" - resolved "https://registry.npmjs.org/@gitbeaker/node/-/node-35.1.0.tgz#a3b2d96534b54d8e3a3c8130da82ebc8802257d8" - integrity sha512-t0lXqSuY93jVffo6WMeo4tvZtkMQXPKuGb1qNh3HOuW4+KyEqmrdQnorGyyRYH7uRTmQeHEe33BL1Ttc5F5YrA== + version "35.4.0" + resolved "https://registry.npmjs.org/@gitbeaker/node/-/node-35.4.0.tgz#096a28fd936dad9220625a917502063adf566acf" + integrity sha512-5isY4/ePtjIs7uFwVW8U5oNNwntyCa3eTs3+tb6CywtLGdlnenk0eNJjZ2Srn8xJOKsOCCpQkT5hP1AOKSAlAQ== dependencies: - "@gitbeaker/core" "^35.1.0" - "@gitbeaker/requester-utils" "^35.1.0" + "@gitbeaker/core" "^35.4.0" + "@gitbeaker/requester-utils" "^35.4.0" delay "^5.0.0" - got "^11.8.2" + got "11.8.3" xcase "^2.0.1" "@gitbeaker/requester-utils@^34.6.0": @@ -1841,10 +1817,10 @@ qs "^6.10.1" xcase "^2.0.1" -"@gitbeaker/requester-utils@^35.1.0": - version "35.1.0" - resolved "https://registry.npmjs.org/@gitbeaker/requester-utils/-/requester-utils-35.1.0.tgz#98c049d6b4e3f5ce222d7376b605e15c59d7bc93" - integrity sha512-00aQYCxs3wBHrD5HGWh0l1FRsX1NYJ1GEq4Reyo1NpVgjwzO/T1jjMFy3jikjJ+UGeg0sfqV9h91mwtCQ4SmRA== +"@gitbeaker/requester-utils@^35.4.0": + version "35.4.0" + resolved "https://registry.npmjs.org/@gitbeaker/requester-utils/-/requester-utils-35.4.0.tgz#918be27441024c841d3f9e09c498e6b24de291e2" + integrity sha512-NkJ55oMM7TNMWUNnzeYLdLOIUFv1LBBN/PCM2u7J5+67gpck03YfWAkgrODIqBePFyrfm19pdka3SUlNBP0G2g== dependencies: form-data "^4.0.0" qs "^6.10.1" @@ -2544,6 +2520,11 @@ resolved "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz#b32366c89b43c6f8cefbdefac778b9c828e3ba8c" integrity sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg== +"@isaacs/string-locale-compare@^1.1.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@isaacs/string-locale-compare/-/string-locale-compare-1.1.0.tgz#291c227e93fd407a96ecd59879a35809120e432b" + integrity sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ== + "@istanbuljs/load-nyc-config@^1.0.0": version "1.0.0" resolved "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.0.0.tgz#10602de5570baea82f8afbfa2630b24e7a8cfe5b" @@ -3742,20 +3723,21 @@ "@nodelib/fs.scandir" "2.1.3" fastq "^1.6.0" -"@npmcli/arborist@^2.2.2": - version "2.8.3" - resolved "https://registry.npmjs.org/@npmcli/arborist/-/arborist-2.8.3.tgz#5569e7d2038f6893abc81f9c879f497b506e6980" - integrity sha512-miFcxbZjmQqeFTeRSLLh+lc/gxIKDO5L4PVCp+dp+kmcwJmYsEJmF7YvHR2yi3jF+fxgvLf3CCFzboPIXAuabg== +"@npmcli/arborist@^4.0.4": + version "4.3.1" + resolved "https://registry.npmjs.org/@npmcli/arborist/-/arborist-4.3.1.tgz#a08cddce3339882f688c1dea1651f6971e781c44" + integrity sha512-yMRgZVDpwWjplorzt9SFSaakWx6QIK248Nw4ZFgkrAy/GvJaFRaSZzE6nD7JBK5r8g/+PTxFq5Wj/sfciE7x+A== dependencies: + "@isaacs/string-locale-compare" "^1.1.0" "@npmcli/installed-package-contents" "^1.0.7" - "@npmcli/map-workspaces" "^1.0.2" - "@npmcli/metavuln-calculator" "^1.1.0" + "@npmcli/map-workspaces" "^2.0.0" + "@npmcli/metavuln-calculator" "^2.0.0" "@npmcli/move-file" "^1.1.0" "@npmcli/name-from-folder" "^1.0.1" - "@npmcli/node-gyp" "^1.0.1" + "@npmcli/node-gyp" "^1.0.3" "@npmcli/package-json" "^1.0.1" - "@npmcli/run-script" "^1.8.2" - bin-links "^2.2.1" + "@npmcli/run-script" "^2.0.0" + bin-links "^3.0.0" cacache "^15.0.3" common-ancestor-path "^1.0.1" json-parse-even-better-errors "^2.3.1" @@ -3765,9 +3747,9 @@ npm-install-checks "^4.0.0" npm-package-arg "^8.1.5" npm-pick-manifest "^6.1.0" - npm-registry-fetch "^11.0.0" - pacote "^11.3.5" - parse-conflict-json "^1.1.1" + npm-registry-fetch "^12.0.1" + pacote "^12.0.2" + parse-conflict-json "^2.0.1" proc-log "^1.0.0" promise-all-reject-late "^1.0.0" promise-call-limit "^1.0.1" @@ -3814,23 +3796,24 @@ npm-bundled "^1.1.1" npm-normalize-package-bin "^1.0.1" -"@npmcli/map-workspaces@^1.0.2": - version "1.0.4" - resolved "https://registry.npmjs.org/@npmcli/map-workspaces/-/map-workspaces-1.0.4.tgz#915708b55afa25e20bc2c14a766c124c2c5d4cab" - integrity sha512-wVR8QxhyXsFcD/cORtJwGQodeeaDf0OxcHie8ema4VgFeqwYkFsDPnSrIRSytX8xR6nKPAH89WnwTcaU608b/Q== +"@npmcli/map-workspaces@^2.0.0": + version "2.0.0" + resolved "https://registry.npmjs.org/@npmcli/map-workspaces/-/map-workspaces-2.0.0.tgz#e342efbbdd0dad1bba5d7723b674ca668bf8ac5a" + integrity sha512-QBJfpCY1NOAkkW3lFfru9VTdqvMB2TN0/vrevl5xBCv5Fi0XDVcA6rqqSau4Ysi4Iw3fBzyXV7hzyTBDfadf7g== dependencies: "@npmcli/name-from-folder" "^1.0.1" glob "^7.1.6" minimatch "^3.0.4" read-package-json-fast "^2.0.1" -"@npmcli/metavuln-calculator@^1.1.0": - version "1.1.1" - resolved "https://registry.npmjs.org/@npmcli/metavuln-calculator/-/metavuln-calculator-1.1.1.tgz#2f95ff3c6d88b366dd70de1c3f304267c631b458" - integrity sha512-9xe+ZZ1iGVaUovBVFI9h3qW+UuECUzhvZPxK9RaEA2mjU26o5D0JloGYWwLYvQELJNmBdQB6rrpuN8jni6LwzQ== +"@npmcli/metavuln-calculator@^2.0.0": + version "2.0.0" + resolved "https://registry.npmjs.org/@npmcli/metavuln-calculator/-/metavuln-calculator-2.0.0.tgz#70937b8b5a5cad5c588c8a7b38c4a8bd6f62c84c" + integrity sha512-VVW+JhWCKRwCTE+0xvD6p3uV4WpqocNYYtzyvenqL/u1Q3Xx6fGTJ+6UoIoii07fbuEO9U3IIyuGY0CYHDv1sg== dependencies: cacache "^15.0.5" - pacote "^11.1.11" + json-parse-even-better-errors "^2.3.1" + pacote "^12.0.0" semver "^7.3.2" "@npmcli/move-file@^1.0.1": @@ -3853,10 +3836,10 @@ resolved "https://registry.npmjs.org/@npmcli/name-from-folder/-/name-from-folder-1.0.1.tgz#77ecd0a4fcb772ba6fe927e2e2e155fbec2e6b1a" integrity sha512-qq3oEfcLFwNfEYOQ8HLimRGKlD8WSeGEdtUa7hmzpR8Sa7haL1KVQrvgO6wqMjhWFFVjgtrh1gIxDz+P8sjUaA== -"@npmcli/node-gyp@^1.0.1", "@npmcli/node-gyp@^1.0.2": - version "1.0.2" - resolved "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-1.0.2.tgz#3cdc1f30e9736dbc417373ed803b42b1a0a29ede" - integrity sha512-yrJUe6reVMpktcvagumoqD9r08fH1iRo01gn1u0zoCApa9lnZGEigVKUd2hzsCId4gdtkZZIVscLhNxMECKgRg== +"@npmcli/node-gyp@^1.0.2", "@npmcli/node-gyp@^1.0.3": + version "1.0.3" + resolved "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-1.0.3.tgz#a912e637418ffc5f2db375e93b85837691a43a33" + integrity sha512-fnkhw+fmX65kiLqk6E3BFLXNC26rUhK90zVwe2yncPliVT/Qos3xjhTLE59Df8KnPlcwIERXKVlU1bXoUQ+liA== "@npmcli/package-json@^1.0.1": version "1.0.1" @@ -3884,6 +3867,16 @@ puka "^1.0.1" read-package-json-fast "^2.0.1" +"@npmcli/run-script@^2.0.0": + version "2.0.0" + resolved "https://registry.npmjs.org/@npmcli/run-script/-/run-script-2.0.0.tgz#9949c0cab415b17aaac279646db4f027d6f1e743" + integrity sha512-fSan/Pu11xS/TdaTpTB0MRn9guwGU8dye+x56mEVgBEd/QsybBbYcAL0phPXi8SGWFEChkQd6M9qL4y6VOpFig== + dependencies: + "@npmcli/node-gyp" "^1.0.2" + "@npmcli/promise-spawn" "^1.3.2" + node-gyp "^8.2.0" + read-package-json-fast "^2.0.1" + "@octokit/app@^12.0.4": version "12.0.5" resolved "https://registry.npmjs.org/@octokit/app/-/app-12.0.5.tgz#0b25446daffcb36967b26944410eab1ccbba0c06" @@ -4272,11 +4265,6 @@ dependencies: "@opentelemetry/context-base" "^0.10.2" -"@opentelemetry/api@^1.0.0": - version "1.0.1" - resolved "https://registry.npmjs.org/@opentelemetry/api/-/api-1.0.1.tgz#03c72f548431da5820a0c8864d1401e348e7e79f" - integrity sha512-H5Djcc2txGAINgf3TNaq4yFofYSIK3722PM89S/3R8FuI/eqi1UscajlXk7EBkG9s2pxss/q6SHlpturaavXaw== - "@opentelemetry/api@^1.0.1": version "1.0.4" resolved "https://registry.npmjs.org/@opentelemetry/api/-/api-1.0.4.tgz#a167e46c10d05a07ab299fc518793b0cff8f6924" @@ -4345,6 +4333,18 @@ resolved "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA= +"@react-hookz/deep-equal@^1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@react-hookz/deep-equal/-/deep-equal-1.0.1.tgz#1e9aad97b964879b54a3909f36f0727befa13e1f" + integrity sha512-6k/pU2jNlgYvKOy84vpCAZ8MGVwybvAdjzrh4UicCVOCPxz0LSBws1OE6O5TO4sPHaSw+yLfNzNK8RicGFc1Kw== + +"@react-hookz/web@^12.3.0": + version "12.3.0" + resolved "https://registry.npmjs.org/@react-hookz/web/-/web-12.3.0.tgz#a9a1311a15171a57d68a3db61492f913d4fd455a" + integrity sha512-Uujp2RfX/oDEtAbdkV0W/nhiQ5ZYVH+MEq04T7/8TstyiwoIlvsRbEic6c6gQA6sQ/lw93cZ8NP8R7AYjiqDvg== + dependencies: + "@react-hookz/deep-equal" "^1.0.1" + "@rjsf/core@^3.2.1": version "3.2.1" resolved "https://registry.npmjs.org/@rjsf/core/-/core-3.2.1.tgz#8a7b24c9a6f01f0ecb093fdfc777172c12b1b009" @@ -4365,14 +4365,14 @@ resolved "https://registry.npmjs.org/@rjsf/material-ui/-/material-ui-3.2.1.tgz#84fbf322485aee3a84101e189161f0687779ec8d" integrity sha512-8UiDeDbjCImFSfOegGu13otQ7OdP9FOYpcLjeouppnhs+MPeIEAtYS+jCcBKmi3reyTagC15/KVSRhde1wS1vg== -"@roadiehq/backstage-plugin-buildkite@^1.3.4": - version "1.3.5" - resolved "https://registry.npmjs.org/@roadiehq/backstage-plugin-buildkite/-/backstage-plugin-buildkite-1.3.5.tgz#c8dd8390c4ca39dd522e481410d2be7fa79c0aec" - integrity sha512-KSITwXNK/sU//yHHrVizgGaHLXRDD2SVRDpwk35PFtY+iDM5msDVTcaGwNWJBOGVkegVTcq3cbHlGnEqm9AtNQ== +"@roadiehq/backstage-plugin-buildkite@^1.3.8": + version "1.3.8" + resolved "https://registry.npmjs.org/@roadiehq/backstage-plugin-buildkite/-/backstage-plugin-buildkite-1.3.8.tgz#fa91880e7d95a82d8d532f663cc9415c74dc6143" + integrity sha512-eZW826eMTgy7znkNRQzIhi/mlL6ztYRGq/+kThX3JjoHyGfIxEd+GnR58YEeuvs5dy277SJ/9gm3iibhK9T9sQ== dependencies: "@backstage/catalog-model" "^0.9.7" "@backstage/core-components" "^0.8.0" - "@backstage/core-plugin-api" "^0.4.0" + "@backstage/core-plugin-api" "^0.6.0" "@backstage/plugin-catalog-react" "^0.6.5" "@backstage/theme" "^0.2.6" "@material-ui/core" "^4.12.1" @@ -4384,14 +4384,14 @@ react-router-dom "6.0.0-beta.0" react-use "^17.2.4" -"@roadiehq/backstage-plugin-github-insights@^1.4.2": - version "1.4.4" - resolved "https://registry.npmjs.org/@roadiehq/backstage-plugin-github-insights/-/backstage-plugin-github-insights-1.4.4.tgz#a77671015cebae9a31133f07e7daa693f391b35c" - integrity sha512-867aiiP7w0mKHONHGgQaMKv3iczi+YGck4apUEj4UyRQkJd+D2W94bK2z3HI6fw0RInpqo383d5VE6Yq1TEJ2A== +"@roadiehq/backstage-plugin-github-insights@^1.5.0": + version "1.5.0" + resolved "https://registry.npmjs.org/@roadiehq/backstage-plugin-github-insights/-/backstage-plugin-github-insights-1.5.0.tgz#9a693be80adc9f3b9cfe5ba615628abde88e121f" + integrity sha512-r2FclGGF/6aTrT6wH5Xq+5ByfVwgCDt83+KINf1ELNuWt5x0nMtguSTyZqJ5n1AdbGybVJZ84dlfbSTa8RTU7g== dependencies: "@backstage/catalog-model" "^0.9.7" "@backstage/core-components" "^0.8.0" - "@backstage/core-plugin-api" "^0.4.0" + "@backstage/core-plugin-api" "^0.6.0" "@backstage/integration-react" "^0.1.10" "@backstage/plugin-catalog-react" "^0.6.5" "@backstage/theme" "^0.2.7" @@ -4399,16 +4399,19 @@ "@material-ui/core" "^4.11.0" "@material-ui/icons" "^4.9.1" "@material-ui/lab" "4.0.0-alpha.45" + "@octokit/request-error" "^2.1.0" "@octokit/rest" "^18.5.3" "@octokit/types" "^6.14.2" history "^5.0.0" + immer "9.0.7" react-router "^6.0.0-beta.0" react-use "^17.2.4" + zustand "3.6.9" -"@roadiehq/backstage-plugin-github-pull-requests@^1.3.2": - version "1.3.7" - resolved "https://registry.npmjs.org/@roadiehq/backstage-plugin-github-pull-requests/-/backstage-plugin-github-pull-requests-1.3.7.tgz#d3c884c9b85f88c5f851f383596a616598c56076" - integrity sha512-a3PBLQ6SRtEDGNIekcGT8v4Aaac3BoEww/UU9uaQuE7bCEVolx2MeOVbSxb1uCWr6C6uGeDF5Kw4S4hPJJcnNg== +"@roadiehq/backstage-plugin-github-pull-requests@^1.4.0": + version "1.4.0" + resolved "https://registry.npmjs.org/@roadiehq/backstage-plugin-github-pull-requests/-/backstage-plugin-github-pull-requests-1.4.0.tgz#3f250c8b13c6b95ec2825f9b7088ea5199054013" + integrity sha512-qrbybOtZdWWWKptGfAvf1vzlwXGcvidWT5Dr6mbibn7GwSxSe4CD58pIEHJzFoT9jLHFGgAn5Uhh2SG/Ek7gbw== dependencies: "@backstage/catalog-model" "^0.9.7" "@backstage/core-components" "^0.8.0" @@ -4420,12 +4423,13 @@ "@octokit/types" "^5.0.1" "@types/node-fetch" "^2.5.7" history "^5.0.0" + lodash "^4.17.21" moment "^2.27.0" node-fetch "^2.6.1" react-router "6.0.0-beta.0" react-use "^17.2.4" -"@roadiehq/backstage-plugin-travis-ci@^1.3.2": +"@roadiehq/backstage-plugin-travis-ci@^1.3.6": version "1.3.6" resolved "https://registry.npmjs.org/@roadiehq/backstage-plugin-travis-ci/-/backstage-plugin-travis-ci-1.3.6.tgz#6f45a42bdf39aa6baab56f0c4400990238df1625" integrity sha512-th+2GaOjkPArDUbTBuhhCz/6WL4gcrVRVAsDHzuSrrJqNtsz6kXdBIHhR/58En16BZ2bnHhRzY87uiUDLjAntA== @@ -4647,100 +4651,46 @@ dependencies: loader-utils "^1.1.0" -"@svgr/babel-plugin-add-jsx-attribute@^5.4.0": - version "5.4.0" - resolved "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-5.4.0.tgz#81ef61947bb268eb9d50523446f9c638fb355906" - integrity sha512-ZFf2gs/8/6B8PnSofI0inYXr2SDNTDScPXhN7k5EqD4aZ3gi6u+rbmZHVB8IM3wDyx8ntKACZbtXSm7oZGRqVg== - "@svgr/babel-plugin-add-jsx-attribute@^6.0.0": version "6.0.0" resolved "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-6.0.0.tgz#bd6d1ff32a31b82b601e73672a789cc41e84fe18" integrity sha512-MdPdhdWLtQsjd29Wa4pABdhWbaRMACdM1h31BY+c6FghTZqNGT7pEYdBoaGeKtdTOBC/XNFQaKVj+r/Ei2ryWA== -"@svgr/babel-plugin-remove-jsx-attribute@^5.4.0": - version "5.4.0" - resolved "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-5.4.0.tgz#6b2c770c95c874654fd5e1d5ef475b78a0a962ef" - integrity sha512-yaS4o2PgUtwLFGTKbsiAy6D0o3ugcUhWK0Z45umJ66EPWunAz9fuFw2gJuje6wqQvQWOTJvIahUwndOXb7QCPg== - "@svgr/babel-plugin-remove-jsx-attribute@^6.0.0": version "6.0.0" resolved "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-6.0.0.tgz#58654908beebfa069681a83332544b17e5237e89" integrity sha512-aVdtfx9jlaaxc3unA6l+M9YRnKIZjOhQPthLKqmTXC8UVkBLDRGwPKo+r8n3VZN8B34+yVajzPTZ+ptTSuZZCw== -"@svgr/babel-plugin-remove-jsx-empty-expression@^5.0.1": - version "5.0.1" - resolved "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-5.0.1.tgz#25621a8915ed7ad70da6cea3d0a6dbc2ea933efd" - integrity sha512-LA72+88A11ND/yFIMzyuLRSMJ+tRKeYKeQ+mR3DcAZ5I4h5CPWN9AHyUzJbWSYp/u2u0xhmgOe0+E41+GjEueA== - "@svgr/babel-plugin-remove-jsx-empty-expression@^6.0.0": version "6.0.0" resolved "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-6.0.0.tgz#d06dd6e8a8f603f92f9979bb9990a1f85a4f57ba" integrity sha512-Ccj42ApsePD451AZJJf1QzTD1B/BOU392URJTeXFxSK709i0KUsGtbwyiqsKu7vsYxpTM0IA5clAKDyf9RCZyA== -"@svgr/babel-plugin-replace-jsx-attribute-value@^5.0.1": - version "5.0.1" - resolved "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-5.0.1.tgz#0b221fc57f9fcd10e91fe219e2cd0dd03145a897" - integrity sha512-PoiE6ZD2Eiy5mK+fjHqwGOS+IXX0wq/YDtNyIgOrc6ejFnxN4b13pRpiIPbtPwHEc+NT2KCjteAcq33/F1Y9KQ== - "@svgr/babel-plugin-replace-jsx-attribute-value@^6.0.0": version "6.0.0" resolved "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-6.0.0.tgz#0b85837577b02c31c09c758a12932820f5245cee" integrity sha512-88V26WGyt1Sfd1emBYmBJRWMmgarrExpKNVmI9vVozha4kqs6FzQJ/Kp5+EYli1apgX44518/0+t9+NU36lThQ== -"@svgr/babel-plugin-svg-dynamic-title@^5.4.0": - version "5.4.0" - resolved "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-5.4.0.tgz#139b546dd0c3186b6e5db4fefc26cb0baea729d7" - integrity sha512-zSOZH8PdZOpuG1ZVx/cLVePB2ibo3WPpqo7gFIjLV9a0QsuQAzJiwwqmuEdTaW2pegyBE17Uu15mOgOcgabQZg== - "@svgr/babel-plugin-svg-dynamic-title@^6.0.0": version "6.0.0" resolved "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-6.0.0.tgz#28236ec26f7ab9d486a487d36ae52d58ba15676f" integrity sha512-F7YXNLfGze+xv0KMQxrl2vkNbI9kzT9oDK55/kUuymh1ACyXkMV+VZWX1zEhSTfEKh7VkHVZGmVtHg8eTZ6PRg== -"@svgr/babel-plugin-svg-em-dimensions@^5.4.0": - version "5.4.0" - resolved "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-5.4.0.tgz#6543f69526632a133ce5cabab965deeaea2234a0" - integrity sha512-cPzDbDA5oT/sPXDCUYoVXEmm3VIoAWAPT6mSPTJNbQaBNUuEKVKyGH93oDY4e42PYHRW67N5alJx/eEol20abw== - "@svgr/babel-plugin-svg-em-dimensions@^6.0.0": version "6.0.0" resolved "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-6.0.0.tgz#40267c5dea1b43c4f83a0eb6169e08b43d8bafce" integrity sha512-+rghFXxdIqJNLQK08kwPBD3Z22/0b2tEZ9lKiL/yTfuyj1wW8HUXu4bo/XkogATIYuXSghVQOOCwURXzHGKyZA== -"@svgr/babel-plugin-transform-react-native-svg@^5.4.0": - version "5.4.0" - resolved "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-5.4.0.tgz#00bf9a7a73f1cad3948cdab1f8dfb774750f8c80" - integrity sha512-3eYP/SaopZ41GHwXma7Rmxcv9uRslRDTY1estspeB1w1ueZWd/tPlMfEOoccYpEMZU3jD4OU7YitnXcF5hLW2Q== - "@svgr/babel-plugin-transform-react-native-svg@^6.0.0": version "6.0.0" resolved "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-6.0.0.tgz#eb688d0a5f539e34d268d8a516e81f5d7fede7c9" integrity sha512-VaphyHZ+xIKv5v0K0HCzyfAaLhPGJXSk2HkpYfXIOKb7DjLBv0soHDxNv6X0vr2titsxE7klb++u7iOf7TSrFQ== -"@svgr/babel-plugin-transform-svg-component@^5.5.0": - version "5.5.0" - resolved "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-5.5.0.tgz#583a5e2a193e214da2f3afeb0b9e8d3250126b4a" - integrity sha512-q4jSH1UUvbrsOtlo/tKcgSeiCHRSBdXoIoqX1pgcKK/aU3JD27wmMKwGtpB8qRYUYoyXvfGxUVKchLuR5pB3rQ== - "@svgr/babel-plugin-transform-svg-component@^6.2.0": version "6.2.0" resolved "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-6.2.0.tgz#7ba61d9fc1fb42b0ba1a04e4630019fa7e993c4f" integrity sha512-bhYIpsORb++wpsp91fymbFkf09Z/YEKR0DnFjxvN+8JHeCUD2unnh18jIMKnDJTWtvpTaGYPXELVe4OOzFI0xg== -"@svgr/babel-preset@^5.5.0": - version "5.5.0" - resolved "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-5.5.0.tgz#8af54f3e0a8add7b1e2b0fcd5a882c55393df327" - integrity sha512-4FiXBjvQ+z2j7yASeGPEi8VD/5rrGQk4Xrq3EdJmoZgz/tpqChpo5hgXDvmEauwtvOc52q8ghhZK4Oy7qph4ig== - dependencies: - "@svgr/babel-plugin-add-jsx-attribute" "^5.4.0" - "@svgr/babel-plugin-remove-jsx-attribute" "^5.4.0" - "@svgr/babel-plugin-remove-jsx-empty-expression" "^5.0.1" - "@svgr/babel-plugin-replace-jsx-attribute-value" "^5.0.1" - "@svgr/babel-plugin-svg-dynamic-title" "^5.4.0" - "@svgr/babel-plugin-svg-em-dimensions" "^5.4.0" - "@svgr/babel-plugin-transform-react-native-svg" "^5.4.0" - "@svgr/babel-plugin-transform-svg-component" "^5.5.0" - "@svgr/babel-preset@^6.2.0": version "6.2.0" resolved "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-6.2.0.tgz#1d3ad8c7664253a4be8e4a0f0e6872f30d8af627" @@ -4755,26 +4705,19 @@ "@svgr/babel-plugin-transform-react-native-svg" "^6.0.0" "@svgr/babel-plugin-transform-svg-component" "^6.2.0" -"@svgr/core@^5.5.0": - version "5.5.0" - resolved "https://registry.npmjs.org/@svgr/core/-/core-5.5.0.tgz#82e826b8715d71083120fe8f2492ec7d7874a579" - integrity sha512-q52VOcsJPvV3jO1wkPtzTuKlvX7Y3xIcWRpCMtBF3MrteZJtBfQw/+u0B1BHy5ColpQc1/YVTrPEtSYIMNZlrQ== +"@svgr/core@^6.2.1": + version "6.2.1" + resolved "https://registry.npmjs.org/@svgr/core/-/core-6.2.1.tgz#195de807a9f27f9e0e0d678e01084b05c54fdf61" + integrity sha512-NWufjGI2WUyrg46mKuySfviEJ6IxHUOm/8a3Ph38VCWSp+83HBraCQrpEM3F3dB6LBs5x8OElS8h3C0oOJaJAA== dependencies: - "@svgr/plugin-jsx" "^5.5.0" + "@svgr/plugin-jsx" "^6.2.1" camelcase "^6.2.0" - cosmiconfig "^7.0.0" + cosmiconfig "^7.0.1" -"@svgr/hast-util-to-babel-ast@^5.5.0": - version "5.5.0" - resolved "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-5.5.0.tgz#5ee52a9c2533f73e63f8f22b779f93cd432a5461" - integrity sha512-cAaR/CAiZRB8GP32N+1jocovUtvlj0+e65TB50/6Lcime+EA49m/8l+P2ko+XPJ4dw3xaPS3jOL4F2X4KWxoeQ== - dependencies: - "@babel/types" "^7.12.6" - -"@svgr/hast-util-to-babel-ast@^6.0.0": - version "6.0.0" - resolved "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-6.0.0.tgz#423329ad866b6c169009cc82b5e28ffee80c857c" - integrity sha512-S+TxtCdDyRGafH1VG1t/uPZ87aOYOHzWL8kqz4FoSZcIbzWA6rnOmjNViNiDzqmEpzp2PW5o5mZfvC9DiVZhTQ== +"@svgr/hast-util-to-babel-ast@^6.0.0", "@svgr/hast-util-to-babel-ast@^6.2.1": + version "6.2.1" + resolved "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-6.2.1.tgz#ae065567b74cbe745afae617053adf9a764bea25" + integrity sha512-pt7MMkQFDlWJVy9ULJ1h+hZBDGFfSCwlBNW1HkLnVi7jUhyEXUaGYWi1x6bM2IXuAR9l265khBT4Av4lPmaNLQ== dependencies: "@babel/types" "^7.15.6" entities "^3.0.1" @@ -4789,17 +4732,17 @@ "@svgr/hast-util-to-babel-ast" "^6.0.0" svg-parser "^2.0.2" -"@svgr/plugin-jsx@^5.5.0": - version "5.5.0" - resolved "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-5.5.0.tgz#1aa8cd798a1db7173ac043466d7b52236b369000" - integrity sha512-V/wVh33j12hGh05IDg8GpIUXbjAPnTdPTKuP4VNLggnwaHMPNQNae2pRnyTAILWCQdz5GyMqtO488g7CKM8CBA== +"@svgr/plugin-jsx@^6.2.1": + version "6.2.1" + resolved "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-6.2.1.tgz#5668f1d2aa18c2f1bb7a1fc9f682d3f9aed263bd" + integrity sha512-u+MpjTsLaKo6r3pHeeSVsh9hmGRag2L7VzApWIaS8imNguqoUwDq/u6U/NDmYs/KAsrmtBjOEaAAPbwNGXXp1g== dependencies: - "@babel/core" "^7.12.3" - "@svgr/babel-preset" "^5.5.0" - "@svgr/hast-util-to-babel-ast" "^5.5.0" + "@babel/core" "^7.15.5" + "@svgr/babel-preset" "^6.2.0" + "@svgr/hast-util-to-babel-ast" "^6.2.1" svg-parser "^2.0.2" -"@svgr/plugin-svgo@6.2.x": +"@svgr/plugin-svgo@6.2.x", "@svgr/plugin-svgo@^6.2.0": version "6.2.0" resolved "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-6.2.0.tgz#4cbe6a33ccccdcae4e3b63ded64cc1cbe1faf48c" integrity sha512-oDdMQONKOJEbuKwuy4Np6VdV6qoaLLvoY86hjvQEgU82Vx1MSWRyYms6Sl0f+NtqxLI/rDVufATbP/ev996k3Q== @@ -4808,42 +4751,34 @@ deepmerge "^4.2.2" svgo "^2.5.0" -"@svgr/plugin-svgo@^5.5.0": - version "5.5.0" - resolved "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-5.5.0.tgz#02da55d85320549324e201c7b2e53bf431fcc246" - integrity sha512-r5swKk46GuQl4RrVejVwpeeJaydoxkdwkM1mBKOgJLBUJPGaLci6ylg/IjhrRsREKDkr4kbMWdgOtbXEh0fyLQ== +"@svgr/rollup@6.2.x": + version "6.2.1" + resolved "https://registry.npmjs.org/@svgr/rollup/-/rollup-6.2.1.tgz#23ac3173d2bd85842ca8858d3435332af1f064ab" + integrity sha512-5X6aMiGL1F5g0TubLY41GJ/Qf0Kz2xtbF37UbRJEHe2Z9CMlGl9Z3fQ8e28vmHrTptmymNRoHssgQ2Ejb1DARQ== dependencies: - cosmiconfig "^7.0.0" - deepmerge "^4.2.2" - svgo "^1.2.2" - -"@svgr/rollup@5.5.x": - version "5.5.0" - resolved "https://registry.npmjs.org/@svgr/rollup/-/rollup-5.5.0.tgz#9ceaaa6d463916e69aff8a9e10b3bb8fbb94688a" - integrity sha512-EiZmH2VTr+Xzyb6Ga8XtGa9MEbiU3WQnB5vHmqhwAUqibU3uwuwr7MN+QwIh/gtBk1ucMim8BCfcRTlLVREM8A== - dependencies: - "@babel/core" "^7.12.3" - "@babel/plugin-transform-react-constant-elements" "^7.12.1" - "@babel/preset-env" "^7.12.1" - "@babel/preset-react" "^7.12.5" - "@svgr/core" "^5.5.0" - "@svgr/plugin-jsx" "^5.5.0" - "@svgr/plugin-svgo" "^5.5.0" + "@babel/core" "^7.15.5" + "@babel/plugin-transform-react-constant-elements" "^7.14.5" + "@babel/preset-env" "^7.15.6" + "@babel/preset-react" "^7.14.5" + "@babel/preset-typescript" "^7.16.0" + "@svgr/core" "^6.2.1" + "@svgr/plugin-jsx" "^6.2.1" + "@svgr/plugin-svgo" "^6.2.0" rollup-pluginutils "^2.8.2" -"@svgr/webpack@5.5.x": - version "5.5.0" - resolved "https://registry.npmjs.org/@svgr/webpack/-/webpack-5.5.0.tgz#aae858ee579f5fa8ce6c3166ef56c6a1b381b640" - integrity sha512-DOBOK255wfQxguUta2INKkzPj6AIS6iafZYiYmHn6W3pHlycSRRlvWKCfLDG10fXfLWqE3DJHgRUOyJYmARa7g== +"@svgr/webpack@6.2.x": + version "6.2.1" + resolved "https://registry.npmjs.org/@svgr/webpack/-/webpack-6.2.1.tgz#ef5d51c1b6be4e7537fb9f76b3f2b2e22b63c58d" + integrity sha512-h09ngMNd13hnePwgXa+Y5CgOjzlCvfWLHg+MBnydEedAnuLRzUHUJmGS3o2OsrhxTOOqEsPOFt5v/f6C5Qulcw== dependencies: - "@babel/core" "^7.12.3" - "@babel/plugin-transform-react-constant-elements" "^7.12.1" - "@babel/preset-env" "^7.12.1" - "@babel/preset-react" "^7.12.5" - "@svgr/core" "^5.5.0" - "@svgr/plugin-jsx" "^5.5.0" - "@svgr/plugin-svgo" "^5.5.0" - loader-utils "^2.0.0" + "@babel/core" "^7.15.5" + "@babel/plugin-transform-react-constant-elements" "^7.14.5" + "@babel/preset-env" "^7.15.6" + "@babel/preset-react" "^7.14.5" + "@babel/preset-typescript" "^7.15.0" + "@svgr/core" "^6.2.1" + "@svgr/plugin-jsx" "^6.2.1" + "@svgr/plugin-svgo" "^6.2.0" "@szmarczak/http-timer@^1.1.2": version "1.1.2" @@ -5023,9 +4958,11 @@ integrity sha512-dB14TltT1SNq73z3MaZfKyyBZ37NAgAFl8jze59bisR4fJ6pB6AYGxItHFkooZbN7UcVJX/cFudM4p8wp1W4rA== "@types/aws4@^1.5.1": - version "1.5.2" - resolved "https://registry.npmjs.org/@types/aws4/-/aws4-1.5.2.tgz#34e35b4405a619b9205be3e7678963bc7c8a47db" - integrity sha512-r8+XOv0BKw3Br0oU6w9cfu21PaQq/5ZeXvMOivNQYJLc9WcPCpEFDaQu72QNEQjYv5Otu48VhjjnbtwrSmk/rg== + version "1.11.1" + resolved "https://registry.npmjs.org/@types/aws4/-/aws4-1.11.1.tgz#1783c88bd2a2fd0ad5ed497668a6d0df8d5f3c43" + integrity sha512-yUnPMlHP5JMZJiiNZElJG5qj1ShezlaET6Bug9SBhYsxKVamh7aOwl7Q/XR1Y//cZ5PoeRb9j4hi9svb2+FLlg== + dependencies: + "@types/node" "*" "@types/babel__core@^7.0.0", "@types/babel__core@^7.1.7": version "7.1.9" @@ -5294,9 +5231,9 @@ "@types/d3-selection" "*" "@types/dagre@^0.7.44": - version "0.7.46" - resolved "https://registry.npmjs.org/@types/dagre/-/dagre-0.7.46.tgz#c51ffcc62ca8a9affa07f5e06842acd840d3d442" - integrity sha512-ku3y+F8sPqmiB5Ugl22NpukI2dLAViJiWwdtueXLeuF4fxZozl+bytPSFVlLu/gDgaKiwobu3LBXXRWktIMiIA== + version "0.7.47" + resolved "https://registry.npmjs.org/@types/dagre/-/dagre-0.7.47.tgz#1d1b89e1fac36aaf5ef5ed6274bb123073095ac5" + integrity sha512-oX+3aRf7L6Cqq1MvbWmmD7FpAU/T8URwFFuHBagAiyHILn3i+RNZ35/tvyq28de+lZGY3W19BxJ7FeITQDO7aA== "@types/debug@^4.0.0": version "4.1.7" @@ -5903,11 +5840,6 @@ dependencies: "@types/node" "*" -"@types/q@^1.5.1": - version "1.5.2" - resolved "https://registry.npmjs.org/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8" - integrity sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw== - "@types/qs@*": version "6.9.6" resolved "https://registry.npmjs.org/@types/qs/-/qs-6.9.6.tgz#df9c3c8b31a247ec315e6996566be3171df4b3b1" @@ -6055,9 +5987,9 @@ integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA== "@types/rollup-plugin-peer-deps-external@^2.2.0": - version "2.2.0" - resolved "https://registry.npmjs.org/@types/rollup-plugin-peer-deps-external/-/rollup-plugin-peer-deps-external-2.2.0.tgz#eae7d8b9d27fa037f5bcaded24e389f85b81973c" - integrity sha512-BiztED+KYJPBI3ihLSOuuZSzy836WAOpC9UrMtDqk3+VeByR8A5pJJ9pCVnq/dfB4wyCeiFL+FlyJnqZuP3pxg== + version "2.2.1" + resolved "https://registry.npmjs.org/@types/rollup-plugin-peer-deps-external/-/rollup-plugin-peer-deps-external-2.2.1.tgz#7711fe77727c2ec920d3e096fa4e61d02734a23d" + integrity sha512-CUK4Mi3M3A/0coRUeo4McvUFOxR5H6UYd6Wt3D+K4c4fJupolMSoIxsZaBG1g/BJQOaujf78Pf7KhgfhrX1FZA== dependencies: "@types/node" "*" rollup "^0.63.4" @@ -6196,6 +6128,13 @@ dependencies: "@types/superagent" "*" +"@types/svgo@^2.6.2": + version "2.6.2" + resolved "https://registry.npmjs.org/@types/svgo/-/svgo-2.6.2.tgz#97d8be0c50ff0562ed7522ba840149aee1c970e3" + integrity sha512-m1SqMc/EDAZ8v0BBX+NmlYytUXtvrMD2/J9LICwnMvAuJwb0GSmACU3XPvcORqE7ghEJA4Mk6NYzpwhQI/biPw== + dependencies: + "@types/node" "*" + "@types/swagger-ui-react@^4.1.1": version "4.1.1" resolved "https://registry.npmjs.org/@types/swagger-ui-react/-/swagger-ui-react-4.1.1.tgz#6ae70f5b966941eb6655d79d1114d9b9ef69a980" @@ -6766,10 +6705,10 @@ agent-base@^6.0.2: dependencies: debug "4" -agentkeepalive@^4.1.3, agentkeepalive@^4.1.4: - version "4.1.4" - resolved "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.1.4.tgz#d928028a4862cb11718e55227872e842a44c945b" - integrity sha512-+V/rGa3EuU74H6wR04plBb7Ks10FbtUQgRj/FQOG7uUIEuaINI+AiqJR1k6t3SVNs7o7ZjIdus6706qqzVq8jQ== +agentkeepalive@^4.1.3, agentkeepalive@^4.1.4, agentkeepalive@^4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.0.tgz#616ce94ccb41d1a39a45d203d8076fe98713062d" + integrity sha512-0PhAp58jZNw13UJv7NVdTGb0ZcghHUb3DrZ046JiiJY/BOaTTpbwdHq2VObPCBV8M2GPh7sgrJ3AQ8Ey468LJw== dependencies: debug "^4.1.0" depd "^1.1.2" @@ -7067,7 +7006,7 @@ aproba@^1.0.3: resolved "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== -aproba@^2.0.0: +"aproba@^1.0.3 || ^2.0.0", aproba@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== @@ -7106,13 +7045,21 @@ archiver@^5.0.2, archiver@^5.3.0: tar-stream "^2.2.0" zip-stream "^4.1.0" -are-we-there-yet@^1.1.5: - version "1.1.7" - resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz#b15474a932adab4ff8a50d9adfa7e4e926f21146" - integrity sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g== +are-we-there-yet@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz#372e0e7bd279d8e94c653aaa1f67200884bf3e1c" + integrity sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw== dependencies: delegates "^1.0.0" - readable-stream "^2.0.6" + readable-stream "^3.6.0" + +are-we-there-yet@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.0.tgz#ba20bd6b553e31d62fc8c31bd23d22b95734390d" + integrity sha512-0GWpv50YSOcLXaN6/FAKY3vfRbllXWV2xvfA/oKJF8pzFhWXPV+yjhJXDBbjscDYowv7Yw1A3uigpzn5iEGTyw== + dependencies: + delegates "^1.0.0" + readable-stream "^3.6.0" are-we-there-yet@~1.1.2: version "1.1.5" @@ -7734,17 +7681,17 @@ bignumber.js@^9.0.0: resolved "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz#8d7ba124c882bfd8e43260c67475518d0689e4e5" integrity sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA== -bin-links@^2.2.1: - version "2.2.1" - resolved "https://registry.npmjs.org/bin-links/-/bin-links-2.2.1.tgz#347d9dbb48f7d60e6c11fe68b77a424bee14d61b" - integrity sha512-wFzVTqavpgCCYAh8SVBdnZdiQMxTkGR+T3b14CNpBXIBe2neJWaMGAZ55XWWHELJJ89dscuq0VCBqcVaIOgCMg== +bin-links@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/bin-links/-/bin-links-3.0.0.tgz#8273063638919f6ba4fbe890de9438c1b3adf0b7" + integrity sha512-fC7kPWcEkAWBgCKxmAMqZldlIeHsXwQy9JXzrppAVQiukGiDKxmYesJcBKWu6UMwx/5GOfo10wtK/4zy+Xt/mg== dependencies: cmd-shim "^4.0.1" - mkdirp "^1.0.3" + mkdirp-infer-owner "^2.0.0" npm-normalize-package-bin "^1.0.0" read-cmd-shim "^2.0.0" rimraf "^3.0.0" - write-file-atomic "^3.0.3" + write-file-atomic "^4.0.0" binary-extensions@^2.0.0: version "2.0.0" @@ -7831,7 +7778,7 @@ bonjour@^3.5.0: multicast-dns "^6.0.1" multicast-dns-service-types "^1.1.0" -boolbase@^1.0.0, boolbase@~1.0.0: +boolbase@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= @@ -8090,7 +8037,7 @@ bytes@3.1.1: resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.1.tgz#3f018291cb4cbad9accb6e6970bca9c8889e879a" integrity sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg== -cacache@^15.0.3, cacache@^15.0.5, cacache@^15.2.0: +cacache@^15.0.3, cacache@^15.0.5, cacache@^15.2.0, cacache@^15.3.0: version "15.3.0" resolved "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz#dc85380fb2f556fe3dda4c719bfa0ec875a7f1eb" integrity sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ== @@ -8147,17 +8094,17 @@ cacheable-request@^6.0.0: normalize-url "^4.1.0" responselike "^1.0.2" -cacheable-request@^7.0.1: - version "7.0.1" - resolved "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.1.tgz#062031c2856232782ed694a257fa35da93942a58" - integrity sha512-lt0mJ6YAnsrBErpTMWeu5kl/tg9xMAWjavYTN6VQXM1A/teBITuNcccXsCxF0tDQQJf9DfAaX5O4e0zp0KlfZw== +cacheable-request@^7.0.2: + version "7.0.2" + resolved "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz#ea0d0b889364a25854757301ca12b2da77f91d27" + integrity sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew== dependencies: clone-response "^1.0.2" get-stream "^5.1.0" http-cache-semantics "^4.0.0" keyv "^4.0.0" lowercase-keys "^2.0.0" - normalize-url "^4.1.0" + normalize-url "^6.0.1" responselike "^2.0.0" cachedir@^2.3.0: @@ -8687,15 +8634,6 @@ co@^4.6.0: resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= -coa@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz#43f6c21151b4ef2bf57187db0d73de229e3e7ec3" - integrity sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA== - dependencies: - "@types/q" "^1.5.1" - chalk "^2.4.1" - q "^1.1.2" - code-error-fragment@0.0.230: version "0.0.230" resolved "https://registry.npmjs.org/code-error-fragment/-/code-error-fragment-0.0.230.tgz#d736d75c832445342eca1d1fedbf17d9618b14d7" @@ -8779,6 +8717,11 @@ color-string@^1.5.2, color-string@^1.6.0: color-name "^1.0.0" simple-swizzle "^0.2.2" +color-support@^1.1.2: + version "1.1.3" + resolved "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" + integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== + color@3.0.x: version "3.0.0" resolved "https://registry.npmjs.org/color/-/color-3.0.0.tgz#d920b4328d534a3ac8295d68f7bd4ba6c427be9a" @@ -9051,7 +8994,7 @@ console-browserify@^1.1.0: resolved "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== -console-control-strings@^1.0.0, console-control-strings@~1.1.0: +console-control-strings@^1.0.0, console-control-strings@^1.1.0, console-control-strings@~1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= @@ -9358,9 +9301,9 @@ create-require@^1.1.0: integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== cronstrue@^1.122.0: - version "1.123.0" - resolved "https://registry.npmjs.org/cronstrue/-/cronstrue-1.123.0.tgz#de622dd8ea07981790f488d3f89a25e6e728ac8b" - integrity sha512-hVu9yNYRYr+jj5KET1p7FaBxFwtCHM1ByffP9lZ6yJ6p53u4VEmzH8117v9PUydxWNzc8Eq+sCZEzsKcB3ckiA== + version "1.125.0" + resolved "https://registry.npmjs.org/cronstrue/-/cronstrue-1.125.0.tgz#8030816d033d00caade9b2a9f9b71e69175bcf42" + integrity sha512-qkC5mVbVGuuyBVXmam5anaRtbLcgfBUKajoyZqCdf/XBdgF43PsLSEm8eEi2dsI3YbqDPbLSH2mWNzM1dVqHgQ== cross-env@^7.0.0: version "7.0.3" @@ -9497,34 +9440,19 @@ css-in-js-utils@^2.0.0: isobject "^3.0.1" css-loader@^6.5.1: - version "6.5.1" - resolved "https://registry.npmjs.org/css-loader/-/css-loader-6.5.1.tgz#0c43d4fbe0d97f699c91e9818cb585759091d1b1" - integrity sha512-gEy2w9AnJNnD9Kuo4XAP9VflW/ujKoS9c/syO+uWMlm5igc7LysKzPXaDoR2vroROkSwsTS2tGr1yGGEbZOYZQ== + version "6.6.0" + resolved "https://registry.npmjs.org/css-loader/-/css-loader-6.6.0.tgz#c792ad5510bd1712618b49381bd0310574fafbd3" + integrity sha512-FK7H2lisOixPT406s5gZM1S3l8GrfhEBT3ZiL2UX1Ng1XWs0y2GPllz/OTyvbaHe12VgQrIXIzuEGVlbUhodqg== dependencies: icss-utils "^5.1.0" - postcss "^8.2.15" + postcss "^8.4.5" postcss-modules-extract-imports "^3.0.0" postcss-modules-local-by-default "^4.0.0" postcss-modules-scope "^3.0.0" postcss-modules-values "^4.0.0" - postcss-value-parser "^4.1.0" + postcss-value-parser "^4.2.0" semver "^7.3.5" -css-select-base-adapter@^0.1.1: - version "0.1.1" - resolved "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz#3b2ff4972cc362ab88561507a95408a1432135d7" - integrity sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w== - -css-select@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz#6a34653356635934a81baca68d0255432105dbef" - integrity sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ== - dependencies: - boolbase "^1.0.0" - css-what "^3.2.1" - domutils "^1.7.0" - nth-check "^1.0.2" - css-select@^4.1.3: version "4.1.3" resolved "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz#a70440f70317f2669118ad74ff105e65849c7067" @@ -9536,14 +9464,6 @@ css-select@^4.1.3: domutils "^2.6.0" nth-check "^2.0.0" -css-tree@1.0.0-alpha.37: - version "1.0.0-alpha.37" - resolved "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz#98bebd62c4c1d9f960ec340cf9f7522e30709a22" - integrity sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg== - dependencies: - mdn-data "2.0.4" - source-map "^0.6.1" - css-tree@^1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/css-tree/-/css-tree-1.1.2.tgz#9ae393b5dafd7dae8a622475caec78d3d8fbd7b5" @@ -9573,11 +9493,6 @@ css-vendor@^2.0.8: "@babel/runtime" "^7.8.3" is-in-browser "^1.0.2" -css-what@^3.2.1: - version "3.4.2" - resolved "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz#ea7026fcb01777edbde52124e21f327e7ae950e4" - integrity sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ== - css-what@^5.0.0: version "5.1.0" resolved "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz#3f7b707aadf633baf62c2ceb8579b545bb40f7fe" @@ -9657,13 +9572,6 @@ cssnano@^5.0.1: lilconfig "^2.0.3" yaml "^1.10.2" -csso@^4.0.2: - version "4.0.2" - resolved "https://registry.npmjs.org/csso/-/csso-4.0.2.tgz#e5f81ab3a56b8eefb7f0092ce7279329f454de3d" - integrity sha512-kS7/oeNVXkHWxby5tHVxlhjizRCSv8QdU7hB2FpdAibDU8FjTAolhNjKNTiLzXtUrKT6HwClE81yXwEk1309wg== - dependencies: - css-tree "1.0.0-alpha.37" - csso@^4.2.0: version "4.2.0" resolved "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529" @@ -10508,14 +10416,6 @@ dom-helpers@^5.0.1: "@babel/runtime" "^7.8.7" csstype "^2.6.7" -dom-serializer@0: - version "0.2.2" - resolved "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" - integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== - dependencies: - domelementtype "^2.0.1" - entities "^2.0.0" - dom-serializer@^1.0.1: version "1.2.0" resolved "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.2.0.tgz#3433d9136aeb3c627981daa385fc7f32d27c48f1" @@ -10535,11 +10435,6 @@ domain-browser@^1.1.1: resolved "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== -domelementtype@1: - version "1.3.1" - resolved "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" - integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== - domelementtype@^2.0.1, domelementtype@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/domelementtype/-/domelementtype-2.1.0.tgz#a851c080a6d1c3d94344aed151d99f669edf585e" @@ -10577,17 +10472,9 @@ dompurify@=2.3.3: integrity sha512-dqnqRkPMAjOZE0FogZ+ceJNM2dZ3V/yNOuFB7+39qpO93hHhfRpHw3heYQC7DPK9FqbQTfBKUJhiSfz4MvXYwg== dompurify@^2.2.7, dompurify@^2.2.9: - version "2.3.5" - resolved "https://registry.npmjs.org/dompurify/-/dompurify-2.3.5.tgz#c83ed5a3ae5ce23e52efe654ea052ffb358dd7e3" - integrity sha512-kD+f8qEaa42+mjdOpKeztu9Mfx5bv9gVLO6K9jRx4uGvh6Wv06Srn4jr1wPNY2OOUGGSKHNFN+A8MA3v0E0QAQ== - -domutils@^1.7.0: - version "1.7.0" - resolved "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" - integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== - dependencies: - dom-serializer "0" - domelementtype "1" + version "2.3.6" + resolved "https://registry.npmjs.org/dompurify/-/dompurify-2.3.6.tgz#2e019d7d7617aacac07cbbe3d88ae3ad354cf875" + integrity sha512-OFP2u/3T1R5CEgWCEONuJ1a5+MFKnOYpkywpUSxv/dj1LeBT1erK+JwM7zK0ROy2BRhqVCf0LRw/kHqKuMkVGg== domutils@^2.5.2, domutils@^2.6.0: version "2.8.0" @@ -10850,7 +10737,7 @@ error@^10.4.0: resolved "https://registry.npmjs.org/error/-/error-10.4.0.tgz#6fcf0fd64bceb1e750f8ed9a3dd880f00e46a487" integrity sha512-YxIFEJuhgcICugOUvRx5th0UM+ActZ9sjY0QJmeVwsQdvosZ7kYzc9QqS0Da3R5iUmgU5meGIxh0xBeZpMVeLw== -es-abstract@^1.17.0-next.1, es-abstract@^1.17.2, es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2: +es-abstract@^1.17.0-next.1, es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2: version "1.18.0" resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0.tgz#ab80b359eecb7ede4c298000390bc5ac3ec7b5a4" integrity sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw== @@ -10948,70 +10835,70 @@ es6-weak-map@^2.0.3: es6-iterator "^2.0.3" es6-symbol "^3.1.1" -esbuild-android-arm64@0.14.21: - version "0.14.21" - resolved "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.21.tgz#8842d0c3b7c81fbe2dc46ddb416ffd6eb822184b" - integrity sha512-Bqgld1TY0wZv8TqiQmVxQFgYzz8ZmyzT7clXBDZFkOOdRybzsnj8AZuK1pwcLVA7Ya6XncHgJqIao7NFd3s0RQ== +esbuild-android-arm64@0.14.22: + version "0.14.22" + resolved "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.22.tgz#fb051169a63307d958aec85ad596cfc7d7770303" + integrity sha512-k1Uu4uC4UOFgrnTj2zuj75EswFSEBK+H6lT70/DdS4mTAOfs2ECv2I9ZYvr3w0WL0T4YItzJdK7fPNxcPw6YmQ== -esbuild-darwin-64@0.14.21: - version "0.14.21" - resolved "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.21.tgz#ec7df02ad88ecf7f8fc23a3ed7917e07dea0c9c9" - integrity sha512-j+Eg+e13djzyYINVvAbOo2/zvZ2DivuJJTaBrJnJHSD7kUNuGHRkHoSfFjbI80KHkn091w350wdmXDNSgRjfYQ== +esbuild-darwin-64@0.14.22: + version "0.14.22" + resolved "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.22.tgz#615ea0a9de67b57a293a7128d7ac83ee307a856d" + integrity sha512-d8Ceuo6Vw6HM3fW218FB6jTY6O3r2WNcTAU0SGsBkXZ3k8SDoRLd3Nrc//EqzdgYnzDNMNtrWegK2Qsss4THhw== -esbuild-darwin-arm64@0.14.21: - version "0.14.21" - resolved "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.21.tgz#0c2a977edec1ef54097ee56a911518c820d4e5e4" - integrity sha512-nDNTKWDPI0RuoPj5BhcSB2z5EmZJJAyRtZLIjyXSqSpAyoB8eyAKXl4lB8U2P78Fnh4Lh1le/fmpewXE04JhBQ== +esbuild-darwin-arm64@0.14.22: + version "0.14.22" + resolved "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.22.tgz#82054dcfcecb15ccfd237093b8008e7745a99ad9" + integrity sha512-YAt9Tj3SkIUkswuzHxkaNlT9+sg0xvzDvE75LlBo4DI++ogSgSmKNR6B4eUhU5EUUepVXcXdRIdqMq9ppeRqfw== -esbuild-freebsd-64@0.14.21: - version "0.14.21" - resolved "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.21.tgz#f5b5fc1d031286c3a0949d1bda7db774b7d0404e" - integrity sha512-zIurkCHXhxELiDZtLGiexi8t8onQc2LtuE+S7457H/pP0g0MLRKMrsn/IN4LDkNe6lvBjuoZZi2OfelOHn831g== +esbuild-freebsd-64@0.14.22: + version "0.14.22" + resolved "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.22.tgz#778a818c5b078d5cdd6bb6c0e0797217d196999b" + integrity sha512-ek1HUv7fkXMy87Qm2G4IRohN+Qux4IcnrDBPZGXNN33KAL0pEJJzdTv0hB/42+DCYWylSrSKxk3KUXfqXOoH4A== -esbuild-freebsd-arm64@0.14.21: - version "0.14.21" - resolved "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.21.tgz#a05cab908013e4992b31a675850b8c44eb468c0c" - integrity sha512-wdxMmkJfbwcN+q85MpeUEamVZ40FNsBa9mPq8tAszDn8TRT2HoJvVRADPIIBa9SWWwlDChIMjkDKAnS3KS/sPA== +esbuild-freebsd-arm64@0.14.22: + version "0.14.22" + resolved "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.22.tgz#18da93b9f3db2e036f72383bfe73b28b73bb332c" + integrity sha512-zPh9SzjRvr9FwsouNYTqgqFlsMIW07O8mNXulGeQx6O5ApgGUBZBgtzSlBQXkHi18WjrosYfsvp5nzOKiWzkjQ== -esbuild-linux-32@0.14.21: - version "0.14.21" - resolved "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.21.tgz#638d244cc58b951f447addb4bade628d126ef84b" - integrity sha512-fmxvyzOPPh2xiEHojpCeIQP6pXcoKsWbz3ryDDIKLOsk4xp3GbpHIEAWP0xTeuhEbendmvBDVKbAVv3PnODXLg== +esbuild-linux-32@0.14.22: + version "0.14.22" + resolved "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.22.tgz#d0d5d9f5bb3536e17ac097e9512019c65b7c0234" + integrity sha512-SnpveoE4nzjb9t2hqCIzzTWBM0RzcCINDMBB67H6OXIuDa4KqFqaIgmTchNA9pJKOVLVIKd5FYxNiJStli21qg== -esbuild-linux-64@0.14.21: - version "0.14.21" - resolved "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.21.tgz#8eb634abee928be7e35b985fafbfef2f2e31397f" - integrity sha512-edZyNOv1ql+kpmlzdqzzDjRQYls+tSyi4QFi+PdBhATJFUqHsnNELWA9vMSzAaInPOEaVUTA5Ml28XFChcy4DA== +esbuild-linux-64@0.14.22: + version "0.14.22" + resolved "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.22.tgz#2773d540971999ea7f38107ef92fca753f6a8c30" + integrity sha512-Zcl9Wg7gKhOWWNqAjygyqzB+fJa19glgl2JG7GtuxHyL1uEnWlpSMytTLMqtfbmRykIHdab797IOZeKwk5g0zg== -esbuild-linux-arm64@0.14.21: - version "0.14.21" - resolved "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.21.tgz#e05599ea6253b58394157da162d856f3ead62f9e" - integrity sha512-t5qxRkq4zdQC0zXpzSB2bTtfLgOvR0C6BXYaRE/6/k8/4SrkZcTZBeNu+xGvwCU4b5dU9ST9pwIWkK6T1grS8g== +esbuild-linux-arm64@0.14.22: + version "0.14.22" + resolved "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.22.tgz#5d4480ce6d6bffab1dd76a23158f5a5ab33e7ba4" + integrity sha512-8q/FRBJtV5IHnQChO3LHh/Jf7KLrxJ/RCTGdBvlVZhBde+dk3/qS9fFsUy+rs3dEi49aAsyVitTwlKw1SUFm+A== -esbuild-linux-arm@0.14.21: - version "0.14.21" - resolved "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.21.tgz#1ae1078231cf689d3ba894a32d3723c0be9b91fd" - integrity sha512-aSU5pUueK6afqmLQsbU+QcFBT62L+4G9hHMJDHWfxgid6hzhSmfRH9U/f+ymvxsSTr/HFRU4y7ox8ZyhlVl98w== +esbuild-linux-arm@0.14.22: + version "0.14.22" + resolved "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.22.tgz#c6391b3f7c8fa6d3b99a7e893ce0f45f3a921eef" + integrity sha512-soPDdbpt/C0XvOOK45p4EFt8HbH5g+0uHs5nUKjHVExfgR7du734kEkXR/mE5zmjrlymk5AA79I0VIvj90WZ4g== -esbuild-linux-mips64le@0.14.21: - version "0.14.21" - resolved "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.21.tgz#f05be62d126764e99b37edcac5bb49b78c7a8890" - integrity sha512-jLZLQGCNlUsmIHtGqNvBs3zN+7a4D9ckf0JZ+jQTwHdZJ1SgV9mAjbB980OFo66LoY+WeM7t3WEnq3FjI1zw4A== +esbuild-linux-mips64le@0.14.22: + version "0.14.22" + resolved "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.22.tgz#2c8dabac355c502e86c38f9f292b3517d8e181f3" + integrity sha512-SiNDfuRXhGh1JQLLA9JPprBgPVFOsGuQ0yDfSPTNxztmVJd8W2mX++c4FfLpAwxuJe183mLuKf7qKCHQs5ZnBQ== -esbuild-linux-ppc64le@0.14.21: - version "0.14.21" - resolved "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.21.tgz#592c98d82dad7982268ef8deed858c4566f07ab1" - integrity sha512-4TWxpK391en2UBUw6GSrukToTDu6lL9vkm3Ll40HrI08WG3qcnJu7bl8e1+GzelDsiw1QmfAY/nNvJ6iaHRpCQ== +esbuild-linux-ppc64le@0.14.22: + version "0.14.22" + resolved "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.22.tgz#69d71b2820d5c94306072dac6094bae38e77d1c0" + integrity sha512-6t/GI9I+3o1EFm2AyN9+TsjdgWCpg2nwniEhjm2qJWtJyJ5VzTXGUU3alCO3evopu8G0hN2Bu1Jhz2YmZD0kng== -esbuild-linux-riscv64@0.14.21: - version "0.14.21" - resolved "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.21.tgz#0db7bd6f10d8f9afea973a7d6bf87b449b864b7b" - integrity sha512-fElngqOaOfTsF+u+oetDLHsPG74vB2ZaGZUqmGefAJn3a5z9Z2pNa4WpVbbKgHpaAAy5tWM1m1sbGohj6Ki6+Q== +esbuild-linux-riscv64@0.14.22: + version "0.14.22" + resolved "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.22.tgz#c0ec0fc3a23624deebf657781550d2329cec4213" + integrity sha512-AyJHipZKe88sc+tp5layovquw5cvz45QXw5SaDgAq2M911wLHiCvDtf/07oDx8eweCyzYzG5Y39Ih568amMTCQ== -esbuild-linux-s390x@0.14.21: - version "0.14.21" - resolved "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.21.tgz#254a9354d34c9d1b41a3e21d2ec9269cbbb2c5df" - integrity sha512-brleZ6R5fYv0qQ7ZBwenQmP6i9TdvJCB092c/3D3pTLQHBGHJb5zWgKxOeS7bdHzmLy6a6W7GbFk6QKpjyD6QA== +esbuild-linux-s390x@0.14.22: + version "0.14.22" + resolved "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.22.tgz#ec2af4572d63336cfb27f5a5c851fb1b6617dd91" + integrity sha512-Sz1NjZewTIXSblQDZWEFZYjOK6p8tV6hrshYdXZ0NHTjWE+lwxpOpWeElUGtEmiPcMT71FiuA9ODplqzzSxkzw== esbuild-loader@^2.18.0: version "2.18.0" @@ -11025,60 +10912,60 @@ esbuild-loader@^2.18.0: tapable "^2.2.0" webpack-sources "^2.2.0" -esbuild-netbsd-64@0.14.21: - version "0.14.21" - resolved "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.21.tgz#4cb783d060b02bf3b897a9a12cce2b3b547726f8" - integrity sha512-nCEgsLCQ8RoFWVV8pVI+kX66ICwbPP/M9vEa0NJGIEB/Vs5sVGMqkf67oln90XNSkbc0bPBDuo4G6FxlF7PN8g== +esbuild-netbsd-64@0.14.22: + version "0.14.22" + resolved "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.22.tgz#0e283278e9fdbaa7f0930f93ee113d7759cd865e" + integrity sha512-TBbCtx+k32xydImsHxvFgsOCuFqCTGIxhzRNbgSL1Z2CKhzxwT92kQMhxort9N/fZM2CkRCPPs5wzQSamtzEHA== -esbuild-openbsd-64@0.14.21: - version "0.14.21" - resolved "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.21.tgz#f886b93feefddbe573528fa4b421c9c6e2bc969b" - integrity sha512-h9zLMyVD0T73MDTVYIb/qUTokwI6EJH9O6wESuTNq6+XpMSr6C5aYZ4fvFKdNELW+Xsod+yDS2hV2JTUAbFrLA== +esbuild-openbsd-64@0.14.22: + version "0.14.22" + resolved "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.22.tgz#2a73bba04e16d8ef278fbe2be85248e12a2f2cc2" + integrity sha512-vK912As725haT313ANZZZN+0EysEEQXWC/+YE4rQvOQzLuxAQc2tjbzlAFREx3C8+uMuZj/q7E5gyVB7TzpcTA== -esbuild-sunos-64@0.14.21: - version "0.14.21" - resolved "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.21.tgz#3829e4d57d4cb6950837fe90b0b67cdfb37cf13a" - integrity sha512-Kl+7Cot32qd9oqpLdB1tEGXEkjBlijrIxMJ0+vlDFaqsODutif25on0IZlFxEBtL2Gosd4p5WCV1U7UskNQfXA== +esbuild-sunos-64@0.14.22: + version "0.14.22" + resolved "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.22.tgz#8fe03513b8b2e682a6d79d5e3ca5849651a3c1d8" + integrity sha512-/mbJdXTW7MTcsPhtfDsDyPEOju9EOABvCjeUU2OJ7fWpX/Em/H3WYDa86tzLUbcVg++BScQDzqV/7RYw5XNY0g== -esbuild-windows-32@0.14.21: - version "0.14.21" - resolved "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.21.tgz#b858a22d1a82e53cdc59310cd56294133f7a95e7" - integrity sha512-V7vnTq67xPBUCk/9UtlolmQ798Ecjdr1ZoI1vcSgw7M82aSSt0eZdP6bh5KAFZU8pxDcx3qoHyWQfHYr11f22A== +esbuild-windows-32@0.14.22: + version "0.14.22" + resolved "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.22.tgz#a75df61e3e49df292a1842be8e877a3153ee644f" + integrity sha512-1vRIkuvPTjeSVK3diVrnMLSbkuE36jxA+8zGLUOrT4bb7E/JZvDRhvtbWXWaveUc/7LbhaNFhHNvfPuSw2QOQg== -esbuild-windows-64@0.14.21: - version "0.14.21" - resolved "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.21.tgz#7bb5a027d5720cf9caf18a4bedd11327208f1f12" - integrity sha512-kDgHjKOHwjfJDCyRGELzVxiP/RBJBTA+wyspf78MTTJQkyPuxH2vChReNdWc+dU2S4gIZFHMdP1Qrl/k22ZmaA== +esbuild-windows-64@0.14.22: + version "0.14.22" + resolved "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.22.tgz#d06cf8bbe4945b8bf95a730d871e54a22f635941" + integrity sha512-AxjIDcOmx17vr31C5hp20HIwz1MymtMjKqX4qL6whPj0dT9lwxPexmLj6G1CpR3vFhui6m75EnBEe4QL82SYqw== -esbuild-windows-arm64@0.14.21: - version "0.14.21" - resolved "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.21.tgz#25df54521ad602c826b262ea2e7cc1fe80f5c2f5" - integrity sha512-8Sbo0zpzgwWrwjQYLmHF78f7E2xg5Ve63bjB2ng3V2aManilnnTGaliq2snYg+NOX60+hEvJHRdVnuIAHW0lVw== +esbuild-windows-arm64@0.14.22: + version "0.14.22" + resolved "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.22.tgz#f8b1b05c548073be8413a5ecb12d7c2f6e717227" + integrity sha512-5wvQ+39tHmRhNpu2Fx04l7QfeK3mQ9tKzDqqGR8n/4WUxsFxnVLfDRBGirIfk4AfWlxk60kqirlODPoT5LqMUg== esbuild@^0.14.1, esbuild@^0.14.10, esbuild@^0.14.6: - version "0.14.21" - resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.14.21.tgz#b3e05f900f1c4394f596d60d63d9816468f0f671" - integrity sha512-7WEoNMBJdLN993dr9h0CpFHPRc3yFZD+EAVY9lg6syJJ12gc5fHq8d75QRExuhnMkT2DaRiIKFThRvDWP+fO+A== + version "0.14.22" + resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.14.22.tgz#2b55fde89d7aa5aaaad791816d58ff9dfc5ed085" + integrity sha512-CjFCFGgYtbFOPrwZNJf7wsuzesx8kqwAffOlbYcFDLFuUtP8xloK1GH+Ai13Qr0RZQf9tE7LMTHJ2iVGJ1SKZA== optionalDependencies: - esbuild-android-arm64 "0.14.21" - esbuild-darwin-64 "0.14.21" - esbuild-darwin-arm64 "0.14.21" - esbuild-freebsd-64 "0.14.21" - esbuild-freebsd-arm64 "0.14.21" - esbuild-linux-32 "0.14.21" - esbuild-linux-64 "0.14.21" - esbuild-linux-arm "0.14.21" - esbuild-linux-arm64 "0.14.21" - esbuild-linux-mips64le "0.14.21" - esbuild-linux-ppc64le "0.14.21" - esbuild-linux-riscv64 "0.14.21" - esbuild-linux-s390x "0.14.21" - esbuild-netbsd-64 "0.14.21" - esbuild-openbsd-64 "0.14.21" - esbuild-sunos-64 "0.14.21" - esbuild-windows-32 "0.14.21" - esbuild-windows-64 "0.14.21" - esbuild-windows-arm64 "0.14.21" + esbuild-android-arm64 "0.14.22" + esbuild-darwin-64 "0.14.22" + esbuild-darwin-arm64 "0.14.22" + esbuild-freebsd-64 "0.14.22" + esbuild-freebsd-arm64 "0.14.22" + esbuild-linux-32 "0.14.22" + esbuild-linux-64 "0.14.22" + esbuild-linux-arm "0.14.22" + esbuild-linux-arm64 "0.14.22" + esbuild-linux-mips64le "0.14.22" + esbuild-linux-ppc64le "0.14.22" + esbuild-linux-riscv64 "0.14.22" + esbuild-linux-s390x "0.14.22" + esbuild-netbsd-64 "0.14.22" + esbuild-openbsd-64 "0.14.22" + esbuild-sunos-64 "0.14.22" + esbuild-windows-32 "0.14.22" + esbuild-windows-64 "0.14.22" + esbuild-windows-arm64 "0.14.22" escalade@^3.1.1: version "3.1.1" @@ -11566,10 +11453,10 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: "@material-ui/icons" "^4.9.1" "@material-ui/lab" "4.0.0-alpha.57" "@octokit/rest" "^18.5.3" - "@roadiehq/backstage-plugin-buildkite" "^1.3.4" - "@roadiehq/backstage-plugin-github-insights" "^1.4.2" - "@roadiehq/backstage-plugin-github-pull-requests" "^1.3.2" - "@roadiehq/backstage-plugin-travis-ci" "^1.3.2" + "@roadiehq/backstage-plugin-buildkite" "^1.3.8" + "@roadiehq/backstage-plugin-github-insights" "^1.5.0" + "@roadiehq/backstage-plugin-github-pull-requests" "^1.4.0" + "@roadiehq/backstage-plugin-travis-ci" "^1.3.6" history "^5.0.0" prop-types "^15.7.2" react "^17.0.2" @@ -11860,7 +11747,7 @@ extsprintf@^1.2.0: resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= -fast-decode-uri-component@^1.0.0: +fast-decode-uri-component@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz#46f8b6c22b30ff7a81357d4f59abfae938202543" integrity sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg== @@ -12096,12 +11983,13 @@ find-cache-dir@^2.0.0: make-dir "^2.0.0" pkg-dir "^3.0.0" -find-my-way@^2.2.2: - version "2.2.5" - resolved "https://registry.npmjs.org/find-my-way/-/find-my-way-2.2.5.tgz#86ce825266fa28cd962e538a45ec2aaa84c3d514" - integrity sha512-GjRZZlGcGmTh9t+6Xrj5K0YprpoAFCAiCPgmAH9Kb09O4oX6hYuckDfnDipYj+Q7B1GtYWSzDI5HEecNYscLQg== +find-my-way@^4.3.3: + version "4.5.1" + resolved "https://registry.npmjs.org/find-my-way/-/find-my-way-4.5.1.tgz#758e959194b90aea0270db18fff75e2fceb2239f" + integrity sha512-kE0u7sGoUFbMXcOG/xpkmz4sRLCklERnBcg7Ftuu1iAxsfEt2S46RLJ3Sq7vshsEy2wJT2hZxE58XZK27qa8kg== dependencies: - fast-decode-uri-component "^1.0.0" + fast-decode-uri-component "^1.0.1" + fast-deep-equal "^3.1.3" safe-regex2 "^2.0.0" semver-store "^0.3.0" @@ -12459,6 +12347,36 @@ functional-red-black-tree@^1.0.1: resolved "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= +gauge@^3.0.0: + version "3.0.2" + resolved "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz#03bf4441c044383908bcfa0656ad91803259b395" + integrity sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q== + dependencies: + aproba "^1.0.3 || ^2.0.0" + color-support "^1.1.2" + console-control-strings "^1.0.0" + has-unicode "^2.0.1" + object-assign "^4.1.1" + signal-exit "^3.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" + wide-align "^1.1.2" + +gauge@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/gauge/-/gauge-4.0.0.tgz#afba07aa0374a93c6219603b1fb83eaa2264d8f8" + integrity sha512-F8sU45yQpjQjxKkm1UOAhf0U/O0aFt//Fl7hsrNVto+patMHjs7dPI9mFOGUKbhrgKm0S3EjW3scMFuQmWSROw== + dependencies: + ansi-regex "^5.0.1" + aproba "^1.0.3 || ^2.0.0" + color-support "^1.1.2" + console-control-strings "^1.0.0" + has-unicode "^2.0.1" + signal-exit "^3.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" + wide-align "^1.1.2" + gauge@~2.7.3: version "2.7.4" resolved "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" @@ -12834,17 +12752,17 @@ google-p12-pem@^3.0.3: dependencies: node-forge "^1.0.0" -got@^11.8.0, got@^11.8.2: - version "11.8.2" - resolved "https://registry.npmjs.org/got/-/got-11.8.2.tgz#7abb3959ea28c31f3576f1576c1effce23f33599" - integrity sha512-D0QywKgIe30ODs+fm8wMZiAcZjypcCodPNuMz5H9Mny7RJ+IjJ10BdmGW7OM7fHXP+O7r6ZwapQ/YQmMSvB0UQ== +got@11.8.3, got@^11.8.0: + version "11.8.3" + resolved "https://registry.npmjs.org/got/-/got-11.8.3.tgz#f496c8fdda5d729a90b4905d2b07dbd148170770" + integrity sha512-7gtQ5KiPh1RtGS9/Jbv1ofDpBFuq42gyfEib+ejaRBJuj/3tQFeR5+gw57e4ipaU8c/rCjvX6fkQz2lyDlGAOg== dependencies: "@sindresorhus/is" "^4.0.0" "@szmarczak/http-timer" "^4.0.5" "@types/cacheable-request" "^6.0.1" "@types/responselike" "^1.0.0" cacheable-lookup "^5.0.3" - cacheable-request "^7.0.1" + cacheable-request "^7.0.2" decompress-response "^6.0.0" http2-wrapper "^1.0.0-beta.5.2" lowercase-keys "^2.0.0" @@ -13254,10 +13172,10 @@ headers-utils@^3.0.2: resolved "https://registry.npmjs.org/headers-utils/-/headers-utils-3.0.2.tgz#dfc65feae4b0e34357308aefbcafa99c895e59ef" integrity sha512-xAxZkM1dRyGV2Ou5bzMxBPNLoRCjcX+ya7KSWybQD2KwLphxsapUVK6x/02o7f4VU6GPSXch9vNY2+gkU8tYWQ== -helmet@^4.0.0: - version "4.4.1" - resolved "https://registry.npmjs.org/helmet/-/helmet-4.4.1.tgz#a17e1444d81d7a83ddc6e6f9bc6e2055b994efe7" - integrity sha512-G8tp0wUMI7i8wkMk2xLcEvESg5PiCitFMYgGRc/PwULB0RVhTP5GFdxOwvJwp9XVha8CuS8mnhmE8I/8dx/pbw== +helmet@^5.0.2: + version "5.0.2" + resolved "https://registry.npmjs.org/helmet/-/helmet-5.0.2.tgz#3264ec6bab96c82deaf65e3403c369424cb2366c" + integrity sha512-QWlwUZZ8BtlvwYVTSDTBChGf8EOcQ2LkGMnQJxSzD1mUu8CCjXJZq/BXP8eWw4kikRnzlhtYo3lCk0ucmYA3Vg== hexoid@1.0.0: version "1.0.0" @@ -13628,6 +13546,11 @@ ignore@^5.1.4, ignore@^5.1.8, ignore@^5.2.0: resolved "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== +immer@9.0.7: + version "9.0.7" + resolved "https://registry.npmjs.org/immer/-/immer-9.0.7.tgz#b6156bd7db55db7abc73fd2fdadf4e579a701075" + integrity sha512-KGllzpbamZDvOIxnmJ0jI840g7Oikx58lBPWV0hUh7dtAyZpFqqrBZdKka5GlTwMTZ1Tjc/bKKW4VSFAt6BqMA== + immer@^9.0.1, immer@^9.0.7: version "9.0.12" resolved "https://registry.npmjs.org/immer/-/immer-9.0.12.tgz#2d33ddf3ee1d247deab9d707ca472c8c942a0f20" @@ -13842,10 +13765,10 @@ interpret@^2.2.0: resolved "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9" integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw== -into-stream@^5.1.1: - version "5.1.1" - resolved "https://registry.npmjs.org/into-stream/-/into-stream-5.1.1.tgz#f9a20a348a11f3c13face22763f2d02e127f4db8" - integrity sha512-krrAJ7McQxGGmvaYbB7Q1mcA+cRwg9Ij2RfWIeVesNBgVDZmzY/Fa4IpZUT3bmdRzMzdf/mzltCG2Dq99IZGBA== +into-stream@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/into-stream/-/into-stream-6.0.0.tgz#4bfc1244c0128224e18b8870e85b2de8e66c6702" + integrity sha512-XHbaOAvP+uFKUFsOgoNPRjLkwB+I22JFPFe5OjTkQ0nwgj6+pSjb4NmB6VMxaPshLiOf+zcpOCBQuLwC1KHhZA== dependencies: from2 "^2.3.0" p-is-promise "^3.0.0" @@ -15563,15 +15486,15 @@ jsx-ast-utils@^3.2.1: array-includes "^3.1.3" object.assign "^4.1.2" -just-diff-apply@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/just-diff-apply/-/just-diff-apply-3.0.0.tgz#a77348d24f0694e378b57293dceb65bdf5a91c4f" - integrity sha512-K2MLc+ZC2DVxX4V61bIKPeMUUfj1YYZ3h0myhchDXOW1cKoPZMnjIoNCqv9bF2n5Oob1PFxuR2gVJxkxz4e58w== +just-diff-apply@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/just-diff-apply/-/just-diff-apply-4.0.1.tgz#da89c5a4ccb14aa8873c70e2c3b6695cef45dab5" + integrity sha512-AKOkzB5P6FkfP21UlZVX/OPXx/sC2GagpLX9cBxqHqDuRjwmZ/AJRKSNrB9jHPpRW1W1ONs6gly1gW46t055nQ== -just-diff@^3.0.1: - version "3.1.1" - resolved "https://registry.npmjs.org/just-diff/-/just-diff-3.1.1.tgz#d50c597c6fd4776495308c63bdee1b6839082647" - integrity sha512-sdMWKjRq8qWZEjDcVA6llnUT8RDEBIfOiGpYFPYa9u+2c39JCsejktSP7mj5eRid5EIvTzIpQ2kDOCw1Nq9BjQ== +just-diff@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/just-diff/-/just-diff-5.0.1.tgz#db8fe1cfeea1156f2374bfb289826dca28e7e390" + integrity sha512-X00TokkRIDotUIf3EV4xUm6ELc/IkqhS/vPSHdWnsM5y0HoNMfEqrazizI7g78lpHvnRSRt/PFfKtRqJCOGIuQ== just-extend@^4.0.2: version "4.2.1" @@ -15748,9 +15671,9 @@ ldap-filter@^0.3.3: assert-plus "^1.0.0" ldapjs@^2.2.0: - version "2.3.0" - resolved "https://registry.npmjs.org/ldapjs/-/ldapjs-2.3.0.tgz#999c85f642216709009dc8728e58ac7793888def" - integrity sha512-3Rbm3CS7vzTccpP1QnzKCEPok60L/b3BFlWU8r93P5oadCAaqCWEH9Td08crPnw4Ti20W8y0+ZKtFFNzxVu4kA== + version "2.3.1" + resolved "https://registry.npmjs.org/ldapjs/-/ldapjs-2.3.1.tgz#04136815fb1f21d692ac87fab5961a04d86e8b04" + integrity sha512-kf0tHHLrpwKaBAQOhYHXgdeh2PkFuCCxWgLb1MRn67ZQVo787D2pij3mmHVZx193GIdM8xcfi8HF6AIYYnj0fQ== dependencies: abstract-logging "^2.0.0" asn1 "^0.2.4" @@ -16373,6 +16296,11 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +lru-cache@^7.3.1: + version "7.3.1" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-7.3.1.tgz#7702e80694ec2bf19865567a469f2b081fcf53f5" + integrity sha512-nX1x4qUrKqwbIAhv4s9et4FIUVzNOpeY07bsjGUy8gwJrXH/wScImSQqXErmo/b2jZY2r0mohbLA9zVj7u1cNw== + lru-queue@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz#2738bd9f0d3cf4f84490c5736c48699ac632cda3" @@ -16439,6 +16367,28 @@ make-error@^1, make-error@^1.1.1, make-error@^1.3.6: resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== +make-fetch-happen@^10.0.1: + version "10.0.2" + resolved "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.0.2.tgz#0afb38d2f951b17ebc482b0b16c8d77f39dfe389" + integrity sha512-JSFLK53NJP22FL/eAGOyKsWbc2G3v+toPMD7Dq9PJKQCvK0i3t8hGkKxe+3YZzwYa+c0kxRHu7uxH3fvO+rsaA== + dependencies: + agentkeepalive "^4.2.0" + cacache "^15.3.0" + http-cache-semantics "^4.1.0" + http-proxy-agent "^5.0.0" + https-proxy-agent "^5.0.0" + is-lambda "^1.0.1" + lru-cache "^7.3.1" + minipass "^3.1.6" + minipass-collect "^1.0.2" + minipass-fetch "^1.4.1" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.4" + negotiator "^0.6.3" + promise-retry "^2.0.1" + socks-proxy-agent "^6.1.1" + ssri "^8.0.1" + make-fetch-happen@^8.0.9: version "8.0.14" resolved "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-8.0.14.tgz#aaba73ae0ab5586ad8eaa68bd83332669393e222" @@ -16460,7 +16410,7 @@ make-fetch-happen@^8.0.9: socks-proxy-agent "^5.0.0" ssri "^8.0.0" -make-fetch-happen@^9.0.1: +make-fetch-happen@^9.1.0: version "9.1.0" resolved "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz#53085a09e7971433e6765f7971bf63f4e05cb968" integrity sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg== @@ -16688,11 +16638,6 @@ mdn-data@2.0.14: resolved "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow== -mdn-data@2.0.4: - version "2.0.4" - resolved "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz#699b3c38ac6f1d728091a64650b65d388502fd5b" - integrity sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA== - mdurl@^1.0.0, mdurl@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" @@ -17232,9 +17177,9 @@ min-indent@^1.0.0: integrity sha1-z8RcN+nsDY8KDsPdTvf3w6vjklY= mini-css-extract-plugin@^2.4.2: - version "2.5.2" - resolved "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.5.2.tgz#b3b9b98320c2c054d92c16f6a94ddfdbbba13755" - integrity sha512-Lwgq9qLNyBK6yNLgzssXnq4r2+mB9Mz3cJWlM8kseysHIvTicFhDNimFgY94jjqlwhNzLPsq8wv4X+vOHtMdYA== + version "2.5.3" + resolved "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.5.3.tgz#c5c79f9b22ce9b4f164e9492267358dbe35376d9" + integrity sha512-YseMB8cs8U/KCaAGQoqYmfUuhhGW0a9p9XvWXrxVOkE3/IiISTLw4ALNt7JR5B2eYauFM+PQGSbXMDmVbR7Tfw== dependencies: schema-utils "^4.0.0" @@ -17283,10 +17228,10 @@ minipass-collect@^1.0.2: dependencies: minipass "^3.0.0" -minipass-fetch@^1.3.0, minipass-fetch@^1.3.2: - version "1.3.3" - resolved "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.3.3.tgz#34c7cea038c817a8658461bf35174551dce17a0a" - integrity sha512-akCrLDWfbdAWkMLBxJEeWTdNsjML+dt5YgOI4gJ53vuO0vrmYQkUPxa6j6V65s9CcePIr2SSWqjT2EcrNseryQ== +minipass-fetch@^1.3.0, minipass-fetch@^1.3.2, minipass-fetch@^1.4.1: + version "1.4.1" + resolved "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz#d75e0091daac1b0ffd7e9d41629faff7d0c1f1b6" + integrity sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw== dependencies: minipass "^3.1.0" minipass-sized "^1.0.3" @@ -17331,10 +17276,10 @@ minipass@^2.6.0, minipass@^2.9.0: safe-buffer "^5.1.2" yallist "^3.0.0" -minipass@^3.0.0, minipass@^3.1.0, minipass@^3.1.1, minipass@^3.1.3: - version "3.1.3" - resolved "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz#7d42ff1f39635482e15f9cdb53184deebd5815fd" - integrity sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg== +minipass@^3.0.0, minipass@^3.1.0, minipass@^3.1.1, minipass@^3.1.3, minipass@^3.1.6: + version "3.1.6" + resolved "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz#3b8150aa688a711a1521af5e8779c1d3bb4f45ee" + integrity sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ== dependencies: yallist "^4.0.0" @@ -17345,7 +17290,7 @@ minizlib@^1.3.3: dependencies: minipass "^2.9.0" -minizlib@^2.0.0, minizlib@^2.1.1: +minizlib@^2.0.0, minizlib@^2.1.1, minizlib@^2.1.2: version "2.1.2" resolved "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== @@ -17380,7 +17325,7 @@ mkdirp-infer-owner@^2.0.0: infer-owner "^1.0.4" mkdirp "^1.0.3" -"mkdirp@>=0.5 0", mkdirp@^0.5.1, mkdirp@^0.5.4, mkdirp@^0.5.5, mkdirp@~0.5.1: +"mkdirp@>=0.5 0", mkdirp@^0.5.1, mkdirp@^0.5.4, mkdirp@^0.5.5: version "0.5.5" resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== @@ -17590,11 +17535,16 @@ nanoclone@^0.2.1: resolved "https://registry.npmjs.org/nanoclone/-/nanoclone-0.2.1.tgz#dd4090f8f1a110d26bb32c49ed2f5b9235209ed4" integrity sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA== -nanoid@^3.1.23, nanoid@^3.1.30: +nanoid@^3.1.23: version "3.2.0" resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz#62667522da6673971cca916a6d3eff3f415ff80c" integrity sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA== +nanoid@^3.2.0: + version "3.3.0" + resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.0.tgz#5906f776fd886c66c24f3653e0c46fcb1d4ad6b0" + integrity sha512-JzxqqT5u/x+/KOFSd7JP15DOo9nOoHpx6DYatqIHUW2+flybkm+mdcraotSQR5WcnZr+qhGVh8Ted0KdfSMxlg== + nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" @@ -17622,6 +17572,11 @@ negotiator@0.6.2, negotiator@^0.6.2: resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== +negotiator@^0.6.3: + version "0.6.3" + resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + neo-async@^2.5.0, neo-async@^2.6.0, neo-async@^2.6.2: version "2.6.2" resolved "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" @@ -17754,6 +17709,22 @@ node-gyp@^7.1.0: tar "^6.0.2" which "^2.0.2" +node-gyp@^8.2.0: + version "8.4.1" + resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz#3d49308fc31f768180957d6b5746845fbd429937" + integrity sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w== + dependencies: + env-paths "^2.2.0" + glob "^7.1.4" + graceful-fs "^4.2.6" + make-fetch-happen "^9.1.0" + nopt "^5.0.0" + npmlog "^6.0.0" + rimraf "^3.0.2" + semver "^7.3.5" + tar "^6.1.2" + which "^2.0.2" + node-int64@^0.4.0: version "0.4.0" resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" @@ -17990,17 +17961,17 @@ npm-pick-manifest@^6.1.0, npm-pick-manifest@^6.1.1: npm-package-arg "^8.1.2" semver "^7.3.4" -npm-registry-fetch@^11.0.0: - version "11.0.0" - resolved "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-11.0.0.tgz#68c1bb810c46542760d62a6a965f85a702d43a76" - integrity sha512-jmlgSxoDNuhAtxUIG6pVwwtz840i994dL14FoNVZisrmZW5kWd63IUTNv1m/hyRSGSqWjCUp/YZlS1BJyNp9XA== +npm-registry-fetch@^12.0.0, npm-registry-fetch@^12.0.1: + version "12.0.2" + resolved "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-12.0.2.tgz#ae583bb3c902a60dae43675b5e33b5b1f6159f1e" + integrity sha512-Df5QT3RaJnXYuOwtXBXS9BWs+tHH2olvkCLh6jcR/b/u3DvPMlp3J0TvvYwplPKxHMOwfg287PYih9QqaVFoKA== dependencies: - make-fetch-happen "^9.0.1" - minipass "^3.1.3" - minipass-fetch "^1.3.0" + make-fetch-happen "^10.0.1" + minipass "^3.1.6" + minipass-fetch "^1.4.1" minipass-json-stream "^1.0.1" - minizlib "^2.0.0" - npm-package-arg "^8.0.0" + minizlib "^2.1.2" + npm-package-arg "^8.1.5" npm-registry-fetch@^9.0.0: version "9.0.0" @@ -18040,12 +18011,25 @@ npmlog@^4.1.2: gauge "~2.7.3" set-blocking "~2.0.0" -nth-check@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" - integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg== +npmlog@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz#f06678e80e29419ad67ab964e0fa69959c1eb8b0" + integrity sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw== dependencies: - boolbase "~1.0.0" + are-we-there-yet "^2.0.0" + console-control-strings "^1.1.0" + gauge "^3.0.0" + set-blocking "^2.0.0" + +npmlog@^6.0.0: + version "6.0.1" + resolved "https://registry.npmjs.org/npmlog/-/npmlog-6.0.1.tgz#06f1344a174c06e8de9c6c70834cfba2964bba17" + integrity sha512-BTHDvY6nrRHuRfyjt1MAufLxYdVXZfd099H4+i1f0lPywNQyI4foeNXJRObB/uy+TYqUW0vAD9gbdSOXPst7Eg== + dependencies: + are-we-there-yet "^3.0.0" + console-control-strings "^1.1.0" + gauge "^4.0.0" + set-blocking "^2.0.0" nth-check@^2.0.0: version "2.0.1" @@ -18157,7 +18141,7 @@ object.fromentries@^2.0.5: define-properties "^1.1.3" es-abstract "^1.19.1" -object.getownpropertydescriptors@^2.0.3, object.getownpropertydescriptors@^2.1.0: +object.getownpropertydescriptors@^2.0.3: version "2.1.0" resolved "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz#369bf1f9592d8ab89d712dced5cb81c7c5352649" integrity sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg== @@ -18180,7 +18164,7 @@ object.pick@^1.3.0: dependencies: isobject "^3.0.1" -object.values@^1.1.0, object.values@^1.1.5: +object.values@^1.1.5: version "1.1.5" resolved "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz#959f63e3ce9ef108720333082131e4a459b716ac" integrity sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg== @@ -18518,6 +18502,14 @@ p-timeout@^3.2.0: dependencies: p-finally "^1.0.0" +p-transform@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/p-transform/-/p-transform-1.3.0.tgz#2da960ba92c6a56efbe75cbd1edf3ea7b3191049" + integrity sha512-UJKdSzgd3KOnXXAtqN5+/eeHcvTn1hBkesEmElVgvO/NAYcxAvmjzIGmnNd3Tb/gRAvMBdNRFD4qAWdHxY6QXg== + dependencies: + debug "^4.3.2" + p-queue "^6.6.2" + p-try@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" @@ -18550,31 +18542,6 @@ packet-reader@1.0.0: resolved "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz#9238e5480dedabacfe1fe3f2771063f164157d74" integrity sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ== -pacote@^11.1.11, pacote@^11.3.5: - version "11.3.5" - resolved "https://registry.npmjs.org/pacote/-/pacote-11.3.5.tgz#73cf1fc3772b533f575e39efa96c50be8c3dc9d2" - integrity sha512-fT375Yczn4zi+6Hkk2TBe1x1sP8FgFsEIZ2/iWaXY2r/NkhDJfxbcn5paz1+RTFCyNf+dPnaoBDJoAxXSU8Bkg== - dependencies: - "@npmcli/git" "^2.1.0" - "@npmcli/installed-package-contents" "^1.0.6" - "@npmcli/promise-spawn" "^1.2.0" - "@npmcli/run-script" "^1.8.2" - cacache "^15.0.5" - chownr "^2.0.0" - fs-minipass "^2.1.0" - infer-owner "^1.0.4" - minipass "^3.1.3" - mkdirp "^1.0.3" - npm-package-arg "^8.0.1" - npm-packlist "^2.1.4" - npm-pick-manifest "^6.0.0" - npm-registry-fetch "^11.0.0" - promise-retry "^2.0.1" - read-package-json-fast "^2.0.1" - rimraf "^3.0.2" - ssri "^8.0.1" - tar "^6.1.0" - pacote@^11.2.6: version "11.2.6" resolved "https://registry.npmjs.org/pacote/-/pacote-11.2.6.tgz#c0426e5d5c8d33aeea3461a75e1390f1ba78f953" @@ -18600,6 +18567,31 @@ pacote@^11.2.6: ssri "^8.0.1" tar "^6.1.0" +pacote@^12.0.0, pacote@^12.0.2: + version "12.0.3" + resolved "https://registry.npmjs.org/pacote/-/pacote-12.0.3.tgz#b6f25868deb810e7e0ddf001be88da2bcaca57c7" + integrity sha512-CdYEl03JDrRO3x18uHjBYA9TyoW8gy+ThVcypcDkxPtKlw76e4ejhYB6i9lJ+/cebbjpqPW/CijjqxwDTts8Ow== + dependencies: + "@npmcli/git" "^2.1.0" + "@npmcli/installed-package-contents" "^1.0.6" + "@npmcli/promise-spawn" "^1.2.0" + "@npmcli/run-script" "^2.0.0" + cacache "^15.0.5" + chownr "^2.0.0" + fs-minipass "^2.1.0" + infer-owner "^1.0.4" + minipass "^3.1.3" + mkdirp "^1.0.3" + npm-package-arg "^8.0.1" + npm-packlist "^3.0.0" + npm-pick-manifest "^6.0.0" + npm-registry-fetch "^12.0.0" + promise-retry "^2.0.1" + read-package-json-fast "^2.0.1" + rimraf "^3.0.2" + ssri "^8.0.1" + tar "^6.1.0" + pako@^1.0.10, pako@~1.0.5: version "1.0.11" resolved "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" @@ -18637,14 +18629,14 @@ parse-asn1@^5.0.0: pbkdf2 "^3.0.3" safe-buffer "^5.1.1" -parse-conflict-json@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/parse-conflict-json/-/parse-conflict-json-1.1.1.tgz#54ec175bde0f2d70abf6be79e0e042290b86701b" - integrity sha512-4gySviBiW5TRl7XHvp1agcS7SOe0KZOjC//71dzZVWJrY9hCrgtvl5v3SyIxCZ4fZF47TxD9nfzmxcx76xmbUw== +parse-conflict-json@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/parse-conflict-json/-/parse-conflict-json-2.0.1.tgz#76647dd072e6068bcaff20be6ccea68a18e1fb58" + integrity sha512-Y7nYw+QaSGBto1LB9lgwOR05Rtz5SbuTf+Oe7HJ6SYQ/DHsvRjQ8O03oWdJbvkt6GzDWospgyZbGmjDYL0sDgA== dependencies: - json-parse-even-better-errors "^2.3.0" - just-diff "^3.0.1" - just-diff-apply "^3.0.0" + json-parse-even-better-errors "^2.3.1" + just-diff "^5.0.1" + just-diff-apply "^4.0.1" parse-entities@^2.0.0: version "2.0.0" @@ -18810,7 +18802,7 @@ passport-oauth2@1.2.0: passport-strategy "1.x.x" uid2 "0.0.x" -passport-oauth2@1.x.x, passport-oauth2@^1.1.2, passport-oauth2@^1.4.0, passport-oauth2@^1.5.0: +passport-oauth2@1.x.x, passport-oauth2@^1.1.2, passport-oauth2@^1.4.0, passport-oauth2@^1.6.1: version "1.6.1" resolved "https://registry.npmjs.org/passport-oauth2/-/passport-oauth2-1.6.1.tgz#c5aee8f849ce8bd436c7f81d904a3cd1666f181b" integrity sha512-ZbV43Hq9d/SBSYQ22GOiglFsjsD1YY/qdiptA+8ej+9C1dL1TVB+mBE5kDH/D4AJo50+2i8f4bx0vg4/yDDZCQ== @@ -19031,10 +19023,10 @@ pg-int8@1.0.1: resolved "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c" integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw== -pg-pool@^3.4.1: - version "3.4.1" - resolved "https://registry.npmjs.org/pg-pool/-/pg-pool-3.4.1.tgz#0e71ce2c67b442a5e862a9c182172c37eda71e9c" - integrity sha512-TVHxR/gf3MeJRvchgNHxsYsTCHQ+4wm3VIHSS19z8NC0+gioEhq1okDY1sm/TYbfoP6JLFx01s0ShvZ3puP/iQ== +pg-pool@^3.5.1: + version "3.5.1" + resolved "https://registry.npmjs.org/pg-pool/-/pg-pool-3.5.1.tgz#f499ce76f9bf5097488b3b83b19861f28e4ed905" + integrity sha512-6iCR0wVrro6OOHFsyavV+i6KYL4lVNyYAB9RD18w66xSzN+d8b66HiwuP30Gp1SH5O9T82fckkzsRjlrhD0ioQ== pg-protocol@^1.5.0: version "1.5.0" @@ -19053,14 +19045,14 @@ pg-types@^2.1.0: postgres-interval "^1.1.0" pg@^8.3.0, pg@^8.4.0: - version "8.7.1" - resolved "https://registry.npmjs.org/pg/-/pg-8.7.1.tgz#9ea9d1ec225980c36f94e181d009ab9f4ce4c471" - integrity sha512-7bdYcv7V6U3KAtWjpQJJBww0UEsWuh4yQ/EjNf2HeO/NnvKjpvhEIe/A/TleP6wtmSKnUnghs5A9jUoK6iDdkA== + version "8.7.3" + resolved "https://registry.npmjs.org/pg/-/pg-8.7.3.tgz#8a5bdd664ca4fda4db7997ec634c6e5455b27c44" + integrity sha512-HPmH4GH4H3AOprDJOazoIcpI49XFsHCe8xlrjHkWiapdbHK+HLtbm/GQzXYAZwmPju/kzKhjaSfMACG+8cgJcw== dependencies: buffer-writer "2.0.0" packet-reader "1.0.0" pg-connection-string "^2.5.0" - pg-pool "^3.4.1" + pg-pool "^3.5.1" pg-protocol "^1.5.0" pg-types "^2.1.0" pgpass "1.x" @@ -19497,19 +19489,19 @@ postcss-value-parser@^3.3.0: resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== -postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb" - integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ== +postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" + integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== -postcss@^8, postcss@^8.1.0, postcss@^8.2.15: - version "8.4.5" - resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz#bae665764dfd4c6fcc24dc0fdf7e7aa00cc77f95" - integrity sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg== +postcss@^8, postcss@^8.1.0, postcss@^8.4.5: + version "8.4.6" + resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.6.tgz#c5ff3c3c457a23864f32cb45ac9b741498a09ae1" + integrity sha512-OovjwIzs9Te46vlEx7+uXB0PLijpwjXGKXjVGGPIGubGpq7uh5Xgf6D6FiJ/SzJMBosHDp6a2hiXOS97iBXcaA== dependencies: - nanoid "^3.1.30" + nanoid "^3.2.0" picocolors "^1.0.0" - source-map-js "^1.0.1" + source-map-js "^1.0.2" postgres-array@~2.0.0: version "2.0.0" @@ -19881,7 +19873,7 @@ puppeteer@^13.1.1: unbzip2-stream "1.4.3" ws "8.2.3" -q@^1.1.2, q@^1.5.1: +q@^1.5.1: version "1.5.1" resolved "https://registry.npmjs.org/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= @@ -20380,7 +20372,7 @@ react-use@^17.2.4: ts-easing "^0.2.0" tslib "^2.1.0" -react-use@^17.3.1: +react-use@^17.3.1, react-use@^17.3.2: version "17.3.2" resolved "https://registry.npmjs.org/react-use/-/react-use-17.3.2.tgz#448abf515f47c41c32455024db28167cb6e53be8" integrity sha512-bj7OD0/1wL03KyWmzFXAFe425zziuTf7q8olwCYBfOeFHY1qfO1FAMjROQLsLZYwG4Rx63xAfb7XAbBrJsZmEw== @@ -21307,9 +21299,9 @@ rollup@^0.63.4: "@types/node" "*" rollup@^2.60.2: - version "2.60.2" - resolved "https://registry.npmjs.org/rollup/-/rollup-2.60.2.tgz#3f45ace36a9b10b4297181831ea0719922513463" - integrity sha512-1Bgjpq61sPjgoZzuiDSGvbI1tD91giZABgjCQBKM5aYLnzjq52GoDuWVwT/cm/MCxCMPU8gqQvkj8doQ5C8Oqw== + version "2.67.2" + resolved "https://registry.npmjs.org/rollup/-/rollup-2.67.2.tgz#d95e15f60932ad21e05a870bd0aa0b235d056f04" + integrity sha512-hoEiBWwZtf1QdK3jZIq59L0FJj4Fiv4RplCO4pvCRC86qsoFurWB4hKQIjoRf3WvJmk5UZ9b0y5ton+62fC7Tw== optionalDependencies: fsevents "~2.3.2" @@ -21427,7 +21419,7 @@ sax@1.2.1: resolved "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" integrity sha1-e45lYZCyKOgaZq6nSEgNgozS03o= -sax@>=0.6.0, sax@~1.2.4: +sax@>=0.6.0: version "1.2.4" resolved "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== @@ -21753,10 +21745,10 @@ side-channel@^1.0.4: get-intrinsic "^1.0.2" object-inspect "^1.9.0" -signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: - version "3.0.3" - resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" - integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== +signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: + 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== signedsource@^1.0.0: version "1.0.0" @@ -21924,10 +21916,10 @@ socks-proxy-agent@^5.0.0: debug "4" socks "^2.3.3" -socks-proxy-agent@^6.0.0: - version "6.1.0" - resolved "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.1.0.tgz#869cf2d7bd10fea96c7ad3111e81726855e285c3" - integrity sha512-57e7lwCN4Tzt3mXz25VxOErJKXlPfXmkMLnk310v/jwW20jWRVcgsOit+xNkN3eIEdB47GwnfAEBLacZ/wVIKg== +socks-proxy-agent@^6.0.0, socks-proxy-agent@^6.1.1: + version "6.1.1" + resolved "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.1.1.tgz#e664e8f1aaf4e1fb3df945f09e3d94f911137f87" + integrity sha512-t8J0kG3csjA4g6FTbsMOWws+7R7vuRC8aQ/wy3/1OWmsgwA68zs/+cExQ0koSitUDXqhufF/YJr9wtNMZHw5Ew== dependencies: agent-base "^6.0.2" debug "^4.3.1" @@ -21976,10 +21968,10 @@ source-list-map@^2.0.1: resolved "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== -source-map-js@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.1.tgz#a1741c131e3c77d048252adfa24e23b908670caf" - integrity sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA== +source-map-js@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== source-map-resolve@^0.5.0: version "0.5.3" @@ -22387,7 +22379,16 @@ string-width@^1.0.1, string-width@^1.0.2: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -"string-width@^1.0.2 || 2", string-width@^2.1.1: +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: + 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" + +string-width@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== @@ -22404,15 +22405,6 @@ string-width@^3.0.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" -string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: - 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" - string-width@^5.0.0: version "5.1.0" resolved "https://registry.npmjs.org/string-width/-/string-width-5.1.0.tgz#5ab00980cfb29f43e736b113a120a73a0fb569d3" @@ -22725,25 +22717,6 @@ svg-parser@^2.0.2: resolved "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz#fdc2e29e13951736140b76cb122c8ee6630eb6b5" integrity sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ== -svgo@^1.2.2: - version "1.3.2" - resolved "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz#b6dc511c063346c9e415b81e43401145b96d4167" - integrity sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw== - dependencies: - chalk "^2.4.1" - coa "^2.0.2" - css-select "^2.0.0" - css-select-base-adapter "^0.1.1" - css-tree "1.0.0-alpha.37" - csso "^4.0.2" - js-yaml "^3.13.1" - mkdirp "~0.5.1" - object.values "^1.1.0" - sax "~1.2.4" - stable "^0.1.8" - unquote "~1.1.1" - util.promisify "~1.0.0" - svgo@^2.5.0, svgo@^2.7.0: version "2.8.0" resolved "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24" @@ -23889,11 +23862,6 @@ unpipe@1.0.0, unpipe@~1.0.0: resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= -unquote@~1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544" - integrity sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ= - unset-value@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" @@ -24044,16 +24012,6 @@ util-promisify@^2.1.0: dependencies: object.getownpropertydescriptors "^2.0.3" -util.promisify@~1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz#6baf7774b80eeb0f7520d8b81d07982a59abbaee" - integrity sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.2" - has-symbols "^1.0.1" - object.getownpropertydescriptors "^2.1.0" - util@0.10.3: version "0.10.3" resolved "https://registry.npmjs.org/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" @@ -24267,9 +24225,9 @@ vm-browserify@^1.0.1: integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== vm2@^3.9.6: - version "3.9.6" - resolved "https://registry.npmjs.org/vm2/-/vm2-3.9.6.tgz#2f9b2fd0d82802dcd872e1011869ba8ae6b74778" - integrity sha512-BF7euUjgO+ezsz2UKex9kO9M/PtDNOf+KEpiqNepZsgf1MT7JYfJEIvG8BoYhZMLAVjqevFJ0UmXNuETe8m5dQ== + version "3.9.7" + resolved "https://registry.npmjs.org/vm2/-/vm2-3.9.7.tgz#bb87aa677c97c61e23a6cb6547e44e990517a6f6" + integrity sha512-g/GZ7V0Mlmch3eDVOATvAXr1GsJNg6kQ5PjvYy3HbJMCRn5slNbo/u73Uy7r5yUej1cRa3ZjtoVwcWSQuQ/fow== dependencies: acorn "^8.7.0" acorn-walk "^8.2.0" @@ -24584,12 +24542,12 @@ which@^2.0.1, which@^2.0.2: dependencies: isexe "^2.0.0" -wide-align@^1.1.0: - version "1.1.3" - resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" - integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== +wide-align@^1.1.0, wide-align@^1.1.2: + version "1.1.5" + resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" + integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== dependencies: - string-width "^1.0.2 || 2" + string-width "^1.0.2 || 2 || 3 || 4" widest-line@^3.1.0: version "3.1.0" @@ -24703,6 +24661,14 @@ write-file-atomic@^3.0.0, write-file-atomic@^3.0.3: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" +write-file-atomic@^4.0.0: + version "4.0.1" + resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz#9faa33a964c1c85ff6f849b80b42a88c2c537c8f" + integrity sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^3.0.7" + write-json-file@^3.2.0: version "3.2.0" resolved "https://registry.npmjs.org/write-json-file/-/write-json-file-3.2.0.tgz#65bbdc9ecd8a1458e15952770ccbadfcff5fe62a" @@ -25000,13 +24966,13 @@ yauzl@^2.10.0: buffer-crc32 "~0.2.3" fd-slicer "~1.1.0" -yeoman-environment@^3.6.0: - version "3.6.0" - resolved "https://registry.npmjs.org/yeoman-environment/-/yeoman-environment-3.6.0.tgz#91267ced0d474c4dec330b83f232e72e796c0730" - integrity sha512-X16N9lhzRdUKFT8MZrpwjLDKsdgAUqh4VPR2wAXeAqjJJaUxYBxCQGFxtZVTf3vbyNuIHXPunwOLtK60bpapbg== +yeoman-environment@^3.9.1: + version "3.9.1" + resolved "https://registry.npmjs.org/yeoman-environment/-/yeoman-environment-3.9.1.tgz#21912bdee4b1d302a5c25a7d31338fa092ea7116" + integrity sha512-IdRnbQt/DSOSnao0oD9c+or1X2UrL+fx9eC0O7Lq/MGZV68nhv9k77MqG+hEAySPSlyCpocVlhfQwV62hczk5Q== dependencies: - "@npmcli/arborist" "^2.2.2" - are-we-there-yet "^1.1.5" + "@npmcli/arborist" "^4.0.4" + are-we-there-yet "^2.0.0" arrify "^2.0.1" binaryextensions "^4.15.0" chalk "^4.1.0" @@ -25028,9 +24994,10 @@ yeoman-environment@^3.6.0: mem-fs "^1.2.0 || ^2.0.0" mem-fs-editor "^8.1.2 || ^9.0.0" minimatch "^3.0.4" - npmlog "^4.1.2" + npmlog "^5.0.1" p-queue "^6.6.2" - pacote "^11.2.6" + p-transform "^1.3.0" + pacote "^12.0.2" preferred-pm "^3.0.3" pretty-bytes "^5.3.0" semver "^7.1.3" @@ -25111,6 +25078,11 @@ zod@^3.11.6, zod@^3.9.5: resolved "https://registry.npmjs.org/zod/-/zod-3.11.6.tgz#e43a5e0c213ae2e02aefe7cb2b1a6fa3d7f1f483" integrity sha512-daZ80A81I3/9lIydI44motWe6n59kRBfNzTuS2bfzVh1nAXi667TOTWWtatxyG+fwgNUiagSj/CWZwRRbevJIg== +zustand@3.6.9: + version "3.6.9" + resolved "https://registry.npmjs.org/zustand/-/zustand-3.6.9.tgz#f61a756ddea9f95c7ee7cfd3af2f88c10078afbc" + integrity sha512-OvDNu/jEWpRnEC7k8xh8GKjqYog7td6FZrLMuHs/IeI8WhrCwV+FngVuwMIFhp5kysZXr6emaeReMqjLGaldAQ== + zwitch@^2.0.0: version "2.0.2" resolved "https://registry.npmjs.org/zwitch/-/zwitch-2.0.2.tgz#91f8d0e901ffa3d66599756dde7f57b17c95dce1"