diff --git a/.changeset/afraid-flies-try.md b/.changeset/afraid-flies-try.md new file mode 100644 index 0000000000..15d2e3942c --- /dev/null +++ b/.changeset/afraid-flies-try.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-cost-insights': patch +--- + +Move cost-insights data specific API types (non react) into an @backstage/plugin-cost-insights-common +isomorphic package. This allows these types to be shared in any backend packages or other cost-insight +modules. diff --git a/.changeset/beige-carpets-double.md b/.changeset/beige-carpets-double.md new file mode 100644 index 0000000000..98e0d8d69a --- /dev/null +++ b/.changeset/beige-carpets-double.md @@ -0,0 +1,9 @@ +--- +'@backstage/plugin-code-coverage': minor +--- + +Cleaned up API exports. + +The `Router` export has been removed; users are expected to use `EntityCodeCoverageContent` instead. + +The `isPluginApplicableToEntity` helper has been deprecated, in favor of the `isCodeCoverageAvailable` helper. diff --git a/.changeset/beige-carpets-triple.md b/.changeset/beige-carpets-triple.md new file mode 100644 index 0000000000..5eda26fb02 --- /dev/null +++ b/.changeset/beige-carpets-triple.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-code-coverage-backend': minor +--- + +Cleaned up API exports. + +The `CodeCoverageApi` and `makeRouter` exports have been removed from the backend, since they were not meant to be exported in the first place. diff --git a/.changeset/blue-monkeys-explain.md b/.changeset/blue-monkeys-explain.md new file mode 100644 index 0000000000..69382ff11d --- /dev/null +++ b/.changeset/blue-monkeys-explain.md @@ -0,0 +1,6 @@ +--- +'@backstage/create-app': patch +--- + +Adds the ability to define the Backstage app name using a `BACKSTAGE_APP_NAME` +environment variable when running `create-app`. diff --git a/.changeset/breezy-poems-grab.md b/.changeset/breezy-poems-grab.md new file mode 100644 index 0000000000..ac250b9c7e --- /dev/null +++ b/.changeset/breezy-poems-grab.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-tech-insights-backend': patch +--- + +TechInsightsBackend: Added missing 'scheduler' to code examples diff --git a/.changeset/breezy-seas-exist.md b/.changeset/breezy-seas-exist.md new file mode 100644 index 0000000000..2b061f11a8 --- /dev/null +++ b/.changeset/breezy-seas-exist.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': patch +--- + +The template editor now shows the cause of request errors that happen during a dry-run. diff --git a/.changeset/bright-balloons-hide.md b/.changeset/bright-balloons-hide.md new file mode 100644 index 0000000000..5163e72dc1 --- /dev/null +++ b/.changeset/bright-balloons-hide.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-components': patch +--- + +Change BackstageIconLinkVertical style to use pallette instead of explicit color diff --git a/.changeset/calm-experts-buy.md b/.changeset/calm-experts-buy.md new file mode 100644 index 0000000000..d95844e298 --- /dev/null +++ b/.changeset/calm-experts-buy.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs-node': minor +--- + +Added local publishing target directory `config`: `techdocs.publisher.local.publishDirectory` diff --git a/.changeset/chilled-mirrors-grab.md b/.changeset/chilled-mirrors-grab.md new file mode 100644 index 0000000000..ecc95680e2 --- /dev/null +++ b/.changeset/chilled-mirrors-grab.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-common': patch +--- + +Fix parsing of S3 URLs for the default region. diff --git a/.changeset/cool-toys-flow.md b/.changeset/cool-toys-flow.md new file mode 100644 index 0000000000..799bf3ace4 --- /dev/null +++ b/.changeset/cool-toys-flow.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-components': minor +--- + +Add `transformLinkUri` and `transformImageUri` to `MarkdownContent` diff --git a/.changeset/create-app-1656408352.md b/.changeset/create-app-1656408352.md new file mode 100644 index 0000000000..b50d431d4b --- /dev/null +++ b/.changeset/create-app-1656408352.md @@ -0,0 +1,5 @@ +--- +'@backstage/create-app': patch +--- + +Bumped create-app version. diff --git a/.changeset/cuddly-flowers-provide.md b/.changeset/cuddly-flowers-provide.md new file mode 100644 index 0000000000..729ac96cda --- /dev/null +++ b/.changeset/cuddly-flowers-provide.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-fossa': patch +--- + +Allow configuration of base URL for Fossa links diff --git a/.changeset/curly-candles-battle.md b/.changeset/curly-candles-battle.md new file mode 100644 index 0000000000..9a4d850fd1 --- /dev/null +++ b/.changeset/curly-candles-battle.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': patch +--- + +Bumped `codemirror` dependencies to `v6.0.0`. diff --git a/.changeset/eight-suits-fail.md b/.changeset/eight-suits-fail.md new file mode 100644 index 0000000000..742154da91 --- /dev/null +++ b/.changeset/eight-suits-fail.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-kubernetes-backend': patch +'@backstage/plugin-kubernetes-common': patch +--- + +Fixed the lack of `limitranges` as part of the Default Objects to fetch from the kubernetes api diff --git a/.changeset/eighty-windows-brush.md b/.changeset/eighty-windows-brush.md new file mode 100644 index 0000000000..753b53fbb4 --- /dev/null +++ b/.changeset/eighty-windows-brush.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-tech-insights-backend': minor +--- + +Allow FactRetrieverRegistry to be injected into buildTechInsightsContext so that we can override default registry implementation. diff --git a/.changeset/five-fireants-run.md b/.changeset/five-fireants-run.md new file mode 100644 index 0000000000..589d46cc81 --- /dev/null +++ b/.changeset/five-fireants-run.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-components': patch +--- + +Fix the EntityLayout header style so that EntityContextMenu button can display in correct shape when user hover on it diff --git a/.changeset/forty-seals-complain.md b/.changeset/forty-seals-complain.md new file mode 100644 index 0000000000..b2435b2d3a --- /dev/null +++ b/.changeset/forty-seals-complain.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend': patch +--- + +Improve error messaging when passing in malformed auth diff --git a/.changeset/great-roses-pump.md b/.changeset/great-roses-pump.md new file mode 100644 index 0000000000..0e15d186d4 --- /dev/null +++ b/.changeset/great-roses-pump.md @@ -0,0 +1,23 @@ +--- +'@backstage/plugin-catalog': patch +--- + +Previously, the color of the Entity Context Menu (in the Entity Page Header) was hardcoded as `white`. + +This was an issue for themes that use a header with a white background. By default, the color of the icon is now `theme.page.fontColor`. + +It can now also be overridden in the theme, which is only necessary if the header title, subtitle and three-dots icon need to have different colors. For example: + +```typescript +export function createThemeOverrides(theme: BackstageTheme): Overrides { + return { + PluginCatalogEntityContextMenu: { + button: { + color: 'blue', + }, + }, + ... + }, + ... + } +``` diff --git a/.changeset/green-actors-argue.md b/.changeset/green-actors-argue.md new file mode 100644 index 0000000000..e21fbb040c --- /dev/null +++ b/.changeset/green-actors-argue.md @@ -0,0 +1,19 @@ +--- +'@backstage/cli': minor +--- + +**BREAKING**: Removed the following deprecated package commands: + +- `app:build` - Use `package build` instead +- `app:serve` - Use `package start` instead +- `backend:build` - Use `package build` instead +- `backend:bundle` - Use `package build` instead +- `backend:dev` - Use `package start` instead +- `plugin:build` - Use `package build` instead +- `plugin:serve` - Use `package start` instead +- `build` - Use `package build` instead +- `lint` - Use `package lint` instead +- `prepack` - Use `package prepack` instead +- `postpack` - Use `package postpack` instead + +In order to replace these you need to have [migrated to using package roles](https://backstage.io/docs/tutorials/package-role-migration). diff --git a/.changeset/happy-boxes-melt.md b/.changeset/happy-boxes-melt.md new file mode 100644 index 0000000000..c478e783d3 --- /dev/null +++ b/.changeset/happy-boxes-melt.md @@ -0,0 +1,6 @@ +--- +'@techdocs/cli': patch +'@backstage/plugin-techdocs-node': patch +--- + +Fix the flag parsing for `legacyCopyReadmeMdToIndexMd` in `techdocs-cli generate` command, and decouple it's logic from the `techdocs-ref` flag. diff --git a/.changeset/hot-rice-sin.md b/.changeset/hot-rice-sin.md new file mode 100644 index 0000000000..5a3d6fdb7a --- /dev/null +++ b/.changeset/hot-rice-sin.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': minor +--- + +Add `allowedRepos` `ui:option` to `RepoUrlPicker` component, and move `repoName` field to own component diff --git a/.changeset/large-kangaroos-poke.md b/.changeset/large-kangaroos-poke.md new file mode 100644 index 0000000000..3a9444cfa1 --- /dev/null +++ b/.changeset/large-kangaroos-poke.md @@ -0,0 +1,13 @@ +--- +'@backstage/create-app': patch +--- + +Added an explicit `node-gyp` dependency to the root `package.json`. This is to work around a bug in older versions of `node-gyp` that causes Python execution to fail on macOS. + +You can add this workaround to your existing project by adding `node-gyp` as a `devDependency` in your root `package.json` file: + +```diff + "devDependencies": { ++ "node-gyp": "^9.0.0" + }, +``` diff --git a/.changeset/lemon-goats-obey.md b/.changeset/lemon-goats-obey.md new file mode 100644 index 0000000000..7bdb59bd61 --- /dev/null +++ b/.changeset/lemon-goats-obey.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-apache-airflow': minor +--- + +Exposed DagTableComponent as standalone component + added a prop to get only select DAGs instead of the full list diff --git a/.changeset/light-hornets-eat.md b/.changeset/light-hornets-eat.md new file mode 100644 index 0000000000..795e51fb67 --- /dev/null +++ b/.changeset/light-hornets-eat.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-cost-insights-common': minor +--- + +Introduces a new isomorphic @backstage/plugin-cost-insight-common package to contain shared types across all other cost insights packages and modules. diff --git a/.changeset/little-geckos-end.md b/.changeset/little-geckos-end.md new file mode 100644 index 0000000000..328095aa44 --- /dev/null +++ b/.changeset/little-geckos-end.md @@ -0,0 +1,18 @@ +--- +'@backstage/plugin-kubernetes-backend': minor +--- + +Add new endpoints to Kubernetes backend plugin + +BREAKING: Kubernetes backend plugin now depends on CatalogApi + +```typescript +// Create new CatalogClient +const catalogApi = new CatalogClient({ discoveryApi: env.discovery }); +const { router } = await KubernetesBuilder.createBuilder({ + logger: env.logger, + config: env.config, + // Inject it into createBuilder params + catalogApi, +}).build(); +``` diff --git a/.changeset/long-bananas-rescue.md b/.changeset/long-bananas-rescue.md new file mode 100644 index 0000000000..d990fd67c6 --- /dev/null +++ b/.changeset/long-bananas-rescue.md @@ -0,0 +1,91 @@ +--- +'@backstage/plugin-catalog-backend-module-msgraph': minor +--- + +Align `msgraph` plugin's entity provider config with other providers. **Deprecated** entity processor as well as previous config. + +You will see warning at the log output until you migrate to the new setup. +All deprecated parts will be removed eventually after giving some time to migrate. + +Please find information on how to migrate your current setup to the new one below. + +**Migration Guide:** + +There were two different way on how to use the msgraph plugin: processor or provider. + +Previous registration for the processor: + +```typescript +// packages/backend/src/plugins/catalog.ts +builder.addProcessor( + MicrosoftGraphOrgReaderProcessor.fromConfig(env.config, { + logger: env.logger, + // [...] + }), +); +``` + +Previous registration when using the provider: + +```typescript +// packages/backend/src/plugins/catalog.ts +builder.addEntityProvider( + MicrosoftGraphOrgEntityProvider.fromConfig(env.config, { + id: 'https://graph.microsoft.com/v1.0', + target: 'https://graph.microsoft.com/v1.0', + logger: env.logger, + schedule: env.scheduler.createScheduledTaskRunner({ + frequency: { minutes: 30 }, + timeout: { minutes: 3 }, + }), + // [...] + }), +); +``` + +Previous configuration as used for both: + +```yaml +# app-config.yaml +catalog: + processors: + microsoftGraphOrg: + providers: + - target: https://graph.microsoft.com/v1.0 + # [...] +``` + +**Replacement:** + +Please check https://github.com/backstage/backstage/blob/master/plugins/catalog-backend-module-msgraph/README.md for the complete documentation of all configuration options (config as well as registration of the provider). + +```yaml +# app-config.yaml +catalog: + providers: + microsoftGraphOrg: + # In case you used the deprecated configuration with the entity provider + # using the value of `target` will keep the same location key for all + providerId: # some stable ID which will be used as part of the location key for all ingested data + target: https://graph.microsoft.com/v1.0 + # [...] +``` + +```typescript +// packages/backend/src/plugins/catalog.ts +builder.addEntityProvider( + MicrosoftGraphOrgEntityProvider.fromConfig(env.config, { + logger: env.logger, + schedule: env.scheduler.createScheduledTaskRunner({ + frequency: { minutes: 30 }, + timeout: { minutes: 3 }, + }), + // [...] + }), +); +``` + +In case you've used multiple entity providers before +**and** you had different transformers for each of them +you can provide these directly at the one `fromConfig` call +by passing a Record with the provider ID as key. diff --git a/.changeset/many-vans-thank.md b/.changeset/many-vans-thank.md new file mode 100644 index 0000000000..16f8c8a69b --- /dev/null +++ b/.changeset/many-vans-thank.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-jenkins': patch +'@backstage/plugin-jenkins-backend': patch +--- + +feature: added support for multiple branches to the `JenkinsApi` diff --git a/.changeset/metal-singers-matter.md b/.changeset/metal-singers-matter.md new file mode 100644 index 0000000000..2c8d370790 --- /dev/null +++ b/.changeset/metal-singers-matter.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Upgrade `@rollup/plugin-node-resolve` to `^13.0.6` diff --git a/.changeset/metal-windows-share.md b/.changeset/metal-windows-share.md new file mode 100644 index 0000000000..b4443a620f --- /dev/null +++ b/.changeset/metal-windows-share.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-search-backend-module-pg': patch +--- + +**DEPRECATED**: `PgSearchEngine` static `from` has been deprecated and will be removed in a future release. Use static `fromConfig` method to instantiate. + +Added support for highlighting matched terms in search result data diff --git a/.changeset/modern-ducks-lay.md b/.changeset/modern-ducks-lay.md new file mode 100644 index 0000000000..bd62c309ba --- /dev/null +++ b/.changeset/modern-ducks-lay.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-stack-overflow': patch +--- + +- Publicly exports `StackOverflowIcon`. +- `HomePageStackOverflowQuestions` accepts optional icon property. diff --git a/.changeset/moody-crabs-march.md b/.changeset/moody-crabs-march.md new file mode 100644 index 0000000000..b5ddf12ffa --- /dev/null +++ b/.changeset/moody-crabs-march.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-vault': patch +'@backstage/plugin-vault-backend': patch +--- + +Added a path notion in addition to secret name to allow to differentiate secrets in sub-paths diff --git a/.changeset/nasty-zoos-cross.md b/.changeset/nasty-zoos-cross.md new file mode 100644 index 0000000000..7a658d7209 --- /dev/null +++ b/.changeset/nasty-zoos-cross.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-github-pull-requests-board': patch +--- + +Support namespaced teams and fetch all kinds diff --git a/.changeset/nervous-humans-sip.md b/.changeset/nervous-humans-sip.md new file mode 100644 index 0000000000..aa1ca2c60a --- /dev/null +++ b/.changeset/nervous-humans-sip.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-app-api': patch +--- + +The `signOut` method of the `IdentityApi` will now navigate the user back to the base URL of the app as indicated by the `app.baseUrl` config. diff --git a/.changeset/ninety-coats-learn.md b/.changeset/ninety-coats-learn.md new file mode 100644 index 0000000000..9d6945e9c0 --- /dev/null +++ b/.changeset/ninety-coats-learn.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-components': patch +--- + +Fix relative `sub-paths` by concatenating the app's base path with them. diff --git a/.changeset/old-onions-hear.md b/.changeset/old-onions-hear.md new file mode 100644 index 0000000000..82dcc09190 --- /dev/null +++ b/.changeset/old-onions-hear.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend': minor +--- + +Update GitLab Merge Request Action to allow source branch to be deleted diff --git a/.changeset/pink-cars-pretend.md b/.changeset/pink-cars-pretend.md new file mode 100644 index 0000000000..c46cb99f55 --- /dev/null +++ b/.changeset/pink-cars-pretend.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-scaffolder-backend': patch +--- + +new setUserAsOwner flag for publish:gitlab action + +The field default is `false`. When true it will use the token configured in the gitlab integration for the matching host, to try and set the user logged in via `repoUrlPicker` `requestUserCredentials` OAuth flow as owner of the repository created in GitLab. diff --git a/.changeset/plenty-clouds-guess.md b/.changeset/plenty-clouds-guess.md new file mode 100644 index 0000000000..cc56bd604d --- /dev/null +++ b/.changeset/plenty-clouds-guess.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend': patch +--- + +Added an option for the auth backend router to select the algorithm for the JWT token signing keys diff --git a/.changeset/polite-lions-sell.md b/.changeset/polite-lions-sell.md new file mode 100644 index 0000000000..07b5fcbd77 --- /dev/null +++ b/.changeset/polite-lions-sell.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend': patch +--- + +Auth provider now also export createAuthProviderIntegration diff --git a/.changeset/popular-pots-yell.md b/.changeset/popular-pots-yell.md new file mode 100644 index 0000000000..f0decc9fb8 --- /dev/null +++ b/.changeset/popular-pots-yell.md @@ -0,0 +1,11 @@ +--- +'@backstage/plugin-auth-backend': minor +--- + +**BREAKING**: Removed all directly exported auth provider factories, option types, and sign-in resolvers. For example: `AwsAlbProviderOptions`, `bitbucketUserIdSignInResolver`, `createGithubProvider`. These are all still accessible via the `providers` export. For example, use `providers.github.create()` rather than `createGithubProvider()`, and `providers.bitbucket.resolvers.userIdMatchingUserEntityAnnotation()` rather than `bitbucketUserIdSignInResolver`. + +**BREAKING**: Removed the exported `AuthProviderFactoryOptions` type as well as the deprecated option fields of the `AuthProviderFactory` callback. This includes the `tokenManager`, `tokenIssuer`, `discovery`, and `catalogApi` fields. Existing usage of these should be replaced with the new utilities in the `resolverContext` field. The deprecated `TokenIssuer` type is now also removed, since it is no longer used. + +**BREAKING**: Removed `getEntityClaims`, use `getDefaultOwnershipEntityRefs` instead. + +**DEPRECATION**: Deprecated `AtlassianAuthProvider` as it was unintentionally exported. diff --git a/.changeset/pre.json b/.changeset/pre.json index 500bf4ac83..7b30cba7ba 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -156,7 +156,101 @@ "@backstage/plugin-user-settings": "0.4.5", "@backstage/plugin-vault": "0.1.0", "@backstage/plugin-vault-backend": "0.1.0", - "@backstage/plugin-xcmetrics": "0.2.26" + "@backstage/plugin-xcmetrics": "0.2.26", + "@backstage/plugin-api-docs-module-protoc-gen-doc": "0.0.0", + "@backstage/plugin-catalog-backend-module-openapi": "0.0.0", + "@backstage/plugin-cost-insights-common": "0.0.0" }, - "changesets": [] + "changesets": [ + "afraid-flies-try", + "beige-horses-scream", + "blue-monkeys-explain", + "breezy-poems-grab", + "breezy-seas-exist", + "bright-balloons-hide", + "calm-experts-buy", + "chilled-mirrors-grab", + "cool-toys-flow", + "create-app-1656408352", + "curly-candles-battle", + "curvy-weeks-matter", + "eight-suits-fail", + "eighty-windows-brush", + "eleven-mice-collect", + "five-fireants-run", + "forty-seals-complain", + "great-roses-pump", + "green-actors-argue", + "happy-boxes-melt", + "hot-rice-sin", + "large-kangaroos-poke", + "lemon-goats-obey", + "light-hornets-eat", + "long-bananas-rescue", + "many-vans-thank", + "metal-singers-matter", + "metal-windows-share", + "modern-ducks-lay", + "moody-crabs-march", + "nasty-zoos-cross", + "nervous-humans-sip", + "old-onions-hear", + "plenty-clouds-guess", + "polite-eagles-invite", + "polite-lions-sell", + "popular-pots-yell", + "pretty-masks-live", + "proud-toys-return", + "purple-beans-march", + "quiet-pens-notice", + "red-games-decide", + "renovate-149779d", + "renovate-2ae4dda", + "renovate-4b5ff24", + "renovate-7438bff", + "renovate-833a91b", + "renovate-9454dab", + "rude-llamas-lie", + "search-boats-double", + "search-lightning-cult", + "search-turtles-itch", + "serious-houses-watch", + "serious-zebras-joke", + "shaggy-melons-drive", + "sharp-numbers-taste", + "sharp-planes-turn", + "shiny-seahorses-do", + "shiny-turkeys-doubt", + "short-deers-remember", + "short-olives-train", + "shy-cameras-develop", + "silent-coats-brake", + "silly-geese-design", + "silver-needles-unite", + "smart-elephants-knock", + "smooth-sheep-hide", + "strange-tables-flash", + "strange-trains-collect", + "strong-lies-explain", + "sweet-plants-sparkle", + "tame-guests-wave", + "techdocs-eyes-sit", + "techdocs-gorgeous-plants-sniff", + "techdocs-sheep-talk", + "techdocs-sixty-mugs-hug", + "techdocs-the-whole-pulse", + "thick-cats-kiss", + "thick-radios-drive", + "thirty-rivers-watch", + "tricky-ravens-visit", + "twelve-candles-jump", + "two-crews-accept", + "unlucky-stingrays-juggle", + "weak-bananas-deliver", + "weak-jeans-cry", + "weak-llamas-repeat", + "wet-dolphins-act", + "wicked-icons-grin", + "wicked-ladybugs-argue" + ] } diff --git a/.changeset/pretty-masks-live.md b/.changeset/pretty-masks-live.md new file mode 100644 index 0000000000..c45ad1e77f --- /dev/null +++ b/.changeset/pretty-masks-live.md @@ -0,0 +1,5 @@ +--- +'@backstage/catalog-model': patch +--- + +Added type predicates for all entity types, e.g. isUserEntity diff --git a/.changeset/proud-toys-return.md b/.changeset/proud-toys-return.md new file mode 100644 index 0000000000..f93e6ef4a8 --- /dev/null +++ b/.changeset/proud-toys-return.md @@ -0,0 +1,5 @@ +--- +'@backstage/catalog-model': minor +--- + +Introduced `GroupDefaultParentEntityPolicy` to set a default group entity parent. diff --git a/.changeset/purple-beans-march.md b/.changeset/purple-beans-march.md new file mode 100644 index 0000000000..f4a3b45ab2 --- /dev/null +++ b/.changeset/purple-beans-march.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Fix `webpack-dev-server` deprecations. diff --git a/.changeset/quiet-pens-notice.md b/.changeset/quiet-pens-notice.md new file mode 100644 index 0000000000..aa6aeb049d --- /dev/null +++ b/.changeset/quiet-pens-notice.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-common': patch +--- + +Improve plural handling in logging output for secrets diff --git a/.changeset/red-games-decide.md b/.changeset/red-games-decide.md new file mode 100644 index 0000000000..208cecfc0a --- /dev/null +++ b/.changeset/red-games-decide.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-api-docs-module-protoc-gen-doc': minor +--- + +Added the new `grpcDocsApiWidget` to render `protoc-gen-doc` generated descriptors by the `grpc-docs` package. diff --git a/.changeset/renovate-0546761.md b/.changeset/renovate-0546761.md new file mode 100644 index 0000000000..ed7b8b19a3 --- /dev/null +++ b/.changeset/renovate-0546761.md @@ -0,0 +1,103 @@ +--- +'@backstage/backend-common': patch +'@backstage/backend-test-utils': patch +'@backstage/catalog-client': patch +'@backstage/cli': patch +'@backstage/config-loader': patch +'@backstage/core-app-api': patch +'@backstage/core-components': patch +'@backstage/core-plugin-api': patch +'@backstage/integration-react': patch +'@backstage/integration': patch +'@backstage/release-manifests': patch +'@backstage/test-utils': patch +'@backstage/plugin-adr-backend': patch +'@backstage/plugin-adr': patch +'@backstage/plugin-airbrake-backend': patch +'@backstage/plugin-airbrake': patch +'@backstage/plugin-allure': patch +'@backstage/plugin-analytics-module-ga': patch +'@backstage/plugin-apache-airflow': patch +'@backstage/plugin-api-docs': patch +'@backstage/plugin-app-backend': patch +'@backstage/plugin-auth-backend': patch +'@backstage/plugin-auth-node': patch +'@backstage/plugin-azure-devops-backend': patch +'@backstage/plugin-azure-devops': patch +'@backstage/plugin-badges': patch +'@backstage/plugin-bitbucket-cloud-common': patch +'@backstage/plugin-bitrise': patch +'@backstage/plugin-catalog-backend-module-azure': patch +'@backstage/plugin-catalog-backend-module-bitbucket-cloud': patch +'@backstage/plugin-catalog-backend-module-bitbucket': patch +'@backstage/plugin-catalog-backend-module-gerrit': patch +'@backstage/plugin-catalog-backend-module-github': patch +'@backstage/plugin-catalog-backend-module-gitlab': patch +'@backstage/plugin-catalog-backend-module-msgraph': patch +'@backstage/plugin-catalog-backend': patch +'@backstage/plugin-catalog-graphql': patch +'@backstage/plugin-catalog-import': patch +'@backstage/plugin-circleci': patch +'@backstage/plugin-cloudbuild': patch +'@backstage/plugin-code-climate': patch +'@backstage/plugin-code-coverage-backend': patch +'@backstage/plugin-code-coverage': patch +'@backstage/plugin-codescene': patch +'@backstage/plugin-config-schema': patch +'@backstage/plugin-cost-insights': patch +'@backstage/plugin-dynatrace': patch +'@backstage/plugin-explore-react': patch +'@backstage/plugin-explore': patch +'@backstage/plugin-firehydrant': patch +'@backstage/plugin-fossa': patch +'@backstage/plugin-gcalendar': patch +'@backstage/plugin-gcp-projects': patch +'@backstage/plugin-git-release-manager': patch +'@backstage/plugin-github-actions': patch +'@backstage/plugin-github-deployments': patch +'@backstage/plugin-github-pull-requests-board': patch +'@backstage/plugin-gitops-profiles': patch +'@backstage/plugin-gocd': patch +'@backstage/plugin-graphiql': patch +'@backstage/plugin-graphql-backend': patch +'@backstage/plugin-home': patch +'@backstage/plugin-ilert': patch +'@backstage/plugin-jenkins-backend': patch +'@backstage/plugin-jenkins': patch +'@backstage/plugin-kafka': patch +'@backstage/plugin-kubernetes': patch +'@backstage/plugin-lighthouse': patch +'@backstage/plugin-newrelic': patch +'@backstage/plugin-org': patch +'@backstage/plugin-pagerduty': patch +'@backstage/plugin-periskop-backend': patch +'@backstage/plugin-periskop': patch +'@backstage/plugin-permission-backend': patch +'@backstage/plugin-permission-common': patch +'@backstage/plugin-permission-node': patch +'@backstage/plugin-rollbar-backend': patch +'@backstage/plugin-rollbar': patch +'@backstage/plugin-scaffolder-backend-module-cookiecutter': patch +'@backstage/plugin-scaffolder-backend': patch +'@backstage/plugin-scaffolder': patch +'@backstage/plugin-search': patch +'@backstage/plugin-sentry': patch +'@backstage/plugin-shortcuts': patch +'@backstage/plugin-sonarqube': patch +'@backstage/plugin-splunk-on-call': patch +'@backstage/plugin-stack-overflow': patch +'@backstage/plugin-tech-insights': patch +'@backstage/plugin-tech-radar': patch +'@backstage/plugin-techdocs-addons-test-utils': patch +'@backstage/plugin-techdocs-backend': patch +'@backstage/plugin-techdocs-module-addons-contrib': patch +'@backstage/plugin-techdocs': patch +'@backstage/plugin-todo-backend': patch +'@backstage/plugin-todo': patch +'@backstage/plugin-user-settings': patch +'@backstage/plugin-vault-backend': patch +'@backstage/plugin-vault': patch +'@backstage/plugin-xcmetrics': patch +--- + +Updated dependency `msw` to `^0.43.0`. diff --git a/.changeset/renovate-149779d.md b/.changeset/renovate-149779d.md new file mode 100644 index 0000000000..58d764485e --- /dev/null +++ b/.changeset/renovate-149779d.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-kafka-backend': patch +--- + +Updated dependency `kafkajs` to `^2.0.0`. diff --git a/.changeset/renovate-2ae4dda.md b/.changeset/renovate-2ae4dda.md new file mode 100644 index 0000000000..2cedbcb9d7 --- /dev/null +++ b/.changeset/renovate-2ae4dda.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-openapi': patch +--- + +Updated dependency `openapi-types` to `^12.0.0`. diff --git a/.changeset/renovate-4b5ff24.md b/.changeset/renovate-4b5ff24.md new file mode 100644 index 0000000000..4867c345d8 --- /dev/null +++ b/.changeset/renovate-4b5ff24.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Updated dependency `run-script-webpack-plugin` to `^0.1.0`. diff --git a/.changeset/renovate-7438bff.md b/.changeset/renovate-7438bff.md new file mode 100644 index 0000000000..43a4ac5016 --- /dev/null +++ b/.changeset/renovate-7438bff.md @@ -0,0 +1,16 @@ +--- +'@backstage/backend-common': patch +'@backstage/backend-tasks': patch +'@backstage/backend-test-utils': patch +'@backstage/plugin-app-backend': patch +'@backstage/plugin-auth-backend': patch +'@backstage/plugin-bazaar-backend': patch +'@backstage/plugin-catalog-backend': patch +'@backstage/plugin-code-coverage-backend': patch +'@backstage/plugin-scaffolder-backend': patch +'@backstage/plugin-search-backend-module-pg': patch +'@backstage/plugin-tech-insights-backend': patch +'@backstage/plugin-techdocs-backend': patch +--- + +Updated dependency `knex` to `^2.0.0`. diff --git a/.changeset/renovate-833a91b.md b/.changeset/renovate-833a91b.md new file mode 100644 index 0000000000..15e23ec5ff --- /dev/null +++ b/.changeset/renovate-833a91b.md @@ -0,0 +1,7 @@ +--- +'@backstage/core-components': patch +'@backstage/plugin-codescene': patch +'@backstage/plugin-sonarqube': patch +--- + +Updated dependency `rc-progress` to `3.4.0`. diff --git a/.changeset/renovate-913f3dc.md b/.changeset/renovate-913f3dc.md new file mode 100644 index 0000000000..edb2f95356 --- /dev/null +++ b/.changeset/renovate-913f3dc.md @@ -0,0 +1,5 @@ +--- +'@backstage/config-loader': patch +--- + +Updated dependency `typescript-json-schema` to `^0.54.0`. diff --git a/.changeset/renovate-9454dab.md b/.changeset/renovate-9454dab.md new file mode 100644 index 0000000000..1f8401e10f --- /dev/null +++ b/.changeset/renovate-9454dab.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend': patch +--- + +Updated dependency `google-auth-library` to `^8.0.0`. diff --git a/.changeset/renovate-cbb545a.md b/.changeset/renovate-cbb545a.md new file mode 100644 index 0000000000..be423e8252 --- /dev/null +++ b/.changeset/renovate-cbb545a.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-api-docs': patch +--- + +Updated dependency `@asyncapi/react-component` to `1.0.0-next.39`. diff --git a/.changeset/rude-llamas-lie.md b/.changeset/rude-llamas-lie.md new file mode 100644 index 0000000000..918d61da6d --- /dev/null +++ b/.changeset/rude-llamas-lie.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-vault': patch +--- + +Export missing parameters and added them to the api-report. Also adapted the API to the expected response from the backend diff --git a/.changeset/search-boats-double.md b/.changeset/search-boats-double.md new file mode 100644 index 0000000000..92fd372cb8 --- /dev/null +++ b/.changeset/search-boats-double.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-search-react': patch +--- + +Fix search pagination to reset page cursor also when a term is cleared. diff --git a/.changeset/search-lightning-cult.md b/.changeset/search-lightning-cult.md new file mode 100644 index 0000000000..79cd256e77 --- /dev/null +++ b/.changeset/search-lightning-cult.md @@ -0,0 +1,24 @@ +--- +'@backstage/plugin-search-backend-module-elasticsearch': minor +--- + +**BREAKING**: In order to remain interoperable with all currently supported +deployments of Elasticsearch, this package will now conditionally use either +the `@elastic/elasticsearch` or `@opensearch-project/opensearch` client when +communicating with your deployed cluster. + +If you do not rely on types exported from this package, or if you do not make +use of the `createElasticSearchClientOptions` or `newClient` methods on the +`ElasticSearchSearchEngine` class, then upgrading to this version should not +require any further action on your part. Everything will continue to work as it +always has. + +If you _do_ rely on either of the above methods or any underlying types, some +changes may be needed to your custom code. A type guard is now exported by this +package (`isOpenSearchCompatible(options)`), which you may use to help clarify +which client options are compatible with which client constructors. + +If you are using this package with the `search.elasticsearch.provider` set to +`aws`, and you are making use of the `newClient` method in particular, you may +wish to start using the `@opensearch-project/opensearch` client in your custom +code. diff --git a/.changeset/search-turtles-itch.md b/.changeset/search-turtles-itch.md new file mode 100644 index 0000000000..2da26fc64a --- /dev/null +++ b/.changeset/search-turtles-itch.md @@ -0,0 +1,13 @@ +--- +'@backstage/plugin-search': patch +--- + +To allow people to use a global search context in the search modal, the code for the search modal has been changed to only create a local search context if there is no parent context already defined. + +If you want to continue using a local context even if you define a global one, you will have to wrap the modal in a new local context manually: + +```tsx + + + +``` diff --git a/.changeset/serious-houses-watch.md b/.changeset/serious-houses-watch.md new file mode 100644 index 0000000000..63d5253bcb --- /dev/null +++ b/.changeset/serious-houses-watch.md @@ -0,0 +1,7 @@ +--- +'@backstage/theme': patch +--- + +**DEPRECATED**: The `bursts` object from `BackstagePaletteAdditions` has been depreciated and will be removed in a future release + +The `genPageTheme` function now includes an optional options object with an optional `fontColor` which defaults to white if not provided. diff --git a/.changeset/serious-zebras-joke.md b/.changeset/serious-zebras-joke.md new file mode 100644 index 0000000000..78f38ca967 --- /dev/null +++ b/.changeset/serious-zebras-joke.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-components': patch +--- + +Support displaying subtitle text in `SidebarSubmenuItem` diff --git a/.changeset/shaggy-melons-drive.md b/.changeset/shaggy-melons-drive.md new file mode 100644 index 0000000000..b5674493f4 --- /dev/null +++ b/.changeset/shaggy-melons-drive.md @@ -0,0 +1,5 @@ +--- +'@backstage/catalog-model': minor +--- + +Adding an optional type field to entity links to group and categorize links diff --git a/.changeset/sharp-numbers-taste.md b/.changeset/sharp-numbers-taste.md new file mode 100644 index 0000000000..4819aca18f --- /dev/null +++ b/.changeset/sharp-numbers-taste.md @@ -0,0 +1,7 @@ +--- +'@backstage/errors': minor +--- + +The `ResponseError.fromResponse` now accepts a more narrow response type, in order to avoid incompatibilities between different fetch implementations. + +The `response` property of `ResponseError` has also been narrowed to a new `ConsumedResponse` type that omits all the properties for consuming the body of the response. This is not considered a breaking change as it was always an error to try to consume the body of the response. diff --git a/.changeset/sharp-planes-turn.md b/.changeset/sharp-planes-turn.md new file mode 100644 index 0000000000..47f6a6176d --- /dev/null +++ b/.changeset/sharp-planes-turn.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-vault-backend': minor +--- + +Throw exceptions instead of swallow them, remove some exported types from the `api-report`, small changes in the API responses & expose the vault `baseUrl` to the frontend as well diff --git a/.changeset/shiny-seahorses-do.md b/.changeset/shiny-seahorses-do.md new file mode 100644 index 0000000000..06892900bf --- /dev/null +++ b/.changeset/shiny-seahorses-do.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-badges-backend': patch +--- + +Add missing installation instructions diff --git a/.changeset/shiny-turkeys-doubt.md b/.changeset/shiny-turkeys-doubt.md new file mode 100644 index 0000000000..edac39182c --- /dev/null +++ b/.changeset/shiny-turkeys-doubt.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-org': patch +--- + +Render namespaces for teams with subtitles in `MyGroupsSidebarItem` diff --git a/.changeset/short-deers-remember.md b/.changeset/short-deers-remember.md new file mode 100644 index 0000000000..7579e7773b --- /dev/null +++ b/.changeset/short-deers-remember.md @@ -0,0 +1,21 @@ +--- +'@backstage/backend-common': patch +'@backstage/integration': patch +'@backstage/plugin-adr': patch +'@backstage/plugin-catalog-backend': patch +'@backstage/plugin-catalog-import': patch +'@backstage/plugin-scaffolder': patch +'@backstage/plugin-scaffolder-backend': patch +'@backstage/plugin-techdocs': patch +'@backstage/plugin-techdocs-module-addons-contrib': patch +'@backstage/plugin-techdocs-node': patch +--- + +Upgrade git-url-parse to 12.0.0. + +Motivation for upgrade is transitively upgrading parse-url which is vulnerable +to several CVEs detected by Snyk. + +- SNYK-JS-PARSEURL-2935944 +- SNYK-JS-PARSEURL-2935947 +- SNYK-JS-PARSEURL-2936249 diff --git a/.changeset/short-olives-train.md b/.changeset/short-olives-train.md new file mode 100644 index 0000000000..594d95f073 --- /dev/null +++ b/.changeset/short-olives-train.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-kubernetes-backend': minor +'@backstage/plugin-kubernetes-common': minor +--- + +Refactor `KubernetesObjectsProvider` with new methods, `KubernetesServiceLocator` now takes an `Entity` instead of `serviceId` diff --git a/.changeset/shy-cameras-develop.md b/.changeset/shy-cameras-develop.md new file mode 100644 index 0000000000..c62a9a56e3 --- /dev/null +++ b/.changeset/shy-cameras-develop.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-catalog-backend-module-openapi': minor +--- + +Add basic OpenAPI \$ref support. + +For more information see [here](https://github.com/backstage/backstage/tree/master/plugins/catalog-backend-module-openapi). diff --git a/.changeset/silent-coats-brake.md b/.changeset/silent-coats-brake.md new file mode 100644 index 0000000000..b1cfbacb6a --- /dev/null +++ b/.changeset/silent-coats-brake.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-catalog': patch +'@backstage/plugin-catalog-backend': patch +--- + +Use entity type predicates from catalog-model diff --git a/.changeset/silly-geese-design.md b/.changeset/silly-geese-design.md new file mode 100644 index 0000000000..d4f8de2510 --- /dev/null +++ b/.changeset/silly-geese-design.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-api-docs': patch +'@backstage/plugin-catalog': minor +--- + +Add hidden title column to catalog and API table to enable filtering by title. diff --git a/.changeset/silver-needles-unite.md b/.changeset/silver-needles-unite.md new file mode 100644 index 0000000000..b5fed7e615 --- /dev/null +++ b/.changeset/silver-needles-unite.md @@ -0,0 +1,26 @@ +--- +'@backstage/plugin-home': patch +--- + +Added support for customizing the time format used in the `HeaderWorldClock` component + +Here's an example of how this can be used in the `HomePage.tsx` found in `\packages\app\src\components\home` to change the clock to be in the 24hr time format: + +```diff ++const timeFormat: Intl.DateTimeFormatOptions = { ++ hour: '2-digit', ++ minute: '2-digit', ++ hour12: false, ++}; + +export const homePage = ( + +
} pageTitleOverride="Home"> ++ +
+ + + + + +``` diff --git a/.changeset/small-shoes-hide.md b/.changeset/small-shoes-hide.md new file mode 100644 index 0000000000..b1f95e9f2d --- /dev/null +++ b/.changeset/small-shoes-hide.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-search-backend-node': patch +--- + +Exports `MissingIndexError` that can be used by the search engines for better error handling when missing index. diff --git a/.changeset/smart-elephants-knock.md b/.changeset/smart-elephants-knock.md new file mode 100644 index 0000000000..7aed10a71e --- /dev/null +++ b/.changeset/smart-elephants-knock.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +The `test` command now ensures that all IO is flushed before exiting when printing `--help`. diff --git a/.changeset/smooth-sheep-hide.md b/.changeset/smooth-sheep-hide.md new file mode 100644 index 0000000000..8a65602ca9 --- /dev/null +++ b/.changeset/smooth-sheep-hide.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-azure-devops': patch +--- + +Exporting azureDevOpsApiRef, AzureGitTagsIcon, and all hooks for the benefit of other plugins. diff --git a/.changeset/strange-tables-flash.md b/.changeset/strange-tables-flash.md new file mode 100644 index 0000000000..b42069aa64 --- /dev/null +++ b/.changeset/strange-tables-flash.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-stack-overflow': patch +'@backstage/plugin-stack-overflow-backend': patch +--- + +app-config is now picked up properly. diff --git a/.changeset/strange-trains-collect.md b/.changeset/strange-trains-collect.md new file mode 100644 index 0000000000..3da9aff515 --- /dev/null +++ b/.changeset/strange-trains-collect.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': patch +--- + +The max content size for dry-run files has been reduced from 256k to 64k. diff --git a/.changeset/strong-lies-explain.md b/.changeset/strong-lies-explain.md new file mode 100644 index 0000000000..d9657be6b4 --- /dev/null +++ b/.changeset/strong-lies-explain.md @@ -0,0 +1,5 @@ +--- +'@backstage/theme': patch +--- + +Adds optional `htmlFontSize` property and also sets typography design tokens for h5 and h6 in base theme. diff --git a/.changeset/sweet-plants-sparkle.md b/.changeset/sweet-plants-sparkle.md new file mode 100644 index 0000000000..69e7647849 --- /dev/null +++ b/.changeset/sweet-plants-sparkle.md @@ -0,0 +1,5 @@ +--- +'@backstage/integration': patch +--- + +Allow frontend visibility for `integrations` itself. diff --git a/.changeset/tame-guests-wave.md b/.changeset/tame-guests-wave.md new file mode 100644 index 0000000000..bbf757084d --- /dev/null +++ b/.changeset/tame-guests-wave.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-azure-devops-backend': patch +--- + +Added comments to example to help avoid confusion as to where lines need to be added diff --git a/.changeset/techdocs-eyes-sit.md b/.changeset/techdocs-eyes-sit.md new file mode 100644 index 0000000000..a09410a4fb --- /dev/null +++ b/.changeset/techdocs-eyes-sit.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs-backend': patch +--- + +Add sample headings on the documented component homepage. diff --git a/.changeset/techdocs-gorgeous-plants-sniff.md b/.changeset/techdocs-gorgeous-plants-sniff.md new file mode 100644 index 0000000000..f5453f35be --- /dev/null +++ b/.changeset/techdocs-gorgeous-plants-sniff.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs': patch +--- + +Reorder browser tab title in Techdocs pages to have the site name first. diff --git a/.changeset/techdocs-sheep-talk.md b/.changeset/techdocs-sheep-talk.md new file mode 100644 index 0000000000..b17408d7a4 --- /dev/null +++ b/.changeset/techdocs-sheep-talk.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs': patch +--- + +Remove the 60% factor from the font size calculation of headers to use the exact size defined in BackstageTheme. diff --git a/.changeset/techdocs-sixty-mugs-hug.md b/.changeset/techdocs-sixty-mugs-hug.md new file mode 100644 index 0000000000..a1a9e815a1 --- /dev/null +++ b/.changeset/techdocs-sixty-mugs-hug.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs': patch +--- + +Fix: When docs are shown in an entity page under the docs tab the sidebars start overlapping with the header and tabs in the page when you scroll the documentation content. diff --git a/.changeset/techdocs-the-whole-pulse.md b/.changeset/techdocs-the-whole-pulse.md new file mode 100644 index 0000000000..b54fb080ae --- /dev/null +++ b/.changeset/techdocs-the-whole-pulse.md @@ -0,0 +1,5 @@ +--- +'@techdocs/cli': patch +--- + +Fixed a bug that prevented docker images from being pulled by default when generating TechDocs. diff --git a/.changeset/ten-cobras-wash.md b/.changeset/ten-cobras-wash.md new file mode 100644 index 0000000000..81915d958d --- /dev/null +++ b/.changeset/ten-cobras-wash.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend': minor +--- + +Allowed post method on /refresh path diff --git a/.changeset/tender-chicken-learn.md b/.changeset/tender-chicken-learn.md new file mode 100644 index 0000000000..bd95c5545f --- /dev/null +++ b/.changeset/tender-chicken-learn.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-search-backend': patch +--- + +If error is `MissingIndexError` we return a 400 response with a more clear error message. diff --git a/.changeset/tender-terms-flash.md b/.changeset/tender-terms-flash.md new file mode 100644 index 0000000000..ca5fdb3799 --- /dev/null +++ b/.changeset/tender-terms-flash.md @@ -0,0 +1,5 @@ +--- +'@backstage/integration': patch +--- + +Avoid double encoding of the file path in `getBitbucketServerDownloadUrl` diff --git a/.changeset/thick-cats-kiss.md b/.changeset/thick-cats-kiss.md new file mode 100644 index 0000000000..8817115ec3 --- /dev/null +++ b/.changeset/thick-cats-kiss.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-catalog': patch +--- + +Adding ability to customize the "unregister entity" menu item in the entity context menu on the entity page with options 'visible','hidden','disabled'.With this three new options, one can hide the "unregister entity" menu item from the list, disable or keep it enabled. + +The boolean input for "unregister entity" will be deprecated later in favour of the above three options. diff --git a/.changeset/thick-radios-drive.md b/.changeset/thick-radios-drive.md new file mode 100644 index 0000000000..130030be59 --- /dev/null +++ b/.changeset/thick-radios-drive.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-adr': patch +--- + +Track discover event and result rank for `AdrSearchResultListItem` diff --git a/.changeset/thirty-rivers-watch.md b/.changeset/thirty-rivers-watch.md new file mode 100644 index 0000000000..d92343f365 --- /dev/null +++ b/.changeset/thirty-rivers-watch.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend': minor +--- + +Added two new scaffolder actions: `github:repo:create` and `github:repo:push` diff --git a/.changeset/tricky-ravens-visit.md b/.changeset/tricky-ravens-visit.md new file mode 100644 index 0000000000..8500c9b64e --- /dev/null +++ b/.changeset/tricky-ravens-visit.md @@ -0,0 +1,6 @@ +--- +'@backstage/core-components': patch +'@backstage/plugin-catalog': patch +--- + +Updated to remove usage of the `bursts` object in the theme palette diff --git a/.changeset/twelve-candles-jump.md b/.changeset/twelve-candles-jump.md new file mode 100644 index 0000000000..9d0cccd0ba --- /dev/null +++ b/.changeset/twelve-candles-jump.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-ldap': patch +--- + +Add possibility to resolve relations by RDN, in addition to UUID and DN diff --git a/.changeset/two-crews-accept.md b/.changeset/two-crews-accept.md new file mode 100644 index 0000000000..9540f97cb5 --- /dev/null +++ b/.changeset/two-crews-accept.md @@ -0,0 +1,15 @@ +--- +'@backstage/plugin-catalog-backend-module-gitlab': patch +--- + +Add the possibility in the `GitlabDiscoveryEntityProvider` to scan the whole project instead of concrete groups. For that, use a configuration like this one, where the group parameter is omitted (not mandatory anymore): + +```yaml +catalog: + providers: + gitlab: + yourProviderId: + host: gitlab-host # Identifies one of the hosts set up in the integrations + branch: main # Optional. Uses `master` as default + entityFilename: catalog-info.yaml # Optional. Defaults to `catalog-info.yaml` +``` diff --git a/.changeset/two-owls-cry.md b/.changeset/two-owls-cry.md new file mode 100644 index 0000000000..ca371781a1 --- /dev/null +++ b/.changeset/two-owls-cry.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-search-backend-module-elasticsearch': patch +--- + +Throws `MissingIndexError` when no index of type exist. diff --git a/.changeset/unlucky-stingrays-juggle.md b/.changeset/unlucky-stingrays-juggle.md new file mode 100644 index 0000000000..f2e83f7163 --- /dev/null +++ b/.changeset/unlucky-stingrays-juggle.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-import': patch +--- + +Support use without `integrations` or only integrations without frontend visible properties (e.g., `bitbucketCloud`) being configured by checking `integrations.github` directly without attempting to load `integrations`. diff --git a/.changeset/weak-bananas-deliver.md b/.changeset/weak-bananas-deliver.md new file mode 100644 index 0000000000..f46c7b7bfe --- /dev/null +++ b/.changeset/weak-bananas-deliver.md @@ -0,0 +1,28 @@ +--- +'@backstage/plugin-pagerduty': minor +--- + +Introduces a new annotation `pagerduty.com/service-id` that can be used instead of the `pagerduty.com/integration-key` annotation. +_Note: If both annotations are specified on a given Entity, then the `pagerduty.com/integration-key` annotation will be prefered_ + +**BREAKING** The `PagerDutyClient.fromConfig` static method now expects a `FetchApi` compatible object and has been refactored to +accept 2 arguments: config and ClientApiDependencies +The `PagerDutyClient` now relies on a `fetchApi` being available to execute `fetch` requests. + +**BREAKING** A new query method `getServiceByEntity` that is used to query for Services by either the `integrationKey` or `serviceId` +annotation values if they are defined. The `integrationKey` value is preferred currently over `serviceId`. As such, the previous +`getServiceByIntegrationKey` method has been removed. + +**BREAKING** The return values for each Client query method has been changed to return an object instead of raw values. +For example, the `getIncidentsByServiceId` query method now returns an object in the shape of `{ incidents: Incident[] }` +instead of just `Incident[]`. +This same pattern goes for `getChangeEventsByServiceId` and `getOnCallByPolicyId` functions. + +**BREAKING** All public exported types that relate to entities within PagerDuty have been prefixed with `PagerDuty` (e.g. `ServicesResponse` is now `PagerDutyServicesResponse` and `User` is now `PagerDutyUser`) + +In addition, various enhancements/bug fixes were introduced: + +- The `PagerDutyCard` component now wraps error and loading messages with an `InfoCard` to contain errors/messages. This enforces a consistent experience on the EntityPage +- If no service can be found for the provided integration key, a new Error Message Empty State component will be shown instead of an error alert +- Introduces the `fetchApi` to replace standard `window.fetch` + - ensures that Identity Authorization is respected and provided in API requests diff --git a/.changeset/weak-jeans-cry.md b/.changeset/weak-jeans-cry.md new file mode 100644 index 0000000000..79f419e3db --- /dev/null +++ b/.changeset/weak-jeans-cry.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': patch +--- + +Add `allowArbitraryValues` to `ui:options` in `OwnedEntityPicker`, similar to `allowArbitraryValues` in `EntityPicker` diff --git a/.changeset/weak-llamas-repeat.md b/.changeset/weak-llamas-repeat.md new file mode 100644 index 0000000000..a86ce3a964 --- /dev/null +++ b/.changeset/weak-llamas-repeat.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs-backend': minor +--- + +Added local publishing target directory `config`: `techdocs.publisher.local.publishDirectory` diff --git a/.changeset/wicked-icons-grin.md b/.changeset/wicked-icons-grin.md new file mode 100644 index 0000000000..8d26a9255e --- /dev/null +++ b/.changeset/wicked-icons-grin.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': patch +--- + +Swap usage of `MaterialTable` with `Table` from `core-components` diff --git a/.changeset/wicked-ladybugs-argue.md b/.changeset/wicked-ladybugs-argue.md new file mode 100644 index 0000000000..9a36cf17cb --- /dev/null +++ b/.changeset/wicked-ladybugs-argue.md @@ -0,0 +1,43 @@ +--- +'@backstage/plugin-catalog': patch +'@backstage/plugin-catalog-react': patch +--- + +Added new `EntityProcessingStatusPicker` that will filter for entities with orphans and/or errors. + +If you are using the default Catalog page this picker will be added automatically. For those who have customized their Catalog page you'll need to add this manually by doing something like this: + +```diff +... +import { + CatalogFilterLayout, + EntityTypePicker, + UserListPicker, + EntityTagPicker ++ EntityProcessingStatusPicker, +} from '@backstage/plugin-catalog-react'; +... +export const CustomCatalogPage = ({ + columns, + actions, + initiallySelectedFilter = 'owned', +}: CatalogPageProps) => { + return ( + ... + + + + + + ... +}; +``` diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 3401dc5b2b..7127fb1da2 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -8,8 +8,7 @@ yarn.lock @backstage/reviewers @backstage-service */yarn.lock @backstage/reviewers @backstage-service /.changeset/cost-insights-* @backstage/reviewers @backstage/silver-lining -/.changeset/search-* @backstage/reviewers @backstage/techdocs-core -/.changeset/techdocs-* @backstage/reviewers @backstage/techdocs-core +/.changeset @backstage/reviewers @backstage/techdocs-core /cypress/src/integration/plugins/techdocs.spec.ts @backstage/reviewers @backstage/techdocs-core /docs/assets/search @backstage/reviewers @backstage/techdocs-core /docs/features/search @backstage/reviewers @backstage/techdocs-core diff --git a/.github/workflows/automate_merge_renovate_prs.yaml b/.github/workflows/automate_merge_renovate_prs.yaml deleted file mode 100644 index 8de488cf05..0000000000 --- a/.github/workflows/automate_merge_renovate_prs.yaml +++ /dev/null @@ -1,85 +0,0 @@ -name: Automate Merge Renovate PRs - -on: - workflow_dispatch: - schedule: - - cron: '*/10 * * * *' - -jobs: - diff: - runs-on: ubuntu-latest - steps: - - uses: actions/github-script@v6 - with: - script: | - const owner = "backstage"; - const repo = "backstage"; - const query = `{ - repository(owner: "backstage", name: "backstage") { - pullRequests(labels: ["dependencies"], last: 10, states: [OPEN]) { - nodes { - title - author { - login - } - number - mergeable - files(first: 1) { - nodes { - path - } - } - changedFiles - commits(last: 1) { - nodes { - commit { - statusCheckRollup { - state - } - } - } - } - reviewDecision - reviews(first: 10) { - nodes { - author { - login - } - } - } - } - } - } - }`; - - const date = new Date(); - if (date.getDay() === 2) { - console.log("Skipping auto merge because Tuesday is release day"); - return; - } - - const r = await github.graphql(query); - const mergable = r.repository.pullRequests.nodes.filter( - (pr) => - pr.author.login === "renovate" && - pr.mergeable === "MERGEABLE" && - pr.changedFiles === 1 && - pr.files.nodes[0].path.split("/").slice(-1)[0] === "yarn.lock" && - pr.commits.nodes[0].commit.statusCheckRollup.state === "SUCCESS" && - pr.reviewDecision === "APPROVED" - ); - - if (mergable.length === 0) { - console.log("no mergable PRs"); - return; - } - - for (const pr of mergable) { - console.log(`Merging #${pr.number} - ${pr.title}`); - await github.rest.pulls.merge({ - owner, - repo, - pull_number: pr.number, - }); - await new Promise((r) => setTimeout(r, 2000)); - } diff --git a/.github/workflows/automate_review-labels-scheduled.yaml b/.github/workflows/automate_review-labels-scheduled.yaml deleted file mode 100644 index 3ba13cfd17..0000000000 --- a/.github/workflows/automate_review-labels-scheduled.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# on a review from someone in the reviewers group, remove the awaiting-review label and add the awaiting-author label -name: Automate review labels - scheduled -on: - schedule: - - cron: '* * * * *' - -jobs: - label: - runs-on: ubuntu-latest - steps: - - name: Get Token - id: get_workflow_token - uses: peter-murray/workflow-application-token-action@v1 - with: - application_id: ${{ secrets.BACKSTAGE_GOALIE_APPLICATION_ID }} - application_private_key: ${{ secrets.BACKSTAGE_GOALIE_PRIVATE_KEY }} - organization: backstage - - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: 14 - - run: npm install codeowners - - - uses: actions/github-script@v6 - id: fix-labels - with: - github-token: ${{ steps.get_workflow_token.outputs.token }} - script: | - const script = require('./scripts/goalie-labels.js') - await script({github, context, core}) diff --git a/.github/workflows/automate_review-labels.yaml b/.github/workflows/automate_review-labels.yaml deleted file mode 100644 index cae71f6aaa..0000000000 --- a/.github/workflows/automate_review-labels.yaml +++ /dev/null @@ -1,84 +0,0 @@ -# When the target of the PR changes, open, re-open or sync, then re-add the label. - -name: Automate review labels -on: - pull_request_target: - types: - - opened - - closed - - synchronize - -permissions: - issues: write - pull-requests: write - -jobs: - label: - runs-on: ubuntu-latest - steps: - # THESE SCRIPTS SHOULD BE INLINED AND NOT IN REPO - # DUE TO THE TOKEN PERMISSIONS THAT ARE GIVEN - # TO THE WORKFLOW. THIS SCRIPT WILL AND SHOULD - # RUN FROM THE BASE REPO ALL TIMES. - - uses: actions/github-script@v6 - id: fix-labels - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - if (['opened', 'synchronize'].includes('${{ github.event.action }}')) { - // if it's the author, always add awaiting-review label - const isAuthor = context.payload.pull_request.user.login === context.actor - if (isAuthor) { - await github.rest.issues.addLabels({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - labels: ['awaiting-review'] - }); - } - } - - if ('${{ github.event.action}}' === 'closed') { - await github.rest.issues.removeLabel({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - labels: 'awaiting-review' - }).catch((e) => { - console.log(e) - }); - } - - - name: Add PRs to review board - uses: actions/github-script@v6 - if: github.event.action == 'opened' || github.event.action == 'reopened' - env: - PROJECT_ID: PN_kwDOBFKqdc02LQ - with: - github-token: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }} - script: | - const prLookup = await github.graphql(` - query($owner: String!, $repo: String!, $number: Int!){ - repository(owner: $owner, name: $repo) { - pullRequest(number: $number) { - id - } - } - } - `, context.issue); - - await github.graphql(` - mutation($projectId: ID!, $contentId: ID!) { - addProjectNextItem(input: { - projectId: $projectId, - contentId: $contentId, - }) { - projectNextItem { - id - } - } - } - `, { - projectId: process.env.PROJECT_ID, - contentId: prLookup.repository.pullRequest.id - }) diff --git a/.github/workflows/automate_stale.yml b/.github/workflows/automate_stale.yml index f9c655fc4a..8978048c89 100644 --- a/.github/workflows/automate_stale.yml +++ b/.github/workflows/automate_stale.yml @@ -25,6 +25,6 @@ jobs: If you are the author and the PR has been closed, feel free to re-open the PR and continue the contribution! days-before-pr-stale: 7 days-before-pr-close: 5 - exempt-pr-labels: reviewer-approved,awaiting-review,will-fix + exempt-pr-labels: reviewer-approved,will-fix stale-pr-label: stale operations-per-run: 100 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0718c8a8b9..06f89b06d3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,9 +9,116 @@ concurrency: cancel-in-progress: true jobs: + # This step only runs yarn install to make sure that an exact match is available + # in the cache. The two following verify and tests jobs then always install from cache. + install: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [14.x, 16.x] + + env: + CI: true + NODE_OPTIONS: --max-old-space-size=4096 + + steps: + - uses: actions/checkout@v3 + + - name: use node.js ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + registry-url: https://registry.npmjs.org/ # Needed for auth + + - name: yarn install + uses: backstage/actions/yarn-install@v0.5.2 + with: + cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} + + # The verify jobs runs all the verification that doesn't require a + # diff towards master, since it takes some time to fetch that. verify: runs-on: ubuntu-latest + needs: install + + strategy: + matrix: + node-version: [14.x, 16.x] + + env: + CI: true + NODE_OPTIONS: --max-old-space-size=4096 + + steps: + - uses: actions/checkout@v3 + + - name: use node.js ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + registry-url: https://registry.npmjs.org/ # Needed for auth + + - name: yarn install + uses: backstage/actions/yarn-install@v0.5.2 + with: + cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} + + - name: verify changesets + run: node scripts/verify-changesets.js + + - name: verify local dependency ranges + run: node scripts/verify-local-dependencies.js + + - name: validate config + run: yarn backstage-cli config:check --lax + + - name: type checking and declarations + run: yarn tsc:full + + - name: prettier + run: yarn prettier:check + + # We need to generate the API references as well, so that we can verify the doc links + - name: check api reports and generate API reference + run: yarn build:api-reports:only --ci --docs + + - name: verify api reference + run: node scripts/verify-api-reference.js + + - name: verify doc links + run: node scripts/verify-links.js + + - name: build all packages + run: yarn backstage-cli repo build --all + + - name: verify type dependencies + run: yarn lint:type-deps + + - name: verify plugin template + run: yarn lerna -- run diff -- --check + + - name: ensure clean working directory + run: | + if files=$(git ls-files --exclude-standard --others --modified) && [[ -z "$files" ]]; then + exit 0 + else + echo "" + echo "Working directory has been modified:" + echo "" + git status --short + echo "" + exit 1 + fi + + # The test job runs all tests as well as any verification step that + # requires a diff towards master. + test: + runs-on: ubuntu-latest + + needs: install + strategy: matrix: node-version: [14.x, 16.x] @@ -64,93 +171,28 @@ jobs: - name: fetch branch master run: git fetch origin master - # Beginning of yarn setup, keep in sync between all workflows. - # TODO(Rugvip): move this to composite action once all features we use are supported - name: use node.js ${{ matrix.node-version }} uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth - # Cache every node_modules folder inside the monorepo - - name: cache all node_modules - id: cache-modules - uses: actions/cache@v3 - with: - path: '**/node_modules' - # We use both yarn.lock and package.json as cache keys to ensure that - # changes to local monorepo packages bust the cache. - key: ${{ runner.os }}-v${{ matrix.node-version }}-node_modules-${{ hashFiles('yarn.lock', '**/package.json') }} - - # If we get a cache hit for node_modules, there's no need to bring in the global - # yarn cache or run yarn install, as all dependencies will be installed already. - - - name: find location of global yarn cache - id: yarn-cache - if: steps.cache-modules.outputs.cache-hit != 'true' - run: echo "::set-output name=dir::$(yarn cache dir)" - - - name: cache global yarn cache - uses: actions/cache@v3 - if: steps.cache-modules.outputs.cache-hit != 'true' - with: - path: ${{ steps.yarn-cache.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn- - - name: yarn install - if: steps.cache-modules.outputs.cache-hit != 'true' - run: yarn install --frozen-lockfile - # End of yarn setup + uses: backstage/actions/yarn-install@v0.5.2 + with: + cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} - name: check for yarn.lock changes id: yarn-lock run: git diff --quiet origin/master HEAD -- yarn.lock continue-on-error: true - - name: prettier - run: yarn prettier:check - - name: lock run: yarn lock:check - - name: validate config - run: yarn backstage-cli config:check --lax - - name: lint run: yarn backstage-cli repo lint --since origin/master - - name: type checking and declarations - run: yarn tsc:full - - # We need to generate the API references as well, so that we can verify the doc links - - name: check api reports and generate API reference - run: yarn build:api-reports:only --ci --docs - - - name: verify api reference - run: node scripts/verify-api-reference.js - - - name: verify changesets - run: node scripts/verify-changesets.js - - - name: verify doc links - run: node scripts/verify-links.js - - - name: verify local dependency ranges - run: node scripts/verify-local-dependencies.js - - - name: build changed packages - if: ${{ steps.yarn-lock.outcome == 'success' }} - run: yarn backstage-cli repo build --all --since origin/master - - - name: build all packages - if: ${{ steps.yarn-lock.outcome == 'failure' }} - run: yarn backstage-cli repo build --all - - - name: verify type dependencies - run: yarn lint:type-deps - - name: test changed packages if: ${{ steps.yarn-lock.outcome == 'success' }} run: yarn lerna -- run test --since origin/master -- --coverage --runInBand @@ -173,9 +215,6 @@ jobs: BACKSTAGE_TEST_DATABASE_POSTGRES9_CONNECTION_STRING: postgresql://postgres:postgres@localhost:${{ job.services.postgres9.ports[5432] }} BACKSTAGE_TEST_DATABASE_MYSQL8_CONNECTION_STRING: mysql://root:root@localhost:${{ job.services.mysql8.ports[3306] }}/ignored - - name: verify plugin template - run: yarn lerna -- run diff -- --check - - name: ensure clean working directory run: | if files=$(git ls-files --exclude-standard --others --modified) && [[ -z "$files" ]]; then diff --git a/.github/workflows/cron.yml b/.github/workflows/cron.yml new file mode 100644 index 0000000000..228d4c62ac --- /dev/null +++ b/.github/workflows/cron.yml @@ -0,0 +1,15 @@ +name: Cron +on: + workflow_dispatch: + schedule: + - cron: '*/5 * * * *' + +jobs: + cron: + runs-on: ubuntu-latest + steps: + - uses: backstage/actions/cron@v0.5.2 + with: + app-id: ${{ secrets.BACKSTAGE_GOALIE_APPLICATION_ID }} + private-key: ${{ secrets.BACKSTAGE_GOALIE_PRIVATE_KEY }} + installation-id: ${{ secrets.BACKSTAGE_GOALIE_INSTALLATION_ID }} diff --git a/.github/workflows/deploy_docker-image.yml b/.github/workflows/deploy_docker-image.yml new file mode 100644 index 0000000000..b41ca516ef --- /dev/null +++ b/.github/workflows/deploy_docker-image.yml @@ -0,0 +1,89 @@ +name: Build and push Docker Hub image +on: + repository_dispatch: + types: [release-published] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: checkout + uses: actions/checkout@v2 + with: + path: backstage + ref: v${{ github.event.client_payload.version }} + + - name: setup-node + uses: actions/setup-node@v1 + with: + node-version: 16.x + registry-url: https://registry.npmjs.org/ + + # Beginning of yarn setup, keep in sync between all workflows. + # TODO(Rugvip): move this to composite action once all features we use are supported + - name: use node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + registry-url: https://registry.npmjs.org/ # Needed for auth + + # Cache every node_modules folder inside the monorepo + - name: cache all node_modules + id: cache-modules + uses: actions/cache@v2 + with: + path: '**/node_modules' + # We use both yarn.lock and package.json as cache keys to ensure that + # changes to local monorepo packages bust the cache. + key: ${{ runner.os }}-v${{ matrix.node-version }}-node_modules-${{ hashFiles('yarn.lock', '**/package.json') }} + + # If we get a cache hit for node_modules, there's no need to bring in the global + # yarn cache or run yarn install, as all dependencies will be installed already. + + - name: find location of global yarn cache + id: yarn-cache + if: steps.cache-modules.outputs.cache-hit != 'true' + run: echo "::set-output name=dir::$(yarn cache dir)" + + - name: cache global yarn cache + uses: actions/cache@v2 + if: steps.cache-modules.outputs.cache-hit != 'true' + with: + path: ${{ steps.yarn-cache.outputs.dir }} + key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + - name: yarn install + if: steps.cache-modules.outputs.cache-hit != 'true' + run: yarn install --frozen-lockfile + # End of yarn setup + + - name: create-app + run: npx @backstage/create-app + env: + BACKSTAGE_APP_NAME: example-app + + - name: yarn build + run: yarn build + working-directory: ./example-app + + - name: Login to GitHub Container Registry + uses: docker/login-action@v1 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Build and push + uses: docker/build-push-action@v3 + with: + context: './example-app' + file: ./example-app/packages/backend/Dockerfile + push: true + tags: | + ghcr.io/${{ github.repository_owner }}/backstage:latest + ghcr.io/${{ github.repository_owner }}/backstage:${{ github.event.client_payload.version }} diff --git a/.github/workflows/deploy_microsite.yml b/.github/workflows/deploy_microsite.yml index d0f8dc1e79..ffada71523 100644 --- a/.github/workflows/deploy_microsite.yml +++ b/.github/workflows/deploy_microsite.yml @@ -55,7 +55,7 @@ jobs: run: ls microsite/build/backstage && ls microsite/build/backstage/storybook - name: Deploy both microsite and storybook to gh-pages - uses: JamesIves/github-pages-deploy-action@v4.3.3 + uses: JamesIves/github-pages-deploy-action@v4.3.4 with: branch: gh-pages folder: microsite/build/backstage diff --git a/.github/workflows/deploy_nightly.yml b/.github/workflows/deploy_nightly.yml index c90894bce4..719b5ea94b 100644 --- a/.github/workflows/deploy_nightly.yml +++ b/.github/workflows/deploy_nightly.yml @@ -20,33 +20,15 @@ jobs: steps: - uses: actions/checkout@v3 - # Beginning of yarn setup, keep in sync between all workflows, see ci.yml - name: use node.js ${{ matrix.node-version }} uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth - - name: cache all node_modules - id: cache-modules - uses: actions/cache@v3 - with: - path: '**/node_modules' - key: ${{ runner.os }}-v${{ matrix.node-version }}-node_modules-${{ hashFiles('yarn.lock', '**/package.json') }} - - name: find location of global yarn cache - id: yarn-cache - if: steps.cache-modules.outputs.cache-hit != 'true' - run: echo "::set-output name=dir::$(yarn cache dir)" - - name: cache global yarn cache - uses: actions/cache@v3 - if: steps.cache-modules.outputs.cache-hit != 'true' - with: - path: ${{ steps.yarn-cache.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn- - name: yarn install - run: yarn install --frozen-lockfile - # End of yarn setup + uses: backstage/actions/yarn-install@v0.5.2 + with: + cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} # No verification done here, only build & publish. If the master branch # is broken we will see that from those builds, but we still want to push nightly diff --git a/.github/workflows/deploy_packages.yml b/.github/workflows/deploy_packages.yml index b63507df0c..371712fedb 100644 --- a/.github/workflows/deploy_packages.yml +++ b/.github/workflows/deploy_packages.yml @@ -61,33 +61,15 @@ jobs: steps: - uses: actions/checkout@v3 - # Beginning of yarn setup, keep in sync between all workflows, see ci.yml - name: use node.js ${{ matrix.node-version }} uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth - - name: cache all node_modules - id: cache-modules - uses: actions/cache@v3 - with: - path: '**/node_modules' - key: ${{ runner.os }}-v${{ matrix.node-version }}-node_modules-${{ hashFiles('yarn.lock', '**/package.json') }} - - name: find location of global yarn cache - id: yarn-cache - if: steps.cache-modules.outputs.cache-hit != 'true' - run: echo "::set-output name=dir::$(yarn cache dir)" - - name: cache global yarn cache - uses: actions/cache@v3 - if: steps.cache-modules.outputs.cache-hit != 'true' - with: - path: ${{ steps.yarn-cache.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn- - name: yarn install - run: yarn install --frozen-lockfile - # End of yarn setup + uses: backstage/actions/yarn-install@v0.5.2 + with: + cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} - name: Fetch previous commit for release check run: git fetch origin '${{ github.event.before }}' @@ -157,33 +139,15 @@ jobs: steps: - uses: actions/checkout@v3 - # Beginning of yarn setup, keep in sync between all workflows, see ci.yml - name: use node.js ${{ matrix.node-version }} uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth - - name: cache all node_modules - id: cache-modules - uses: actions/cache@v3 - with: - path: '**/node_modules' - key: ${{ runner.os }}-v${{ matrix.node-version }}-node_modules-${{ hashFiles('yarn.lock', '**/package.json') }} - - name: find location of global yarn cache - id: yarn-cache - if: steps.cache-modules.outputs.cache-hit != 'true' - run: echo "::set-output name=dir::$(yarn cache dir)" - - name: cache global yarn cache - uses: actions/cache@v3 - if: steps.cache-modules.outputs.cache-hit != 'true' - with: - path: ${{ steps.yarn-cache.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn- - name: yarn install - run: yarn install --frozen-lockfile - # End of yarn setup + uses: backstage/actions/yarn-install@v0.5.2 + with: + cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} - name: build type declarations run: yarn tsc:full @@ -209,7 +173,7 @@ jobs: # Grabs the version in the root package.json and creates a tag on GitHub - name: Create a release tag id: create_tag - run: node scripts/create-release-tag.js --dispatch-workflows + run: node scripts/create-release-tag.js env: GITHUB_TOKEN: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }} @@ -219,6 +183,13 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }} + - name: Dispatch repository event + uses: peter-evans/repository-dispatch@v2 + with: + token: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }} + event-type: release-published + client-payload: '{"version": "${{ steps.create_tag.outputs.version }}"}' + # Notify everyone about this great new release :D - name: Discord notification uses: Ilshidur/action-discord@0.3.2 diff --git a/.github/workflows/issue.yaml b/.github/workflows/issue.yaml new file mode 100644 index 0000000000..de02e45e76 --- /dev/null +++ b/.github/workflows/issue.yaml @@ -0,0 +1,13 @@ +name: Issue +on: + issues: + types: [opened] + +jobs: + sync: + runs-on: ubuntu-latest + + if: github.repository == 'backstage/backstage' + steps: + - name: Issue sync + uses: backstage/actions/issue-sync@v0.5.2 diff --git a/.github/workflows/pr-review-comment-trigger.yaml b/.github/workflows/pr-review-comment-trigger.yaml new file mode 100644 index 0000000000..25475a03dc --- /dev/null +++ b/.github/workflows/pr-review-comment-trigger.yaml @@ -0,0 +1,19 @@ +# This workflow is used to trigger the "PR Review Comment" workflow. This chaining is needed +# because workflows triggered by pull_request_review_comment do not have access to secrets. + +name: PR Review Comment Trigger +on: + pull_request_review_comment: + types: + - created + +jobs: + trigger: + runs-on: ubuntu-latest + + # The "PR Review Comment" workflow will check the success status of this workflow and only mark + # the PR for re-review if this workflow was successful, which is when the author leaves a review comment. + if: github.repository == 'backstage/backstage' && github.event.comment.user.id == github.event.pull_request.user.id + + steps: + - run: echo "This PR needs another review" diff --git a/.github/workflows/pr-review-comment.yaml b/.github/workflows/pr-review-comment.yaml new file mode 100644 index 0000000000..65252bae09 --- /dev/null +++ b/.github/workflows/pr-review-comment.yaml @@ -0,0 +1,24 @@ +# This workflow is triggered by "PR Review Comment Trigger" + +name: PR Review Comment +on: + workflow_run: + workflows: [PR Review Comment Trigger] + types: + - completed + +jobs: + re-review: + runs-on: ubuntu-latest + + # The triggering workflow will report success if the PR needs re-review + if: github.repository == 'backstage/backstage' && github.event.workflow_run.conclusion == 'success' + + steps: + - uses: backstage/actions/re-review@v0.5.2 + with: + app-id: ${{ secrets.BACKSTAGE_GOALIE_APPLICATION_ID }} + private-key: ${{ secrets.BACKSTAGE_GOALIE_PRIVATE_KEY }} + installation-id: ${{ secrets.BACKSTAGE_GOALIE_INSTALLATION_ID }} + project-id: PVT_kwDOBFKqdc02LQ + issue-number: ${{ github.event.workflow_run.pull_requests[0].number }} diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml new file mode 100644 index 0000000000..e5945f6f20 --- /dev/null +++ b/.github/workflows/pr.yaml @@ -0,0 +1,29 @@ +name: PR +on: + pull_request_target: + types: + - opened + - synchronize + - reopened + - closed + issue_comment: + types: + - created + +jobs: + sync: + runs-on: ubuntu-latest + + # Avoid running on issue comments + if: github.repository == 'backstage/backstage' && ( github.event.pull_request || github.event.issue.pull_request ) + steps: + - name: PR sync + uses: backstage/actions/pr-sync@v0.5.2 + with: + github-token: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }} + app-id: ${{ secrets.BACKSTAGE_GOALIE_APPLICATION_ID }} + private-key: ${{ secrets.BACKSTAGE_GOALIE_PRIVATE_KEY }} + installation-id: ${{ secrets.BACKSTAGE_GOALIE_INSTALLATION_ID }} + project-id: PVT_kwDOBFKqdc02LQ + excluded-users: ${{ secrets.OOO_USERS }} + owning-teams: '@backstage/techdocs' diff --git a/.github/workflows/sync_approve_renovate_pr.yaml b/.github/workflows/sync_approve_renovate_pr.yaml deleted file mode 100644 index 2d25bea223..0000000000 --- a/.github/workflows/sync_approve_renovate_pr.yaml +++ /dev/null @@ -1,37 +0,0 @@ -name: Approve renovate lock file changes -on: - pull_request_target: - paths: - - '.github/workflows/sync_renovate-changesets.yml' - - '**/yarn.lock' - -jobs: - generate-changeset: - runs-on: ubuntu-latest - if: github.actor == 'renovate[bot]' && github.repository == 'backstage/backstage' - steps: - - name: Approve - uses: actions/github-script@v6 - with: - github-token: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }} - script: | - const owner = 'backstage'; - const repo = 'backstage'; - - const r = await github.rest.pulls.listFiles({ - owner, - repo, - pull_number: context.issue.number, - }); - - if (r.data.some((f) => f.filename.split('/').slice(-1)[0] !== 'yarn.lock')) { - console.log('skipping approval since some files are not yarn.lock'); - return; - } - - await github.rest.pulls.createReview({ - owner, - repo, - pull_number: context.issue.number, - event: 'APPROVE' - }) diff --git a/.github/workflows/sync_code-formatting.yml b/.github/workflows/sync_code-formatting.yml index b6fce0e68d..b04a0a3de0 100644 --- a/.github/workflows/sync_code-formatting.yml +++ b/.github/workflows/sync_code-formatting.yml @@ -14,33 +14,15 @@ jobs: # Fetch changes to previous commit - required for 'only_changed' in Prettier action fetch-depth: 0 - # Beginning of yarn setup, keep in sync between all workflows, see ci.yml - name: use node.js ${{ matrix.node-version }} uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth - - name: cache all node_modules - id: cache-modules - uses: actions/cache@v3 - with: - path: '**/node_modules' - key: ${{ runner.os }}-v${{ matrix.node-version }}-node_modules-${{ hashFiles('yarn.lock', '**/package.json') }} - - name: find location of global yarn cache - id: yarn-cache - if: steps.cache-modules.outputs.cache-hit != 'true' - run: echo "::set-output name=dir::$(yarn cache dir)" - - name: cache global yarn cache - uses: actions/cache@v3 - if: steps.cache-modules.outputs.cache-hit != 'true' - with: - path: ${{ steps.yarn-cache.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn- - name: yarn install - run: yarn install --frozen-lockfile - # End of yarn setup + uses: backstage/actions/yarn-install@v0.5.2 + with: + cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} - name: Run Prettier on ADOPTERS.md uses: creyD/prettier_action@v4.2 diff --git a/.github/workflows/sync_issue-labels.yml b/.github/workflows/sync_issue-labels.yml deleted file mode 100644 index 91b5f79f5d..0000000000 --- a/.github/workflows/sync_issue-labels.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: Sync Issue Labels -on: - issues: - types: [opened] -jobs: - label-issue: - runs-on: ubuntu-latest - if: github.repository == 'backstage/backstage' - steps: - - name: View context attributes - uses: actions/github-script@v6 - with: - script: | - const keywords = { - 'techdocs|tech-docs|tech docs': 'docs-like-code', - 'search': 'search', - 'catalog': 'catalog', - 'scaffolder': 'scaffolder', - }; - - const labels = Object.entries(keywords) - .map(([regexp, label]) => { - if (new RegExp(regexp, 'gi').test(context.payload.issue.title)) { - return label; - } - }) - .filter(Boolean); - - if(!labels.length) { - return; - } - - github.rest.issues.addLabels({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - labels - }); diff --git a/.github/workflows/sync_release-manifest.yml b/.github/workflows/sync_release-manifest.yml index 816a3e632f..8cf6991aaf 100644 --- a/.github/workflows/sync_release-manifest.yml +++ b/.github/workflows/sync_release-manifest.yml @@ -1,10 +1,7 @@ name: Sync Release Manifest on: - workflow_dispatch: - inputs: - version: - description: Version number, without any 'v' prefix - required: true + repository_dispatch: + types: [release-published] jobs: create-new-version: @@ -23,7 +20,7 @@ jobs: with: path: backstage # 'v' prefix is added here for the tag, we keep it out of the manifest logic - ref: v${{ github.event.inputs.version }} + ref: v${{ github.event.client_payload.version }} # Checkout backstage/versions into /backstage/versions, which is where store the output - name: Checkout versions @@ -44,10 +41,10 @@ jobs: cd backstage mkdir -p scripts wget -O scripts/assemble-manifest.js https://raw.githubusercontent.com/backstage/backstage/master/scripts/assemble-manifest.js - node scripts/assemble-manifest.js ${{ github.event.inputs.version }} + node scripts/assemble-manifest.js ${{ github.event.client_payload.version }} cd versions git add . - git commit -am "${{ github.event.inputs.version }}" + git commit -am "${{ github.event.client_payload.version }}" git push - name: Dispatch update-helper update diff --git a/.github/workflows/sync_snyk-github-issues.yml b/.github/workflows/sync_snyk-github-issues.yml index e45a36c8e8..d2af1307b0 100644 --- a/.github/workflows/sync_snyk-github-issues.yml +++ b/.github/workflows/sync_snyk-github-issues.yml @@ -16,33 +16,15 @@ jobs: steps: - uses: actions/checkout@v3 - # Beginning of yarn setup, keep in sync between all workflows, see ci.yml - name: use node.js ${{ matrix.node-version }} uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth - - name: cache all node_modules - id: cache-modules - uses: actions/cache@v3 - with: - path: '**/node_modules' - key: ${{ runner.os }}-v${{ matrix.node-version }}-node_modules-${{ hashFiles('yarn.lock', '**/package.json') }} - - name: find location of global yarn cache - id: yarn-cache - if: steps.cache-modules.outputs.cache-hit != 'true' - run: echo "::set-output name=dir::$(yarn cache dir)" - - name: cache global yarn cache - uses: actions/cache@v3 - if: steps.cache-modules.outputs.cache-hit != 'true' - with: - path: ${{ steps.yarn-cache.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn- - name: yarn install - run: yarn install --frozen-lockfile - # End of yarn setup + uses: backstage/actions/yarn-install@v0.5.2 + with: + cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} - name: Create Snyk report uses: snyk/actions/node@master diff --git a/.github/workflows/verify_dco.yaml b/.github/workflows/verify_dco.yaml deleted file mode 100644 index 2094327d23..0000000000 --- a/.github/workflows/verify_dco.yaml +++ /dev/null @@ -1,65 +0,0 @@ -name: Verify DCO -on: - schedule: - - cron: '*/15 * * * *' - -jobs: - dco-helper: - runs-on: ubuntu-latest - steps: - - name: Verify DCO status for open pull requests - uses: actions/github-script@v6 - with: - script: | - const owner = "backstage"; - const repo = "backstage"; - const pulls = await github.paginate(github.rest.pulls.list, { - state: "open", - owner, - repo, - }); - - for (const pull of pulls) { - // Pick out the PRs that have the DCO check - const checks = await github.rest.checks.listForRef({ - owner, - repo, - ref: pull.head.sha, - check_name: "DCO", - status: "completed", - }); - // Skip if there are no checks - if (!checks.data.check_runs.length) { - continue; - } - // Skip if the conclusion is not action_required - if (checks.data.check_runs[0].conclusion !== "action_required") { - console.log(`No checks found for PR #${pull.number}, skipping`); - continue; - } - - const comments = await github.paginate(github.rest.issues.listComments, { - owner, - repo, - issue_number: pull.number, - }); - if (comments.find((c) => - c.user.login === "github-actions[bot]" && - c.body.includes("") - ) - ) { - console.log(`already commented on PR #${pull.number}, skipping`); - continue; - } - console.log(`creating comment on PR #${pull.number}`); - const body = ` - Thanks for the contribution! - All commits need to be DCO signed before they are reviewed. Please refer to the the [DCO section in CONTRIBUTING.md](https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md#developer-certificate-of-origin) or the [DCO](${checks.data.check_runs[0].html_url}) status for more info. - `; - await github.rest.issues.createComment({ - repo, - owner, - issue_number: pull.number, - body, - }); - } diff --git a/.github/workflows/verify_e2e-linux.yml b/.github/workflows/verify_e2e-linux.yml index 884d8bf172..811372d54d 100644 --- a/.github/workflows/verify_e2e-linux.yml +++ b/.github/workflows/verify_e2e-linux.yml @@ -40,35 +40,15 @@ jobs: steps: - uses: actions/checkout@v3 - # Beginning of yarn setup, keep in sync between all workflows, see ci.yml - name: use node.js ${{ matrix.node-version }} uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth - - name: cache all node_modules - id: cache-modules - uses: actions/cache@v3 - with: - path: '**/node_modules' - key: ${{ runner.os }}-v${{ matrix.node-version }}-node_modules-${{ hashFiles('yarn.lock', '**/package.json') }} - - name: find location of global yarn cache - id: yarn-cache - if: steps.cache-modules.outputs.cache-hit != 'true' - run: echo "::set-output name=dir::$(yarn cache dir)" - - name: setup chrome - uses: browser-actions/setup-chrome@latest - - name: cache global yarn cache - uses: actions/cache@v3 - if: steps.cache-modules.outputs.cache-hit != 'true' - with: - path: ${{ steps.yarn-cache.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn- - name: yarn install - run: yarn install --frozen-lockfile - # End of yarn setup + uses: backstage/actions/yarn-install@v0.5.2 + with: + cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} - run: yarn tsc - run: yarn backstage-cli repo build diff --git a/.github/workflows/verify_storybook.yml b/.github/workflows/verify_storybook.yml index a13aa3ae71..1aea51bec9 100644 --- a/.github/workflows/verify_storybook.yml +++ b/.github/workflows/verify_storybook.yml @@ -17,44 +17,30 @@ on: jobs: chromatic: - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} + + strategy: + matrix: + os: [ubuntu-latest] + node-version: [16.x] + steps: - uses: actions/checkout@v3 with: fetch-depth: 0 # Required to retrieve git history - # Beginning of yarn setup, keep in sync between all workflows, see ci.yml - name: use node.js ${{ matrix.node-version }} uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth - - name: cache all node_modules - id: cache-modules - uses: actions/cache@v3 + - name: yarn install + uses: backstage/actions/yarn-install@v0.5.2 with: - path: '**/node_modules' - key: ${{ runner.os }}-v${{ matrix.node-version }}-node_modules-${{ hashFiles('yarn.lock', '**/package.json') }} - - name: find location of global yarn cache - id: yarn-cache - if: steps.cache-modules.outputs.cache-hit != 'true' - run: echo "::set-output name=dir::$(yarn cache dir)" - - name: cache global yarn cache - uses: actions/cache@v3 - if: steps.cache-modules.outputs.cache-hit != 'true' - with: - path: ${{ steps.yarn-cache.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn- - - - name: top-level install - run: yarn install --frozen-lockfile - + cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} - name: storybook yarn install run: yarn install --frozen-lockfile working-directory: storybook - # End of yarn setup - run: yarn build-storybook diff --git a/.github/workflows/verify_windows.yml b/.github/workflows/verify_windows.yml index bb8aa9e5aa..e286d42c7e 100644 --- a/.github/workflows/verify_windows.yml +++ b/.github/workflows/verify_windows.yml @@ -26,25 +26,15 @@ jobs: steps: - uses: actions/checkout@v3 - # Beginning of yarn setup, keep in sync between all workflows, see ci.yml - name: use node.js ${{ matrix.node-version }} uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth - - name: find location of global yarn cache - id: yarn-cache - run: echo "::set-output name=dir::$(yarn cache dir)" - - name: cache global yarn cache - uses: actions/cache@v3 - with: - path: ${{ steps.yarn-cache.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn- + + # Windows file operation slowness means there's no point caching this - name: yarn install run: yarn install --frozen-lockfile - # End of yarn setup - name: lint run: yarn backstage-cli repo lint diff --git a/.prettierignore b/.prettierignore index 393c35fdbe..8f1fae0456 100644 --- a/.prettierignore +++ b/.prettierignore @@ -5,6 +5,7 @@ coverage *.hbs templates api-report.md +cli-report.md plugins/scaffolder-backend/sample-templates .vscode dist-types diff --git a/ADOPTERS.md b/ADOPTERS.md index 4df952be6d..6bf1f482bf 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -1,9 +1,11 @@ # Adopters -_If you're using Backstage in your organization, please try to add your company name to this list. This really helps the project to gain momentum and credibility. It's a small contribution back to the project with a big impact._ +_If you're using Backstage in your organization, please try to add your company name to this list. It really helps the project to gain momentum and credibility. It's a small contribution back to the project with a big impact._ +_You can do this by using the [Adopter form](https://form.typeform.com/to/zcOaKikB) or by editing this file after following the [CONTRIBUTING.md](./CONTRIBUTING.md)._ + | Organization | Contact | Description of Use | -| --------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|-----------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | [Spotify](https://www.spotify.com) | [@leemills83](https://github.com/leemills83) | Main interface towards all of Spotify's infrastructure and technical documentation. | | [bol.com](https://www.bol.com) | [@sagacity](https://github.com/sagacity) | Initial work being done to unify platform tooling. | | [DFDS](https://www.dfds.com) | [@carlsendk](https://github.com/carlsendk) | V2 self-service platform. | @@ -21,7 +23,7 @@ _If you're using Backstage in your organization, please try to add your company | [Fiverr](https://www.fiverr.com) | [@nirga](https://github.com/nirga) | Unifying separate tools that developers are using today (i.e. monitoring, dead letter queues management, etc.) into a single platform. | | [Zalando SE](https://www.zalando.de) | [@leviferreira](https://github.com/leviferreira) | Building V2 of the Internal Development Portal. | | [LegalZoom](https://legalzoom.com) | [@backjo](https://github.com/backjo) | Developer portal - hub for all engineering projects and metadata. | -| [Expedia Group](https://www.expediagroup.com) | [@guillermomanzo](https://github.com/guillermomanzo), [Sheena Sharma](mailto:shesharma@expediagroup.com) | EG Common Developer Toolkit | +| [Expedia Group](https://www.expediagroup.com) | [@guillermomanzo](https://github.com/guillermomanzo), [Sheena Sharma](mailto:shesharma@expediagroup.com), [@ajbw](https://github.com/ajbw) | EG Common Developer Toolkit | | [Paddle.com](https://paddle.com) | [Ioannis Georgoulas](https://github.com/geototti21) | Developer portal (Tech Docs, Service Catalog, Internal Tooling), we use vanilla Backstage FE and custom BE implementation in Go | | [Acast.com](https://acast.com) | [Olle Lundberg](https://github.com/lndbrg) | Developer portal with tech docs, service catalog and a bunch of other internal tooling | | [Lunar](https://lunar.app) | [Jacob Valdemar](https://github.com/JacobValdemar) | Internal developer portal for service overview and insights, API documentation, technical guides, onboarding guides and RFC's. | @@ -34,9 +36,9 @@ _If you're using Backstage in your organization, please try to add your company | [Netflix](https://www.netflix.com/) | [bleathem](https://github.com/bleathem) | Our Backstage implementation will be the front door to a unified experience connecting our internal platform products across important workflows with integrated knowledge and support. | | [b.well](https://www.icanbwell.com/) | [Jacob Rosales](https://github.com/jrosales) | Foundation for our engineering portal and cloud insights. | | [PagerDuty](https://www.pagerduty.com/) | [Mark Shaw](https://github.com/markshawtoronto) | Developer portal, initially focused on software templates and tech-docs. | -| [MoonShiner](https://moonshiner.at) | [Fabian Hippmann](https://github.com/FabianHippmann) | Developer portal - helps us keep track of our customer projects, onboard new developers & improve our development process 🌕🚀🧑‍🚀 | +| [MoonShiner](https://moonshiner.at) | [Fabian Hippmann](https://github.com/FabianHippmann) | Developer portal - helps us keep track of our customer projects, onboard new developers & improve our development process 🌕🚀🧑‍🚀 | | [FundApps](https://www.fundapps.co/) | [Elliot Greenwood](https://github.com/egnwd) | Developer Portal - A place for us to keep track of our projects and documentation for all services and processes | -| [DAZN](https://dazn.com/) | [Lou Bichard](https://twitter.com/loujaybee), [Marco Crivellaro](https://github.com/crivetechie), [Alex Hollerith](mailto:alex.hollerith@dazn.com) | Ingesting all of DAZN's repos for the catalog, migrating our internal platform apps (pull request boards, release information, inner source marketplace etc) to Backstage plugins (where applicable). | +| [DAZN](https://dazn.com/) | [David Rubio Vidal](https://github.com/davidrv87), [Marco Crivellaro](https://github.com/crivetechie), [Alex Hollerith](mailto:alex.hollerith@dazn.com), [Kamil Wolny](https://github.com/mrwolny) | Ingesting all of DAZN's repos for the catalog, migrating our internal platform apps (pull request boards, release information, inner source marketplace etc) to Backstage plugins (where applicable). | | [HelloFresh](https://www.hellofresh.de/) | [@iammuho](https://github.com/iammuho), [@ElenaForester](https://github.com/ElenaForester), [@diegomarangoni](https://github.com/diegomarangoni) | Our developer portal at HelloFresh - Spread across an organisation of 500+ engineers globally. | | [FactSet](https://www.factset.com/) | [@kuangp](https://github.com/kuangp) | Developer portal to provide discoverability to all internal components, APIs, documentation, and scaffold templates with integrations to our internal infrastructure tools. | | [Workrise](https://www.workrise.com/) | [Michael Rode](https://github.com/michaelrode) | Developer portal, main gateway to our infrastructure, documentation and internal tooling. | @@ -161,10 +163,9 @@ _If you're using Backstage in your organization, please try to add your company | [OVHcloud](https://www.ovhcloud.com/fr/) | [Jean-Philippe Blary](https://github.com/blaryjp), [Arnaud Bauer](mailto:arnaud.bauer@ovhcloud.com), [Flavien Chantelot](https://github.com/Dorn-) | We're providing Backstage to our collaborators to ease their daily jobs, and let them extends it using plugins. | | [Procter & Gamble](https://us.pg.com/) | [Binita Nayak](https://github.com/binitan), [Josh Rose](https://github.com/joshuarose), [RJ Winkler](https://github.com/rjwink) | P&G leverages Backstage to build internal developer portal to ensure developers' happiness. This developer portal shall act as single source of information needed by development teams to seamlessly create, find and maintain their software components/resources/documentation. | | [SANS Institute](https://www.sans.org) | [Christopher Klewin](mailto:cklewin@sans.org) | Developer portal for centralized visibility, reporting, and tooling across multiple organizations. | -| [Okay](https://www.okayhq.com/) | [Tomas Barreto](mailto:tomas@okayhq.com) +| [Okay](https://www.okayhq.com/) | [Tomas Barreto](mailto:tomas@okayhq.com) | Service catalog, developer portal, and technical documentation | | [Kaluza](https://www.kaluza.com) | [James Condren](mailto:james.condron@kaluza.com) | To provide an automated golden path to developers, with a focus on discovery and documentation | | [LinkedIn](https://linkedin.com) | [Joshua Lawrence](mailto:jlawrence@linkedin.com) | We are building a platform for internal web tools | -| [SANS Institute](https://www.sans.org) | [Justin Selleck](mailto:jselleck@sans.org) | SANS uses backstage to track components in github and to facilitate docs near code. | | [Forto](https://forto.com) | [Rodolfo Matos](mailto:rodolfo.matos@forto.com) | Still in a experimental phase/assessing the organisational fit. We will be using it mostly a developer portal -- pretty standard use case. | | [BetterUp](https://betterup.com) | [Jordan Hochenbaum](mailto:jordan.hochenbaum@betterup.co) | We're starting to use Backstage as the central hub for service discovery, documentation, and develop experience. | | [warung pintar](https://warungpintar.co.id/) | [Muhammad Rafly Andrianza](mailto:rafly.andrianza@warungpintar.co) | Initial Work Developer Portal with TechRadar, Service Catalogue, TechDocs, anything about platform & infrastructure resources. | @@ -172,11 +173,20 @@ _If you're using Backstage in your organization, please try to add your company | [AEB](https://www.aeb.com/) | [David Fankhänel](mailto:dfl@aeb.com) | Central developer platform for creating new apps via templates, getting an overview via software catalog, etc | | [SALTO Systems](https://saltosystems.com) | [Ian Cowley](mailto:i.cowley@saltosystems.com) | Currently using Backstage as an internal documentation portal. | | [Lummo](https://lummo.com) | [Anjul Sahu](mailto:anjul@lummo.com) | We are building the internal developer portal using Backstage and bringing up all integrations and service information at one place. | -| [Frontside](https://frontside.com) | [Taras Mankovski](mailto:taras@frontside.com) | +| [Frontside](https://frontside.com) | [Taras Mankovski](mailto:taras@frontside.com) | | | [Stepstone](https://www.stepstone.com/en/) | [Neil Kennedy](mailto:neil.kennedy@stepstone.com) | StepStone is using Backstage to solve problems around ownership and visibility of our applications. We have thousands of repos, multiple legacy systems and a growing platform that is hard to maintain. Backstage is forming the centre of our push to embrace the chaos. | | [idwall](https://idwall.co) | [Rodrigo Catão Araujo](mailto:rodrigo@idwall.co) | Developer Portal for internal engineers to access service catalog, documentation, observability, infrastructure and internal tooling. | | [Jaguar Land Rover](https://www.jaguarlandrover.com) | [Josh Walker](mailto:jwalke18@jaguarlandrover.com) | Users can request a Gitlab user, which creates a commit with the Terraform code. | -| [GlovoApp](http://glovoapp.com/) | [Chris Biancucci](mailto:christian.biancucci@glovoapp.com) | We have recently adopted Backstage and we are using it to improve our Developer Experience: simplifying, automating, and keeping things in order for every existing and new service developed. | -| [Dixa](https://dixa.com) | [Jens Møller](mailto:jsc@dixa.com) | We are in early stages, but using it to get overview of our repositories and ownership of these. We want among many things to use it for compliance and easier access to key metrics for our repos. | +| [Glovo](http://glovoapp.com/) | [Yaser Toutah](mailto:yaser.toutah@glovoapp.com) | Developer Portal to improve our Developer Experience, identify ownership and track metadata for our services and tools. It's our Service Catalog. In addition to that, we use it for Service Creation, and much more. | +| [Dixa](https://dixa.com) | [Jens Møller](https://github.com/jensamoller) | We are in early stages, but using it to get overview of our repositories and ownership of these. We want among many things to use it for compliance and easier access to key metrics for our repos. | | [Notino](https://notino.com) | [Jan Remunda](mailto:jan.remunda@notino.com) | Backstage is our developer portal. We use it as service catalog and for technical documentation. | +| [Polarpoint](https://polarpoint.io/) | [Surj Bains](https://github.com/polarpoint-io) | We are using Backstage as our Developer portal as well as for hosting our DevOps portal for software catalog. | | [Niche](https://niche.com) | [Zach Romitz](mailto:zach.romitz@niche.com) | We are using the Software Catalog, Software Templates, API documentation, and Techdocs to try and centralize service information. | +| [Mercedes-Benz.io](https://www.mercedes-benz.io/) | [Manuel Santos](https://github.com/manusant) | At Mercedes-Benz we use it as a developer portal with software catalog, TechDocs, Scaffolding and custom plugins. It provides an overview of our tech ecosystem to our product development teams. The portal also serves as a way to foster collaboration among the numerous companies of the Mercedes-Benz Group. | +| [Funding Circle](https://www.fundingcircle.com/) | [Ariel Pacciaroni](https://github.com/arielpacciaroni) | We are building the internal developer portal using Backstage project and centralizing all services information at one place. The portal helps us track down repositories ownership as well as direct access to key information on every component. | +| [Clarivate](https://www.clarivate.com) | [Gabriele Carteni](mailto:gabriele.carteni@clarivate.com) | We are building our Developer Portal using Backstage to have a better control over our software ecosystem, integrate SDLC tools and promote best practices | +| [Cho Tot](https://www.chotot.com) | [Chotot Team](mailto:sre@chotot.vn) | Internal developer portal, service catalog with CI/CD tools. | +| [William Hill](https://www.williamhillgroup.com/) | [Pat Mills](mailto:pat.mills@williamhill.com), [Nathan Flynn](mailto:nflynn@williamhill.co.uk), and [Nishkarsh Raj](mailto:nishkarsh.raj@williamhill.co.uk) | William Hill are leveraging Backstage to build our Engineering Portal. Our mission is to centralize the software catalog inventory to enable service discoverability, reduce the onboarding time for new Engineers, provide a single pane of glass to accelerate Developer Productivity and Save Engineers time. Our aspiration is to create an InnerSource community focussed on organization-wide patterns that are re-usable and can be self-served with the Scaffolder. | +| [Vodafone NewZealand Limited](https://vodafone.co.nz) | [Ankit Gupta](mailto:ankit.gupta@vodafone.nz), [DevOps COE](mailto:devopstooling@vodafone.nz) | Vodafone NZ are leveraging Backstage to build centralised and self service Engineering Portal. Our mission is to standardised Pipeline templates across the Engineering teams, One shop stop to create the pipelines and repository with a template approach which reduces creation part from days to minutes and no wait time for developers. A unified view for Azure DevOps pipeline, Azure Repo pull requests, Deployment status from Azure RedHat Openshift-ArgoCD and SonarQube Security and code quality scans report on a single pan to provide a streamlined view for all microservices across the app stack. | +| [Coamo](http://www.coamo.com.br) | [@holiiveira](https://github.com/holiiveira), [@gpxlnx](https://github.com/gpxlnx) | We're starting to use it as the main tool of a DevOps platform. Our goal is to provide software templates, centralize our software catalog enabling efficient service discovery, and make it easy to manage the entire software ecosystem in one place. + | diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index eb60bc48e0..1afbf072fc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -58,9 +58,9 @@ If you are proposing a feature: - Remember that this is a volunteer-driven project, and that contributions are welcome :) -### Add your company to ADOPTERS +### Add your company to `ADOPTERS` -Have you started using Backstage? Adding your company to [ADOPTERS](ADOPTERS.md) really helps the project. +Have you started using Backstage? Adding your company to [ADOPTERS](ADOPTERS.md) really helps the project, you can do this by filling out this [Adopter form](https://form.typeform.com/to/zcOaKikB). ## Get Started! diff --git a/README.md b/README.md index 5dba1fdf52..a6e740a427 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ ![headline](docs/assets/headline.png) +> 🏖 From July 7th due to Summer Vacations for some of the maintainers, expect the project to move a little slower than normal, and support to be limited. Normal service will resume on August 8th 🏝 + # [Backstage](https://backstage.io) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) diff --git a/app-config.yaml b/app-config.yaml index 5919deb1ee..9a3206026e 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -171,26 +171,26 @@ integrations: github: - host: github.com token: ${GITHUB_TOKEN} - ### Example for how to add your GitHub Enterprise instance using the API: - # - host: ghe.example.net - # apiBaseUrl: https://ghe.example.net/api/v3 - # token: ${GHE_TOKEN} - ### Example for how to add your GitHub Enterprise instance using raw HTTP fetches (token is optional): - # - host: ghe.example.net - # rawBaseUrl: https://ghe.example.net/raw - # token: ${GHE_TOKEN} + ### Example for how to add your GitHub Enterprise instance using the API: + # - host: ghe.example.net + # apiBaseUrl: https://ghe.example.net/api/v3 + # token: ${GHE_TOKEN} + ### Example for how to add your GitHub Enterprise instance using raw HTTP fetches (token is optional): + # - host: ghe.example.net + # rawBaseUrl: https://ghe.example.net/raw + # token: ${GHE_TOKEN} gitlab: - host: gitlab.com token: ${GITLAB_TOKEN} - bitbucket: - - host: bitbucket.org - username: ${BITBUCKET_USERNAME} - appPassword: ${BITBUCKET_APP_PASSWORD} - ### Example for how to add your bitbucket server instance using the API: - # - host: server.bitbucket.com - # apiBaseUrl: server.bitbucket.com - # username: ${BITBUCKET_SERVER_USERNAME} - # appPassword: ${BITBUCKET_SERVER_APP_PASSWORD} + ### Example for how to add a bitbucket cloud integration + # bitbucketCloud: + # - username: ${BITBUCKET_USERNAME} + # appPassword: ${BITBUCKET_APP_PASSWORD} + ### Example for how to add your bitbucket server instance using the API: + # - host: server.bitbucket.com + # apiBaseUrl: server.bitbucket.com + # username: ${BITBUCKET_SERVER_USERNAME} + # appPassword: ${BITBUCKET_SERVER_APP_PASSWORD} azure: - host: dev.azure.com token: ${AZURE_TOKEN} @@ -234,16 +234,6 @@ catalog: # dn: ou=access,ou=groups,ou=example,dc=example,dc=net # options: # filter: (&(objectClass=some-group-class)(!(groupType=email))) - microsoftGraphOrg: - ### Example for how to add your Microsoft Graph tenant - #providers: - # - target: https://graph.microsoft.com/v1.0 - # authority: https://login.microsoftonline.com - # tenantId: ${MICROSOFT_GRAPH_TENANT_ID} - # clientId: ${MICROSOFT_GRAPH_CLIENT_ID} - # clientSecret: ${MICROSOFT_GRAPH_CLIENT_SECRET_TOKEN} - # userFilter: accountEnabled eq true and userType eq 'member' - # groupFilter: securityEnabled eq false and mailEnabled eq true and groupTypes/any(c:c+eq+'Unified') locations: # Add a location here to ingest it, for example from a URL: diff --git a/contrib/docs/tutorials/aws-alb-aad-oidc-auth.md b/contrib/docs/tutorials/aws-alb-aad-oidc-auth.md index 2b3e02c18b..3cedf5634b 100644 --- a/contrib/docs/tutorials/aws-alb-aad-oidc-auth.md +++ b/contrib/docs/tutorials/aws-alb-aad-oidc-auth.md @@ -122,10 +122,7 @@ When using ALB auth you can configure it as described [here](https://backstage.i - replace the content of `packages/backend/plugin/auth.ts` with the below and tweak it according to your needs. ```ts -import { - createRouter, - createAwsAlbProvider, -} from '@backstage/plugin-auth-backend'; +import { createRouter, providers } from '@backstage/plugin-auth-backend'; import { DEFAULT_NAMESPACE, stringifyEntityRef, @@ -145,7 +142,7 @@ export default async function createPlugin({ database, discovery, providerFactories: { - awsalb: createAwsAlbProvider({ + awsalb: providers.awsAlb.create({ authHandler: async ({ fullProfile }) => { let email: string | undefined = undefined; if (fullProfile.emails && fullProfile.emails.length > 0) { diff --git a/contrib/docs/tutorials/prometheus-metrics-output.png b/contrib/docs/tutorials/prometheus-metrics-output.png new file mode 100644 index 0000000000..f7fac739ac Binary files /dev/null and b/contrib/docs/tutorials/prometheus-metrics-output.png differ diff --git a/contrib/docs/tutorials/prometheus-metrics.md b/contrib/docs/tutorials/prometheus-metrics.md new file mode 100644 index 0000000000..5b7dc61df3 --- /dev/null +++ b/contrib/docs/tutorials/prometheus-metrics.md @@ -0,0 +1,108 @@ +# Prometheus + +## Overview + +This is a small tutorial that goes over how to setup your Backstage instance to output metrics in a format that can be pulled in by Prometheus. + +## How to Setup Prometheus Metrics + +1. First we need to add the needed dependencies to the `package.json` in the `\packages\backend`: + + ```diff + // packages/backend/package.json + "dependencies": { + + "express-prom-bundle": "^6.3.6", + + "prom-client": "^14.0.1", + ``` + +2. Now we want to run `yarn install` from the root of the project to get those dependencies in place +3. Then we need to add a handler for the metrics by creating a file called `metrics.ts` in the `\packages\backend\src` folder +4. Next we add the following content to the `metrics.ts` file: + + ```ts + // packages/backend/src/metrics.ts + import { useHotCleanup } from '@backstage/backend-common'; + import { RequestHandler } from 'express'; + import promBundle from 'express-prom-bundle'; + import prom from 'prom-client'; + import * as url from 'url'; + + const rootRegEx = new RegExp('^/([^/]*)/.*'); + const apiRegEx = new RegExp('^/api/([^/]*)/.*'); + + export function normalizePath(req: any): string { + const path = url.parse(req.originalUrl || req.url).pathname || '/'; + + // Capture /api/ and the plugin name + if (apiRegEx.test(path)) { + return path.replace(apiRegEx, '/api/$1'); + } + + // Only the first path segment at root level + return path.replace(rootRegEx, '/$1'); + } + + /** + * Adds a /metrics endpoint, register default runtime metrics and instrument the router. + */ + export function metricsHandler(): RequestHandler { + // We can only initialize the metrics once and have to clean them up between hot reloads + useHotCleanup(module, () => prom.register.clear()); + + return promBundle({ + includeMethod: true, + includePath: true, + // Using includePath alone is problematic, as it will include path labels with high + // cardinality (e.g. path params). Instead we would have to template them. However, this + // is difficult, as every backend plugin might use different routes. Instead we only take + // the first directory of the path, to have at least an idea how each plugin performs: + normalizePath, + promClient: { collectDefaultMetrics: {} }, + }); + } + ``` + +5. Now we will extend the router configuration with the `metricsHandler`: + + ```diff + +import { metricsHandler } from './metrics'; + + ... + + const service = createServiceBuilder(module) + .loadConfig(config) + .addRouter('', await healthcheck(healthcheckEnv)) + + .addRouter('', metricsHandler()) + .addRouter('/api', apiRouter); + ``` + +6. You now have everything setup, from the `\packages\backend` folder run `yarn start` this will start up the backend +7. Now in a browser load up `http://localhost:7007/metrics`, if everything went smoothly you should see metrics in your browser something like this: + + ![Prometheus Metrics Example Output](prometheus-metrics-output.png) + +## Metrics + +The following sections goes over the included and experimental metrics available once you have completed this tutorial + +## Included + +This tutorials uses the [`express-prom-bundle`](https://github.com/jochen-schweizer/express-prom-bundle) and the [`prom-client`](https://github.com/siimon/prom-client) to make this all work. They both come with some built in metrics: + +- `express-prom-bundle` comes with 2 metrics: + - `up`: this normally will be just 1 + - `http_request_duration_seconds`: http latency histogram/summary labeled with `status_code`, `method` and `path` +- `prom-client` comes with a collection of metrics around memory, CPU, processes, etc. You can see the supported metrics in the `prom-client's` [`lib/metrics`](https://github.com/siimon/prom-client/tree/master/lib/metrics) folder. + +### Experimental + +There are some custom metrics that have been added to Backstage will be output for you, these are currently deemed experimental and may be changed or removed in a future release. Here is a rough list, again subject to changes: + +- `catalog_entities_count`: Total amount of entities in the catalog +- `catalog_registered_locations_count`: Total amount of registered locations in the catalog +- `catalog_relations_count`: Total amount of relations between entities +- `catalog_stitched_entities_count`: Amount of entities stitched +- `catalog_processed_entities_count`: Amount of entities processed +- `catalog_processing_duration_seconds`: Time spent executing the full processing flow +- `catalog_processors_duration_seconds`: Time spent executing catalog processors +- `catalog_processing_queue_delay_seconds`: The amount of delay between being scheduled for processing, and the start of actually being processed diff --git a/cypress/yarn.lock b/cypress/yarn.lock index 53f61fd113..991d2d8562 100644 --- a/cypress/yarn.lock +++ b/cypress/yarn.lock @@ -40,14 +40,14 @@ lodash.once "^4.1.1" "@types/node@*": - version "17.0.40" - resolved "https://registry.npmjs.org/@types/node/-/node-17.0.40.tgz#76ee88ae03650de8064a6cf75b8d95f9f4a16090" - integrity sha512-UXdBxNGqTMtm7hCwh9HtncFVLrXoqA3oJW30j6XWp5BH/wu3mVeaxo7cq5benFdBw34HB3XDT2TRPI7rXZ+mDg== + version "18.0.0" + resolved "https://registry.npmjs.org/@types/node/-/node-18.0.0.tgz#67c7b724e1bcdd7a8821ce0d5ee184d3b4dd525a" + integrity sha512-cHlGmko4gWLVI27cGJntjs/Sj8th9aYwplmZFwmmgYQQvL5NUsgVJG7OddLvNfLqYS31KFN0s3qlaD9qCaxACA== "@types/node@^14.14.31": - version "14.18.20" - resolved "https://registry.npmjs.org/@types/node/-/node-14.18.20.tgz#268f028b36eaf51181c3300252f605488c4f0650" - integrity sha512-Q8KKwm9YqEmUBRsqJ2GWJDtXltBDxTdC4m5vTdXBolu2PeQh8LX+f6BTwU+OuXPu37fLxoN6gidqBmnky36FXA== + version "14.18.21" + resolved "https://registry.npmjs.org/@types/node/-/node-14.18.21.tgz#0155ee46f6be28b2ff0342ca1a9b9fd4468bef41" + integrity sha512-x5W9s+8P4XteaxT/jKF0PSb7XEvo5VmqEWgsMlyeY4ZlLK8I6aH6g5TPPyDlLAep+GYf4kefb7HFyc7PAO3m+Q== "@types/sinonjs__fake-timers@8.1.1": version "8.1.1" @@ -121,9 +121,9 @@ astral-regex@^2.0.0: integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== async@^3.2.0: - version "3.2.3" - resolved "https://registry.npmjs.org/async/-/async-3.2.3.tgz#ac53dafd3f4720ee9e8a160628f18ea91df196c9" - integrity sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g== + version "3.2.4" + resolved "https://registry.npmjs.org/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c" + integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ== asynckit@^0.4.0: version "0.4.0" @@ -217,9 +217,9 @@ check-more-types@^2.24.0: integrity sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA== ci-info@^3.2.0: - version "3.3.1" - resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.3.1.tgz#58331f6f472a25fe3a50a351ae3052936c2c7f32" - integrity sha512-SXgeMX9VwDe7iFFaEWkA5AstuER9YKqy4EhHqr4DVqkwmD9rpVimkMKWHdjn30Ja45txyjhSn63lVX69eVCckg== + version "3.3.2" + resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.3.2.tgz#6d2967ffa407466481c6c90b6e16b3098f080128" + integrity sha512-xmDt/QIAdeZ9+nfdPsaBCpMvHNLFiLdjj59qjqn+6iPe6YmHGQ35sBnQ8uslRBXFmXkiZQOJRjvQeoGppoTjjg== clean-stack@^2.0.0: version "2.2.0" @@ -263,9 +263,9 @@ color-name@~1.1.4: integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== colorette@^2.0.16: - version "2.0.17" - resolved "https://registry.npmjs.org/colorette/-/colorette-2.0.17.tgz#5dd4c0d15e2984b7433cb4a9f2ead45063b80c47" - integrity sha512-hJo+3Bkn0NCHybn9Tu35fIeoOKGOk5OCC32y4Hz2It+qlCO2Q3DeQ1hRn/tDDMQKRYUEzqsl7jbF6dYKjlE60g== + version "2.0.19" + resolved "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798" + integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ== combined-stream@^1.0.6, combined-stream@~1.0.6: version "1.0.8" @@ -304,9 +304,9 @@ cross-spawn@^7.0.0: which "^2.0.1" cypress@^10.0.0: - version "10.0.3" - resolved "https://registry.npmjs.org/cypress/-/cypress-10.0.3.tgz#889b4bef863b7d1ef1b608b85b964394ad350c5f" - integrity sha512-8C82XTybsEmJC9POYSNITGUhMLCRwB9LadP0x33H+52QVoBjhsWvIzrI+ybCe0+TyxaF0D5/9IL2kSTgjqCB9A== + version "10.3.0" + resolved "https://registry.npmjs.org/cypress/-/cypress-10.3.0.tgz#fae8d32f0822fcfb938e79c7c31ef344794336ae" + integrity sha512-txkQWKzvBVnWdCuKs5Xc08gjpO89W2Dom2wpZgT9zWZT5jXxqPIxqP/NC1YArtkpmp3fN5HW8aDjYBizHLUFvg== dependencies: "@cypress/request" "^2.88.10" "@cypress/xvfb" "^1.2.4" @@ -878,7 +878,7 @@ qs@~6.5.2: request-progress@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz#4ca754081c7fec63f505e4faa825aa06cd669dbe" - integrity sha1-TKdUCBx/7GP1BeT6qCWqBs1mnb4= + integrity sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg== dependencies: throttleit "^1.0.0" @@ -1014,12 +1014,12 @@ supports-color@^8.1.1: throttleit@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c" - integrity sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw= + integrity sha512-rkTVqu6IjfQ/6+uNuuc3sZek4CEYxTJom3IktzgdSxcZqdARuebbA/f4QmAxMQIxqq9ZLEUkSYqvuk1I6VKq4g== through@^2.3.8: version "2.3.8" resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== tmp@~0.2.1: version "0.2.1" @@ -1044,14 +1044,14 @@ tslib@^2.1.0: tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= + integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w== dependencies: safe-buffer "^5.0.1" tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" resolved "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= + integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA== type-fest@^0.21.3: version "0.21.3" @@ -1059,9 +1059,9 @@ type-fest@^0.21.3: integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== typescript@^4.1.3: - version "4.7.3" - resolved "https://registry.npmjs.org/typescript/-/typescript-4.7.3.tgz#8364b502d5257b540f9de4c40be84c98e23a129d" - integrity sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA== + version "4.7.4" + resolved "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235" + integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ== universalify@^2.0.0: version "2.0.0" @@ -1081,7 +1081,7 @@ uuid@^8.3.2: verror@1.10.0: version "1.10.0" resolved "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= + integrity sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw== dependencies: assert-plus "^1.0.0" core-util-is "1.0.2" @@ -1115,7 +1115,7 @@ wrap-ansi@^7.0.0: wrappy@1: version "1.0.2" resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== yallist@^4.0.0: version "4.0.0" @@ -1125,7 +1125,7 @@ yallist@^4.0.0: yauzl@^2.10.0: version "2.10.0" resolved "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" - integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk= + integrity sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g== dependencies: buffer-crc32 "~0.2.3" fd-slicer "~1.1.0" diff --git a/docs/FAQ.md b/docs/FAQ.md index 96d49ff060..f695a59410 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -223,8 +223,7 @@ For more information, see our No, this is not a service offering. We build the piece of software, and someone in your infrastructure team is responsible for -[deploying](https://backstage.io/docs/getting-started/deployment-k8s) and -maintaining it. +[deploying](https://backstage.io/docs/deployment) and maintaining it. ### How secure is Backstage? diff --git a/docs/auth/add-auth-provider.md b/docs/auth/add-auth-provider.md index eb8973bec1..01c18f04cd 100644 --- a/docs/auth/add-auth-provider.md +++ b/docs/auth/add-auth-provider.md @@ -350,6 +350,7 @@ router.get('/auth/providerA/handler/frame'); router.post('/auth/providerA/handler/frame'); router.post('/auth/providerA/logout'); router.get('/auth/providerA/refresh'); // if supported +router.post('/auth/providerA/refresh'); // if supported ``` As you can see each endpoint is prefixed with both `/auth` and its provider diff --git a/docs/auth/bitbucket/provider.md b/docs/auth/bitbucket/provider.md index c54fb75ffa..36859dab45 100644 --- a/docs/auth/bitbucket/provider.md +++ b/docs/auth/bitbucket/provider.md @@ -57,7 +57,7 @@ In order to use the Bitbucket provider for sign-in, you must configure it with a `signIn.resolver`. See the [Sign-In Resolver documentation](../identity-resolver.md) for more details on how this is done. Note that for the Bitbucket provider, you'll want to use -`bitbucket` as the provider ID, and `createBitbucketProvider` for the provider +`bitbucket` as the provider ID, and `providers.bitbucket.create` for the provider factory. The `@backstage/plugin-auth-backend` plugin also comes with two built-in @@ -74,16 +74,14 @@ same way, but uses the Bitbucket user ID instead, and matches on the The following is an example of how to use one of the built-in resolvers: ```ts -import { - createBitbucketProvider, - bitbucketUsernameSignInResolver, -} from '@backstage/plugin-auth-backend'; +import { providers } from '@backstage/plugin-auth-backend'; // ... providerFactories: { - bitbucket: createBitbucketProvider({ + bitbucket: providers.bitbucket.create({ signIn: { - resolver: bitbucketUsernameSignInResolver, + resolver: + providers.bitbucket.resolvers.usernameMatchingUserEntityAnnotation(), }, }), }, diff --git a/docs/auth/identity-resolver.md b/docs/auth/identity-resolver.md index b314954105..06ada040e4 100644 --- a/docs/auth/identity-resolver.md +++ b/docs/auth/identity-resolver.md @@ -110,6 +110,7 @@ Now let's look at the example, with the rest of the commentary being made with i the code comments: ```ts +// File: packages/backend/src/plugins/auth.ts import { createRouter, providers, @@ -170,11 +171,21 @@ property of each of the auth provider integrations. For example, the Google prov a built in resolver that works just like the one we defined above: ```ts -providers.google.create({ - signIn: { - resolver: providers.google.resolvers.emailLocalPartMatchingUserEntityName(), - }, -}); +// File: packages/backend/src/plugins/auth.ts +export default async function createPlugin( + // ... + return await createRouter({ + // ... + providerFactories: { + // ... + google: providers.google.create({ + signIn: { + resolver: providers.google.resolvers.emailLocalPartMatchingUserEntityName(), + }, + }); + } + }) +) ``` There are also other options, like the this one that looks up a user @@ -195,40 +206,49 @@ that happens during sign-in you can replace `ctx.signInWithCatalogUser` with a s of lower-level calls: ```ts +// File: packages/backend/src/plugins/auth.ts import { getDefaultOwnershipRefs } from '@backstage/plugin-auth-backend'; -// This example only shows the resolver function itself. -async ({ profile: { email } }, ctx) => { - if (!email) { - throw new Error('User profile contained no email'); - } +export default async function createPlugin( + // ... + return await createRouter({ + // ... + providerFactories: { + // ... + google: async ({ profile: { email } }, ctx) => { + if (!email) { + throw new Error('User profile contained no email'); + } - // This step calls the catalog to look up a user entity. You could for example - // replace it with a call to a different external system. - const { entity } = await ctx.findCatalogUser({ - annotations: { - 'acme.org/email': email, - }, - }); + // This step calls the catalog to look up a user entity. You could for example + // replace it with a call to a different external system. + const { entity } = await ctx.findCatalogUser({ + annotations: { + 'acme.org/email': email, + }, + }); - // In this step we extract the ownership references from the user entity using - // the standard logic. It uses a reference to the entity itself, as well as the - // target of each `memberOf` relation where the target is of the kind `Group`. - // - // If you replace the catalog lookup with something does not return - // an entity you will need to replace this step as well. - // - // You might also replace it if you for example want to filter out certain groups. - const ownershipRefs = getDefaultOwnershipRefs(entity); + // In this step we extract the ownership references from the user entity using + // the standard logic. It uses a reference to the entity itself, as well as the + // target of each `memberOf` relation where the target is of the kind `Group`. + // + // If you replace the catalog lookup with something that does not return + // an entity you will need to replace this step as well. + // + // You might also replace it if you for example want to filter out certain groups. + const ownershipRefs = getDefaultOwnershipRefs(entity); - // The last step is to issue the token, where we might provide more options in the future. - return ctx.issueToken({ - claims: { - sub: stringifyEntityRef(entity), - ent: ownershipRefs, - }, - }); -}; + // The last step is to issue the token, where we might provide more options in the future. + return ctx.issueToken({ + claims: { + sub: stringifyEntityRef(entity), + ent: ownershipRefs, + }, + }); + }; + } + }) +) ``` ## Sign-In without Users in the Catalog @@ -252,38 +272,47 @@ check like in the example below, or you might for example look up the GitHub org that the user belongs to using the user access token in the provided result object. ```ts +// File: packages/backend/src/plugins/auth.ts import { DEFAULT_NAMESPACE, stringifyEntityRef, } from '@backstage/catalog-model'; -// This example only shows the resolver function itself. -async ({ profile }, ctx) => { - if (!profile.email) { - throw new Error( - 'Login failed, user profile does not contain an email', - ); - } - // Split the email into the local part and the domain. - const [localPart, domain] = profile.email.split('@'); +export default async function createPlugin( + // ... + return await createRouter({ + // ... + providerFactories: { + // ... + google: async ({ profile }, ctx) => { + if (!profile.email) { + throw new Error( + 'Login failed, user profile does not contain an email', + ); + } + // Split the email into the local part and the domain. + const [localPart, domain] = profile.email.split('@'); - // Next we verify the email domain. It is recommended to include this - // kind of check if you don't look up the user in an external service. - if (domain !== 'acme.org') { - throw new Error('Login failed, user email domain check failed'); - } + // Next we verify the email domain. It is recommended to include this + // kind of check if you don't look up the user in an external service. + if (domain !== 'acme.org') { + throw new Error('Login failed, user email domain check failed'); + } - // By using `stringifyEntityRef` we ensure that the reference is formatted correctly - const userEntityRef = stringifyEntityRef({ - kind: 'User', - name: localPart, - namespace: DEFAULT_NAMESPACE, - }); + // By using `stringifyEntityRef` we ensure that the reference is formatted correctly + const userEntityRef = stringifyEntityRef({ + kind: 'User', + name: localPart, + namespace: DEFAULT_NAMESPACE, + }); - return ctx.issueToken({ - claims: { - sub: userEntityRef, - ent: [userEntityRef], - }, - }); -}, + return ctx.issueToken({ + claims: { + sub: userEntityRef, + ent: [userEntityRef], + }, + }); + }, + } + }) +) ``` ## AuthHandler @@ -304,7 +333,7 @@ export default async function createPlugin( return await createRouter({ ... providerFactories: { - google: createGoogleProvider({ + google: providers.google.create({ authHandler: async ({ fullProfile // Type: passport.Profile, idToken // Type: (Optional) string, diff --git a/docs/auth/index.md b/docs/auth/index.md index c34d244886..e713e722ef 100644 --- a/docs/auth/index.md +++ b/docs/auth/index.md @@ -185,6 +185,24 @@ const app = createApp({ When using multiple auth providers like this, it's important that you configure the different sign-in resolvers so that they resolve to the same identity regardless of the method used. +## Scaffolder Configuration (Software Templates) + +If you want to use the authentication capabilities of the [Repository Picker](../features/software-templates/writing-templates.md#the-repository-picker) inside your software templates you will need to configure the [`ScmAuthApi`](https://backstage.io/docs/reference/integration-react.scmauthapi) alongside your authentication provider. It is an API used to authenticate towards different SCM systems in a generic way, based on what resource is being accessed. + +To set it up, you'll need to add an API factory entry to `packages/app/src/apis.ts`. The example below sets up the `ScmAuthApi` for an already configured GitLab authentication provider: + +```ts +createApiFactory({ + api: scmAuthApiRef, + deps: { + gitlabAuthApi: gitlabAuthApiRef, + }, + factory: ({ gitlabAuthApi }) => ScmAuth.forGitlab(gitlabAuthApi), +}); +``` + +In case you are using a custom authentication providers, you might need to add a [custom `ScmAuthApi` implementation](./index.md#custom-scmauthapi-implementation). + ## For Plugin Developers The Backstage frontend core APIs provide a set of Utility APIs for plugin developers diff --git a/docs/features/search/search-engines.md b/docs/features/search/search-engines.md index 9bb8b8c343..ecd8a85109 100644 --- a/docs/features/search/search-engines.md +++ b/docs/features/search/search-engines.md @@ -59,10 +59,38 @@ configured and make the following changes to your backend: // Initialize a connection to a search engine. const searchEngine = (await PgSearchEngine.supported(env.database)) - ? await PgSearchEngine.from({ database: env.database }) + ? await PgSearchEngine.fromConfig(env.config, { database: env.database }) : new LunrSearchEngine({ logger: env.logger }); ``` +## Optional Configuration + +The following is an example of the optional configuration that can be applied when using Postgres as the search backend. Currently this is mostly for just the highlight feature: + +```yaml +search: + pg: + highlightOptions: + useHighlight: true # Used to enable to disable the highlight feature. The default value is true + maxWord: 35 # Used to set the longest headlines to output. The default value is 35. + minWord: 15 # Used to set the shortest headlines to output. The default value is 15. + shortWord: 3 # Words of this length or less will be dropped at the start and end of a headline, unless they are query terms. The default value of three (3) eliminates common English articles. + highlightAll: false # If true the whole document will be used as the headline, ignoring the preceding three parameters. The default is false. + maxFragments: 0 # Maximum number of text fragments to display. The default value of zero selects a non-fragment-based headline generation method. A value greater than zero selects fragment-based headline generation (see the linked documentation above for more details). + fragmentDelimiter: ' ... ' # Delimiter string used to concatenate fragments. Defaults to " ... ". +``` + +**Note:** the highlight search term feature uses `ts_headline` which has been known to potentially impact performance. You only need this minimal config to disable it should you have issues: + +```yaml +search: + pg: + highlightOptions: + useHighlight: false +``` + +The Postgres documentation on [Highlighting Results](https://www.postgresql.org/docs/current/textsearch-controls.html#TEXTSEARCH-HEADLINE) has more details. + ## ElasticSearch Backstage supports ElasticSearch search engine connections, indexing and @@ -80,15 +108,16 @@ const searchEngine = await ElasticSearchSearchEngine.initialize({ const indexBuilder = new IndexBuilder({ logger: env.logger, searchEngine }); ``` -For the engine to be available, your backend package needs a dependency into +For the engine to be available, your backend package needs a dependency on package `@backstage/plugin-search-backend-module-elasticsearch`. ElasticSearch needs some additional configuration before it is ready to use within your instance. The configuration options are documented in the [configuration schema definition file.](https://github.com/backstage/backstage/blob/master/plugins/search-backend-module-elasticsearch/config.d.ts) -The underlying functionality is using official ElasticSearch client version 7.x, -meaning that ElasticSearch version 7 is the only one confirmed to be supported. +The underlying functionality uses either the official ElasticSearch client +version 7.x (meaning that ElasticSearch version 7 is the only one confirmed to +be supported), or the OpenSearch client, when the `aws` provider is configured. Should you need to create your own bespoke search experiences that require more than just a query translator (such as faceted search or Relay pagination), you @@ -97,9 +126,19 @@ search clients. The version of the client need not be the same as one used internally by the elastic search engine plugin. For example: ```typescript -import { Client } from '@elastic/elastic-search'; +import { isOpenSearchCompatible } from '@backstage/plugin-search-backend-module-elasticsearch'; +import { Client as ElasticClient } from '@elastic/elastic-search'; +import { Client as OpenSearchClient } from '@opensearch-project/opensearch'; -const client = searchEngine.newClient(options => new Client(options)); +const client = searchEngine.newClient(options => { + // In reality, you would only import / instantiate one of the following, but + // for illustrative purposes, here are both: + if (isOpenSearchCompatible(options)) { + return new OpenSearchClient(options); + } else { + return new ElasticClient(options); + } +}); ``` #### Set custom index template diff --git a/docs/features/software-catalog/configuration.md b/docs/features/software-catalog/configuration.md index 849823a59e..5abd266099 100644 --- a/docs/features/software-catalog/configuration.md +++ b/docs/features/software-catalog/configuration.md @@ -106,8 +106,7 @@ with [Static Location Configuration](#static-location-configuration) or a discovery processor like [GitHub Discovery](../../integrations/github/discovery.md). To enforce usage of processors to locate entities we can configure the catalog into `readonly` mode. -This configuration disables the mutating backend catalog APIs and disallows -users from registering new entities at run-time. +This configuration disables registering and deleting locations with the catalog APIs. ```yaml catalog: @@ -117,6 +116,8 @@ catalog: > **Note that any plugin relying on the catalog API for creating, updating and > deleting entities will not work in this mode.** +Deleting an entity by UUID, `DELETE /entities/by-uid/:uid`, is allowed when using this mode. It may be rediscovered as noted in [explicit deletion](life-of-an-entity.md#explicit-deletion). + A common use case for this configuration is when organizations have a remote source that should be mirrored into Backstage. To make Backstage a mirror of this remote source, users cannot also register new entities with e.g. the diff --git a/docs/features/software-catalog/descriptor-format.md b/docs/features/software-catalog/descriptor-format.md index 86c832e3d2..81e3604ffe 100644 --- a/docs/features/software-catalog/descriptor-format.md +++ b/docs/features/software-catalog/descriptor-format.md @@ -55,6 +55,7 @@ metadata: - url: https://admin.example-org.com title: Admin Dashboard icon: dashboard + type: admin-dashboard spec: type: website lifecycle: production @@ -83,7 +84,8 @@ This is the same entity as returned in JSON from the software catalog API: { "url": "https://admin.example-org.com", "title": "Admin Dashboard", - "icon": "dashboard" + "icon": "dashboard", + "type": "admin-dashboard" } ], "tags": ["java"], @@ -353,6 +355,7 @@ Fields of a link are: | `url` | String | [Required] A `url` in a standard `uri` format (e.g. `https://example.com/some/page`) | | `title` | String | [Optional] A user friendly display name for the link. | | `icon` | String | [Optional] A key representing a visual icon to be displayed in the UI. | +| `type` | String | [Optional] An optional value to categorize links into specific groups. | _NOTE_: The `icon` field value is meant to be a semantic key that will map to a specific icon that may be provided by an icon library (e.g. `material-ui` @@ -362,6 +365,8 @@ Backstage integrator will ultimately be left to provide the appropriate icon component mappings. A generic fallback icon would be provided if a mapping cannot be resolved. +The semantics of the `type` field are undefined. The adopter is free to define their own set of types and utilize them as they wish. Some potential use cases can be to utilize the type field to validate certain links exist on entities or to create customized UI components for specific link types. + ## Common to All Kinds: Relations The `relations` root field is a read-only list of relations, between the current diff --git a/docs/features/software-templates/adding-templates.md b/docs/features/software-templates/adding-templates.md index db765fc7ee..e8176a688b 100644 --- a/docs/features/software-templates/adding-templates.md +++ b/docs/features/software-templates/adding-templates.md @@ -86,6 +86,13 @@ contains more information about the required fields. Once we have a `template.yaml` ready, we can then add it to the software catalog for use by the scaffolder. +> Note: When you add or modify a template, you will need to refresh the location entity. +> Otherwise, Backstage won't display the template in the available templates, +> or it will keep showing the old template. You can refresh the location instance by +> going into `Catalog` web page, choosing `Locations` instead of `Components`, and selecting the correct location entity. +> From there, you can click on the refresh icon representing "Scheduled entity refresh" action. +> Afterwards, you should see your template updated. + You can add the template files to the catalog through [static location configuration](../software-catalog/configuration.md#static-location-configuration), for example: @@ -97,6 +104,8 @@ catalog: target: https://github.com/backstage/software-templates/blob/main/scaffolder-templates/react-ssr-template/template.yaml rules: - allow: [Template] + - type: file + target: template.yaml # Backstage will expect the file to be in packages/backend/template.yaml ``` Or you can add the template using the `catalog-import` plugin, which unless diff --git a/docs/features/software-templates/writing-custom-actions.md b/docs/features/software-templates/writing-custom-actions.md index 8e698e1a05..a9e1d297f3 100644 --- a/docs/features/software-templates/writing-custom-actions.md +++ b/docs/features/software-templates/writing-custom-actions.md @@ -9,8 +9,9 @@ by writing custom actions which can be used along side our [built-in actions](./builtin-actions.md). > Note: When adding custom actions, the actions array will **replace the -> built-in actions too**. To ensure you can continue to include the builtin -> actions, see below to include them during registration of your action. +> built-in actions too**. Meaning, you will no longer be able to use them. +> If you want to continue using the builtin actions, include them in the actions +> array when registering your custom actions, as seen below. ## Writing your Custom Action @@ -122,27 +123,32 @@ will set the available actions that the scaffolder has access to. ```ts import { createBuiltinActions } from '@backstage/plugin-scaffolder-backend'; import { ScmIntegrations } from '@backstage/integration'; +import { createNewFileAction } from './actions/custom'; -const integrations = ScmIntegrations.fromConfig(env.config); +export default async function createPlugin( + env: PluginEnvironment, +): Promise { + const catalogClient = new CatalogClient({ discoveryApi: env.discovery }); + const integrations = ScmIntegrations.fromConfig(env.config); -const builtInActions = createBuiltinActions({ - containerRunner, - integrations, - catalogClient, - config: env.config, - reader: env.reader, -}); + const builtInActions = createBuiltinActions({ + integrations, + catalogClient, + config: env.config, + reader: env.reader, + }); -const actions = [...builtInActions, createNewFileAction()]; -return await createRouter({ - containerRunner, - catalogClient, - actions, - logger: env.logger, - config: env.config, - database: env.database, - reader: env.reader, -}); + const actions = [...builtInActions, createNewFileAction()]; + + return createRouter({ + actions, + catalogClient: catalogClient, + logger: env.logger, + config: env.config, + database: env.database, + reader: env.reader, + }); +} ``` ## List of custom action packages diff --git a/docs/features/software-templates/writing-templates.md b/docs/features/software-templates/writing-templates.md index 27e6e76817..81367b19c5 100644 --- a/docs/features/software-templates/writing-templates.md +++ b/docs/features/software-templates/writing-templates.md @@ -320,6 +320,30 @@ The `allowedHosts` part should be set to where you wish to enable this template to publish to. And it can be any host that is listed in your `integrations` config in `app-config.yaml`. +Besides specifying `allowedHosts` you can also restrict the template to publish to +repositories owned by specific users/groups/namespaces by setting the `allowedOwners` +option. With the `allowedRepos` option you are able to narrow it down further to a +specific set of repository names. A full example could look like this: + +```yaml +- title: Choose a location + required: + - repoUrl + properties: + repoUrl: + title: Repository Location + type: string + ui:field: RepoUrlPicker + ui:options: + allowedHosts: + - github.com + allowedOwners: + - backstage + - someGithubUser + allowedRepos: + - backstage +``` + The `RepoUrlPicker` is a custom field that we provide part of the `plugin-scaffolder`. You can provide your own custom fields by [writing your own Custom Field Extensions](./writing-custom-field-extensions.md) @@ -397,6 +421,9 @@ There's also the ability to pass additional scopes when requesting the `oauth` token from the user, which you can do on a per-provider basis, in case your template can be published to multiple providers. +Note, that you will need to configure an [authentication provider](../../auth/index.md#configuring-authentication-providers), alongside the +[`ScmAuthApi`](../../auth/index.md#scaffolder-configuration-software-templates) for your source code management (SCM) service to make this feature work. + ### Accessing the signed-in users details Sometimes when authoring templates, you'll want to access the user that is running the template, and get details from the profile or the users `Entity` in the Catalog. @@ -482,6 +509,64 @@ the value of `firstName` from the parameters). This is great for passing the values from the form into different steps and reusing these input variables. These template strings preserve the type of the parameter. +The `${{ parameters.firstName }}` pattern will work only in the template file. +If you want to start using values provided from the UI in your code, you will have to use +the `${{ values.firstName }}` pattern. Additionally, you have to pass +the parameters from the UI to the input of the `fetch:template` step. + +```yaml +apiVersion: scaffolder.backstage.io/v1beta3 +kind: Template +metadata: + name: v1beta3-demo + title: Test Action + description: scaffolder v1beta3 template demo +spec: + owner: backstage/techdocs-core + type: service + parameters: + - title: Fill in some steps + required: + - name + properties: + name: + title: Name + type: string + description: Unique name of your project + urlParameter: + title: URL endpoint + type: string + description: URL endpoint at which the component can be reached + default: 'https://www.example.com' + enabledDB: + title: Enable Database + type: boolean + default: false + ... + steps: + - id: fetch-base + name: Fetch Base + action: fetch:template + input: + url: ./template + values: + name: ${{ parameters.name }} + url: ${{ parameters.urlParameter }} + enabledDB: ${{ parameters.enabledDB }} +``` + +Afterwards, if you are using the builtin templating action, you can start using +the variables in your code. You can use also any other templating functions from +[Nunjucks](https://mozilla.github.io/nunjucks/templating.html#tags) as well. + +```bash +#!/bin/bash +echo "Hi my name is ${{ values.name }}, and you can fine me at ${{ values.url }}!" +{% if values.enabledDB %} +echo "You have enabled your database!" +{% endif %} +``` + As you can see above in the `Outputs` section, `actions` and `steps` can also output things. You can grab that output using `steps.$stepId.output.$property`. diff --git a/docs/features/techdocs/addons.md b/docs/features/techdocs/addons.md index 831729d093..fe1058b2ca 100644 --- a/docs/features/techdocs/addons.md +++ b/docs/features/techdocs/addons.md @@ -52,6 +52,8 @@ Addons are rendered in the order in which they are registered. ## Installing and using Addons +To start using Addons you need to add the `@backstage/plugin-techdocs-module-addons-contrib` package to your app. You can do that by running this command from the root of your project: `yarn add --cwd packages/app @backstage/plugin-techdocs-module-addons-contrib` + Addons can be installed and configured in much the same way as extensions for other Backstage plugins: by adding them underneath an extension registry component (``) under the route representing the TechDocs Reader @@ -74,6 +76,18 @@ import { ReportIssue } from '@backstage/plugin-techdocs-module-addons-contrib'; ; ``` +If you are using a custom [TechDocs reader page](./how-to-guides.md#how-to-customize-the-techdocs-reader-page) your setup will be very similar, here's an example: + +```ts +}> + + + {/* Other addons can be added here. */} + + {techDocsPage} // This is your custom TechDocs reader page + +``` + The process for configuring Addons on the documentation tab on the entity page is very similar; instead of adding the `` registry under a ``, you'd add it as a child of ``: diff --git a/docs/features/techdocs/configuration.md b/docs/features/techdocs/configuration.md index d14850da77..8a54d76ed0 100644 --- a/docs/features/techdocs/configuration.md +++ b/docs/features/techdocs/configuration.md @@ -74,6 +74,12 @@ techdocs: type: 'local' + # Optional when techdocs.publisher.type is set to 'local'. + + local: + # (Optional). Set this to specify where the generated documentation is stored. + publishDirectory: '/path/to/local/directory' + # Required when techdocs.publisher.type is set to 'googleGcs'. Skip otherwise. googleGcs: @@ -154,7 +160,8 @@ techdocs: # techdocs.cache is optional, and is only recommended when you've configured # an external techdocs.publisher.type above. Also requires backend.cache to - # be configured with a valid cache store. + # be configured with a valid cache store. Configure techdocs.cache.ttl to + # enable caching of techdocs assets. cache: # Represents the number of milliseconds a statically built asset should # stay cached. Cache invalidation is handled automatically by the frontend, diff --git a/docs/getting-started/configuration.md b/docs/getting-started/configuration.md index 59780d2a01..3413f32875 100644 --- a/docs/getting-started/configuration.md +++ b/docs/getting-started/configuration.md @@ -155,6 +155,8 @@ auth: clientSecret: YOUR CLIENT SECRET ``` +### Add sign-in option to the frontend + Backstage will re-read the configuration. If there's no errors, that's great! We can continue with the last part of the configuration. The next step is needed to change the sign-in page, this you actually need to add in the source code. @@ -185,10 +187,11 @@ components: { }, ``` -> Since [v1.1.0](https://github.com/backstage/backstage/releases/tag/v1.1.0-next.3), you must provide an [explicit sign-in resolver](../auth/identity-resolver.md). +> Note: The default Backstage app comes with a guest Sign In Resolver. This resolver makes all users share a single "guest" identity and is only intended as a minimum requirement to quickly get up and running. You can read more about how [Sign In Resolvers](../auth/identity-resolver.md#sign-in-resolvers) play a role in creating a [Backstage User Identity](../auth/identity-resolver.md#backstage-user-identity) for logged in users. -That should be it. You can stop your Backstage App. When you start it again and -go to your Backstage portal in your browser, you should have your login prompt! +Restart Backstage from the terminal, by stopping it with `Control-C`, and starting it with `yarn dev` . You should be welcomed by a login prompt! + +> Note: Sometimes the frontend starts before the backend resulting in errors on the sign in page. Wait for the backend to start and then reload Backstage to proceed. To learn more about Authentication in Backstage, here are some docs you could read: diff --git a/docs/getting-started/homepage.md b/docs/getting-started/homepage.md index 2f86380b13..eac76b5fdc 100644 --- a/docs/getting-started/homepage.md +++ b/docs/getting-started/homepage.md @@ -157,7 +157,7 @@ export const HomePage = () => { return ( - + ); diff --git a/docs/getting-started/index.md b/docs/getting-started/index.md index 8c2f6bc865..d560b97eae 100644 --- a/docs/getting-started/index.md +++ b/docs/getting-started/index.md @@ -21,7 +21,7 @@ guide to do a repository-based installation. ### Prerequisites -- Access to a Linux-based operating system, such as Linux, MacOS or +- Access to a Unix-based operating system, such as Linux, MacOS or [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 diff --git a/docs/getting-started/project-structure.md b/docs/getting-started/project-structure.md index cbe84db2e0..8dca898ae7 100644 --- a/docs/getting-started/project-structure.md +++ b/docs/getting-started/project-structure.md @@ -28,7 +28,7 @@ the code. sub-folder which is used for a markdown spellchecker. - [`.yarn/`](https://github.com/backstage/backstage/tree/master/.yarn) - - Backstage ships with it's own `yarn` implementation. This allows us to have + Backstage ships with its own `yarn` implementation. This allows us to have better control over our `yarn.lock` file and hopefully avoid problems due to yarn versioning differences. diff --git a/docs/integrations/azure/discovery.md b/docs/integrations/azure/discovery.md index c607a6550e..6a420462c0 100644 --- a/docs/integrations/azure/discovery.md +++ b/docs/integrations/azure/discovery.md @@ -45,7 +45,7 @@ catalog: anotherProviderId: # another identifier organization: myorg project: myproject - repository: '*' # this will match all repos starting with service-* + repository: '*' # this will match all repos path: /src/*/catalog-info.yaml # this will search for files deep inside the /src folder yetAotherProviderId: # guess, what? Another one :) host: selfhostedazure.yourcompany.com diff --git a/docs/integrations/github/github-apps.md b/docs/integrations/github/github-apps.md index 5725e67c7b..4f2c58bbec 100644 --- a/docs/integrations/github/github-apps.md +++ b/docs/integrations/github/github-apps.md @@ -79,7 +79,7 @@ privateKey: | ### Including in Integrations Config Once the credentials are stored in a YAML file generated by `create-github-app`, -or manually by following the [GitHub Enterprise](#gitHub-enterprise) +or manually by following the [GitHub Enterprise](#github-enterprise) instructions, they can be included in the `app-config.yaml` under the `integrations` section. diff --git a/docs/integrations/gitlab/discovery.md b/docs/integrations/gitlab/discovery.md index ea151e9415..aad73c8209 100644 --- a/docs/integrations/gitlab/discovery.md +++ b/docs/integrations/gitlab/discovery.md @@ -22,7 +22,7 @@ catalog: yourProviderId: host: gitlab-host # Identifies one of the hosts set up in the integrations branch: main # Optional. Uses `master` as default - group: example-group # Group and subgroup (if needed) to look for repositories + group: example-group # Optional. Group and subgroup (if needed) to look for repositories. If not present the whole project will be scanned entityFilename: catalog-info.yaml # Optional. Defaults to `catalog-info.yaml` ``` diff --git a/docs/overview/architecture-overview.md b/docs/overview/architecture-overview.md index 382399e603..3c9417268b 100644 --- a/docs/overview/architecture-overview.md +++ b/docs/overview/architecture-overview.md @@ -341,7 +341,8 @@ separate Docker images. The backend container can be built by running the following command: ```bash -yarn run docker-build +yarn run build +yarn run build-image ``` This will create a container called `example-backend`. diff --git a/docs/overview/roadmap.md b/docs/overview/roadmap.md index 727000728f..df242ed172 100644 --- a/docs/overview/roadmap.md +++ b/docs/overview/roadmap.md @@ -15,9 +15,9 @@ work"](#future-work). With "next" we mean features planned for release within the ongoing quarter from April through June 2022. With "future" we mean features on the radar, but not yet scheduled. -| [What's next](#whats-next) | [Future work](#future-work) | -| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | -| [Ease of onboarding](#ease-of-onboarding)
[Backstage Search 1.0](#search-1.0)
[TechDocs Addon Framework](#techdocs-addon-framework)
[Backend Services (initial)](#backend-services-initial)
[Backstage Security Audit](#backstage-security-audit)
[SIGs for contributors](#sigs-for-contributors) | Security Plan (and Strategy)
Composable Homepage 1.0
GraphQL
Telemetry
Improved UX design | +| [What's next](#whats-next) | [Future work](#future-work) | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | +| [Backstage Search 1.0](#search-1.0)
[Backend Services (MVP)](#backend-services-mvp)
[Backstage Security Audit](#backstage-security-audit)
[Backstage Threat Model](#backstage-threat-model)
[TechDocs Addon Framework](#techdocs-addon-framework)
[Software Catalog pagination](#software-catalog-pagination)
[More SIGs](#more-sigs) | Ease of onboarding
Composable Homepage 1.0
Creator experience
GraphQL
Telemetry | The long-term roadmap (12 - 36 months) is not detailed in the public roadmap. Third-party contributions are also not currently included in the roadmap. Let us @@ -30,47 +30,22 @@ The feature set below is planned for the ongoing quarter, and grouped by theme. The list order doesn't necessarily reflect priority, and the development/release cycle will vary based on maintainer schedules. -### Ease of onboarding - -A faster (with less development) and easier setup of a proof-of-concept -deployment, as part of the onboarding experience, has been a common and loud -suggestion from new adopters as well as analysts looking at Backstage. - -With this initiative we plan to start facing this important topic with the most -commonly used and challenging tasks. More in particular we plan to reduce the -effort required to go from zero to production in installing and customizing -Backstage, as well as reducing the effort required to populate the Software -Catalog. - -More iterations will be required in the following quarters, but this will be a -good improvement in the onboarding experience, especially for the benefit of new -adopters. - ### Backstage Search 1.0 Fix the few remaining issues to get Backstage Search platform up to 1.0. For more information, see the [Backstage Search documentation and roadmap page](https://backstage.io/docs/features/search/search-overview). -### TechDocs Addon Framework - -Addons are TechDocs features that are added on top of the base docs-like-code experience. An example would be a feature that showed comments on the page. We plan to add an Addon framework and open source a selection of the Addons that we use internally at Spotify. We encourage the Backstage community to add further Addons. - -For more information about the TechDocs Addon Framework, see the documentation page [here](https://backstage.io/docs/features/techdocs/addons) - -For general information about TechDocs including roadmap, see [here](https://backstage.io/docs/features/techdocs/techdocs-overview). - -### Backend Services (initial) +### Backend Services (MVP) To better scale and maintain the Backstage instances, a backend services system is planned to be introduced as part of the software architecture. This layer of backend services will help in decoupling the various modules (e.g. Catalog and Scaffolder) from the frontend experience. -In this quarter we plan to start designing the new architecture, together with -the first experimentation and development of the software components. +After the experimentation and design happened in the past quarter, soon we plan to release a first version to start providing the first benefits to adopters and developers. ### Backstage Security Audit -This is the continuation of the initiative started in the previous quarter. This +This is the continuation of the initiative started in the previous quarters. This quarter will see the publication of the report describing the outcome of the audit, together the first fixes and the development of some of the changes required to address the vulnerabilities. @@ -84,12 +59,34 @@ initiative. This initiative is done together with, and with the support of, the [Cloud Native Computing Foundation (CNCF)](https://www.cncf.io/). -### SIGs for contributors +### Backstage Threat Model -The request to better coordinate the increasing number of contributions coming -from the various adopters' developers is loud and clear. We think that the -community is mature enough to start launching the SIGs (Special Interest Groups) -following the successful model of Kubernetes. +This is another (relevant) initiative planned to make Backstage a secure product for the adopters. The goals of this initiative are: + +1. Understand where security investment and attention is needed. +2. Guide the upcoming security audit. +3. Communicate expectations to Backstage adopters and inform and attract security researchers. + +The planned artifacts are: + +- Concise high level threat model that will be included as part of the Backstage security documentation. +- Granular threat model created in conjunction with the security audit to inform further security investment areas for Backstage. + +### TechDocs Addon Framework + +Addons are TechDocs features that are added on top of the base docs-like-code experience. An example would be a feature that showed comments on the page. We plan to add an Addon framework and open source a selection of the Addons that we use internally at Spotify. We encourage the Backstage community to add further Addons. + +For more information about the TechDocs Addon Framework, see the documentation page [here](https://backstage.io/docs/features/techdocs/addons). + +For general information about TechDocs including roadmap, see [here](https://backstage.io/docs/features/techdocs/techdocs-overview). + +### Software Catalog pagination + +Today adopters with a big catalog (with several thousands of software components) might not have an ideal end-user experience when viewing the `/catalog` page. The issue is related to how the entities are fetched by the frontend. In order to provide a better end-user experience the pagination of the catalog’s entities needs to be enforced. Some experimentation is already completed but in this quarter we plan to continue, and hopefully complete, this relevant enhancement. + +### More SIGs + +In the last quarter we launched the [Catalog SIG (Special Interest Group)](https://github.com/backstage/community/tree/main/sigs/sig-catalog) to better coordinate the increasing number of contributions to the project. We think that this is the proper path to follow to engage more with the contributors. For this reason we will launch other SIGs dedicated to the most interesting topics for the community. ## Future work @@ -97,18 +94,17 @@ The following feature list doesn't represent a commitment to develop, and the list order doesn't reflect any priority or importance, but these features are on the maintainers' radar, with clear interest expressed by the community. -- **Security Plan (and Strategy):** The purpose of the Security Strategy is to - move another step along the path to maturing the platform, setting the - expectations of any adopters from a security standpoint. +- **Ease of onboarding:** A faster (with less development) and easier setup of + Backstage and the most relevant/adopted plugins. - **Composable Homepage 1.0:** Driving this to 1.0 by adding some composable components. +- **Creator experience:** Provide a better Backstage user experience through + visual guidelines and templates, especially navigation across plug-ins and + portal functionalities. - **[GraphQL](https://graphql.org/) support:** Introduce the ability to query Backstage backend services with a standard query language for APIs. - **Telemetry:** To efficiently generate logging and metrics in such a way that adopters can get insights so that Backstage can be monitored and improved. -- **Improved UX design:** Provide a better Backstage user experience through - visual guidelines and templates, especially navigation across plug-ins and - portal functionalities. ## How to influence the roadmap diff --git a/docs/overview/versioning-policy.md b/docs/overview/versioning-policy.md index 7430f3c200..282906c580 100644 --- a/docs/overview/versioning-policy.md +++ b/docs/overview/versioning-policy.md @@ -135,3 +135,21 @@ package export. accessed via `/beta` or `/alpha` imports. - `@alpha` - here be dragons. Not visible in the main package entry point, alpha exports must be accessed via `/alpha` imports. + +## Node.js Releases + +The Backstage project uses [Node.js](https://nodejs.org/) for both its development +tooling and backend runtime. In order for expectations to be clear we use the +following schedule for determining the [Node.js releases](https://nodejs.org/en/about/releases/) that we support: + +- At any given point in time we support exactly two adjacent even-numbered + releases of Node.js, for example v12 and v14. +- Three months before a Node.js release becomes _Active LTS_ we switch support + to that release and the previous one. This is halfway through the _Current LTS_ + cycle for that release and occurs at the end of July every year. + +When we say _Supporting_ a Node.js release, that means the following: + +- The CI pipeline in the main Backstage repo tests towards the supported releases, and we encourage any other Backstage related projects to do the same. +- New Backstage projects created with `@backstage/create-app` will have their `engines.node` version set accordingly. +- Dropping compatibility with unsupported releases is not considered a breaking change. This includes using new syntax or APIs, as well as bumping dependencies that drop support for these versions. diff --git a/docs/permissions/plugin-authors/03-adding-a-resource-permission-check.md b/docs/permissions/plugin-authors/03-adding-a-resource-permission-check.md index e818557402..a76518b202 100644 --- a/docs/permissions/plugin-authors/03-adding-a-resource-permission-check.md +++ b/docs/permissions/plugin-authors/03-adding-a-resource-permission-check.md @@ -160,12 +160,12 @@ Create a new `plugins/todo-list-backend/src/conditionExports.ts` file and add th ```typescript import { TODO_LIST_RESOURCE_TYPE } from '@internal/plugin-todo-list-common'; import { createConditionExports } from '@backstage/plugin-permission-node'; -import { permissionRules } from './service/rules'; +import { rules } from './service/rules'; const { conditions, createConditionalDecision } = createConditionExports({ - pluginId: 'catalog', - resourceType: RESOURCE_TYPE_CATALOG_ENTITY, - rules: permissionRules, + pluginId: 'todolist', + resourceType: TODO_LIST_RESOURCE_TYPE, + rules, }); export const todoListConditions = conditions; @@ -173,7 +173,12 @@ export const todoListConditions = conditions; export const createTodoListConditionalDecision = createConditionalDecision; ``` -Make sure `todoListConditions` and `createTodoListConditionalDecision` are exported from the `todo-list-backend` package. +Make sure `todoListConditions` and `createTodoListConditionalDecision` are exported from the `todo-list-backend` package by editing `plugins/todo-list-backend/src/index.ts`: + +```diff + export * from './service/router'; ++ export * from './conditionExports'; +``` ## Test the authorized update endpoint diff --git a/docs/releases/v1.4.0-next.0-changelog.md b/docs/releases/v1.4.0-next.0-changelog.md new file mode 100644 index 0000000000..c6b9fd7cf9 --- /dev/null +++ b/docs/releases/v1.4.0-next.0-changelog.md @@ -0,0 +1,1365 @@ +# Release v1.4.0-next.0 + +## @backstage/catalog-model@1.1.0-next.0 + +### Minor Changes + +- 1380b389dc: Adding an optional type field to entity links to group and categorize links + +### Patch Changes + +- c3cfc83af2: Updated JSDoc to be MDX compatible. + +## @backstage/plugin-api-docs-module-protoc-gen-doc@0.1.0-next.0 + +### Minor Changes + +- e0328f2107: Added the new `grpcDocsApiWidget` to render `protoc-gen-doc` generated descriptors by the `grpc-docs` package. + +## @backstage/plugin-kubernetes-backend@0.7.0-next.0 + +### Minor Changes + +- 0791af993f: Refactor `KubernetesObjectsProvider` with new methods, `KubernetesServiceLocator` now takes an `Entity` instead of `serviceId` + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/plugin-kubernetes-common@0.4.0-next.0 + +## @backstage/plugin-kubernetes-common@0.4.0-next.0 + +### Minor Changes + +- 0791af993f: Refactor `KubernetesObjectsProvider` with new methods, `KubernetesServiceLocator` now takes an `Entity` instead of `serviceId` + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + +## @backstage/plugin-pagerduty@0.5.0-next.0 + +### Minor Changes + +- 8798f8d93f: Introduces a new annotation `pagerduty.com/service-id` that can be used instead of the `pagerduty.com/integration-key` annotation. + _Note: If both annotations are specified on a given Entity, then the `pagerduty.com/integration-key` annotation will be prefered_ + + **BREAKING** The `PagerDutyClient.fromConfig` static method now expects a `FetchApi` compatible object and has been refactored to + accept 2 arguments: config and ClientApiDependencies + The `PagerDutyClient` now relies on a `fetchApi` being available to execute `fetch` requests. + + **BREAKING** A new query method `getServiceByEntity` that is used to query for Services by either the `integrationKey` or `serviceId` + annotation values if they are defined. The `integrationKey` value is preferred currently over `serviceId`. As such, the previous + `getServiceByIntegrationKey` method has been removed. + + **BREAKING** The return values for each Client query method has been changed to return an object instead of raw values. + For example, the `getIncidentsByServiceId` query method now returns an object in the shape of `{ incidents: Incident[] }` + instead of just `Incident[]`. + This same pattern goes for `getChangeEventsByServiceId` and `getOnCallByPolicyId` functions. + + **BREAKING** All public exported types that relate to entities within PagerDuty have been prefixed with `PagerDuty` (e.g. `ServicesResponse` is now `PagerDutyServicesResponse` and `User` is now `PagerDutyUser`) + + In addition, various enhancements/bug fixes were introduced: + + - The `PagerDutyCard` component now wraps error and loading messages with an `InfoCard` to contain errors/messages. This enforces a consistent experience on the EntityPage + - If no service can be found for the provided integration key, a new Error Message Empty State component will be shown instead of an error alert + - Introduces the `fetchApi` to replace standard `window.fetch` + - ensures that Identity Authorization is respected and provided in API requests + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + +## @backstage/plugin-scaffolder@1.4.0-next.0 + +### Minor Changes + +- 3500c13a33: A new template editor has been added which is accessible via the context menu on the top right hand corner of the Create page. It allows you to load a template from a local directory, edit it with a preview, execute it in dry-run mode, and view the results. Note that the [File System Access API](https://developer.mozilla.org/en-US/docs/Web/API/File_System_Access_API) must be supported by your browser for this to be available. + + To support the new template editor the `ScaffolderApi` now has an optional `dryRun` method, which is implemented by the default `ScaffolderClient`. + +### Patch Changes + +- 37539e29d8: The template editor now shows the cause of request errors that happen during a dry-run. +- 842282ecf9: Bumped `codemirror` dependencies to `v6.0.0`. +- 464bb0e6c8: The max content size for dry-run files has been reduced from 256k to 64k. +- a7c0b34d70: Swap usage of `MaterialTable` with `Table` from `core-components` +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/catalog-client@1.0.4-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + - @backstage/plugin-scaffolder-common@1.1.2-next.0 + - @backstage/integration-react@1.1.2-next.0 + +## @backstage/plugin-scaffolder-backend@1.4.0-next.0 + +### Minor Changes + +- 3500c13a33: Added a new `/v2/dry-run` endpoint that allows for a synchronous dry run of a provided template. A `supportsDryRun` option has been added to `createTemplateAction`, which signals whether the action should be executed during dry runs. When enabled, the action context will have the new `isDryRun` property set to signal if the action is being executed during a dry run. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.0 + - @backstage/catalog-client@1.0.4-next.0 + - @backstage/plugin-scaffolder-common@1.1.2-next.0 + +## @backstage/plugin-vault-backend@0.2.0-next.0 + +### Minor Changes + +- 5ebf2c7023: Throw exceptions instead of swallow them, remove some exported types from the `api-report`, small changes in the API responses & expose the vault `baseUrl` to the frontend as well + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/backend-tasks@0.3.3-next.0 + - @backstage/backend-test-utils@0.1.26-next.0 + +## @backstage/app-defaults@1.0.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + - @backstage/core-app-api@1.0.4-next.0 + +## @backstage/backend-common@0.14.1-next.0 + +### Patch Changes + +- b1edb5cfd9: Fix parsing of S3 URLs for the default region. +- c3cfc83af2: Updated JSDoc to be MDX compatible. +- Updated dependencies + - @backstage/integration@1.2.2-next.0 + +## @backstage/backend-tasks@0.3.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + +## @backstage/backend-test-utils@0.1.26-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/cli@0.17.3-next.0 + +## @backstage/catalog-client@1.0.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + +## @backstage/cli@0.17.3-next.0 + +### Patch Changes + +- d2256c0384: Fix `webpack-dev-server` deprecations. + +## @backstage/core-app-api@1.0.4-next.0 + +### Patch Changes + +- 8fe2357101: The `signOut` method of the `IdentityApi` will now navigate the user back to the base URL of the app as indicated by the `app.baseUrl` config. + +## @backstage/core-components@0.9.6-next.0 + +### Patch Changes + +- c3cfc83af2: Updated JSDoc to be MDX compatible. + +## @backstage/create-app@0.4.29-next.0 + +### Patch Changes + +- bc87604c26: Added an explicit `node-gyp` dependency to the root `package.json`. This is to work around a bug in older versions of `node-gyp` that causes Python execution to fail on macOS. + + You can add this workaround to your existing project by adding `node-gyp` as a `devDependency` in your root `package.json` file: + + ```diff + "devDependencies": { + + "node-gyp": "^9.0.0" + }, + ``` + +## @backstage/dev-utils@1.0.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/core-app-api@1.0.4-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + - @backstage/app-defaults@1.0.4-next.0 + - @backstage/integration-react@1.1.2-next.0 + - @backstage/test-utils@1.1.2-next.0 + +## @backstage/integration@1.2.2-next.0 + +### Patch Changes + +- 8829e175f2: Allow frontend visibility for `integrations` itself. + +## @backstage/integration-react@1.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + - @backstage/integration@1.2.2-next.0 + +## @techdocs/cli@1.1.3-next.0 + +### Patch Changes + +- 14ce0d9347: Fixed a bug that prevented docker images from being pulled by default when generating TechDocs. +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/plugin-techdocs-node@1.1.3-next.0 + +## @backstage/test-utils@1.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.0.4-next.0 + +## @backstage/plugin-adr@0.1.2-next.0 + +### Patch Changes + +- 7d47e7e512: Track discover event and result rank for `AdrSearchResultListItem` +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-adr-common@0.1.2-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + - @backstage/integration-react@1.1.2-next.0 + - @backstage/plugin-search-react@0.2.2-next.0 + +## @backstage/plugin-adr-backend@0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/catalog-client@1.0.4-next.0 + - @backstage/plugin-adr-common@0.1.2-next.0 + +## @backstage/plugin-adr-common@0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/integration@1.2.2-next.0 + +## @backstage/plugin-airbrake@0.3.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/dev-utils@1.0.4-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + - @backstage/test-utils@1.1.2-next.0 + +## @backstage/plugin-airbrake-backend@0.2.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + +## @backstage/plugin-allure@0.1.23-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + +## @backstage/plugin-analytics-module-ga@0.1.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + +## @backstage/plugin-apache-airflow@0.1.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + +## @backstage/plugin-api-docs@0.8.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog@1.3.1-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + +## @backstage/plugin-app-backend@0.3.34-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + +## @backstage/plugin-auth-backend@0.14.2-next.0 + +### Patch Changes + +- 859346bfbb: Updated dependency `google-auth-library` to `^8.0.0`. +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/plugin-auth-node@0.2.3-next.0 + - @backstage/catalog-client@1.0.4-next.0 + +## @backstage/plugin-auth-node@0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + +## @backstage/plugin-azure-devops@0.1.23-next.0 + +### Patch Changes + +- e049e41048: Exporting azureDevOpsApiRef, AzureGitTagsIcon, and all hooks for the benefit of other plugins. +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + +## @backstage/plugin-azure-devops-backend@0.3.13-next.0 + +### Patch Changes + +- 13a232ec22: Added comments to example to help avoid confusion as to where lines need to be added +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + +## @backstage/plugin-badges@0.2.31-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + +## @backstage/plugin-badges-backend@0.1.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/catalog-client@1.0.4-next.0 + +## @backstage/plugin-bazaar@0.1.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog@1.3.1-next.0 + - @backstage/cli@0.17.3-next.0 + - @backstage/catalog-client@1.0.4-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + +## @backstage/plugin-bazaar-backend@0.1.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/backend-test-utils@0.1.26-next.0 + +## @backstage/plugin-bitbucket-cloud-common@0.1.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.2.2-next.0 + +## @backstage/plugin-bitrise@0.1.34-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + +## @backstage/plugin-catalog@1.3.1-next.0 + +### Patch Changes + +- dcaf1cb418: Previously, the color of the Entity Context Menu (in the Entity Page Header) was hardcoded as `white`. + + This was an issue for themes that use a header with a white background. By default, the color of the icon is now `theme.palette.bursts.fontColor`. + + It can now also be overridden in the theme, which is only necessary if the header title, subtitle and three-dots icon need to have different colors. For example: + + ```typescript + export function createThemeOverrides(theme: BackstageTheme): Overrides { + return { + PluginCatalogEntityContextMenu: { + button: { + color: 'blue', + }, + }, + ... + }, + ... + } + ``` + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/catalog-client@1.0.4-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + - @backstage/integration-react@1.1.2-next.0 + - @backstage/plugin-search-react@0.2.2-next.0 + +## @backstage/plugin-catalog-backend@1.2.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/plugin-permission-node@0.6.3-next.0 + - @backstage/catalog-client@1.0.4-next.0 + - @backstage/plugin-scaffolder-common@1.1.2-next.0 + +## @backstage/plugin-catalog-backend-module-aws@0.1.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/backend-tasks@0.3.3-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.0 + +## @backstage/plugin-catalog-backend-module-azure@0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/backend-tasks@0.3.3-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.0 + +## @backstage/plugin-catalog-backend-module-bitbucket@0.2.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.1.1-next.0 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.1.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.2.2-next.0 + - @backstage/backend-tasks@0.3.3-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.1.1-next.0 + +## @backstage/plugin-catalog-backend-module-gerrit@0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/backend-tasks@0.3.3-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.0 + +## @backstage/plugin-catalog-backend-module-github@0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/backend-tasks@0.3.3-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.0 + +## @backstage/plugin-catalog-backend-module-gitlab@0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/backend-tasks@0.3.3-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.0 + +## @backstage/plugin-catalog-backend-module-ldap@0.5.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/backend-tasks@0.3.3-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.0 + +## @backstage/plugin-catalog-backend-module-msgraph@0.3.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/backend-tasks@0.3.3-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.0 + +## @backstage/plugin-catalog-graph@0.2.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/catalog-client@1.0.4-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + +## @backstage/plugin-catalog-graphql@0.3.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + +## @backstage/plugin-catalog-import@0.8.10-next.0 + +### Patch Changes + +- 272106fdad: Support use without `integrations` or only integrations without frontend visible properties (e.g., `bitbucketCloud`) being configured by checking `integrations.github` directly without attempting to load `integrations`. +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/catalog-client@1.0.4-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + - @backstage/integration-react@1.1.2-next.0 + +## @backstage/plugin-catalog-react@1.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/catalog-client@1.0.4-next.0 + +## @backstage/plugin-cicd-statistics@0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + +## @backstage/plugin-cicd-statistics-module-gitlab@0.1.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/plugin-cicd-statistics@0.1.9-next.0 + +## @backstage/plugin-circleci@0.3.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + +## @backstage/plugin-cloudbuild@0.3.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + +## @backstage/plugin-code-climate@0.1.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + +## @backstage/plugin-code-coverage@0.1.34-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + +## @backstage/plugin-code-coverage-backend@0.1.32-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/catalog-client@1.0.4-next.0 + +## @backstage/plugin-codescene@0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + +## @backstage/plugin-config-schema@0.1.30-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + +## @backstage/plugin-cost-insights@0.11.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + +## @backstage/plugin-dynatrace@0.1.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + +## @backstage/plugin-explore@0.3.38-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + +## @backstage/plugin-firehydrant@0.1.24-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + +## @backstage/plugin-fossa@0.2.39-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + +## @backstage/plugin-gcalendar@0.3.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + +## @backstage/plugin-gcp-projects@0.3.26-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + +## @backstage/plugin-git-release-manager@0.3.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + - @backstage/integration@1.2.2-next.0 + +## @backstage/plugin-github-actions@0.5.7-next.0 + +### Patch Changes + +- 217f919f0a: Minor cleanup of the API surface. +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + +## @backstage/plugin-github-deployments@0.1.38-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + - @backstage/integration-react@1.1.2-next.0 + +## @backstage/plugin-github-pull-requests-board@0.1.1-next.0 + +### Patch Changes + +- c6690d9d24: Fix bug on fetching teams repositories where were being filtered by type service unnecessarily +- 04e1504e85: Support namespaced teams and fetch all kinds +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + +## @backstage/plugin-gitops-profiles@0.3.25-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + +## @backstage/plugin-gocd@0.1.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + +## @backstage/plugin-graphiql@0.2.39-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + +## @backstage/plugin-graphql-backend@0.1.24-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/plugin-catalog-graphql@0.3.11-next.0 + +## @backstage/plugin-home@0.4.23-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-stack-overflow@0.1.3-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + +## @backstage/plugin-ilert@0.1.33-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + +## @backstage/plugin-jenkins@0.7.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + +## @backstage/plugin-jenkins-backend@0.1.24-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/plugin-auth-node@0.2.3-next.0 + - @backstage/catalog-client@1.0.4-next.0 + +## @backstage/plugin-kafka@0.3.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + +## @backstage/plugin-kafka-backend@0.2.27-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + +## @backstage/plugin-kubernetes@0.6.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-kubernetes-common@0.4.0-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + +## @backstage/plugin-lighthouse@0.3.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + +## @backstage/plugin-newrelic@0.3.25-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + +## @backstage/plugin-newrelic-dashboard@0.1.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + +## @backstage/plugin-org@0.5.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + +## @backstage/plugin-periskop@0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + +## @backstage/plugin-periskop-backend@0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + +## @backstage/plugin-permission-backend@0.5.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/plugin-auth-node@0.2.3-next.0 + - @backstage/plugin-permission-node@0.6.3-next.0 + +## @backstage/plugin-permission-node@0.6.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/plugin-auth-node@0.2.3-next.0 + +## @backstage/plugin-proxy-backend@0.2.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + +## @backstage/plugin-rollbar@0.4.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + +## @backstage/plugin-rollbar-backend@0.1.31-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/plugin-scaffolder-backend@1.4.0-next.0 + - @backstage/integration@1.2.2-next.0 + +## @backstage/plugin-scaffolder-backend-module-rails@0.4.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/plugin-scaffolder-backend@1.4.0-next.0 + - @backstage/integration@1.2.2-next.0 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.2.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.4.0-next.0 + +## @backstage/plugin-scaffolder-common@1.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + +## @backstage/plugin-search@0.9.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + - @backstage/plugin-search-react@0.2.2-next.0 + +## @backstage/plugin-search-backend@0.5.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/plugin-auth-node@0.2.3-next.0 + - @backstage/plugin-permission-node@0.6.3-next.0 + - @backstage/plugin-search-backend-node@0.6.3-next.0 + +## @backstage/plugin-search-backend-module-elasticsearch@0.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-node@0.6.3-next.0 + +## @backstage/plugin-search-backend-module-pg@0.3.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/plugin-search-backend-node@0.6.3-next.0 + +## @backstage/plugin-search-backend-node@0.6.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/backend-tasks@0.3.3-next.0 + +## @backstage/plugin-search-react@0.2.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + +## @backstage/plugin-sentry@0.3.45-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + +## @backstage/plugin-shortcuts@0.2.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + +## @backstage/plugin-sonarqube@0.3.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + +## @backstage/plugin-splunk-on-call@0.3.31-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + +## @backstage/plugin-stack-overflow@0.1.3-next.0 + +### Patch Changes + +- 12ae3eed2f: - Publicly exports `StackOverflowIcon`. + - `HomePageStackOverflowQuestions` accepts optional icon property. +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-home@0.4.23-next.0 + +## @backstage/plugin-tech-insights@0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + +## @backstage/plugin-tech-insights-backend@0.4.2-next.0 + +### Patch Changes + +- 2ef58ab539: TechInsightsBackend: Added missing 'scheduler' to code examples +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/backend-tasks@0.3.3-next.0 + - @backstage/plugin-tech-insights-node@0.3.2-next.0 + - @backstage/catalog-client@1.0.4-next.0 + +## @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/plugin-tech-insights-node@0.3.2-next.0 + +## @backstage/plugin-tech-insights-node@0.3.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + +## @backstage/plugin-tech-radar@0.5.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + +## @backstage/plugin-techdocs@1.2.1-next.0 + +### Patch Changes + +- 3cbebf710e: Reorder browser tab title in Techdocs pages to have the site name first. +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-techdocs-react@1.0.2-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + - @backstage/integration-react@1.1.2-next.0 + - @backstage/plugin-search-react@0.2.2-next.0 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-techdocs-react@1.0.2-next.0 + - @backstage/plugin-catalog@1.3.1-next.0 + - @backstage/core-app-api@1.0.4-next.0 + - @backstage/plugin-techdocs@1.2.1-next.0 + - @backstage/integration-react@1.1.2-next.0 + - @backstage/plugin-search-react@0.2.2-next.0 + - @backstage/test-utils@1.1.2-next.0 + +## @backstage/plugin-techdocs-backend@1.1.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/plugin-techdocs-node@1.1.3-next.0 + - @backstage/catalog-client@1.0.4-next.0 + +## @backstage/plugin-techdocs-module-addons-contrib@1.0.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-techdocs-react@1.0.2-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/integration-react@1.1.2-next.0 + +## @backstage/plugin-techdocs-node@1.1.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/integration@1.2.2-next.0 + +## @backstage/plugin-techdocs-react@1.0.2-next.0 + +### Patch Changes + +- c3cfc83af2: Updated JSDoc to be MDX compatible. +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + +## @backstage/plugin-todo@0.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + +## @backstage/plugin-todo-backend@0.1.31-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/catalog-client@1.0.4-next.0 + +## @backstage/plugin-user-settings@0.4.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + +## @backstage/plugin-vault@0.1.1-next.0 + +### Patch Changes + +- 5ebf2c7023: Export missing parameters and added them to the api-report. Also adapted the API to the expected response from the backend +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + +## @backstage/plugin-xcmetrics@0.2.27-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + +## example-app@0.2.73-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder@1.4.0-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-techdocs-react@1.0.2-next.0 + - @backstage/plugin-catalog@1.3.1-next.0 + - @backstage/plugin-stack-overflow@0.1.3-next.0 + - @backstage/core-app-api@1.0.4-next.0 + - @backstage/cli@0.17.3-next.0 + - @backstage/plugin-azure-devops@0.1.23-next.0 + - @backstage/plugin-techdocs@1.2.1-next.0 + - @backstage/plugin-catalog-import@0.8.10-next.0 + - @backstage/plugin-pagerduty@0.5.0-next.0 + - @backstage/plugin-github-actions@0.5.7-next.0 + - @backstage/plugin-airbrake@0.3.7-next.0 + - @backstage/plugin-api-docs@0.8.7-next.0 + - @backstage/plugin-badges@0.2.31-next.0 + - @backstage/plugin-catalog-graph@0.2.19-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + - @backstage/plugin-circleci@0.3.7-next.0 + - @backstage/plugin-cloudbuild@0.3.7-next.0 + - @backstage/plugin-code-coverage@0.1.34-next.0 + - @backstage/plugin-cost-insights@0.11.29-next.0 + - @backstage/plugin-dynatrace@0.1.1-next.0 + - @backstage/plugin-explore@0.3.38-next.0 + - @backstage/plugin-gocd@0.1.13-next.0 + - @backstage/plugin-home@0.4.23-next.0 + - @backstage/plugin-jenkins@0.7.6-next.0 + - @backstage/plugin-kafka@0.3.7-next.0 + - @backstage/plugin-kubernetes@0.6.7-next.0 + - @backstage/plugin-lighthouse@0.3.7-next.0 + - @backstage/plugin-newrelic-dashboard@0.1.15-next.0 + - @backstage/plugin-org@0.5.7-next.0 + - @backstage/plugin-rollbar@0.4.7-next.0 + - @backstage/plugin-search@0.9.1-next.0 + - @backstage/plugin-sentry@0.3.45-next.0 + - @backstage/plugin-tech-insights@0.2.3-next.0 + - @backstage/plugin-todo@0.2.9-next.0 + - @backstage/app-defaults@1.0.4-next.0 + - @backstage/integration-react@1.1.2-next.0 + - @backstage/plugin-apache-airflow@0.1.15-next.0 + - @backstage/plugin-gcalendar@0.3.3-next.0 + - @backstage/plugin-gcp-projects@0.3.26-next.0 + - @backstage/plugin-graphiql@0.2.39-next.0 + - @backstage/plugin-newrelic@0.3.25-next.0 + - @backstage/plugin-search-react@0.2.2-next.0 + - @backstage/plugin-shortcuts@0.2.8-next.0 + - @backstage/plugin-tech-radar@0.5.14-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.0.2-next.0 + - @backstage/plugin-user-settings@0.4.6-next.0 + +## example-backend@0.2.73-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-tech-insights-backend@0.4.2-next.0 + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/plugin-scaffolder-backend@1.4.0-next.0 + - @backstage/plugin-auth-backend@0.14.2-next.0 + - @backstage/plugin-kubernetes-backend@0.7.0-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/plugin-azure-devops-backend@0.3.13-next.0 + - example-app@0.2.73-next.0 + - @backstage/backend-tasks@0.3.3-next.0 + - @backstage/plugin-app-backend@0.3.34-next.0 + - @backstage/plugin-auth-node@0.2.3-next.0 + - @backstage/plugin-badges-backend@0.1.28-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.0 + - @backstage/plugin-code-coverage-backend@0.1.32-next.0 + - @backstage/plugin-graphql-backend@0.1.24-next.0 + - @backstage/plugin-jenkins-backend@0.1.24-next.0 + - @backstage/plugin-kafka-backend@0.2.27-next.0 + - @backstage/plugin-permission-backend@0.5.9-next.0 + - @backstage/plugin-permission-node@0.6.3-next.0 + - @backstage/plugin-proxy-backend@0.2.28-next.0 + - @backstage/plugin-rollbar-backend@0.1.31-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.2-next.0 + - @backstage/plugin-search-backend@0.5.4-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@0.1.6-next.0 + - @backstage/plugin-search-backend-module-pg@0.3.5-next.0 + - @backstage/plugin-search-backend-node@0.6.3-next.0 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.18-next.0 + - @backstage/plugin-tech-insights-node@0.3.2-next.0 + - @backstage/plugin-techdocs-backend@1.1.3-next.0 + - @backstage/plugin-todo-backend@0.1.31-next.0 + - @backstage/catalog-client@1.0.4-next.0 + +## techdocs-cli-embedded-app@0.2.72-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-techdocs-react@1.0.2-next.0 + - @backstage/plugin-catalog@1.3.1-next.0 + - @backstage/core-app-api@1.0.4-next.0 + - @backstage/cli@0.17.3-next.0 + - @backstage/plugin-techdocs@1.2.1-next.0 + - @backstage/app-defaults@1.0.4-next.0 + - @backstage/integration-react@1.1.2-next.0 + - @backstage/test-utils@1.1.2-next.0 + +## @internal/plugin-todo-list@1.0.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + +## @internal/plugin-todo-list-backend@1.0.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/plugin-auth-node@0.2.3-next.0 diff --git a/docs/releases/v1.4.0-next.1-changelog.md b/docs/releases/v1.4.0-next.1-changelog.md new file mode 100644 index 0000000000..0780178d4d --- /dev/null +++ b/docs/releases/v1.4.0-next.1-changelog.md @@ -0,0 +1,1474 @@ +# Release v1.4.0-next.1 + +## @backstage/cli@0.18.0-next.1 + +### Minor Changes + +- 96a82d9791: **BREAKING**: Removed the following deprecated package commands: + + - `app:build` - Use `package build` instead + - `app:serve` - Use `package start` instead + - `backend:build` - Use `package build` instead + - `backend:bundle` - Use `package build` instead + - `backend:dev` - Use `package start` instead + - `plugin:build` - Use `package build` instead + - `plugin:serve` - Use `package start` instead + - `build` - Use `package build` instead + - `lint` - Use `package lint` instead + - `prepack` - Use `package prepack` instead + - `postpack` - Use `package postpack` instead + + In order to replace these you need to have [migrated to using package roles](https://backstage.io/docs/tutorials/package-role-migration). + +### Patch Changes + +- 86640214f0: Upgrade `@rollup/plugin-node-resolve` to `^13.0.6` +- e661242844: Updated dependency `run-script-webpack-plugin` to `^0.1.0`. +- Updated dependencies + - @backstage/errors@1.1.0-next.0 + - @backstage/config-loader@1.1.3-next.0 + +## @backstage/errors@1.1.0-next.0 + +### Minor Changes + +- 6d61b44466: The `ResponseError.fromResponse` now accepts a more narrow response type, in order to avoid incompatibilities between different fetch implementations. + + The `response` property of `ResponseError` has also been narrowed to a new `ConsumedResponse` type that omits all the properties for consuming the body of the response. This is not considered a breaking change as it was always an error to try to consume the body of the response. + +## @backstage/plugin-apache-airflow@0.2.0-next.1 + +### Minor Changes + +- 01f976ea72: Exposed DagTableComponent as standalone component + added a prop to get only select DAGs instead of the full list + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + +## @backstage/plugin-auth-backend@0.15.0-next.1 + +### Minor Changes + +- 9d4040777e: **BREAKING**: Removed all directly exported auth provider factories, option types, and sign-in resolvers. For example: `AwsAlbProviderOptions`, `bitbucketUserIdSignInResolver`, `createGithubProvider`. These are all still accessible via the `providers` export. For example, use `providers.github.create()` rather than `createGithubProvider()`, and `providers.bitbucket.resolvers.userIdMatchingUserEntityAnnotation()` rather than `bitbucketUserIdSignInResolver`. + + **BREAKING**: Removed the exported `AuthProviderFactoryOptions` type as well as the deprecated option fields of the `AuthProviderFactory` callback. This includes the `tokenManager`, `tokenIssuer`, `discovery`, and `catalogApi` fields. Existing usage of these should be replaced with the new utilities in the `resolverContext` field. The deprecated `TokenIssuer` type is now also removed, since it is no longer used. + + **BREAKING**: Removed `getEntityClaims`, use `getDefaultOwnershipEntityRefs` instead. + + **DEPRECATION**: Deprecated `AtlassianAuthProvider` as it was unintentionally exported. + +### Patch Changes + +- f2cf79d62e: Added an option for the auth backend router to select the algorithm for the JWT token signing keys +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/catalog-client@1.0.4-next.1 + - @backstage/plugin-auth-node@0.2.3-next.1 + +## @backstage/plugin-catalog-backend-module-openapi@0.1.0-next.0 + +### Minor Changes + +- 67503d159e: Add basic OpenAPI \\$ref support. + + For more information see [here](https://github.com/backstage/backstage/tree/master/plugins/catalog-backend-module-openapi). + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/plugin-catalog-backend@1.2.1-next.1 + - @backstage/integration@1.2.2-next.1 + +## @backstage/plugin-search-backend-module-elasticsearch@0.2.0-next.1 + +### Minor Changes + +- c5af773757: **BREAKING**: In order to remain interoperable with all currently supported + deployments of Elasticsearch, this package will now conditionally use either + the `@elastic/elasticsearch` or `@opensearch-project/opensearch` client when + communicating with your deployed cluster. + + If you do not rely on types exported from this package, or if you do not make + use of the `createElasticSearchClientOptions` or `newClient` methods on the + `ElasticSearchSearchEngine` class, then upgrading to this version should not + require any further action on your part. Everything will continue to work as it + always has. + + If you _do_ rely on either of the above methods or any underlying types, some + changes may be needed to your custom code. A type guard is now exported by this + package (`isOpenSearchCompatible(options)`), which you may use to help clarify + which client options are compatible with which client constructors. + + If you are using this package with the `search.elasticsearch.provider` set to + `aws`, and you are making use of the `newClient` method in particular, you may + wish to start using the `@opensearch-project/opensearch` client in your custom + code. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-node@0.6.3-next.1 + - @backstage/plugin-search-common@0.3.6-next.0 + +## @backstage/plugin-techdocs-backend@1.2.0-next.1 + +### Minor Changes + +- 860765ff45: Added local publishing target directory `config`: `techdocs.publisher.local.publishDirectory` + +### Patch Changes + +- 726577958f: Add sample headings on the documented component homepage. +- Updated dependencies + - @backstage/plugin-techdocs-node@1.2.0-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/catalog-client@1.0.4-next.1 + - @backstage/integration@1.2.2-next.1 + - @backstage/plugin-catalog-common@1.0.4-next.0 + - @backstage/plugin-permission-common@0.6.3-next.0 + - @backstage/plugin-search-common@0.3.6-next.0 + +## @backstage/plugin-techdocs-node@1.2.0-next.1 + +### Minor Changes + +- 860765ff45: Added local publishing target directory `config`: `techdocs.publisher.local.publishDirectory` + +### Patch Changes + +- a5d73da942: Fix the flag parsing for `legacyCopyReadmeMdToIndexMd` in `techdocs-cli generate` command, and decouple it's logic from the `techdocs-ref` flag. +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/integration@1.2.2-next.1 + - @backstage/plugin-search-common@0.3.6-next.0 + +## @backstage/app-defaults@1.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-permission-react@0.4.3-next.0 + +## @backstage/backend-common@0.14.1-next.1 + +### Patch Changes + +- 0fc57887e8: Improve plural handling in logging output for secrets +- Updated dependencies + - @backstage/errors@1.1.0-next.0 + - @backstage/integration@1.2.2-next.1 + - @backstage/config-loader@1.1.3-next.0 + +## @backstage/backend-tasks@0.3.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + +## @backstage/backend-test-utils@0.1.26-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.18.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + +## @backstage/catalog-client@1.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + +## @backstage/catalog-model@1.1.0-next.1 + +### Patch Changes + +- f1dcc6f3c6: Added type predicates for all entity types, e.g. isUserEntity +- Updated dependencies + - @backstage/errors@1.1.0-next.0 + +## @backstage/config-loader@1.1.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.1.0-next.0 + +## @backstage/core-components@0.9.6-next.1 + +### Patch Changes + +- 3c440ea77e: Change BackstageIconLinkVertical style to use pallette instead of explicit color +- 7e115d42f9: Support displaying subtitle text in `SidebarSubmenuItem` +- Updated dependencies + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + +## @backstage/create-app@0.4.29-next.1 + +### Patch Changes + +- Bumped create-app version. + +## @backstage/dev-utils@1.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/app-defaults@1.0.4-next.1 + - @backstage/integration-react@1.1.2-next.1 + - @backstage/test-utils@1.1.2-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## @backstage/integration@1.2.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.1.0-next.0 + +## @backstage/integration-react@1.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/integration@1.2.2-next.1 + +## @techdocs/cli@1.1.3-next.1 + +### Patch Changes + +- a5d73da942: Fix the flag parsing for `legacyCopyReadmeMdToIndexMd` in `techdocs-cli generate` command, and decouple it's logic from the `techdocs-ref` flag. +- Updated dependencies + - @backstage/plugin-techdocs-node@1.2.0-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + +## @backstage/test-utils@1.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-permission-common@0.6.3-next.0 + - @backstage/plugin-permission-react@0.4.3-next.0 + +## @backstage/theme@0.2.16-next.0 + +### Patch Changes + +- 4c09c09102: Adds optional `htmlFontSize` property and also sets typography design tokens for h5 and h6 in base theme. + +## @backstage/plugin-adr@0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/integration-react@1.1.2-next.1 + - @backstage/plugin-adr-common@0.1.2-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.1 + - @backstage/plugin-search-common@0.3.6-next.0 + - @backstage/plugin-search-react@0.2.2-next.1 + +## @backstage/plugin-adr-backend@0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/catalog-client@1.0.4-next.1 + - @backstage/integration@1.2.2-next.1 + - @backstage/plugin-adr-common@0.1.2-next.1 + - @backstage/plugin-search-common@0.3.6-next.0 + +## @backstage/plugin-adr-common@0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/integration@1.2.2-next.1 + - @backstage/plugin-search-common@0.3.6-next.0 + +## @backstage/plugin-airbrake@0.3.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/dev-utils@1.0.4-next.1 + - @backstage/test-utils@1.1.2-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## @backstage/plugin-allure@0.1.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## @backstage/plugin-analytics-module-ga@0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/theme@0.2.16-next.0 + +## @backstage/plugin-api-docs@0.8.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/plugin-catalog@1.3.1-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## @backstage/plugin-app-backend@0.3.34-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.1 + - @backstage/config-loader@1.1.3-next.0 + +## @backstage/plugin-auth-node@0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + +## @backstage/plugin-azure-devops@0.1.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## @backstage/plugin-badges@0.2.31-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## @backstage/plugin-badges-backend@0.1.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/catalog-client@1.0.4-next.1 + +## @backstage/plugin-bazaar@0.1.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/cli@0.18.0-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/plugin-catalog@1.3.1-next.1 + - @backstage/catalog-client@1.0.4-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## @backstage/plugin-bitrise@0.1.34-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## @backstage/plugin-catalog@1.3.1-next.1 + +### Patch Changes + +- f1dcc6f3c6: Use entity type predicates from catalog-model +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + - @backstage/catalog-client@1.0.4-next.1 + - @backstage/integration-react@1.1.2-next.1 + - @backstage/plugin-catalog-common@1.0.4-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + - @backstage/plugin-search-common@0.3.6-next.0 + - @backstage/plugin-search-react@0.2.2-next.1 + +## @backstage/plugin-catalog-backend@1.2.1-next.1 + +### Patch Changes + +- f1dcc6f3c6: Use entity type predicates from catalog-model +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/catalog-client@1.0.4-next.1 + - @backstage/integration@1.2.2-next.1 + - @backstage/plugin-catalog-common@1.0.4-next.0 + - @backstage/plugin-permission-common@0.6.3-next.0 + - @backstage/plugin-permission-node@0.6.3-next.1 + - @backstage/plugin-search-common@0.3.6-next.0 + +## @backstage/plugin-catalog-backend-module-aws@0.1.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.1 + - @backstage/backend-tasks@0.3.3-next.1 + - @backstage/integration@1.2.2-next.1 + +## @backstage/plugin-catalog-backend-module-azure@0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.1 + - @backstage/backend-tasks@0.3.3-next.1 + - @backstage/integration@1.2.2-next.1 + +## @backstage/plugin-catalog-backend-module-bitbucket@0.2.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.1 + - @backstage/integration@1.2.2-next.1 + +## @backstage/plugin-catalog-backend-module-gerrit@0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.1 + - @backstage/backend-tasks@0.3.3-next.1 + - @backstage/integration@1.2.2-next.1 + +## @backstage/plugin-catalog-backend-module-github@0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.1 + - @backstage/backend-tasks@0.3.3-next.1 + - @backstage/integration@1.2.2-next.1 + +## @backstage/plugin-catalog-backend-module-gitlab@0.1.5-next.1 + +### Patch Changes + +- 49ff472c0b: Add the possibility in the `GitlabDiscoveryEntityProvider` to scan the whole project instead of concrete groups. For that, use a configuration like this one, where the group parameter is omitted (not mandatory anymore): + + ```yaml + catalog: + providers: + gitlab: + yourProviderId: + host: gitlab-host # Identifies one of the hosts set up in the integrations + branch: main # Optional. Uses `master` as default + entityFilename: catalog-info.yaml # Optional. Defaults to `catalog-info.yaml` + ``` + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.1 + - @backstage/backend-tasks@0.3.3-next.1 + - @backstage/integration@1.2.2-next.1 + +## @backstage/plugin-catalog-backend-module-ldap@0.5.1-next.1 + +### Patch Changes + +- fbfbff6bf7: Add possibility to resolve relations by RDN, in addition to UUID and DN +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.1 + - @backstage/backend-tasks@0.3.3-next.1 + +## @backstage/plugin-catalog-common@1.0.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.6.3-next.0 + - @backstage/plugin-search-common@0.3.6-next.0 + +## @backstage/plugin-catalog-graph@0.2.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/catalog-client@1.0.4-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## @backstage/plugin-catalog-import@0.8.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/catalog-client@1.0.4-next.1 + - @backstage/integration@1.2.2-next.1 + - @backstage/integration-react@1.1.2-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## @backstage/plugin-catalog-react@1.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + - @backstage/catalog-client@1.0.4-next.1 + - @backstage/integration@1.2.2-next.1 + - @backstage/plugin-catalog-common@1.0.4-next.0 + - @backstage/plugin-permission-common@0.6.3-next.0 + - @backstage/plugin-permission-react@0.4.3-next.0 + +## @backstage/plugin-circleci@0.3.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## @backstage/plugin-cloudbuild@0.3.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## @backstage/plugin-code-climate@0.1.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## @backstage/plugin-code-coverage@0.1.34-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## @backstage/plugin-code-coverage-backend@0.1.32-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/catalog-client@1.0.4-next.1 + - @backstage/integration@1.2.2-next.1 + +## @backstage/plugin-codescene@0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + +## @backstage/plugin-config-schema@0.1.30-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + +## @backstage/plugin-cost-insights@0.11.29-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + +## @backstage/plugin-dynatrace@0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + +## @backstage/plugin-explore@0.3.38-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## @backstage/plugin-firehydrant@0.1.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## @backstage/plugin-fossa@0.2.39-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## @backstage/plugin-gcalendar@0.3.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + +## @backstage/plugin-gcp-projects@0.3.26-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/theme@0.2.16-next.0 + +## @backstage/plugin-git-release-manager@0.3.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/integration@1.2.2-next.1 + +## @backstage/plugin-github-actions@0.5.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/integration@1.2.2-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## @backstage/plugin-github-deployments@0.1.38-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + - @backstage/integration@1.2.2-next.1 + - @backstage/integration-react@1.1.2-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## @backstage/plugin-github-pull-requests-board@0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/integration@1.2.2-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## @backstage/plugin-gitops-profiles@0.3.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/theme@0.2.16-next.0 + +## @backstage/plugin-gocd@0.1.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## @backstage/plugin-graphiql@0.2.39-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/theme@0.2.16-next.0 + +## @backstage/plugin-home@0.4.23-next.1 + +### Patch Changes + +- a46e317a75: Added support for customizing the time format used in the `HeaderWorldClock` component + + Here's an example of how this can be used in the `HomePage.tsx` found in `\packages\app\src\components\home` to change the clock to be in the 24hr time format: + + ```diff + +const timeFormat: Intl.DateTimeFormatOptions = { + + hour: '2-digit', + + minute: '2-digit', + + hour12: false, + +}; + + export const homePage = ( + +
} pageTitleOverride="Home"> + + +
+ + + + + + ``` + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/plugin-stack-overflow@0.1.3-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## @backstage/plugin-ilert@0.1.33-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## @backstage/plugin-jenkins@0.7.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + - @backstage/plugin-jenkins-common@0.1.6-next.0 + +## @backstage/plugin-jenkins-backend@0.1.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/catalog-client@1.0.4-next.1 + - @backstage/plugin-auth-node@0.2.3-next.1 + - @backstage/plugin-jenkins-common@0.1.6-next.0 + - @backstage/plugin-permission-common@0.6.3-next.0 + +## @backstage/plugin-jenkins-common@0.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-common@1.0.4-next.0 + - @backstage/plugin-permission-common@0.6.3-next.0 + +## @backstage/plugin-kafka@0.3.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## @backstage/plugin-kafka-backend@0.2.27-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + +## @backstage/plugin-kubernetes@0.6.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## @backstage/plugin-kubernetes-backend@0.7.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + +## @backstage/plugin-lighthouse@0.3.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## @backstage/plugin-newrelic@0.3.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/theme@0.2.16-next.0 + +## @backstage/plugin-newrelic-dashboard@0.1.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## @backstage/plugin-org@0.5.7-next.1 + +### Patch Changes + +- 1e984b11fc: Render namespaces for teams with subtitles in `MyGroupsSidebarItem` +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## @backstage/plugin-pagerduty@0.5.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## @backstage/plugin-periskop@0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## @backstage/plugin-permission-backend@0.5.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/plugin-auth-node@0.2.3-next.1 + - @backstage/plugin-permission-common@0.6.3-next.0 + - @backstage/plugin-permission-node@0.6.3-next.1 + +## @backstage/plugin-permission-common@0.6.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.1.0-next.0 + +## @backstage/plugin-permission-node@0.6.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/plugin-auth-node@0.2.3-next.1 + - @backstage/plugin-permission-common@0.6.3-next.0 + +## @backstage/plugin-permission-react@0.4.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.6.3-next.0 + +## @backstage/plugin-rollbar@0.4.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## @backstage/plugin-scaffolder@1.4.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + - @backstage/catalog-client@1.0.4-next.1 + - @backstage/integration@1.2.2-next.1 + - @backstage/integration-react@1.1.2-next.1 + - @backstage/plugin-catalog-common@1.0.4-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + - @backstage/plugin-permission-react@0.4.3-next.0 + +## @backstage/plugin-scaffolder-backend@1.4.0-next.1 + +### Patch Changes + +- 801d606909: Improve error messaging when passing in malformed auth +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.1 + - @backstage/catalog-client@1.0.4-next.1 + - @backstage/integration@1.2.2-next.1 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.2.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.4.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/integration@1.2.2-next.1 + +## @backstage/plugin-scaffolder-backend-module-rails@0.4.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.4.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/integration@1.2.2-next.1 + +## @backstage/plugin-search@0.9.1-next.1 + +### Patch Changes + +- 509c4092f0: To allow people to use a global search context in the search modal, the code for the search modal has been changed to only create a local search context if there is no parent context already defined. + + If you want to continue using a local context even if you define a global one, you will have to wrap the modal in a new local context manually: + + ```tsx + + + + ``` + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + - @backstage/plugin-search-common@0.3.6-next.0 + - @backstage/plugin-search-react@0.2.2-next.1 + +## @backstage/plugin-search-backend@0.5.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/plugin-auth-node@0.2.3-next.1 + - @backstage/plugin-permission-common@0.6.3-next.0 + - @backstage/plugin-permission-node@0.6.3-next.1 + - @backstage/plugin-search-backend-node@0.6.3-next.1 + - @backstage/plugin-search-common@0.3.6-next.0 + +## @backstage/plugin-search-backend-module-pg@0.3.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.1 + - @backstage/plugin-search-backend-node@0.6.3-next.1 + - @backstage/plugin-search-common@0.3.6-next.0 + +## @backstage/plugin-search-backend-node@0.6.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/backend-tasks@0.3.3-next.1 + - @backstage/plugin-permission-common@0.6.3-next.0 + - @backstage/plugin-search-common@0.3.6-next.0 + +## @backstage/plugin-search-common@0.3.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.6.3-next.0 + +## @backstage/plugin-search-react@0.2.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-search-common@0.3.6-next.0 + +## @backstage/plugin-sentry@0.3.45-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## @backstage/plugin-shortcuts@0.2.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/theme@0.2.16-next.0 + +## @backstage/plugin-sonarqube@0.3.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## @backstage/plugin-splunk-on-call@0.3.31-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## @backstage/plugin-stack-overflow@0.1.3-next.1 + +### Patch Changes + +- 52b4f796e3: app-config is now picked up properly. +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/plugin-home@0.4.23-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-search-common@0.3.6-next.0 + +## @backstage/plugin-stack-overflow-backend@0.1.3-next.0 + +### Patch Changes + +- 52b4f796e3: app-config is now picked up properly. +- Updated dependencies + - @backstage/plugin-search-common@0.3.6-next.0 + +## @backstage/plugin-tech-insights@0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## @backstage/plugin-tech-insights-backend@0.4.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/backend-tasks@0.3.3-next.1 + - @backstage/catalog-client@1.0.4-next.1 + +## @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + +## @backstage/plugin-tech-radar@0.5.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/theme@0.2.16-next.0 + +## @backstage/plugin-techdocs@1.2.1-next.1 + +### Patch Changes + +- 726577958f: Remove the 60% factor from the font size calculation of headers to use the exact size defined in BackstageTheme. +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + - @backstage/integration@1.2.2-next.1 + - @backstage/integration-react@1.1.2-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.1 + - @backstage/plugin-search-common@0.3.6-next.0 + - @backstage/plugin-search-react@0.2.2-next.1 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/plugin-catalog@1.3.1-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-techdocs@1.2.1-next.1 + - @backstage/integration-react@1.1.2-next.1 + - @backstage/test-utils@1.1.2-next.1 + - @backstage/plugin-search-react@0.2.2-next.1 + +## @backstage/plugin-techdocs-module-addons-contrib@1.0.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/integration@1.2.2-next.1 + - @backstage/integration-react@1.1.2-next.1 + +## @backstage/plugin-todo@0.2.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## @backstage/plugin-todo-backend@0.1.31-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/catalog-client@1.0.4-next.1 + - @backstage/integration@1.2.2-next.1 + +## @backstage/plugin-user-settings@0.4.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/theme@0.2.16-next.0 + +## @backstage/plugin-vault@0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## @backstage/plugin-vault-backend@0.2.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/backend-tasks@0.3.3-next.1 + - @backstage/backend-test-utils@0.1.26-next.1 + +## @backstage/plugin-xcmetrics@0.2.27-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + +## example-app@0.2.73-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/cli@0.18.0-next.1 + - @backstage/plugin-apache-airflow@0.2.0-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/plugin-search@0.9.1-next.1 + - @backstage/plugin-org@0.5.7-next.1 + - @backstage/plugin-catalog@1.3.1-next.1 + - @backstage/plugin-home@0.4.23-next.1 + - @backstage/plugin-stack-overflow@0.1.3-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-techdocs@1.2.1-next.1 + - @backstage/app-defaults@1.0.4-next.1 + - @backstage/integration-react@1.1.2-next.1 + - @backstage/plugin-airbrake@0.3.7-next.1 + - @backstage/plugin-api-docs@0.8.7-next.1 + - @backstage/plugin-azure-devops@0.1.23-next.1 + - @backstage/plugin-badges@0.2.31-next.1 + - @backstage/plugin-catalog-common@1.0.4-next.0 + - @backstage/plugin-catalog-graph@0.2.19-next.1 + - @backstage/plugin-catalog-import@0.8.10-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.1 + - @backstage/plugin-circleci@0.3.7-next.1 + - @backstage/plugin-cloudbuild@0.3.7-next.1 + - @backstage/plugin-code-coverage@0.1.34-next.1 + - @backstage/plugin-cost-insights@0.11.29-next.1 + - @backstage/plugin-dynatrace@0.1.1-next.1 + - @backstage/plugin-explore@0.3.38-next.1 + - @backstage/plugin-gcalendar@0.3.3-next.1 + - @backstage/plugin-gcp-projects@0.3.26-next.1 + - @backstage/plugin-github-actions@0.5.7-next.1 + - @backstage/plugin-gocd@0.1.13-next.1 + - @backstage/plugin-graphiql@0.2.39-next.1 + - @backstage/plugin-jenkins@0.7.6-next.1 + - @backstage/plugin-kafka@0.3.7-next.1 + - @backstage/plugin-kubernetes@0.6.7-next.1 + - @backstage/plugin-lighthouse@0.3.7-next.1 + - @backstage/plugin-newrelic@0.3.25-next.1 + - @backstage/plugin-newrelic-dashboard@0.1.15-next.1 + - @backstage/plugin-pagerduty@0.5.0-next.1 + - @backstage/plugin-permission-react@0.4.3-next.0 + - @backstage/plugin-rollbar@0.4.7-next.1 + - @backstage/plugin-scaffolder@1.4.0-next.1 + - @backstage/plugin-search-common@0.3.6-next.0 + - @backstage/plugin-sentry@0.3.45-next.1 + - @backstage/plugin-shortcuts@0.2.8-next.1 + - @backstage/plugin-tech-insights@0.2.3-next.1 + - @backstage/plugin-tech-radar@0.5.14-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.0.2-next.1 + - @backstage/plugin-todo@0.2.9-next.1 + - @backstage/plugin-user-settings@0.4.6-next.1 + - @backstage/plugin-search-react@0.2.2-next.1 + +## example-backend@0.2.73-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.4.0-next.1 + - @backstage/plugin-auth-backend@0.15.0-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@0.2.0-next.1 + - @backstage/plugin-catalog-backend@1.2.1-next.1 + - @backstage/plugin-techdocs-backend@1.2.0-next.1 + - example-app@0.2.73-next.1 + - @backstage/backend-tasks@0.3.3-next.1 + - @backstage/catalog-client@1.0.4-next.1 + - @backstage/integration@1.2.2-next.1 + - @backstage/plugin-app-backend@0.3.34-next.1 + - @backstage/plugin-auth-node@0.2.3-next.1 + - @backstage/plugin-badges-backend@0.1.28-next.1 + - @backstage/plugin-code-coverage-backend@0.1.32-next.1 + - @backstage/plugin-jenkins-backend@0.1.24-next.1 + - @backstage/plugin-kafka-backend@0.2.27-next.1 + - @backstage/plugin-kubernetes-backend@0.7.0-next.1 + - @backstage/plugin-permission-backend@0.5.9-next.1 + - @backstage/plugin-permission-common@0.6.3-next.0 + - @backstage/plugin-permission-node@0.6.3-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.2-next.1 + - @backstage/plugin-search-backend@0.5.4-next.1 + - @backstage/plugin-search-backend-module-pg@0.3.5-next.1 + - @backstage/plugin-search-backend-node@0.6.3-next.1 + - @backstage/plugin-tech-insights-backend@0.4.2-next.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.18-next.1 + - @backstage/plugin-todo-backend@0.1.31-next.1 + +## techdocs-cli-embedded-app@0.2.72-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/cli@0.18.0-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/plugin-catalog@1.3.1-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-techdocs@1.2.1-next.1 + - @backstage/app-defaults@1.0.4-next.1 + - @backstage/integration-react@1.1.2-next.1 + - @backstage/test-utils@1.1.2-next.1 + +## @internal/plugin-todo-list@1.0.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/theme@0.2.16-next.0 + +## @internal/plugin-todo-list-backend@1.0.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/plugin-auth-node@0.2.3-next.1 + +## @internal/plugin-todo-list-common@1.0.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.6.3-next.0 diff --git a/docs/releases/v1.4.0-next.2-changelog.md b/docs/releases/v1.4.0-next.2-changelog.md new file mode 100644 index 0000000000..fe00c648dd --- /dev/null +++ b/docs/releases/v1.4.0-next.2-changelog.md @@ -0,0 +1,1308 @@ +# Release v1.4.0-next.2 + +## @backstage/catalog-model@1.1.0-next.2 + +### Minor Changes + +- 4cc81372f8: Introduced `GroupDefaultParentEntityPolicy` to set a default group entity parent. + +## @backstage/core-components@0.10.0-next.2 + +### Minor Changes + +- 32204fa794: Add `transformLinkUri` and `transformImageUri` to `MarkdownContent` + +### Patch Changes + +- b4b711bcc2: Fix the EntityLayout header style so that EntityContextMenu button can display in correct shape when user hover on it +- 15201b1032: Updated dependency `rc-progress` to `3.4.0`. +- 385389d23c: Updated to remove usage of the `bursts` object in the theme palette +- Updated dependencies + - @backstage/theme@0.2.16-next.1 + +## @backstage/plugin-catalog@1.4.0-next.2 + +### Minor Changes + +- a274fe38b9: Add hidden title column to catalog and API table to enable filtering by title. + +### Patch Changes + +- 258057a4b9: Adding ability to customize the "unregister entity" menu item in the entity context menu on the entity page with options 'visible','hidden','disabled'.With this three new options, one can hide the "unregister entity" menu item from the list, disable or keep it enabled. + + The boolean input for "unregister entity" will be deprecated later in favour of the above three options. + +- 385389d23c: Updated to remove usage of the `bursts` object in the theme palette + +- be26d95141: Added new `EntityProcessingStatusPicker` that will filter for entities with orphans and/or errors. + + If you are using the default Catalog page this picker will be added automatically. For those who have customized their Catalog page you'll need to add this manually by doing something like this: + + ```diff + ... + import { + CatalogFilterLayout, + EntityTypePicker, + UserListPicker, + EntityTagPicker + + EntityProcessingStatusPicker, + } from '@backstage/plugin-catalog-react'; + ... + export const CustomCatalogPage = ({ + columns, + actions, + initiallySelectedFilter = 'owned', + }: CatalogPageProps) => { + return ( + ... + + + + + + ... + }; + ``` + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/plugin-search-react@0.2.2-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + - @backstage/integration-react@1.1.2-next.2 + +## @backstage/plugin-catalog-backend-module-msgraph@0.4.0-next.1 + +### Minor Changes + +- a145672f0f: Align `msgraph` plugin's entity provider config with other providers. **Deprecated** entity processor as well as previous config. + + You will see warning at the log output until you migrate to the new setup. + All deprecated parts will be removed eventually after giving some time to migrate. + + Please find information on how to migrate your current setup to the new one below. + + **Migration Guide:** + + There were two different way on how to use the msgraph plugin: processor or provider. + + Previous registration for the processor: + + ```typescript + // packages/backend/src/plugins/catalog.ts + builder.addProcessor( + MicrosoftGraphOrgReaderProcessor.fromConfig(env.config, { + logger: env.logger, + // [...] + }), + ); + ``` + + Previous registration when using the provider: + + ```typescript + // packages/backend/src/plugins/catalog.ts + builder.addEntityProvider( + MicrosoftGraphOrgEntityProvider.fromConfig(env.config, { + id: 'https://graph.microsoft.com/v1.0', + target: 'https://graph.microsoft.com/v1.0', + logger: env.logger, + schedule: env.scheduler.createScheduledTaskRunner({ + frequency: { minutes: 30 }, + timeout: { minutes: 3 }, + }), + // [...] + }), + ); + ``` + + Previous configuration as used for both: + + ```yaml + # app-config.yaml + catalog: + processors: + microsoftGraphOrg: + providers: + - target: https://graph.microsoft.com/v1.0 + # [...] + ``` + + **Replacement:** + + Please check for the complete documentation of all configuration options (config as well as registration of the provider). + + ```yaml + # app-config.yaml + catalog: + providers: + microsoftGraphOrg: + # In case you used the deprecated configuration with the entity provider + # using the value of `target` will keep the same location key for all + providerId: # some stable ID which will be used as part of the location key for all ingested data + target: https://graph.microsoft.com/v1.0 + # [...] + ``` + + ```typescript + // packages/backend/src/plugins/catalog.ts + builder.addEntityProvider( + MicrosoftGraphOrgEntityProvider.fromConfig(env.config, { + logger: env.logger, + schedule: env.scheduler.createScheduledTaskRunner({ + frequency: { minutes: 30 }, + timeout: { minutes: 3 }, + }), + // [...] + }), + ); + ``` + + In case you've used multiple entity providers before + **and** you had different transformers for each of them + you can provide these directly at the one `fromConfig` call + by passing a Record with the provider ID as key. + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/backend-tasks@0.3.3-next.2 + - @backstage/plugin-catalog-backend@1.2.1-next.2 + +## @backstage/plugin-cost-insights-common@0.1.0-next.0 + +### Minor Changes + +- 81dd5ea989: Introduces a new isomorphic @backstage/plugin-cost-insight-common package to contain shared types across all other cost insights packages and modules. + +## @backstage/plugin-scaffolder@1.4.0-next.2 + +### Minor Changes + +- d8eb82f447: Add `allowedRepos` `ui:option` to `RepoUrlPicker` component, and move `repoName` field to own component + +### Patch Changes + +- e2d7b76f43: Upgrade git-url-parse to 12.0.0. + + Motivation for upgrade is transitively upgrading parse-url which is vulnerable + to several CVEs detected by Snyk. + + - SNYK-JS-PARSEURL-2935944 + - SNYK-JS-PARSEURL-2935947 + - SNYK-JS-PARSEURL-2936249 + +- 14146703e5: Add `allowArbitraryValues` to `ui:options` in `OwnedEntityPicker`, similar to `allowArbitraryValues` in `EntityPicker` + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/integration@1.2.2-next.2 + - @backstage/plugin-catalog-react@1.1.2-next.2 + - @backstage/integration-react@1.1.2-next.2 + +## @backstage/plugin-scaffolder-backend@1.4.0-next.2 + +### Minor Changes + +- 4baf8a4ece: Update GitLab Merge Request Action to allow source branch to be deleted +- 2db07887cb: Added two new scaffolder actions: `github:repo:create` and `github:repo:push` + +### Patch Changes + +- 679b32172e: Updated dependency `knex` to `^2.0.0`. + +- e2d7b76f43: Upgrade git-url-parse to 12.0.0. + + Motivation for upgrade is transitively upgrading parse-url which is vulnerable + to several CVEs detected by Snyk. + + - SNYK-JS-PARSEURL-2935944 + - SNYK-JS-PARSEURL-2935947 + - SNYK-JS-PARSEURL-2936249 + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/backend-common@0.14.1-next.2 + - @backstage/plugin-catalog-backend@1.2.1-next.2 + - @backstage/integration@1.2.2-next.2 + +## @backstage/plugin-tech-insights-backend@0.5.0-next.2 + +### Minor Changes + +- 818fa28d71: Allow FactRetrieverRegistry to be injected into buildTechInsightsContext so that we can override default registry implementation. + +### Patch Changes + +- 679b32172e: Updated dependency `knex` to `^2.0.0`. +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/backend-common@0.14.1-next.2 + - @backstage/backend-tasks@0.3.3-next.2 + +## @backstage/app-defaults@1.0.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + +## @backstage/backend-common@0.14.1-next.2 + +### Patch Changes + +- 679b32172e: Updated dependency `knex` to `^2.0.0`. + +- e2d7b76f43: Upgrade git-url-parse to 12.0.0. + + Motivation for upgrade is transitively upgrading parse-url which is vulnerable + to several CVEs detected by Snyk. + + - SNYK-JS-PARSEURL-2935944 + - SNYK-JS-PARSEURL-2935947 + - SNYK-JS-PARSEURL-2936249 + +- Updated dependencies + - @backstage/integration@1.2.2-next.2 + +## @backstage/backend-tasks@0.3.3-next.2 + +### Patch Changes + +- 679b32172e: Updated dependency `knex` to `^2.0.0`. +- Updated dependencies + - @backstage/backend-common@0.14.1-next.2 + +## @backstage/backend-test-utils@0.1.26-next.2 + +### Patch Changes + +- 679b32172e: Updated dependency `knex` to `^2.0.0`. +- Updated dependencies + - @backstage/backend-common@0.14.1-next.2 + - @backstage/cli@0.18.0-next.2 + +## @backstage/cli@0.18.0-next.2 + +### Patch Changes + +- f6b6fb7165: The `test` command now ensures that all IO is flushed before exiting when printing `--help`. + +## @backstage/create-app@0.4.29-next.2 + +### Patch Changes + +- f281ad17c0: Adds the ability to define the Backstage app name using a `BACKSTAGE_APP_NAME` + environment variable when running `create-app`. + +## @backstage/dev-utils@1.0.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + - @backstage/app-defaults@1.0.4-next.2 + - @backstage/integration-react@1.1.2-next.2 + +## @backstage/integration@1.2.2-next.2 + +### Patch Changes + +- e2d7b76f43: Upgrade git-url-parse to 12.0.0. + + Motivation for upgrade is transitively upgrading parse-url which is vulnerable + to several CVEs detected by Snyk. + + - SNYK-JS-PARSEURL-2935944 + - SNYK-JS-PARSEURL-2935947 + - SNYK-JS-PARSEURL-2936249 + +## @backstage/integration-react@1.1.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/integration@1.2.2-next.2 + +## @backstage/theme@0.2.16-next.1 + +### Patch Changes + +- ff4f56eb49: **DEPRECATED**: The `bursts` object from `BackstagePaletteAdditions` has been depreciated and will be removed in a future release + + The `genPageTheme` function now includes an optional options object with an optional `fontColor` which defaults to white if not provided. + +## @backstage/plugin-adr@0.1.2-next.2 + +### Patch Changes + +- e2d7b76f43: Upgrade git-url-parse to 12.0.0. + + Motivation for upgrade is transitively upgrading parse-url which is vulnerable + to several CVEs detected by Snyk. + + - SNYK-JS-PARSEURL-2935944 + - SNYK-JS-PARSEURL-2935947 + - SNYK-JS-PARSEURL-2936249 + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/plugin-search-react@0.2.2-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + - @backstage/integration-react@1.1.2-next.2 + +## @backstage/plugin-airbrake@0.3.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + - @backstage/dev-utils@1.0.4-next.2 + +## @backstage/plugin-allure@0.1.23-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## @backstage/plugin-analytics-module-ga@0.1.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + +## @backstage/plugin-apache-airflow@0.2.0-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + +## @backstage/plugin-api-docs@0.8.7-next.2 + +### Patch Changes + +- a274fe38b9: Add hidden title column to catalog and API table to enable filtering by title. +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog@1.4.0-next.2 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## @backstage/plugin-app-backend@0.3.34-next.2 + +### Patch Changes + +- 679b32172e: Updated dependency `knex` to `^2.0.0`. +- Updated dependencies + - @backstage/backend-common@0.14.1-next.2 + +## @backstage/plugin-auth-backend@0.15.0-next.2 + +### Patch Changes + +- 8e03db907a: Auth provider now also export createAuthProviderIntegration +- 679b32172e: Updated dependency `knex` to `^2.0.0`. +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/backend-common@0.14.1-next.2 + +## @backstage/plugin-azure-devops@0.1.23-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## @backstage/plugin-badges@0.2.31-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## @backstage/plugin-badges-backend@0.1.28-next.2 + +### Patch Changes + +- 58fd5ee9d5: Add missing installation instructions +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/backend-common@0.14.1-next.2 + +## @backstage/plugin-bazaar@0.1.22-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/plugin-catalog@1.4.0-next.2 + - @backstage/cli@0.18.0-next.2 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## @backstage/plugin-bazaar-backend@0.1.18-next.1 + +### Patch Changes + +- 679b32172e: Updated dependency `knex` to `^2.0.0`. +- Updated dependencies + - @backstage/backend-common@0.14.1-next.2 + - @backstage/backend-test-utils@0.1.26-next.2 + +## @backstage/plugin-bitrise@0.1.34-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## @backstage/plugin-catalog-backend@1.2.1-next.2 + +### Patch Changes + +- 679b32172e: Updated dependency `knex` to `^2.0.0`. + +- e2d7b76f43: Upgrade git-url-parse to 12.0.0. + + Motivation for upgrade is transitively upgrading parse-url which is vulnerable + to several CVEs detected by Snyk. + + - SNYK-JS-PARSEURL-2935944 + - SNYK-JS-PARSEURL-2935947 + - SNYK-JS-PARSEURL-2936249 + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/backend-common@0.14.1-next.2 + - @backstage/integration@1.2.2-next.2 + +## @backstage/plugin-catalog-backend-module-openapi@0.1.0-next.1 + +### Patch Changes + +- 4881dc4c84: Updated dependency `openapi-types` to `^12.0.0`. +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/backend-common@0.14.1-next.2 + - @backstage/plugin-catalog-backend@1.2.1-next.2 + - @backstage/integration@1.2.2-next.2 + +## @backstage/plugin-catalog-graph@0.2.19-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## @backstage/plugin-catalog-import@0.8.10-next.2 + +### Patch Changes + +- e2d7b76f43: Upgrade git-url-parse to 12.0.0. + + Motivation for upgrade is transitively upgrading parse-url which is vulnerable + to several CVEs detected by Snyk. + + - SNYK-JS-PARSEURL-2935944 + - SNYK-JS-PARSEURL-2935947 + - SNYK-JS-PARSEURL-2936249 + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/integration@1.2.2-next.2 + - @backstage/plugin-catalog-react@1.1.2-next.2 + - @backstage/integration-react@1.1.2-next.2 + +## @backstage/plugin-catalog-react@1.1.2-next.2 + +### Patch Changes + +- be26d95141: Added new `EntityProcessingStatusPicker` that will filter for entities with orphans and/or errors. + + If you are using the default Catalog page this picker will be added automatically. For those who have customized their Catalog page you'll need to add this manually by doing something like this: + + ```diff + ... + import { + CatalogFilterLayout, + EntityTypePicker, + UserListPicker, + EntityTagPicker + + EntityProcessingStatusPicker, + } from '@backstage/plugin-catalog-react'; + ... + export const CustomCatalogPage = ({ + columns, + actions, + initiallySelectedFilter = 'owned', + }: CatalogPageProps) => { + return ( + ... + + + + + + ... + }; + ``` + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/integration@1.2.2-next.2 + +## @backstage/plugin-circleci@0.3.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## @backstage/plugin-cloudbuild@0.3.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## @backstage/plugin-code-climate@0.1.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## @backstage/plugin-code-coverage@0.1.34-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## @backstage/plugin-code-coverage-backend@0.1.32-next.2 + +### Patch Changes + +- 679b32172e: Updated dependency `knex` to `^2.0.0`. +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/backend-common@0.14.1-next.2 + - @backstage/integration@1.2.2-next.2 + +## @backstage/plugin-codescene@0.1.2-next.2 + +### Patch Changes + +- 15201b1032: Updated dependency `rc-progress` to `3.4.0`. +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + +## @backstage/plugin-config-schema@0.1.30-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + +## @backstage/plugin-cost-insights@0.11.29-next.2 + +### Patch Changes + +- 3e032a5de2: Move cost-insights data specific API types (non react) into an @backstage/plugin-cost-insights-common + isomorphic package. This allows these types to be shared in any backend packages or other cost-insight + modules. +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/plugin-cost-insights-common@0.1.0-next.0 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + +## @backstage/plugin-dynatrace@0.1.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + +## @backstage/plugin-explore@0.3.38-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## @backstage/plugin-firehydrant@0.1.24-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## @backstage/plugin-fossa@0.2.39-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## @backstage/plugin-gcalendar@0.3.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + +## @backstage/plugin-gcp-projects@0.3.26-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + +## @backstage/plugin-git-release-manager@0.3.20-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/integration@1.2.2-next.2 + +## @backstage/plugin-github-actions@0.5.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/integration@1.2.2-next.2 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## @backstage/plugin-github-deployments@0.1.38-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/integration@1.2.2-next.2 + - @backstage/plugin-catalog-react@1.1.2-next.2 + - @backstage/integration-react@1.1.2-next.2 + +## @backstage/plugin-github-pull-requests-board@0.1.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/integration@1.2.2-next.2 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## @backstage/plugin-gitops-profiles@0.3.25-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + +## @backstage/plugin-gocd@0.1.13-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## @backstage/plugin-graphiql@0.2.39-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + +## @backstage/plugin-home@0.4.23-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + - @backstage/plugin-stack-overflow@0.1.3-next.2 + +## @backstage/plugin-ilert@0.1.33-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## @backstage/plugin-jenkins@0.7.6-next.2 + +### Patch Changes + +- 8747824221: feature: added support for multiple branches to the `JenkinsApi` +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## @backstage/plugin-jenkins-backend@0.1.24-next.2 + +### Patch Changes + +- 8747824221: feature: added support for multiple branches to the `JenkinsApi` +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/backend-common@0.14.1-next.2 + +## @backstage/plugin-kafka@0.3.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## @backstage/plugin-kafka-backend@0.2.27-next.2 + +### Patch Changes + +- 8751667541: Updated dependency `kafkajs` to `^2.0.0`. +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/backend-common@0.14.1-next.2 + +## @backstage/plugin-kubernetes@0.6.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/plugin-kubernetes-common@0.4.0-next.1 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## @backstage/plugin-kubernetes-backend@0.7.0-next.2 + +### Patch Changes + +- 60e5f9fe68: Fixed the lack of `limitranges` as part of the Default Objects to fetch from the kubernetes api +- Updated dependencies + - @backstage/plugin-kubernetes-common@0.4.0-next.1 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/backend-common@0.14.1-next.2 + +## @backstage/plugin-kubernetes-common@0.4.0-next.1 + +### Patch Changes + +- 60e5f9fe68: Fixed the lack of `limitranges` as part of the Default Objects to fetch from the kubernetes api +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.2 + +## @backstage/plugin-lighthouse@0.3.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## @backstage/plugin-newrelic@0.3.25-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + +## @backstage/plugin-newrelic-dashboard@0.1.15-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## @backstage/plugin-org@0.5.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## @backstage/plugin-pagerduty@0.5.0-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## @backstage/plugin-periskop@0.1.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## @backstage/plugin-rollbar@0.4.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## @backstage/plugin-search@0.9.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/plugin-search-react@0.2.2-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## @backstage/plugin-search-backend-module-pg@0.3.5-next.2 + +### Patch Changes + +- 423e3d8e95: **DEPRECATED**: `PgSearchEngine` static `from` has been deprecated and will be removed in a future release. Use static `fromConfig` method to instantiate. + + Added support for highlighting matched terms in search result data + +- 679b32172e: Updated dependency `knex` to `^2.0.0`. + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.2 + +## @backstage/plugin-search-react@0.2.2-next.2 + +### Patch Changes + +- 60408ca9d4: Fix search pagination to reset page cursor also when a term is cleared. +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + +## @backstage/plugin-sentry@0.3.45-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## @backstage/plugin-shortcuts@0.2.8-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + +## @backstage/plugin-sonarqube@0.3.7-next.2 + +### Patch Changes + +- 15201b1032: Updated dependency `rc-progress` to `3.4.0`. +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## @backstage/plugin-splunk-on-call@0.3.31-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## @backstage/plugin-stack-overflow@0.1.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-home@0.4.23-next.2 + +## @backstage/plugin-tech-insights@0.2.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## @backstage/plugin-tech-radar@0.5.14-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + +## @backstage/plugin-techdocs@1.2.1-next.2 + +### Patch Changes + +- e2d7b76f43: Upgrade git-url-parse to 12.0.0. + + Motivation for upgrade is transitively upgrading parse-url which is vulnerable + to several CVEs detected by Snyk. + + - SNYK-JS-PARSEURL-2935944 + - SNYK-JS-PARSEURL-2935947 + - SNYK-JS-PARSEURL-2936249 + +- 7739141ab2: Fix: When docs are shown in an entity page under the docs tab the sidebars start overlapping with the header and tabs in the page when you scroll the documentation content. + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/plugin-search-react@0.2.2-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/integration@1.2.2-next.2 + - @backstage/plugin-catalog-react@1.1.2-next.2 + - @backstage/integration-react@1.1.2-next.2 + - @backstage/plugin-techdocs-react@1.0.2-next.1 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/plugin-search-react@0.2.2-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-techdocs@1.2.1-next.2 + - @backstage/plugin-catalog@1.4.0-next.2 + - @backstage/integration-react@1.1.2-next.2 + - @backstage/plugin-techdocs-react@1.0.2-next.1 + +## @backstage/plugin-techdocs-backend@1.2.0-next.2 + +### Patch Changes + +- 679b32172e: Updated dependency `knex` to `^2.0.0`. +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/backend-common@0.14.1-next.2 + - @backstage/integration@1.2.2-next.2 + - @backstage/plugin-techdocs-node@1.2.0-next.2 + +## @backstage/plugin-techdocs-module-addons-contrib@1.0.2-next.2 + +### Patch Changes + +- e2d7b76f43: Upgrade git-url-parse to 12.0.0. + + Motivation for upgrade is transitively upgrading parse-url which is vulnerable + to several CVEs detected by Snyk. + + - SNYK-JS-PARSEURL-2935944 + - SNYK-JS-PARSEURL-2935947 + - SNYK-JS-PARSEURL-2936249 + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/integration@1.2.2-next.2 + - @backstage/integration-react@1.1.2-next.2 + - @backstage/plugin-techdocs-react@1.0.2-next.1 + +## @backstage/plugin-techdocs-node@1.2.0-next.2 + +### Patch Changes + +- e2d7b76f43: Upgrade git-url-parse to 12.0.0. + + Motivation for upgrade is transitively upgrading parse-url which is vulnerable + to several CVEs detected by Snyk. + + - SNYK-JS-PARSEURL-2935944 + - SNYK-JS-PARSEURL-2935947 + - SNYK-JS-PARSEURL-2936249 + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/backend-common@0.14.1-next.2 + - @backstage/integration@1.2.2-next.2 + +## @backstage/plugin-techdocs-react@1.0.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + +## @backstage/plugin-todo@0.2.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## @backstage/plugin-user-settings@0.4.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + +## @backstage/plugin-vault@0.1.1-next.2 + +### Patch Changes + +- 7ee4abdcc9: Added a path notion in addition to secret name to allow to differentiate secrets in sub-paths +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## @backstage/plugin-vault-backend@0.2.0-next.2 + +### Patch Changes + +- 7ee4abdcc9: Added a path notion in addition to secret name to allow to differentiate secrets in sub-paths +- Updated dependencies + - @backstage/backend-common@0.14.1-next.2 + - @backstage/backend-tasks@0.3.3-next.2 + - @backstage/backend-test-utils@0.1.26-next.2 + +## @backstage/plugin-xcmetrics@0.2.27-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + +## example-app@0.2.73-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-cost-insights@0.11.29-next.2 + - @backstage/core-components@0.10.0-next.2 + - @backstage/plugin-scaffolder@1.4.0-next.2 + - @backstage/plugin-jenkins@0.7.6-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/plugin-search-react@0.2.2-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-import@0.8.10-next.2 + - @backstage/plugin-techdocs@1.2.1-next.2 + - @backstage/plugin-techdocs-module-addons-contrib@1.0.2-next.2 + - @backstage/plugin-api-docs@0.8.7-next.2 + - @backstage/plugin-catalog@1.4.0-next.2 + - @backstage/cli@0.18.0-next.2 + - @backstage/plugin-catalog-react@1.1.2-next.2 + - @backstage/app-defaults@1.0.4-next.2 + - @backstage/integration-react@1.1.2-next.2 + - @backstage/plugin-airbrake@0.3.7-next.2 + - @backstage/plugin-apache-airflow@0.2.0-next.2 + - @backstage/plugin-azure-devops@0.1.23-next.2 + - @backstage/plugin-badges@0.2.31-next.2 + - @backstage/plugin-catalog-graph@0.2.19-next.2 + - @backstage/plugin-circleci@0.3.7-next.2 + - @backstage/plugin-cloudbuild@0.3.7-next.2 + - @backstage/plugin-code-coverage@0.1.34-next.2 + - @backstage/plugin-dynatrace@0.1.1-next.2 + - @backstage/plugin-explore@0.3.38-next.2 + - @backstage/plugin-gcalendar@0.3.3-next.2 + - @backstage/plugin-gcp-projects@0.3.26-next.2 + - @backstage/plugin-github-actions@0.5.7-next.2 + - @backstage/plugin-gocd@0.1.13-next.2 + - @backstage/plugin-graphiql@0.2.39-next.2 + - @backstage/plugin-home@0.4.23-next.2 + - @backstage/plugin-kafka@0.3.7-next.2 + - @backstage/plugin-kubernetes@0.6.7-next.2 + - @backstage/plugin-lighthouse@0.3.7-next.2 + - @backstage/plugin-newrelic@0.3.25-next.2 + - @backstage/plugin-newrelic-dashboard@0.1.15-next.2 + - @backstage/plugin-org@0.5.7-next.2 + - @backstage/plugin-pagerduty@0.5.0-next.2 + - @backstage/plugin-rollbar@0.4.7-next.2 + - @backstage/plugin-search@0.9.1-next.2 + - @backstage/plugin-sentry@0.3.45-next.2 + - @backstage/plugin-shortcuts@0.2.8-next.2 + - @backstage/plugin-stack-overflow@0.1.3-next.2 + - @backstage/plugin-tech-insights@0.2.3-next.2 + - @backstage/plugin-tech-radar@0.5.14-next.2 + - @backstage/plugin-techdocs-react@1.0.2-next.1 + - @backstage/plugin-todo@0.2.9-next.2 + - @backstage/plugin-user-settings@0.4.6-next.2 + +## example-backend@0.2.73-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes-backend@0.7.0-next.2 + - @backstage/plugin-tech-insights-backend@0.5.0-next.2 + - @backstage/plugin-jenkins-backend@0.1.24-next.2 + - @backstage/plugin-search-backend-module-pg@0.3.5-next.2 + - @backstage/plugin-scaffolder-backend@1.4.0-next.2 + - @backstage/plugin-auth-backend@0.15.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/plugin-kafka-backend@0.2.27-next.2 + - @backstage/backend-common@0.14.1-next.2 + - @backstage/backend-tasks@0.3.3-next.2 + - @backstage/plugin-app-backend@0.3.34-next.2 + - @backstage/plugin-catalog-backend@1.2.1-next.2 + - @backstage/plugin-code-coverage-backend@0.1.32-next.2 + - @backstage/plugin-techdocs-backend@1.2.0-next.2 + - @backstage/plugin-badges-backend@0.1.28-next.2 + - @backstage/integration@1.2.2-next.2 + - example-app@0.2.73-next.2 + +## techdocs-cli-embedded-app@0.2.72-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-techdocs@1.2.1-next.2 + - @backstage/plugin-catalog@1.4.0-next.2 + - @backstage/cli@0.18.0-next.2 + - @backstage/app-defaults@1.0.4-next.2 + - @backstage/integration-react@1.1.2-next.2 + - @backstage/plugin-techdocs-react@1.0.2-next.1 + +## @internal/plugin-todo-list@1.0.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 diff --git a/microsite/data/on-demand/20211117-01.yaml b/microsite/data/on-demand/20211117-1.yaml similarity index 100% rename from microsite/data/on-demand/20211117-01.yaml rename to microsite/data/on-demand/20211117-1.yaml diff --git a/microsite/data/on-demand/20211118-01.yaml b/microsite/data/on-demand/20211118-1.yaml similarity index 100% rename from microsite/data/on-demand/20211118-01.yaml rename to microsite/data/on-demand/20211118-1.yaml diff --git a/microsite/data/on-demand/20211215-01.yaml b/microsite/data/on-demand/20211215-1.yaml similarity index 100% rename from microsite/data/on-demand/20211215-01.yaml rename to microsite/data/on-demand/20211215-1.yaml diff --git a/microsite/data/on-demand/20211216-01.yaml b/microsite/data/on-demand/20211216-1.yaml similarity index 100% rename from microsite/data/on-demand/20211216-01.yaml rename to microsite/data/on-demand/20211216-1.yaml diff --git a/microsite/data/on-demand/20220216-01.yaml b/microsite/data/on-demand/20220216-1.yaml similarity index 100% rename from microsite/data/on-demand/20220216-01.yaml rename to microsite/data/on-demand/20220216-1.yaml diff --git a/microsite/data/on-demand/20220223-01.yaml b/microsite/data/on-demand/20220223-1.yaml similarity index 100% rename from microsite/data/on-demand/20220223-01.yaml rename to microsite/data/on-demand/20220223-1.yaml diff --git a/microsite/data/on-demand/20220518-01.yaml b/microsite/data/on-demand/20220518-1.yaml similarity index 100% rename from microsite/data/on-demand/20220518-01.yaml rename to microsite/data/on-demand/20220518-1.yaml diff --git a/microsite/data/on-demand/20220525.yaml b/microsite/data/on-demand/20220525-1.yaml similarity index 100% rename from microsite/data/on-demand/20220525.yaml rename to microsite/data/on-demand/20220525-1.yaml diff --git a/microsite/data/on-demand/20220615-01.yaml b/microsite/data/on-demand/20220615-1.yaml similarity index 97% rename from microsite/data/on-demand/20220615-01.yaml rename to microsite/data/on-demand/20220615-1.yaml index 8ac660a71c..fb296dd6ce 100644 --- a/microsite/data/on-demand/20220615-01.yaml +++ b/microsite/data/on-demand/20220615-1.yaml @@ -1,7 +1,7 @@ --- title: Adopters Community Sessions date: June 15, 2022 -category: Upcoming +category: Meetup description: Adopters Community Session ✨. It's the monthly meetup where we all come together to listen to the latest maintainer updates, learn from each other about adopting, share exciting new demos or discuss any relevant topic like developer effectiveness, developer experience, developer portals, etc. youtubeUrl: https://youtu.be/aKZnjnE5Wy8 youtubeImgUrl: https://backstage.io/img/b-sessions.png diff --git a/microsite/data/on-demand/20220622-1.yaml b/microsite/data/on-demand/20220622-1.yaml index 0bbd53525a..27634609cb 100644 --- a/microsite/data/on-demand/20220622-1.yaml +++ b/microsite/data/on-demand/20220622-1.yaml @@ -1,9 +1,9 @@ --- title: Contributor Community Sessions date: June 22, 2022 -category: Upcoming +category: Meetup description: Join the maintainers and contributors for the Contributor Community Sessions -youtubeUrl: https://youtu.be/aKZnjnE5Wy8 +youtubeUrl: https://youtu.be/E-jWqWXBxUY youtubeImgUrl: https://backstage.io/img/b-sessions.png rsvpUrl: https://calendar.google.com/calendar/embed?src=c_qup9gbhn9sqpuao6trttd8mk5s@group.calendar.google.com eventUrl: https://github.com/backstage/community/issues/49 diff --git a/microsite/data/on-demand/20220720-1.yaml b/microsite/data/on-demand/20220720-1.yaml new file mode 100644 index 0000000000..a1f51859f4 --- /dev/null +++ b/microsite/data/on-demand/20220720-1.yaml @@ -0,0 +1,9 @@ +--- +title: Adopters Community Sessions +date: July 20, 2022 +category: Upcoming +description: Adopters Community Session ✨. It's the monthly meetup where we all come together to listen to the latest maintainer updates, learn from each other about adopting, share exciting new demos or discuss any relevant topic like developer effectiveness, developer experience, developer portals, etc. +youtubeUrl: https://youtu.be/4VFNlPxWcx8 +youtubeImgUrl: https://backstage.io/img/b-sessions.png +rsvpUrl: https://calendar.google.com/calendar/embed?src=c_qup9gbhn9sqpuao6trttd8mk5s@group.calendar.google.com +eventUrl: https://github.com/backstage/community/issues/52 diff --git a/microsite/data/on-demand/20220727-1.yaml b/microsite/data/on-demand/20220727-1.yaml new file mode 100644 index 0000000000..5f7712596f --- /dev/null +++ b/microsite/data/on-demand/20220727-1.yaml @@ -0,0 +1,9 @@ +--- +title: Contributor Community Sessions +date: July 27, 2022 +category: Upcoming +description: Join the maintainers and contributors for the Contributor Community Sessions +youtubeUrl: https://youtu.be/4VFNlPxWcx8 +youtubeImgUrl: https://backstage.io/img/b-sessions.png +rsvpUrl: https://calendar.google.com/calendar/embed?src=c_qup9gbhn9sqpuao6trttd8mk5s@group.calendar.google.com +eventUrl: https://github.com/backstage/community/issues/52 diff --git a/microsite/data/plugins/aws-proton.yaml b/microsite/data/plugins/aws-proton.yaml new file mode 100644 index 0000000000..022b553b24 --- /dev/null +++ b/microsite/data/plugins/aws-proton.yaml @@ -0,0 +1,9 @@ +--- +title: AWS Proton +author: Amazon Web Services +authorUrl: https://aws.amazon.com/ +category: Infrastructure +description: Create and view AWS Proton services for your components in Backstage. +documentation: https://github.com/awslabs/aws-proton-plugins-for-backstage#readme +iconUrl: https://github.com/awslabs/aws-proton-plugins-for-backstage/blob/main/docs/images/proton-logo.png?raw=true +npmPackageName: '@aws/aws-proton-plugin-for-backstage' diff --git a/microsite/data/plugins/dora-metrics.yaml b/microsite/data/plugins/dora-metrics.yaml new file mode 100644 index 0000000000..b94499e324 --- /dev/null +++ b/microsite/data/plugins/dora-metrics.yaml @@ -0,0 +1,9 @@ +--- +title: DORA Metrics +author: Okay +authorUrl: https://www.okayhq.com +category: Metrics +description: Embed dashboards (like DORA metrics) in your team or service pages from any dev tools (including Github, Gitlab, Jira, Argo, CircleCI, Buildkite, Pagerduty, Rollbar, Sentry, etc). +documentation: https://github.com/OkayHQ/backstage-plugin +iconUrl: img/okay.png +npmPackageName: '@okayhq/backstage-plugin' diff --git a/microsite/data/plugins/gke-usage.yaml b/microsite/data/plugins/gke-usage.yaml index e092f84973..9668b18fdf 100644 --- a/microsite/data/plugins/gke-usage.yaml +++ b/microsite/data/plugins/gke-usage.yaml @@ -5,7 +5,7 @@ authorUrl: https://bestsellerit.com category: Discovery description: This plugin will show you the cost and resource usage of your application within Google Kubernetes Engine (GKE). documentation: https://github.com/BESTSELLER/backstage-plugin-gkeusage/blob/master/README.md -iconUrl: https://bestsellerit.com/img/google-container-engine_avatar.svg +iconUrl: img/gke-logo.png npmPackageName: '@bestsellerit/backstage-plugin-gkeusage' tags: - gke diff --git a/microsite/data/plugins/harbor.yaml b/microsite/data/plugins/harbor.yaml index 9023e0c434..f959613d4c 100644 --- a/microsite/data/plugins/harbor.yaml +++ b/microsite/data/plugins/harbor.yaml @@ -5,7 +5,7 @@ authorUrl: https://bestsellerit.com category: Discovery description: This plugin will show you information about Docker images within the Harbor cloud native registry. documentation: https://github.com/BESTSELLER/backstage-plugin-harbor/blob/master/README.md -iconUrl: https://bestsellerit.com/img/terraform-harbor/goharbor.jpeg +iconUrl: https://raw.githubusercontent.com/cncf/artwork/master/projects/harbor/icon/color/harbor-icon-color.svg npmPackageName: '@bestsellerit/backstage-plugin-harbor' tags: - goharbor diff --git a/microsite/data/plugins/humanitec.yaml b/microsite/data/plugins/humanitec.yaml new file mode 100644 index 0000000000..bd5dec9dc6 --- /dev/null +++ b/microsite/data/plugins/humanitec.yaml @@ -0,0 +1,11 @@ +--- +title: Humanitec Platform Orchestrator +author: Frontside +authorUrl: 'https://frontside.com' +category: Deployment # A single category e.g. CI, Machine Learning, Services, Monitoring +description: | + Show workloads, environments and resources deployed by Humanitec Platform Orchestrator. + Plugin includes an Entity ComponentCard, Backend API route and scaffolder actions. +documentation: https://github.com/thefrontside/backstage/tree/main/plugins/humanitec +iconUrl: img/humanitec-logo.png +npmPackageName: '@frontside/backstage-plugin-humanitec' diff --git a/microsite/data/plugins/rootly.yaml b/microsite/data/plugins/rootly.yaml new file mode 100644 index 0000000000..c1769f637a --- /dev/null +++ b/microsite/data/plugins/rootly.yaml @@ -0,0 +1,9 @@ +--- +title: Rootly +author: Rootly +authorUrl: https://rootly.com/ +category: Incident Management +description: Import your Backstage entities into Rootly services and view incidents & analytics. +documentation: https://github.com/rootlyhq/backstage-plugin/blob/master/README.md +iconUrl: https://raw.githubusercontent.com/rootlyhq/backstage-plugin/master/docs/logo.png +npmPackageName: '@rootly/backstage-plugin' diff --git a/microsite/data/plugins/stack-overflow.yaml b/microsite/data/plugins/stack-overflow.yaml new file mode 100644 index 0000000000..0d734446d7 --- /dev/null +++ b/microsite/data/plugins/stack-overflow.yaml @@ -0,0 +1,9 @@ +--- +title: Stack Overflow +author: Spotify +authorUrl: https://github.com/spotify +category: Discovery +description: Provides Stack Overflow specific functionality that can be used in different ways (e.g. for homepage and search) to compose your Backstage App. +documentation: https://github.com/backstage/backstage/blob/master/plugins/stack-overflow +iconUrl: img/stack-overflow-logo.svg +npmPackageName: '@backstage/plugin-stack-overflow' diff --git a/microsite/pages/en/community.js b/microsite/pages/en/community.js index 26366b25df..3d79c82f93 100644 --- a/microsite/pages/en/community.js +++ b/microsite/pages/en/community.js @@ -8,6 +8,30 @@ const React = require('react'); const Components = require(`${process.cwd()}/core/Components.js`); const Block = Components.Block; +const BulletLine = Components.BulletLine; + +const PARTNERS = [ + { + name: 'Frontside Software', + url: 'https://frontside.com/backstage/', + logo: 'img/partner-logo-frontside.png', + }, + { + name: 'Roadie', + url: 'https://roadie.io/', + logo: 'img/partner-logo-roadie.png', + }, + { + name: 'ThoughtWorks', + url: 'https://www.thoughtworks.com', + logo: 'img/partner-logo-thoughtworks.png', + }, + { + name: 'VMWare', + url: 'https://www.vmware.com', + logo: 'img/partner-logo-vmware.png', + }, +]; const Background = props => { const { config: siteConfig } = props; @@ -17,14 +41,11 @@ const Background = props => { - Backstage Community - - + Backstage Community - What's the use of having fun if you can't share it? Exactly. Join - the vibrant community around the Backstage project. Be it on - GitHub, social media, Discord... You'll find a welcoming - environment. To ensure this, we follow the{' '} + Join the vibrant community around Backstage through social media + and different meetups. To ensure that you have a welcoming + environment, we follow{' '} {' '} CNCF Code of Conduct @@ -32,110 +53,110 @@ const Background = props => { in everything we do. - + - Main community channels -
- Chat and get support on our{' '} -
Discord -
- Get into contributing with the{' '} - - Good First Issues - -
- Subscribe to the{' '} - - Community newsletter - -
- Join the{' '} - - Twitter community - -
+ + Get started in our community! + +
- - - - Backstage Community Sessions - - Missed a meetup? Wondering when the next one is coming up? We've - got you covered! Check out our all-new Meetups page. - - Meetups - - - Adopter Community Sessions - - Backstage Community Sessions is the monthly meetup where we all - come together to listen to the latest maintainer updates, learn - from each other about adopting, share exciting new demos or - discuss any relevant topic like developer effectiveness, developer - experience, developer portals, etc. Have something to share, or a - burning question? Add it to the{' '} - issue. - - - - Contributor Community Sessions - - Discuss all things contributing, diving deep under the hood of - Backstage (Backstage of Backstage? Backerstage?). An open - discussion with maintainers and contributors of Backstage. If you - like Backstage, this is your favorite Zoom meeting of the month, - guaranteed! Have something to share, or a burning question? Add it - to the{' '} - issue. - + + + + Offical Backstage initiatives + + Stay tuned to the latest developments + + + + + Community sessions + + Maintainers and adopters meet monthly to share updates, demos, + and ideas. Yep, all sessions are recorded! + + + Join a session + + + + + Newsletter + + The official monthly Backstage newsletter. Don't miss the latest + news from your favorite project! + + + Subscribe + + + + + Contributor Spotlight + + A recognition for valuable community work. Nominate contributing + members for their efforts! We'll put them in the spotlight ❤️ + + Nominate now + + - - - - - Backstage official Newsletter + + + + Community initiatives - + + Open Mic Meetup - The official monthly Backstage newsletter. Containing the latest - news from your favorite project. - - - Subscribe - - - - - - - - - Spotlight - - A recognition for valuable community work, the{' '} - Contributor Spotlight. Nominate contributing members for - their efforts! We'll put them in the spotlight ❤️. -
-
- Nominate now -
- - Open Mic Meetup - - A monthly casual get together of Backstage users sharing their - experiences and helping each other. Hosted by{' '} + A casual get together of Backstage users sharing their experiences + and helping each other. Hosted by{' '} Roadie.io and{' '} Frontside Software. -
Learn more
- - Backstage Weekly + + Backstage Weekly Newsletter A weekly newsletter with news, updates and things community from your friends at Roadie.io. @@ -146,6 +167,23 @@ const Background = props => {
+ + + + + Commercial Partners + + {PARTNERS.map(partner => ( + + + + {partner.name} + + + + ))} + + ); }; diff --git a/microsite/pages/en/link.js b/microsite/pages/en/link.js index 727b15bfd8..6f56aa768c 100644 --- a/microsite/pages/en/link.js +++ b/microsite/pages/en/link.js @@ -5,7 +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', + 'scm-auth': '/docs/auth/#scaffolder-configuration-software-templates', }; const fallback = '/docs'; diff --git a/microsite/pages/en/live.js b/microsite/pages/en/live.js index 062af419fc..f2ebd4bb1d 100644 --- a/microsite/pages/en/live.js +++ b/microsite/pages/en/live.js @@ -34,7 +34,7 @@ const Background = props => { diff --git a/microsite/static/img/gke-logo.png b/microsite/static/img/gke-logo.png new file mode 100644 index 0000000000..5af1abbf9a Binary files /dev/null and b/microsite/static/img/gke-logo.png differ diff --git a/microsite/static/img/humanitec-logo.png b/microsite/static/img/humanitec-logo.png new file mode 100644 index 0000000000..69ab02e9cd Binary files /dev/null and b/microsite/static/img/humanitec-logo.png differ diff --git a/microsite/static/img/okay.png b/microsite/static/img/okay.png new file mode 100644 index 0000000000..357219d9d2 Binary files /dev/null and b/microsite/static/img/okay.png differ diff --git a/microsite/static/img/partner-logo-frontside.png b/microsite/static/img/partner-logo-frontside.png new file mode 100644 index 0000000000..c8cad6bce1 Binary files /dev/null and b/microsite/static/img/partner-logo-frontside.png differ diff --git a/microsite/static/img/partner-logo-roadie.png b/microsite/static/img/partner-logo-roadie.png new file mode 100644 index 0000000000..41b169f55b Binary files /dev/null and b/microsite/static/img/partner-logo-roadie.png differ diff --git a/microsite/static/img/partner-logo-thoughtworks.png b/microsite/static/img/partner-logo-thoughtworks.png new file mode 100644 index 0000000000..53c3bc2a9e Binary files /dev/null and b/microsite/static/img/partner-logo-thoughtworks.png differ diff --git a/microsite/static/img/partner-logo-vmware.png b/microsite/static/img/partner-logo-vmware.png new file mode 100644 index 0000000000..049975ca15 Binary files /dev/null and b/microsite/static/img/partner-logo-vmware.png differ diff --git a/microsite/static/img/stack-overflow-logo.svg b/microsite/static/img/stack-overflow-logo.svg new file mode 100644 index 0000000000..d2fba99094 --- /dev/null +++ b/microsite/static/img/stack-overflow-logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/microsite/yarn.lock b/microsite/yarn.lock index 84a93573bd..f4831e2b42 100644 --- a/microsite/yarn.lock +++ b/microsite/yarn.lock @@ -5210,9 +5210,9 @@ prepend-http@^2.0.0: integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= prettier@^2.6.2: - version "2.6.2" - resolved "https://registry.npmjs.org/prettier/-/prettier-2.6.2.tgz#e26d71a18a74c3d0f0597f55f01fb6c06c206032" - integrity sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew== + version "2.7.1" + resolved "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64" + integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== prismjs@^1.22.0: version "1.27.0" diff --git a/package.json b/package.json index dd2a85e757..9f219cfa11 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "@types/react": "^17", "@types/react-dom": "^17" }, - "version": "1.3.0", + "version": "1.4.0-next.2", "dependencies": { "@manypkg/get-packages": "^1.1.3", "@microsoft/api-documenter": "^7.17.11", diff --git a/packages/app-defaults/CHANGELOG.md b/packages/app-defaults/CHANGELOG.md index fb1756eba2..2786d4a5e4 100644 --- a/packages/app-defaults/CHANGELOG.md +++ b/packages/app-defaults/CHANGELOG.md @@ -1,5 +1,30 @@ # @backstage/app-defaults +## 1.0.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + +## 1.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-permission-react@0.4.3-next.0 + +## 1.0.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + - @backstage/core-app-api@1.0.4-next.0 + ## 1.0.3 ### Patch Changes diff --git a/packages/app-defaults/package.json b/packages/app-defaults/package.json index 0a35b16c3a..e67af42404 100644 --- a/packages/app-defaults/package.json +++ b/packages/app-defaults/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/app-defaults", "description": "Provides the default wiring of a Backstage App", - "version": "1.0.3", + "version": "1.0.4-next.2", "private": false, "publishConfig": { "access": "public", @@ -33,11 +33,11 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/core-components": "^0.9.5", - "@backstage/core-app-api": "^1.0.3", + "@backstage/core-components": "^0.10.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/plugin-permission-react": "^0.4.2", - "@backstage/theme": "^0.2.15", + "@backstage/plugin-permission-react": "^0.4.3-next.0", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "react-router-dom": "6.0.0-beta.0" @@ -46,8 +46,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@types/jest": "^26.0.7", diff --git a/packages/app/CHANGELOG.md b/packages/app/CHANGELOG.md index 74601b6417..0f28d87448 100644 --- a/packages/app/CHANGELOG.md +++ b/packages/app/CHANGELOG.md @@ -1,5 +1,172 @@ # example-app +## 0.2.73-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-cost-insights@0.11.29-next.2 + - @backstage/core-components@0.10.0-next.2 + - @backstage/plugin-scaffolder@1.4.0-next.2 + - @backstage/plugin-jenkins@0.7.6-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/plugin-search-react@0.2.2-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-import@0.8.10-next.2 + - @backstage/plugin-techdocs@1.2.1-next.2 + - @backstage/plugin-techdocs-module-addons-contrib@1.0.2-next.2 + - @backstage/plugin-api-docs@0.8.7-next.2 + - @backstage/plugin-catalog@1.4.0-next.2 + - @backstage/cli@0.18.0-next.2 + - @backstage/plugin-catalog-react@1.1.2-next.2 + - @backstage/app-defaults@1.0.4-next.2 + - @backstage/integration-react@1.1.2-next.2 + - @backstage/plugin-airbrake@0.3.7-next.2 + - @backstage/plugin-apache-airflow@0.2.0-next.2 + - @backstage/plugin-azure-devops@0.1.23-next.2 + - @backstage/plugin-badges@0.2.31-next.2 + - @backstage/plugin-catalog-graph@0.2.19-next.2 + - @backstage/plugin-circleci@0.3.7-next.2 + - @backstage/plugin-cloudbuild@0.3.7-next.2 + - @backstage/plugin-code-coverage@0.1.34-next.2 + - @backstage/plugin-dynatrace@0.1.1-next.2 + - @backstage/plugin-explore@0.3.38-next.2 + - @backstage/plugin-gcalendar@0.3.3-next.2 + - @backstage/plugin-gcp-projects@0.3.26-next.2 + - @backstage/plugin-github-actions@0.5.7-next.2 + - @backstage/plugin-gocd@0.1.13-next.2 + - @backstage/plugin-graphiql@0.2.39-next.2 + - @backstage/plugin-home@0.4.23-next.2 + - @backstage/plugin-kafka@0.3.7-next.2 + - @backstage/plugin-kubernetes@0.6.7-next.2 + - @backstage/plugin-lighthouse@0.3.7-next.2 + - @backstage/plugin-newrelic@0.3.25-next.2 + - @backstage/plugin-newrelic-dashboard@0.1.15-next.2 + - @backstage/plugin-org@0.5.7-next.2 + - @backstage/plugin-pagerduty@0.5.0-next.2 + - @backstage/plugin-rollbar@0.4.7-next.2 + - @backstage/plugin-search@0.9.1-next.2 + - @backstage/plugin-sentry@0.3.45-next.2 + - @backstage/plugin-shortcuts@0.2.8-next.2 + - @backstage/plugin-stack-overflow@0.1.3-next.2 + - @backstage/plugin-tech-insights@0.2.3-next.2 + - @backstage/plugin-tech-radar@0.5.14-next.2 + - @backstage/plugin-techdocs-react@1.0.2-next.1 + - @backstage/plugin-todo@0.2.9-next.2 + - @backstage/plugin-user-settings@0.4.6-next.2 + +## 0.2.73-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/cli@0.18.0-next.1 + - @backstage/plugin-apache-airflow@0.2.0-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/plugin-search@0.9.1-next.1 + - @backstage/plugin-org@0.5.7-next.1 + - @backstage/plugin-catalog@1.3.1-next.1 + - @backstage/plugin-home@0.4.23-next.1 + - @backstage/plugin-stack-overflow@0.1.3-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-techdocs@1.2.1-next.1 + - @backstage/app-defaults@1.0.4-next.1 + - @backstage/integration-react@1.1.2-next.1 + - @backstage/plugin-airbrake@0.3.7-next.1 + - @backstage/plugin-api-docs@0.8.7-next.1 + - @backstage/plugin-azure-devops@0.1.23-next.1 + - @backstage/plugin-badges@0.2.31-next.1 + - @backstage/plugin-catalog-common@1.0.4-next.0 + - @backstage/plugin-catalog-graph@0.2.19-next.1 + - @backstage/plugin-catalog-import@0.8.10-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.1 + - @backstage/plugin-circleci@0.3.7-next.1 + - @backstage/plugin-cloudbuild@0.3.7-next.1 + - @backstage/plugin-code-coverage@0.1.34-next.1 + - @backstage/plugin-cost-insights@0.11.29-next.1 + - @backstage/plugin-dynatrace@0.1.1-next.1 + - @backstage/plugin-explore@0.3.38-next.1 + - @backstage/plugin-gcalendar@0.3.3-next.1 + - @backstage/plugin-gcp-projects@0.3.26-next.1 + - @backstage/plugin-github-actions@0.5.7-next.1 + - @backstage/plugin-gocd@0.1.13-next.1 + - @backstage/plugin-graphiql@0.2.39-next.1 + - @backstage/plugin-jenkins@0.7.6-next.1 + - @backstage/plugin-kafka@0.3.7-next.1 + - @backstage/plugin-kubernetes@0.6.7-next.1 + - @backstage/plugin-lighthouse@0.3.7-next.1 + - @backstage/plugin-newrelic@0.3.25-next.1 + - @backstage/plugin-newrelic-dashboard@0.1.15-next.1 + - @backstage/plugin-pagerduty@0.5.0-next.1 + - @backstage/plugin-permission-react@0.4.3-next.0 + - @backstage/plugin-rollbar@0.4.7-next.1 + - @backstage/plugin-scaffolder@1.4.0-next.1 + - @backstage/plugin-search-common@0.3.6-next.0 + - @backstage/plugin-sentry@0.3.45-next.1 + - @backstage/plugin-shortcuts@0.2.8-next.1 + - @backstage/plugin-tech-insights@0.2.3-next.1 + - @backstage/plugin-tech-radar@0.5.14-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.0.2-next.1 + - @backstage/plugin-todo@0.2.9-next.1 + - @backstage/plugin-user-settings@0.4.6-next.1 + - @backstage/plugin-search-react@0.2.2-next.1 + +## 0.2.73-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder@1.4.0-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-techdocs-react@1.0.2-next.0 + - @backstage/plugin-catalog@1.3.1-next.0 + - @backstage/plugin-stack-overflow@0.1.3-next.0 + - @backstage/core-app-api@1.0.4-next.0 + - @backstage/cli@0.17.3-next.0 + - @backstage/plugin-azure-devops@0.1.23-next.0 + - @backstage/plugin-techdocs@1.2.1-next.0 + - @backstage/plugin-catalog-import@0.8.10-next.0 + - @backstage/plugin-pagerduty@0.5.0-next.0 + - @backstage/plugin-github-actions@0.5.7-next.0 + - @backstage/plugin-airbrake@0.3.7-next.0 + - @backstage/plugin-api-docs@0.8.7-next.0 + - @backstage/plugin-badges@0.2.31-next.0 + - @backstage/plugin-catalog-graph@0.2.19-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + - @backstage/plugin-circleci@0.3.7-next.0 + - @backstage/plugin-cloudbuild@0.3.7-next.0 + - @backstage/plugin-code-coverage@0.1.34-next.0 + - @backstage/plugin-cost-insights@0.11.29-next.0 + - @backstage/plugin-dynatrace@0.1.1-next.0 + - @backstage/plugin-explore@0.3.38-next.0 + - @backstage/plugin-gocd@0.1.13-next.0 + - @backstage/plugin-home@0.4.23-next.0 + - @backstage/plugin-jenkins@0.7.6-next.0 + - @backstage/plugin-kafka@0.3.7-next.0 + - @backstage/plugin-kubernetes@0.6.7-next.0 + - @backstage/plugin-lighthouse@0.3.7-next.0 + - @backstage/plugin-newrelic-dashboard@0.1.15-next.0 + - @backstage/plugin-org@0.5.7-next.0 + - @backstage/plugin-rollbar@0.4.7-next.0 + - @backstage/plugin-search@0.9.1-next.0 + - @backstage/plugin-sentry@0.3.45-next.0 + - @backstage/plugin-tech-insights@0.2.3-next.0 + - @backstage/plugin-todo@0.2.9-next.0 + - @backstage/app-defaults@1.0.4-next.0 + - @backstage/integration-react@1.1.2-next.0 + - @backstage/plugin-apache-airflow@0.1.15-next.0 + - @backstage/plugin-gcalendar@0.3.3-next.0 + - @backstage/plugin-gcp-projects@0.3.26-next.0 + - @backstage/plugin-graphiql@0.2.39-next.0 + - @backstage/plugin-newrelic@0.3.25-next.0 + - @backstage/plugin-search-react@0.2.2-next.0 + - @backstage/plugin-shortcuts@0.2.8-next.0 + - @backstage/plugin-tech-radar@0.5.14-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.0.2-next.0 + - @backstage/plugin-user-settings@0.4.6-next.0 + ## 0.2.72 ### Patch Changes diff --git a/packages/app/package.json b/packages/app/package.json index df9119d602..c114d79250 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,67 +1,67 @@ { "name": "example-app", - "version": "0.2.72", + "version": "0.2.73-next.2", "private": true, "backstage": { "role": "frontend" }, "bundled": true, "dependencies": { - "@backstage/app-defaults": "^1.0.3", - "@backstage/catalog-model": "^1.0.3", - "@backstage/cli": "^0.17.2", + "@backstage/app-defaults": "^1.0.4-next.2", + "@backstage/catalog-model": "^1.1.0-next.2", + "@backstage/cli": "^0.18.0-next.2", "@backstage/config": "^1.0.1", - "@backstage/core-app-api": "^1.0.3", - "@backstage/core-components": "^0.9.5", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/integration-react": "^1.1.1", - "@backstage/plugin-airbrake": "^0.3.6", - "@backstage/plugin-api-docs": "^0.8.6", - "@backstage/plugin-azure-devops": "^0.1.22", - "@backstage/plugin-apache-airflow": "^0.1.14", - "@backstage/plugin-badges": "^0.2.30", - "@backstage/plugin-catalog": "^1.3.0", - "@backstage/plugin-catalog-common": "^1.0.3", - "@backstage/plugin-catalog-graph": "^0.2.18", - "@backstage/plugin-catalog-import": "^0.8.9", - "@backstage/plugin-catalog-react": "^1.1.1", - "@backstage/plugin-circleci": "^0.3.6", - "@backstage/plugin-cloudbuild": "^0.3.6", - "@backstage/plugin-code-coverage": "^0.1.33", - "@backstage/plugin-cost-insights": "^0.11.28", - "@backstage/plugin-dynatrace": "^0.1.0", - "@backstage/plugin-explore": "^0.3.37", - "@backstage/plugin-gcalendar": "^0.3.2", - "@backstage/plugin-gcp-projects": "^0.3.25", - "@backstage/plugin-github-actions": "^0.5.6", - "@backstage/plugin-gocd": "^0.1.12", - "@backstage/plugin-graphiql": "^0.2.38", - "@backstage/plugin-home": "^0.4.22", - "@backstage/plugin-jenkins": "^0.7.5", - "@backstage/plugin-kafka": "^0.3.6", - "@backstage/plugin-kubernetes": "^0.6.6", - "@backstage/plugin-lighthouse": "^0.3.6", - "@backstage/plugin-newrelic": "^0.3.24", - "@backstage/plugin-newrelic-dashboard": "^0.1.14", - "@backstage/plugin-org": "^0.5.6", - "@backstage/plugin-pagerduty": "0.4.0", - "@backstage/plugin-permission-react": "^0.4.2", - "@backstage/plugin-rollbar": "^0.4.6", - "@backstage/plugin-scaffolder": "^1.3.0", - "@backstage/plugin-search": "^0.9.0", - "@backstage/plugin-search-react": "^0.2.1", - "@backstage/plugin-search-common": "^0.3.5", - "@backstage/plugin-sentry": "^0.3.44", - "@backstage/plugin-shortcuts": "^0.2.7", - "@backstage/plugin-stack-overflow": "^0.1.2", - "@backstage/plugin-tech-radar": "^0.5.13", - "@backstage/plugin-techdocs": "^1.2.0", - "@backstage/plugin-techdocs-react": "^1.0.1", - "@backstage/plugin-techdocs-module-addons-contrib": "^1.0.1", - "@backstage/plugin-todo": "^0.2.8", - "@backstage/plugin-user-settings": "^0.4.5", - "@backstage/plugin-tech-insights": "^0.2.2", - "@backstage/theme": "^0.2.15", + "@backstage/integration-react": "^1.1.2-next.2", + "@backstage/plugin-airbrake": "^0.3.7-next.2", + "@backstage/plugin-api-docs": "^0.8.7-next.2", + "@backstage/plugin-azure-devops": "^0.1.23-next.2", + "@backstage/plugin-apache-airflow": "^0.2.0-next.2", + "@backstage/plugin-badges": "^0.2.31-next.2", + "@backstage/plugin-catalog": "^1.4.0-next.2", + "@backstage/plugin-catalog-common": "^1.0.4-next.0", + "@backstage/plugin-catalog-graph": "^0.2.19-next.2", + "@backstage/plugin-catalog-import": "^0.8.10-next.2", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", + "@backstage/plugin-circleci": "^0.3.7-next.2", + "@backstage/plugin-cloudbuild": "^0.3.7-next.2", + "@backstage/plugin-code-coverage": "^0.1.34-next.2", + "@backstage/plugin-cost-insights": "^0.11.29-next.2", + "@backstage/plugin-dynatrace": "^0.1.1-next.2", + "@backstage/plugin-explore": "^0.3.38-next.2", + "@backstage/plugin-gcalendar": "^0.3.3-next.2", + "@backstage/plugin-gcp-projects": "^0.3.26-next.2", + "@backstage/plugin-github-actions": "^0.5.7-next.2", + "@backstage/plugin-gocd": "^0.1.13-next.2", + "@backstage/plugin-graphiql": "^0.2.39-next.2", + "@backstage/plugin-home": "^0.4.23-next.2", + "@backstage/plugin-jenkins": "^0.7.6-next.2", + "@backstage/plugin-kafka": "^0.3.7-next.2", + "@backstage/plugin-kubernetes": "^0.6.7-next.2", + "@backstage/plugin-lighthouse": "^0.3.7-next.2", + "@backstage/plugin-newrelic": "^0.3.25-next.2", + "@backstage/plugin-newrelic-dashboard": "^0.1.15-next.2", + "@backstage/plugin-org": "^0.5.7-next.2", + "@backstage/plugin-pagerduty": "0.5.0-next.2", + "@backstage/plugin-permission-react": "^0.4.3-next.0", + "@backstage/plugin-rollbar": "^0.4.7-next.2", + "@backstage/plugin-scaffolder": "^1.4.0-next.2", + "@backstage/plugin-search": "^0.9.1-next.2", + "@backstage/plugin-search-react": "^0.2.2-next.2", + "@backstage/plugin-search-common": "^0.3.6-next.0", + "@backstage/plugin-sentry": "^0.3.45-next.2", + "@backstage/plugin-shortcuts": "^0.2.8-next.2", + "@backstage/plugin-stack-overflow": "^0.1.3-next.2", + "@backstage/plugin-tech-radar": "^0.5.14-next.2", + "@backstage/plugin-techdocs": "^1.2.1-next.2", + "@backstage/plugin-techdocs-react": "^1.0.2-next.1", + "@backstage/plugin-techdocs-module-addons-contrib": "^1.0.2-next.2", + "@backstage/plugin-todo": "^0.2.9-next.2", + "@backstage/plugin-user-settings": "^0.4.6-next.2", + "@backstage/plugin-tech-insights": "^0.2.3-next.2", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -81,7 +81,7 @@ "zen-observable": "^0.8.15" }, "devDependencies": { - "@backstage/test-utils": "^1.1.1", + "@backstage/test-utils": "^1.1.2-next.1", "@rjsf/core": "^3.2.1", "@testing-library/cypress": "^8.0.2", "@testing-library/jest-dom": "^5.10.1", diff --git a/packages/app/src/components/catalog/EntityPage.tsx b/packages/app/src/components/catalog/EntityPage.tsx index 1958aabd2e..155dc071ff 100644 --- a/packages/app/src/components/catalog/EntityPage.tsx +++ b/packages/app/src/components/catalog/EntityPage.tsx @@ -167,7 +167,12 @@ const EntityLayoutWrapper = (props: { children?: ReactNode }) => { return ( <> - + {props.children}
} pageTitleOverride="Home"> - +
diff --git a/packages/backend-common/CHANGELOG.md b/packages/backend-common/CHANGELOG.md index 9e5a28f76b..a052e37fe7 100644 --- a/packages/backend-common/CHANGELOG.md +++ b/packages/backend-common/CHANGELOG.md @@ -1,5 +1,41 @@ # @backstage/backend-common +## 0.14.1-next.2 + +### Patch Changes + +- 679b32172e: Updated dependency `knex` to `^2.0.0`. +- e2d7b76f43: Upgrade git-url-parse to 12.0.0. + + Motivation for upgrade is transitively upgrading parse-url which is vulnerable + to several CVEs detected by Snyk. + + - SNYK-JS-PARSEURL-2935944 + - SNYK-JS-PARSEURL-2935947 + - SNYK-JS-PARSEURL-2936249 + +- Updated dependencies + - @backstage/integration@1.2.2-next.2 + +## 0.14.1-next.1 + +### Patch Changes + +- 0fc57887e8: Improve plural handling in logging output for secrets +- Updated dependencies + - @backstage/errors@1.1.0-next.0 + - @backstage/integration@1.2.2-next.1 + - @backstage/config-loader@1.1.3-next.0 + +## 0.14.1-next.0 + +### Patch Changes + +- b1edb5cfd9: Fix parsing of S3 URLs for the default region. +- c3cfc83af2: Updated JSDoc to be MDX compatible. +- Updated dependencies + - @backstage/integration@1.2.2-next.0 + ## 0.14.0 ### Minor Changes diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index d4da05eaa6..422465ee6f 100644 --- a/packages/backend-common/package.json +++ b/packages/backend-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-common", "description": "Common functionality library for Backstage backends", - "version": "0.14.0", + "version": "0.14.1-next.2", "main": "src/index.ts", "types": "src/index.ts", "private": false, @@ -36,9 +36,9 @@ "dependencies": { "@backstage/cli-common": "^0.1.9", "@backstage/config": "^1.0.1", - "@backstage/config-loader": "^1.1.2", - "@backstage/errors": "^1.0.0", - "@backstage/integration": "^1.2.1", + "@backstage/config-loader": "^1.1.3-next.0", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/integration": "^1.2.2-next.2", "@backstage/types": "^1.0.0", "@google-cloud/storage": "^6.0.0", "@manypkg/get-packages": "^1.1.3", @@ -58,14 +58,14 @@ "express": "^4.17.1", "express-promise-router": "^4.1.0", "fs-extra": "10.1.0", - "git-url-parse": "^11.6.0", + "git-url-parse": "^12.0.0", "helmet": "^5.0.2", "isomorphic-git": "^1.8.0", "jose": "^4.6.0", "keyv": "^4.0.3", "keyv-memcache": "^1.2.5", "@keyv/redis": "^2.2.3", - "knex": "^1.0.2", + "knex": "^2.0.0", "lodash": "^4.17.21", "logform": "^2.3.2", "luxon": "^2.3.1", @@ -91,8 +91,8 @@ } }, "devDependencies": { - "@backstage/backend-test-utils": "^0.1.25", - "@backstage/cli": "^0.17.2", + "@backstage/backend-test-utils": "^0.1.26-next.2", + "@backstage/cli": "^0.18.0-next.2", "@types/archiver": "^5.1.0", "@types/base64-stream": "^1.0.2", "@types/compression": "^1.7.0", @@ -112,7 +112,7 @@ "better-sqlite3": "^7.5.0", "http-errors": "^2.0.0", "mock-fs": "^5.1.0", - "msw": "^0.42.0", + "msw": "^0.43.0", "mysql2": "^2.2.5", "recursive-readdir": "^2.2.2", "supertest": "^6.1.3" diff --git a/packages/backend-common/src/config.ts b/packages/backend-common/src/config.ts index 94b362d99d..608869ea93 100644 --- a/packages/backend-common/src/config.ts +++ b/packages/backend-common/src/config.ts @@ -53,7 +53,9 @@ const updateRedactionList = ( ); logger.info( - `${values.size} secrets found in the config which will be redacted`, + `${values.size} secret${ + values.size > 1 ? 's' : '' + } found in the config which will be redacted`, ); setRootLoggerRedactionList(Array.from(values)); diff --git a/packages/backend-common/src/database/DatabaseManager.ts b/packages/backend-common/src/database/DatabaseManager.ts index 503945e594..004e7d13cd 100644 --- a/packages/backend-common/src/database/DatabaseManager.ts +++ b/packages/backend-common/src/database/DatabaseManager.ts @@ -251,7 +251,7 @@ export class DatabaseManager { // include base connection if client type has not been overridden ...(overridden ? {} : baseConnection), ...connection, - }; + } as Partial; } /** diff --git a/packages/backend-common/src/reading/AwsS3UrlReader.test.ts b/packages/backend-common/src/reading/AwsS3UrlReader.test.ts index 0ae64e9404..454b8a2c5a 100644 --- a/packages/backend-common/src/reading/AwsS3UrlReader.test.ts +++ b/packages/backend-common/src/reading/AwsS3UrlReader.test.ts @@ -39,6 +39,15 @@ const treeResponseFactory = DefaultReadTreeResponseFactory.create({ describe('parseUrl', () => { it('supports all aws formats', () => { + expect( + parseUrl('https://s3.amazonaws.com/my.bucket-3/a/puppy.jpg', { + host: 'amazonaws.com', + }), + ).toEqual({ + path: 'a/puppy.jpg', + bucket: 'my.bucket-3', + region: 'us-east-1', + }); expect( parseUrl('https://s3.us-west-2.amazonaws.com/my.bucket-3/a/puppy.jpg', { host: 'amazonaws.com', diff --git a/packages/backend-common/src/reading/AwsS3UrlReader.ts b/packages/backend-common/src/reading/AwsS3UrlReader.ts index b0ac81676a..7c314cf036 100644 --- a/packages/backend-common/src/reading/AwsS3UrlReader.ts +++ b/packages/backend-common/src/reading/AwsS3UrlReader.ts @@ -35,6 +35,8 @@ import { ForwardedError, NotModifiedError } from '@backstage/errors'; import { ListObjectsV2Output, ObjectList } from 'aws-sdk/clients/s3'; import { ReadUrlResponseFactory } from './ReadUrlResponseFactory'; +const DEFAULT_REGION = 'us-east-1'; + /** * Path style URLs: https://s3.(region).amazonaws.com/(bucket)/(key) * The region can also be on the old form: https://s3-(region).amazonaws.com/(bucket)/(key) @@ -57,7 +59,7 @@ export function parseUrl( // Treat Amazon hosted separately because it has special region logic if (config.host === 'amazonaws.com') { const match = host.match( - /^(?:([a-z0-9.-]+)\.)?s3[.-]([a-z0-9-]+)\.amazonaws\.com$/, + /^(?:([a-z0-9.-]+)\.)?s3(?:[.-]([a-z0-9-]+))?\.amazonaws\.com$/, ); if (!match) { throw new Error(`Invalid AWS S3 URL ${url}`); @@ -76,14 +78,14 @@ export function parseUrl( return { path: pathname.substring(slashIndex + 1), bucket: pathname.substring(0, slashIndex), - region: hostRegion, + region: hostRegion ?? DEFAULT_REGION, }; } return { path: pathname, bucket: hostBucket, - region: hostRegion, + region: hostRegion ?? DEFAULT_REGION, }; } diff --git a/packages/backend-common/src/reading/ReadUrlResponseFactory.test.ts b/packages/backend-common/src/reading/ReadUrlResponseFactory.test.ts index c8a659e792..ff975de9bb 100644 --- a/packages/backend-common/src/reading/ReadUrlResponseFactory.test.ts +++ b/packages/backend-common/src/reading/ReadUrlResponseFactory.test.ts @@ -78,8 +78,7 @@ describe('ReadUrlResponseFactory', () => { let readable: NodeJS.ReadableStream; beforeEach(() => { - // @ts-ignore - readable = new Stream({ encoding: 'utf-8' }); + readable = new Stream({ encoding: 'utf-8' }) as NodeJS.ReadableStream; readable.readable = true; // Write data asynchronously, as soon as possible. diff --git a/packages/backend-tasks/CHANGELOG.md b/packages/backend-tasks/CHANGELOG.md index 34be280bbc..782088ff84 100644 --- a/packages/backend-tasks/CHANGELOG.md +++ b/packages/backend-tasks/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/backend-tasks +## 0.3.3-next.2 + +### Patch Changes + +- 679b32172e: Updated dependency `knex` to `^2.0.0`. +- Updated dependencies + - @backstage/backend-common@0.14.1-next.2 + +## 0.3.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + +## 0.3.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + ## 0.3.2 ### Patch Changes diff --git a/packages/backend-tasks/package.json b/packages/backend-tasks/package.json index e96a71c597..91b94d4d1c 100644 --- a/packages/backend-tasks/package.json +++ b/packages/backend-tasks/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-tasks", "description": "Common distributed task management library for Backstage backends", - "version": "0.3.2", + "version": "0.3.3-next.2", "main": "src/index.ts", "types": "src/index.ts", "private": false, @@ -33,13 +33,13 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", + "@backstage/backend-common": "^0.14.1-next.2", "@backstage/config": "^1.0.1", - "@backstage/errors": "^1.0.0", + "@backstage/errors": "^1.1.0-next.0", "@backstage/types": "^1.0.0", "@types/luxon": "^2.0.4", "cron": "^2.0.0", - "knex": "^1.0.2", + "knex": "^2.0.0", "lodash": "^4.17.21", "luxon": "^2.0.2", "node-abort-controller": "^3.0.1", @@ -48,8 +48,8 @@ "zod": "^3.9.5" }, "devDependencies": { - "@backstage/backend-test-utils": "^0.1.25", - "@backstage/cli": "^0.17.2", + "@backstage/backend-test-utils": "^0.1.26-next.2", + "@backstage/cli": "^0.18.0-next.2", "@types/cron": "^2.0.0", "wait-for-expect": "^3.0.2" }, diff --git a/packages/backend-test-utils/CHANGELOG.md b/packages/backend-test-utils/CHANGELOG.md index 104f17a2e8..e0bb57a3f0 100644 --- a/packages/backend-test-utils/CHANGELOG.md +++ b/packages/backend-test-utils/CHANGELOG.md @@ -1,5 +1,30 @@ # @backstage/backend-test-utils +## 0.1.26-next.2 + +### Patch Changes + +- 679b32172e: Updated dependency `knex` to `^2.0.0`. +- Updated dependencies + - @backstage/backend-common@0.14.1-next.2 + - @backstage/cli@0.18.0-next.2 + +## 0.1.26-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.18.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + +## 0.1.26-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/cli@0.17.3-next.0 + ## 0.1.25 ### Patch Changes diff --git a/packages/backend-test-utils/package.json b/packages/backend-test-utils/package.json index abc55944ea..53953ba85e 100644 --- a/packages/backend-test-utils/package.json +++ b/packages/backend-test-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-test-utils", "description": "Test helpers library for Backstage backends", - "version": "0.1.25", + "version": "0.1.26-next.2", "main": "src/index.ts", "types": "src/index.ts", "private": false, @@ -34,19 +34,19 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", - "@backstage/cli": "^0.17.2", + "@backstage/backend-common": "^0.14.1-next.2", + "@backstage/cli": "^0.18.0-next.2", "@backstage/config": "^1.0.1", "better-sqlite3": "^7.5.0", - "knex": "^1.0.2", - "msw": "^0.42.0", + "knex": "^2.0.0", + "msw": "^0.43.0", "mysql2": "^2.2.5", "pg": "^8.3.0", "testcontainers": "^8.1.2", "uuid": "^8.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2" + "@backstage/cli": "^0.18.0-next.2" }, "files": [ "dist" diff --git a/packages/backend/CHANGELOG.md b/packages/backend/CHANGELOG.md index 1602a34c37..02eac85805 100644 --- a/packages/backend/CHANGELOG.md +++ b/packages/backend/CHANGELOG.md @@ -1,5 +1,100 @@ # example-backend +## 0.2.73-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes-backend@0.7.0-next.2 + - @backstage/plugin-tech-insights-backend@0.5.0-next.2 + - @backstage/plugin-jenkins-backend@0.1.24-next.2 + - @backstage/plugin-search-backend-module-pg@0.3.5-next.2 + - @backstage/plugin-scaffolder-backend@1.4.0-next.2 + - @backstage/plugin-auth-backend@0.15.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/plugin-kafka-backend@0.2.27-next.2 + - @backstage/backend-common@0.14.1-next.2 + - @backstage/backend-tasks@0.3.3-next.2 + - @backstage/plugin-app-backend@0.3.34-next.2 + - @backstage/plugin-catalog-backend@1.2.1-next.2 + - @backstage/plugin-code-coverage-backend@0.1.32-next.2 + - @backstage/plugin-techdocs-backend@1.2.0-next.2 + - @backstage/plugin-badges-backend@0.1.28-next.2 + - @backstage/integration@1.2.2-next.2 + - example-app@0.2.73-next.2 + +## 0.2.73-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.4.0-next.1 + - @backstage/plugin-auth-backend@0.15.0-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@0.2.0-next.1 + - @backstage/plugin-catalog-backend@1.2.1-next.1 + - @backstage/plugin-techdocs-backend@1.2.0-next.1 + - example-app@0.2.73-next.1 + - @backstage/backend-tasks@0.3.3-next.1 + - @backstage/catalog-client@1.0.4-next.1 + - @backstage/integration@1.2.2-next.1 + - @backstage/plugin-app-backend@0.3.34-next.1 + - @backstage/plugin-auth-node@0.2.3-next.1 + - @backstage/plugin-badges-backend@0.1.28-next.1 + - @backstage/plugin-code-coverage-backend@0.1.32-next.1 + - @backstage/plugin-jenkins-backend@0.1.24-next.1 + - @backstage/plugin-kafka-backend@0.2.27-next.1 + - @backstage/plugin-kubernetes-backend@0.7.0-next.1 + - @backstage/plugin-permission-backend@0.5.9-next.1 + - @backstage/plugin-permission-common@0.6.3-next.0 + - @backstage/plugin-permission-node@0.6.3-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.2-next.1 + - @backstage/plugin-search-backend@0.5.4-next.1 + - @backstage/plugin-search-backend-module-pg@0.3.5-next.1 + - @backstage/plugin-search-backend-node@0.6.3-next.1 + - @backstage/plugin-tech-insights-backend@0.4.2-next.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.18-next.1 + - @backstage/plugin-todo-backend@0.1.31-next.1 + +## 0.2.73-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-tech-insights-backend@0.4.2-next.0 + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/plugin-scaffolder-backend@1.4.0-next.0 + - @backstage/plugin-auth-backend@0.14.2-next.0 + - @backstage/plugin-kubernetes-backend@0.7.0-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/plugin-azure-devops-backend@0.3.13-next.0 + - example-app@0.2.73-next.0 + - @backstage/backend-tasks@0.3.3-next.0 + - @backstage/plugin-app-backend@0.3.34-next.0 + - @backstage/plugin-auth-node@0.2.3-next.0 + - @backstage/plugin-badges-backend@0.1.28-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.0 + - @backstage/plugin-code-coverage-backend@0.1.32-next.0 + - @backstage/plugin-graphql-backend@0.1.24-next.0 + - @backstage/plugin-jenkins-backend@0.1.24-next.0 + - @backstage/plugin-kafka-backend@0.2.27-next.0 + - @backstage/plugin-permission-backend@0.5.9-next.0 + - @backstage/plugin-permission-node@0.6.3-next.0 + - @backstage/plugin-proxy-backend@0.2.28-next.0 + - @backstage/plugin-rollbar-backend@0.1.31-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.2-next.0 + - @backstage/plugin-search-backend@0.5.4-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@0.1.6-next.0 + - @backstage/plugin-search-backend-module-pg@0.3.5-next.0 + - @backstage/plugin-search-backend-node@0.6.3-next.0 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.18-next.0 + - @backstage/plugin-tech-insights-node@0.3.2-next.0 + - @backstage/plugin-techdocs-backend@1.1.3-next.0 + - @backstage/plugin-todo-backend@0.1.31-next.0 + - @backstage/catalog-client@1.0.4-next.0 + ## 0.2.72 ### Patch Changes diff --git a/packages/backend/package.json b/packages/backend/package.json index 9dedf360c1..df6fe5ec3b 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -1,6 +1,6 @@ { "name": "example-backend", - "version": "0.2.72", + "version": "0.2.73-next.2", "main": "dist/index.cjs.js", "types": "src/index.ts", "license": "Apache-2.0", @@ -26,39 +26,39 @@ "build-image": "docker build ../.. -f Dockerfile --tag example-backend" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", - "@backstage/backend-tasks": "^0.3.2", - "@backstage/catalog-client": "^1.0.3", - "@backstage/catalog-model": "^1.0.3", + "@backstage/backend-common": "^0.14.1-next.2", + "@backstage/backend-tasks": "^0.3.3-next.2", + "@backstage/catalog-client": "^1.0.4-next.1", + "@backstage/catalog-model": "^1.1.0-next.2", "@backstage/config": "^1.0.1", - "@backstage/integration": "^1.2.1", - "@backstage/plugin-app-backend": "^0.3.33", - "@backstage/plugin-auth-backend": "^0.14.1", - "@backstage/plugin-auth-node": "^0.2.2", - "@backstage/plugin-azure-devops-backend": "^0.3.12", - "@backstage/plugin-badges-backend": "^0.1.27", - "@backstage/plugin-catalog-backend": "^1.2.0", - "@backstage/plugin-code-coverage-backend": "^0.1.31", - "@backstage/plugin-graphql-backend": "^0.1.23", - "@backstage/plugin-jenkins-backend": "^0.1.23", - "@backstage/plugin-kubernetes-backend": "^0.6.0", - "@backstage/plugin-kafka-backend": "^0.2.26", - "@backstage/plugin-permission-backend": "^0.5.8", - "@backstage/plugin-permission-common": "^0.6.2", - "@backstage/plugin-permission-node": "^0.6.2", - "@backstage/plugin-proxy-backend": "^0.2.27", - "@backstage/plugin-rollbar-backend": "^0.1.30", - "@backstage/plugin-scaffolder-backend": "^1.3.0", - "@backstage/plugin-scaffolder-backend-module-rails": "^0.4.1", - "@backstage/plugin-search-backend": "^0.5.3", - "@backstage/plugin-search-backend-node": "^0.6.2", - "@backstage/plugin-search-backend-module-elasticsearch": "^0.1.5", - "@backstage/plugin-search-backend-module-pg": "^0.3.4", - "@backstage/plugin-techdocs-backend": "^1.1.2", - "@backstage/plugin-tech-insights-backend": "^0.4.1", - "@backstage/plugin-tech-insights-node": "^0.3.1", - "@backstage/plugin-tech-insights-backend-module-jsonfc": "^0.1.17", - "@backstage/plugin-todo-backend": "^0.1.30", + "@backstage/integration": "^1.2.2-next.2", + "@backstage/plugin-app-backend": "^0.3.34-next.2", + "@backstage/plugin-auth-backend": "^0.15.0-next.2", + "@backstage/plugin-auth-node": "^0.2.3-next.1", + "@backstage/plugin-azure-devops-backend": "^0.3.13-next.0", + "@backstage/plugin-badges-backend": "^0.1.28-next.2", + "@backstage/plugin-catalog-backend": "^1.2.1-next.2", + "@backstage/plugin-code-coverage-backend": "^0.1.32-next.2", + "@backstage/plugin-graphql-backend": "^0.1.24-next.0", + "@backstage/plugin-jenkins-backend": "^0.1.24-next.2", + "@backstage/plugin-kubernetes-backend": "^0.7.0-next.2", + "@backstage/plugin-kafka-backend": "^0.2.27-next.2", + "@backstage/plugin-permission-backend": "^0.5.9-next.1", + "@backstage/plugin-permission-common": "^0.6.3-next.0", + "@backstage/plugin-permission-node": "^0.6.3-next.1", + "@backstage/plugin-proxy-backend": "^0.2.28-next.0", + "@backstage/plugin-rollbar-backend": "^0.1.31-next.0", + "@backstage/plugin-scaffolder-backend": "^1.4.0-next.2", + "@backstage/plugin-scaffolder-backend-module-rails": "^0.4.2-next.1", + "@backstage/plugin-search-backend": "^0.5.4-next.1", + "@backstage/plugin-search-backend-node": "^0.6.3-next.1", + "@backstage/plugin-search-backend-module-elasticsearch": "^0.2.0-next.1", + "@backstage/plugin-search-backend-module-pg": "^0.3.5-next.2", + "@backstage/plugin-techdocs-backend": "^1.2.0-next.2", + "@backstage/plugin-tech-insights-backend": "^0.5.0-next.2", + "@backstage/plugin-tech-insights-node": "^0.3.2-next.0", + "@backstage/plugin-tech-insights-backend-module-jsonfc": "^0.1.18-next.1", + "@backstage/plugin-todo-backend": "^0.1.31-next.1", "@gitbeaker/node": "^35.1.0", "@octokit/rest": "^18.5.3", "better-sqlite3": "^7.5.0", @@ -75,7 +75,7 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.17.2", + "@backstage/cli": "^0.18.0-next.2", "@types/dockerode": "^3.3.0", "@types/express": "^4.17.6", "@types/express-serve-static-core": "^4.17.5", diff --git a/packages/backend/src/plugins/kubernetes.ts b/packages/backend/src/plugins/kubernetes.ts index 8023d549ff..3bc7a5dcbe 100644 --- a/packages/backend/src/plugins/kubernetes.ts +++ b/packages/backend/src/plugins/kubernetes.ts @@ -17,13 +17,16 @@ import { KubernetesBuilder } from '@backstage/plugin-kubernetes-backend'; import { Router } from 'express'; import { PluginEnvironment } from '../types'; +import { CatalogClient } from '@backstage/catalog-client'; export default async function createPlugin( env: PluginEnvironment, ): Promise { + const catalogApi = new CatalogClient({ discoveryApi: env.discovery }); const { router } = await KubernetesBuilder.createBuilder({ logger: env.logger, config: env.config, + catalogApi, }).build(); return router; } diff --git a/packages/backend/src/plugins/search.ts b/packages/backend/src/plugins/search.ts index a0ea83ab61..c478ecdd05 100644 --- a/packages/backend/src/plugins/search.ts +++ b/packages/backend/src/plugins/search.ts @@ -39,7 +39,9 @@ async function createSearchEngine( } if (await PgSearchEngine.supported(env.database)) { - return await PgSearchEngine.from({ database: env.database }); + return await PgSearchEngine.fromConfig(env.config, { + database: env.database, + }); } return new LunrSearchEngine({ logger: env.logger }); diff --git a/packages/catalog-client/CHANGELOG.md b/packages/catalog-client/CHANGELOG.md index 93d232dc24..0b0d29b940 100644 --- a/packages/catalog-client/CHANGELOG.md +++ b/packages/catalog-client/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/catalog-client +## 1.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + +## 1.0.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + ## 1.0.3 ### Patch Changes diff --git a/packages/catalog-client/package.json b/packages/catalog-client/package.json index 76818ed10f..3fbf662615 100644 --- a/packages/catalog-client/package.json +++ b/packages/catalog-client/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/catalog-client", "description": "An isomorphic client for the catalog backend", - "version": "1.0.3", + "version": "1.0.4-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,14 +33,14 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", - "@backstage/errors": "^1.0.0", + "@backstage/catalog-model": "^1.1.0-next.1", + "@backstage/errors": "^1.1.0-next.0", "cross-fetch": "^3.1.5" }, "devDependencies": { - "@backstage/cli": "^0.17.2", + "@backstage/cli": "^0.18.0-next.1", "@types/jest": "^26.0.7", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/packages/catalog-model/CHANGELOG.md b/packages/catalog-model/CHANGELOG.md index 7d491dad5b..910fc92cd2 100644 --- a/packages/catalog-model/CHANGELOG.md +++ b/packages/catalog-model/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/catalog-model +## 1.1.0-next.2 + +### Minor Changes + +- 4cc81372f8: Introduced `GroupDefaultParentEntityPolicy` to set a default group entity parent. + +## 1.1.0-next.1 + +### Patch Changes + +- f1dcc6f3c6: Added type predicates for all entity types, e.g. isUserEntity +- Updated dependencies + - @backstage/errors@1.1.0-next.0 + +## 1.1.0-next.0 + +### Minor Changes + +- 1380b389dc: Adding an optional type field to entity links to group and categorize links + +### Patch Changes + +- c3cfc83af2: Updated JSDoc to be MDX compatible. + ## 1.0.3 ### Patch Changes diff --git a/packages/catalog-model/api-report.md b/packages/catalog-model/api-report.md index fca23d6ab9..9b9136fc3c 100644 --- a/packages/catalog-model/api-report.md +++ b/packages/catalog-model/api-report.md @@ -159,6 +159,7 @@ export type EntityLink = { url: string; title?: string; icon?: string; + type?: string; }; // @public @@ -229,6 +230,13 @@ export function getEntitySourceLocation(entity: Entity): { target: string; }; +// @public +export class GroupDefaultParentEntityPolicy implements EntityPolicy { + constructor(parentEntityRef: string); + // (undocumented) + enforce(entity: Entity): Promise; +} + // @public interface GroupEntityV1alpha1 extends Entity { // (undocumented) @@ -254,6 +262,36 @@ export { GroupEntityV1alpha1 }; // @public export const groupEntityV1alpha1Validator: KindValidator; +// @public (undocumented) +export function isApiEntity(entity: Entity): entity is ApiEntityV1alpha1; + +// @public (undocumented) +export function isComponentEntity( + entity: Entity, +): entity is ComponentEntityV1alpha1; + +// @public (undocumented) +export function isDomainEntity(entity: Entity): entity is DomainEntityV1alpha1; + +// @public (undocumented) +export function isGroupEntity(entity: Entity): entity is GroupEntityV1alpha1; + +// @public (undocumented) +export function isLocationEntity( + entity: Entity, +): entity is LocationEntityV1alpha1; + +// @public (undocumented) +export function isResourceEntity( + entity: Entity, +): entity is ResourceEntityV1alpha1; + +// @public (undocumented) +export function isSystemEntity(entity: Entity): entity is SystemEntityV1alpha1; + +// @public (undocumented) +export function isUserEntity(entity: Entity): entity is UserEntityV1alpha1; + // @public export type KindValidator = { check(entity: Entity): Promise; diff --git a/packages/catalog-model/package.json b/packages/catalog-model/package.json index 328482fd24..a58fdcf4d5 100644 --- a/packages/catalog-model/package.json +++ b/packages/catalog-model/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/catalog-model", "description": "Types and validators that help describe the model of a Backstage Catalog", - "version": "1.0.3", + "version": "1.1.0-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,7 +35,7 @@ }, "dependencies": { "@backstage/config": "^1.0.1", - "@backstage/errors": "^1.0.0", + "@backstage/errors": "^1.1.0-next.0", "@backstage/types": "^1.0.0", "ajv": "^8.10.0", "json-schema": "^0.4.0", @@ -43,7 +43,7 @@ "uuid": "^8.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", + "@backstage/cli": "^0.18.0-next.2", "@types/jest": "^26.0.7", "@types/json-schema": "^7.0.5", "@types/lodash": "^4.14.151", diff --git a/packages/catalog-model/src/entity/Entity.ts b/packages/catalog-model/src/entity/Entity.ts index 96f19b2c8a..80c9adaffb 100644 --- a/packages/catalog-model/src/entity/Entity.ts +++ b/packages/catalog-model/src/entity/Entity.ts @@ -210,4 +210,9 @@ export type EntityLink = { * An optional semantic key that represents a visual icon. */ icon?: string; + + /** + * An optional value to categorize links into specific groups + */ + type?: string; }; diff --git a/packages/catalog-model/src/entity/conditions.test.ts b/packages/catalog-model/src/entity/conditions.test.ts new file mode 100644 index 0000000000..046f1c60e4 --- /dev/null +++ b/packages/catalog-model/src/entity/conditions.test.ts @@ -0,0 +1,172 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Entity } from './Entity'; +import { + isApiEntity, + isComponentEntity, + isDomainEntity, + isGroupEntity, + isLocationEntity, + isResourceEntity, + isSystemEntity, + isUserEntity, +} from './conditions'; + +const apiEntity: Entity = { + apiVersion: '', + kind: 'api', + metadata: { name: 'api' }, +}; +const componentEntity: Entity = { + apiVersion: '', + kind: 'component', + metadata: { name: 'Component' }, +}; +const domainEntity: Entity = { + apiVersion: '', + kind: 'domain', + metadata: { name: 'Domain' }, +}; +const groupEntity: Entity = { + apiVersion: '', + kind: 'group', + metadata: { name: 'Group' }, +}; +const locationEntity: Entity = { + apiVersion: '', + kind: 'location', + metadata: { name: 'Location' }, +}; +const resourceEntity: Entity = { + apiVersion: '', + kind: 'resource', + metadata: { name: 'Resource' }, +}; +const systemEntity: Entity = { + apiVersion: '', + kind: 'system', + metadata: { name: 'System' }, +}; +const userEntity: Entity = { + apiVersion: '', + kind: 'user', + metadata: { name: 'User' }, +}; + +describe('isApiEntity', () => { + it('should check for the intended type', () => { + expect(isApiEntity(componentEntity)).not.toBeTruthy(); + expect(isApiEntity(domainEntity)).not.toBeTruthy(); + expect(isApiEntity(groupEntity)).not.toBeTruthy(); + expect(isApiEntity(locationEntity)).not.toBeTruthy(); + expect(isApiEntity(resourceEntity)).not.toBeTruthy(); + expect(isApiEntity(systemEntity)).not.toBeTruthy(); + expect(isApiEntity(userEntity)).not.toBeTruthy(); + expect(isApiEntity(apiEntity)).toBeTruthy(); + }); +}); + +describe('isComponentEntity', () => { + it('should check for the intended type', () => { + expect(isComponentEntity(apiEntity)).not.toBeTruthy(); + expect(isComponentEntity(domainEntity)).not.toBeTruthy(); + expect(isComponentEntity(groupEntity)).not.toBeTruthy(); + expect(isComponentEntity(locationEntity)).not.toBeTruthy(); + expect(isComponentEntity(resourceEntity)).not.toBeTruthy(); + expect(isComponentEntity(systemEntity)).not.toBeTruthy(); + expect(isComponentEntity(userEntity)).not.toBeTruthy(); + expect(isComponentEntity(componentEntity)).toBeTruthy(); + }); +}); + +describe('isDomainEntity', () => { + it('should check for the intended type', () => { + expect(isDomainEntity(apiEntity)).not.toBeTruthy(); + expect(isDomainEntity(componentEntity)).not.toBeTruthy(); + expect(isDomainEntity(groupEntity)).not.toBeTruthy(); + expect(isDomainEntity(locationEntity)).not.toBeTruthy(); + expect(isDomainEntity(resourceEntity)).not.toBeTruthy(); + expect(isDomainEntity(systemEntity)).not.toBeTruthy(); + expect(isDomainEntity(userEntity)).not.toBeTruthy(); + expect(isDomainEntity(domainEntity)).toBeTruthy(); + }); +}); + +describe('isGroupEntity', () => { + it('should check for the intended type', () => { + expect(isGroupEntity(apiEntity)).not.toBeTruthy(); + expect(isGroupEntity(componentEntity)).not.toBeTruthy(); + expect(isGroupEntity(domainEntity)).not.toBeTruthy(); + expect(isGroupEntity(locationEntity)).not.toBeTruthy(); + expect(isGroupEntity(resourceEntity)).not.toBeTruthy(); + expect(isGroupEntity(systemEntity)).not.toBeTruthy(); + expect(isGroupEntity(userEntity)).not.toBeTruthy(); + expect(isGroupEntity(groupEntity)).toBeTruthy(); + }); +}); + +describe('isLocationEntity', () => { + it('should check for the intended type', () => { + expect(isLocationEntity(apiEntity)).not.toBeTruthy(); + expect(isLocationEntity(componentEntity)).not.toBeTruthy(); + expect(isLocationEntity(domainEntity)).not.toBeTruthy(); + expect(isLocationEntity(groupEntity)).not.toBeTruthy(); + expect(isLocationEntity(resourceEntity)).not.toBeTruthy(); + expect(isLocationEntity(systemEntity)).not.toBeTruthy(); + expect(isLocationEntity(userEntity)).not.toBeTruthy(); + expect(isLocationEntity(locationEntity)).toBeTruthy(); + }); +}); + +describe('isResourceEntity', () => { + it('should check for the intended type', () => { + expect(isResourceEntity(apiEntity)).not.toBeTruthy(); + expect(isResourceEntity(componentEntity)).not.toBeTruthy(); + expect(isResourceEntity(domainEntity)).not.toBeTruthy(); + expect(isResourceEntity(groupEntity)).not.toBeTruthy(); + expect(isResourceEntity(locationEntity)).not.toBeTruthy(); + expect(isResourceEntity(systemEntity)).not.toBeTruthy(); + expect(isResourceEntity(userEntity)).not.toBeTruthy(); + expect(isResourceEntity(resourceEntity)).toBeTruthy(); + }); +}); + +describe('isSystemEntity', () => { + it('should check for the intended type', () => { + expect(isSystemEntity(apiEntity)).not.toBeTruthy(); + expect(isSystemEntity(componentEntity)).not.toBeTruthy(); + expect(isSystemEntity(domainEntity)).not.toBeTruthy(); + expect(isSystemEntity(groupEntity)).not.toBeTruthy(); + expect(isSystemEntity(locationEntity)).not.toBeTruthy(); + expect(isSystemEntity(resourceEntity)).not.toBeTruthy(); + expect(isSystemEntity(userEntity)).not.toBeTruthy(); + expect(isSystemEntity(systemEntity)).toBeTruthy(); + }); +}); + +describe('isUserEntity', () => { + it('should check for the intended type', () => { + expect(isUserEntity(apiEntity)).not.toBeTruthy(); + expect(isUserEntity(componentEntity)).not.toBeTruthy(); + expect(isUserEntity(domainEntity)).not.toBeTruthy(); + expect(isUserEntity(groupEntity)).not.toBeTruthy(); + expect(isUserEntity(locationEntity)).not.toBeTruthy(); + expect(isUserEntity(resourceEntity)).not.toBeTruthy(); + expect(isUserEntity(systemEntity)).not.toBeTruthy(); + expect(isUserEntity(userEntity)).toBeTruthy(); + }); +}); diff --git a/packages/catalog-model/src/entity/conditions.ts b/packages/catalog-model/src/entity/conditions.ts new file mode 100644 index 0000000000..d761695b5e --- /dev/null +++ b/packages/catalog-model/src/entity/conditions.ts @@ -0,0 +1,76 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + ApiEntity, + ComponentEntity, + DomainEntity, + GroupEntity, + LocationEntity, + ResourceEntity, + SystemEntity, + UserEntity, +} from '../kinds'; +import { Entity } from './Entity'; + +/** + * @public + */ +export function isApiEntity(entity: Entity): entity is ApiEntity { + return entity.kind.toLocaleUpperCase('en-US') === 'API'; +} +/** + * @public + */ +export function isComponentEntity(entity: Entity): entity is ComponentEntity { + return entity.kind.toLocaleUpperCase('en-US') === 'COMPONENT'; +} +/** + * @public + */ +export function isDomainEntity(entity: Entity): entity is DomainEntity { + return entity.kind.toLocaleUpperCase('en-US') === 'DOMAIN'; +} +/** + * @public + */ +export function isGroupEntity(entity: Entity): entity is GroupEntity { + return entity.kind.toLocaleUpperCase('en-US') === 'GROUP'; +} +/** + * @public + */ +export function isLocationEntity(entity: Entity): entity is LocationEntity { + return entity.kind.toLocaleUpperCase('en-US') === 'LOCATION'; +} +/** + * @public + */ +export function isResourceEntity(entity: Entity): entity is ResourceEntity { + return entity.kind.toLocaleUpperCase('en-US') === 'RESOURCE'; +} +/** + * @public + */ +export function isSystemEntity(entity: Entity): entity is SystemEntity { + return entity.kind.toLocaleUpperCase('en-US') === 'SYSTEM'; +} +/** + * @public + */ +export function isUserEntity(entity: Entity): entity is UserEntity { + return entity.kind.toLocaleUpperCase('en-US') === 'USER'; +} diff --git a/packages/catalog-model/src/entity/index.ts b/packages/catalog-model/src/entity/index.ts index 45ee673167..039529bf3e 100644 --- a/packages/catalog-model/src/entity/index.ts +++ b/packages/catalog-model/src/entity/index.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +export * from './conditions'; export { DEFAULT_NAMESPACE, ANNOTATION_EDIT_URL, diff --git a/packages/catalog-model/src/entity/policies/GroupDefaultParentEntityPolicy.test.ts b/packages/catalog-model/src/entity/policies/GroupDefaultParentEntityPolicy.test.ts new file mode 100644 index 0000000000..d5eb6145c2 --- /dev/null +++ b/packages/catalog-model/src/entity/policies/GroupDefaultParentEntityPolicy.test.ts @@ -0,0 +1,71 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { UserEntity, GroupEntity } from '../../kinds'; +import { GroupDefaultParentEntityPolicy } from './GroupDefaultParentEntityPolicy'; + +describe('GroupDefaultParentEntityPolicy', () => { + it('should ignore non-group entities', async () => { + const p = new GroupDefaultParentEntityPolicy('name'); + const u: UserEntity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'User', + metadata: { name: 'n' }, + spec: { profile: {}, memberOf: ['c'] }, + }; + const result = await p.enforce(u); + expect(result).toEqual({ + apiVersion: 'backstage.io/v1alpha1', + kind: 'User', + metadata: { name: 'n' }, + spec: { profile: {}, memberOf: ['c'] }, + }); + }); + + it('should parent group entities', async () => { + const p = new GroupDefaultParentEntityPolicy('name'); + const g: GroupEntity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { name: 'n' }, + spec: { type: 'foo', children: [] }, + }; + const result = await p.enforce(g); + expect(result).toEqual({ + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { name: 'n' }, + spec: { type: 'foo', parent: 'group:default/name', children: [] }, + }); + }); + + it('should not replace existing parents', async () => { + const p = new GroupDefaultParentEntityPolicy('namespace/name'); + const g: GroupEntity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { name: 'n' }, + spec: { type: 'foo', parent: 'group:something/else', children: [] }, + }; + const result = await p.enforce(g); + expect(result).toEqual({ + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { name: 'n' }, + spec: { type: 'foo', parent: 'group:something/else', children: [] }, + }); + }); +}); diff --git a/packages/catalog-model/src/entity/policies/GroupDefaultParentEntityPolicy.ts b/packages/catalog-model/src/entity/policies/GroupDefaultParentEntityPolicy.ts new file mode 100644 index 0000000000..8eb0aef757 --- /dev/null +++ b/packages/catalog-model/src/entity/policies/GroupDefaultParentEntityPolicy.ts @@ -0,0 +1,68 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Entity } from '../Entity'; +import { GroupEntity } from '../../kinds'; +import { EntityPolicy } from './types'; +import { DEFAULT_NAMESPACE } from '../constants'; +import { parseEntityRef, stringifyEntityRef } from '../ref'; + +/** + * DefaultParentPolicy is an EntityPolicy that updates group entities + * with a parent of last resort. This ensures that, while we preserve + * any existing group hierarchies, we can guarantee that there is a + * single global root of the group hierarchy. + * + * @public + */ +export class GroupDefaultParentEntityPolicy implements EntityPolicy { + private readonly parentRef: string; + + constructor(parentEntityRef: string) { + const { kind, namespace, name } = parseEntityRef(parentEntityRef, { + defaultKind: 'Group', + defaultNamespace: DEFAULT_NAMESPACE, + }); + + if (kind.toLocaleUpperCase('en-US') !== 'GROUP') { + throw new TypeError('group parent must be a group'); + } + + this.parentRef = stringifyEntityRef({ + kind: kind, + namespace: namespace, + name: name, + }); + } + + async enforce(entity: Entity): Promise { + if (entity.kind !== 'Group') { + return entity; + } + + const group = entity as GroupEntity; + if (group.spec.parent) { + return group; + } + + // Avoid making the parent entity it's own parent. + if (stringifyEntityRef(group) !== this.parentRef) { + group.spec.parent = this.parentRef; + } + + return group; + } +} diff --git a/packages/catalog-model/src/entity/policies/index.ts b/packages/catalog-model/src/entity/policies/index.ts index ae14007d80..d5740c0955 100644 --- a/packages/catalog-model/src/entity/policies/index.ts +++ b/packages/catalog-model/src/entity/policies/index.ts @@ -15,6 +15,7 @@ */ export { DefaultNamespaceEntityPolicy } from './DefaultNamespaceEntityPolicy'; +export { GroupDefaultParentEntityPolicy } from './GroupDefaultParentEntityPolicy'; export { FieldFormatEntityPolicy } from './FieldFormatEntityPolicy'; export { NoForeignRootFieldsEntityPolicy } from './NoForeignRootFieldsEntityPolicy'; export { SchemaValidEntityPolicy } from './SchemaValidEntityPolicy'; diff --git a/packages/catalog-model/src/schema/EntityMeta.schema.json b/packages/catalog-model/src/schema/EntityMeta.schema.json index cfdf9539c2..483e69f672 100644 --- a/packages/catalog-model/src/schema/EntityMeta.schema.json +++ b/packages/catalog-model/src/schema/EntityMeta.schema.json @@ -108,6 +108,12 @@ "description": "A key representing a visual icon to be displayed in the UI.", "examples": ["dashboard"], "minLength": 1 + }, + "type": { + "type": "string", + "description": "An optional value to categorize links into specific groups.", + "examples": ["runbook", "documentation", "logs", "dashboard"], + "minLength": 1 } } } diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 4da56c18bd..b4dbb1cdc5 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,45 @@ # @backstage/cli +## 0.18.0-next.2 + +### Patch Changes + +- f6b6fb7165: The `test` command now ensures that all IO is flushed before exiting when printing `--help`. + +## 0.18.0-next.1 + +### Minor Changes + +- 96a82d9791: **BREAKING**: Removed the following deprecated package commands: + + - `app:build` - Use `package build` instead + - `app:serve` - Use `package start` instead + - `backend:build` - Use `package build` instead + - `backend:bundle` - Use `package build` instead + - `backend:dev` - Use `package start` instead + - `plugin:build` - Use `package build` instead + - `plugin:serve` - Use `package start` instead + - `build` - Use `package build` instead + - `lint` - Use `package lint` instead + - `prepack` - Use `package prepack` instead + - `postpack` - Use `package postpack` instead + + In order to replace these you need to have [migrated to using package roles](https://backstage.io/docs/tutorials/package-role-migration). + +### Patch Changes + +- 86640214f0: Upgrade `@rollup/plugin-node-resolve` to `^13.0.6` +- e661242844: Updated dependency `run-script-webpack-plugin` to `^0.1.0`. +- Updated dependencies + - @backstage/errors@1.1.0-next.0 + - @backstage/config-loader@1.1.3-next.0 + +## 0.17.3-next.0 + +### Patch Changes + +- d2256c0384: Fix `webpack-dev-server` deprecations. + ## 0.17.2 ### Patch Changes diff --git a/packages/cli/cli-report.md b/packages/cli/cli-report.md new file mode 100644 index 0000000000..8c678d885e --- /dev/null +++ b/packages/cli/cli-report.md @@ -0,0 +1,563 @@ +## CLI Report file for "@backstage/cli" + +> Do not edit this file. It is a report generated by `yarn build:api-reports` + +### `backstage-cli` + +``` +Usage: backstage-cli [options] [command] + +Options: + -V, --version + -h, --help + +Commands: + create [options] + create-plugin [options] + plugin:diff [options] + test + config:docs [options] + config:print [options] + config:check [options] + config:schema [options] + repo [command] + package [command] + migrate [command] + versions:bump [options] + versions:check [options] + clean + build-workspace [packages...] + create-github-app + info + help [command] +``` + +### `backstage-cli build-workspace` + +``` +Usage: backstage-cli build-workspace [options] [packages...] + +Options: + -h, --help +``` + +### `backstage-cli clean` + +``` +Usage: backstage-cli clean [options] + +Options: + -h, --help +``` + +### `backstage-cli config:check` + +``` +Usage: backstage-cli config:check [options] + +Options: + --package + --lax + --frontend + --deprecated + --config + -h, --help +``` + +### `backstage-cli config:docs` + +``` +Usage: backstage-cli config:docs [options] + +Options: + --package + -h, --help +``` + +### `backstage-cli config:print` + +``` +Usage: backstage-cli config:print [options] + +Options: + --package + --lax + --frontend + --with-secrets + --format + --config + -h, --help +``` + +### `backstage-cli config:schema` + +``` +Usage: backstage-cli config:schema [options] + +Options: + --package + --format + -h, --help +``` + +### `backstage-cli create` + +``` +Usage: backstage-cli create [options] + +Options: + --select + --option = + --scope + --npm-registry + --no-private + -h, --help +``` + +### `backstage-cli create-github-app` + +``` +Usage: backstage-cli create-github-app [options] + +Options: + -h, --help +``` + +### `backstage-cli create-plugin` + +``` +Usage: backstage-cli create-plugin [options] + +Options: + --backend + --scope + --npm-registry + --no-private + -h, --help +``` + +### `backstage-cli info` + +``` +Usage: backstage-cli info [options] + +Options: + -h, --help +``` + +### `backstage-cli migrate` + +``` +Usage: backstage-cli migrate [options] [command] [command] + +Options: + -h, --help + +Commands: + package-roles + package-scripts + package-lint-configs + help [command] +``` + +### `backstage-cli migrate package-lint-configs` + +``` +Usage: backstage-cli migrate package-lint-configs [options] + +Options: + -h, --help +``` + +### `backstage-cli migrate package-roles` + +``` +Usage: backstage-cli migrate package-roles [options] + +Options: + -h, --help +``` + +### `backstage-cli migrate package-scripts` + +``` +Usage: backstage-cli migrate package-scripts [options] + +Options: + -h, --help +``` + +### `backstage-cli package` + +``` +Usage: backstage-cli package [options] [command] [command] + +Options: + -h, --help + +Commands: + start [options] + build [options] + lint [options] [directories...] + test + clean + prepack + postpack + help [command] +``` + +### `backstage-cli package build` + +``` +Usage: backstage-cli package build [options] + +Options: + --role + --minify + --experimental-type-build + --skip-build-dependencies + --stats + --config + -h, --help +``` + +### `backstage-cli package clean` + +``` +Usage: backstage-cli package clean [options] + +Options: + -h, --help +``` + +### `backstage-cli package lint` + +``` +Usage: backstage-cli package lint [options] [directories...] + +Options: + --format + --fix + -h, --help +``` + +### `backstage-cli package postpack` + +``` +Usage: backstage-cli package postpack [options] + +Options: + -h, --help +``` + +### `backstage-cli package prepack` + +``` +Usage: backstage-cli package prepack [options] + +Options: + -h, --help +``` + +### `backstage-cli package start` + +``` +Usage: backstage-cli package start [options] + +Options: + --config + --role + --check + --inspect + --inspect-brk + -h, --help +``` + +### `backstage-cli package test` + +``` +Usage: backstage-cli [--config=] [TestPathPattern] + +Options: + -h, --help + -v, --version + --all + --automock + -b, --bail + --cache + --cacheDirectory + --changedFilesWithAncestor + --changedSince + --ci + --clearCache + --clearMocks + --collectCoverage + --collectCoverageFrom + --collectCoverageOnlyFrom + --color + --colors + -c, --config + --coverage + --coverageDirectory + --coveragePathIgnorePatterns + --coverageProvider + --coverageReporters + --coverageThreshold + --debug + --detectLeaks + --detectOpenHandles + --env + --errorOnDeprecated + -e, --expand + --filter + --findRelatedTests + --forceExit + --globalSetup + --globalTeardown + --globals + --haste + --init + --injectGlobals + --json + --lastCommit + --listTests + --logHeapUsage + --maxConcurrency + -w, --maxWorkers + --moduleDirectories + --moduleFileExtensions + --moduleNameMapper + --modulePathIgnorePatterns + --modulePaths + --noStackTrace + --notify + --notifyMode + -o, --onlyChanged + -f, --onlyFailures + --outputFile + --passWithNoTests + --preset + --prettierPath + --projects + --reporters + --resetMocks + --resetModules + --resolver + --restoreMocks + --rootDir + --roots + -i, --runInBand + --runTestsByPath + --runner + --selectProjects + --setupFiles + --setupFilesAfterEnv + --showConfig + --silent + --skipFilter + --snapshotSerializers + --testEnvironment + --testEnvironmentOptions + --testFailureExitCode + --testLocationInResults + --testMatch + -t, --testNamePattern + --testPathIgnorePatterns + --testPathPattern + --testRegex + --testResultsProcessor + --testRunner + --testSequencer + --testTimeout + --testURL + --timers + --transform + --transformIgnorePatterns + --unmockedModulePathPatterns + -u, --updateSnapshot + --useStderr + --verbose + --watch + --watchAll + --watchPathIgnorePatterns + --watchman +``` + +### `backstage-cli plugin:diff` + +``` +Usage: backstage-cli plugin:diff [options] + +Options: + --check + --yes + -h, --help +``` + +### `backstage-cli repo` + +``` +Usage: backstage-cli repo [options] [command] [command] + +Options: + -h, --help + +Commands: + build [options] + lint [options] + help [command] +``` + +### `backstage-cli repo build` + +``` +Usage: backstage-cli repo build [options] + +Options: + --all + --since + -h, --help +``` + +### `backstage-cli repo lint` + +``` +Usage: backstage-cli repo lint [options] + +Options: + --format + --since + --fix + -h, --help +``` + +### `backstage-cli test` + +``` +Usage: backstage-cli [--config=] [TestPathPattern] + +Options: + -h, --help + -v, --version + --all + --automock + -b, --bail + --cache + --cacheDirectory + --changedFilesWithAncestor + --changedSince + --ci + --clearCache + --clearMocks + --collectCoverage + --collectCoverageFrom + --collectCoverageOnlyFrom + --color + --colors + -c, --config + --coverage + --coverageDirectory + --coveragePathIgnorePatterns + --coverageProvider + --coverageReporters + --coverageThreshold + --debug + --detectLeaks + --detectOpenHandles + --env + --errorOnDeprecated + -e, --expand + --filter + --findRelatedTests + --forceExit + --globalSetup + --globalTeardown + --globals + --haste + --init + --injectGlobals + --json + --lastCommit + --listTests + --logHeapUsage + --maxConcurrency + -w, --maxWorkers + --moduleDirectories + --moduleFileExtensions + --moduleNameMapper + --modulePathIgnorePatterns + --modulePaths + --noStackTrace + --notify + --notifyMode + -o, --onlyChanged + -f, --onlyFailures + --outputFile + --passWithNoTests + --preset + --prettierPath + --projects + --reporters + --resetMocks + --resetModules + --resolver + --restoreMocks + --rootDir + --roots + -i, --runInBand + --runTestsByPath + --runner + --selectProjects + --setupFiles + --setupFilesAfterEnv + --showConfig + --silent + --skipFilter + --snapshotSerializers + --testEnvironment + --testEnvironmentOptions + --testFailureExitCode + --testLocationInResults + --testMatch + -t, --testNamePattern + --testPathIgnorePatterns + --testPathPattern + --testRegex + --testResultsProcessor + --testRunner + --testSequencer + --testTimeout + --testURL + --timers + --transform + --transformIgnorePatterns + --unmockedModulePathPatterns + -u, --updateSnapshot + --useStderr + --verbose + --watch + --watchAll + --watchPathIgnorePatterns + --watchman +``` + +### `backstage-cli versions:bump` + +``` +Usage: backstage-cli versions:bump [options] + +Options: + --pattern + --release + -h, --help +``` + +### `backstage-cli versions:check` + +``` +Usage: backstage-cli versions:check [options] + +Options: + --fix + -h, --help +``` diff --git a/packages/cli/package.json b/packages/cli/package.json index 071fc74f97..aead136ec6 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/cli", "description": "CLI for developing Backstage plugins and apps", - "version": "0.17.2", + "version": "0.18.0-next.2", "private": false, "publishConfig": { "access": "public" @@ -33,8 +33,8 @@ "dependencies": { "@backstage/cli-common": "^0.1.9", "@backstage/config": "^1.0.1", - "@backstage/config-loader": "^1.1.2", - "@backstage/errors": "^1.0.0", + "@backstage/config-loader": "^1.1.3-next.0", + "@backstage/errors": "^1.1.0-next.0", "@backstage/release-manifests": "^0.0.4", "@backstage/types": "^1.0.0", "@hot-loader/react-dom-v16": "npm:@hot-loader/react-dom@^16.0.2", @@ -43,7 +43,7 @@ "@octokit/request": "^5.4.12", "@rollup/plugin-commonjs": "^22.0.0", "@rollup/plugin-json": "^4.1.0", - "@rollup/plugin-node-resolve": "^13.0.0", + "@rollup/plugin-node-resolve": "^13.0.6", "@rollup/plugin-yaml": "^3.1.0", "@spotify/eslint-config-base": "^13.0.0", "@spotify/eslint-config-react": "^13.0.0", @@ -110,7 +110,7 @@ "rollup-plugin-esbuild": "^4.7.2", "rollup-plugin-postcss": "^4.0.0", "rollup-pluginutils": "^2.8.2", - "run-script-webpack-plugin": "^0.0.14", + "run-script-webpack-plugin": "^0.1.0", "semver": "^7.3.2", "style-loader": "^3.3.1", "sucrase": "^3.20.2", @@ -126,14 +126,14 @@ "zod": "^3.11.6" }, "devDependencies": { - "@backstage/backend-common": "^0.14.0", + "@backstage/backend-common": "^0.14.1-next.2", "@backstage/config": "^1.0.1", - "@backstage/core-app-api": "^1.0.3", - "@backstage/core-components": "^0.9.5", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", - "@backstage/theme": "^0.2.15", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", + "@backstage/theme": "^0.2.16-next.1", "@types/diff": "^5.0.0", "@types/express": "^4.17.6", "@types/fs-extra": "^9.0.1", @@ -152,7 +152,7 @@ "@types/yarnpkg__lockfile": "^1.1.4", "del": "^6.0.0", "mock-fs": "^5.1.0", - "msw": "^0.42.0", + "msw": "^0.43.0", "nodemon": "^2.0.2", "ts-node": "^10.0.0" }, diff --git a/packages/cli/src/commands/app/build.ts b/packages/cli/src/commands/app/build.ts deleted file mode 100644 index f90052bc83..0000000000 --- a/packages/cli/src/commands/app/build.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import fs from 'fs-extra'; -import { OptionValues } from 'commander'; -import { buildBundle } from '../../lib/bundler'; -import { getEnvironmentParallelism } from '../../lib/parallel'; -import { loadCliConfig } from '../../lib/config'; -import { paths } from '../../lib/paths'; - -export default async (opts: OptionValues) => { - const { name } = await fs.readJson(paths.resolveTarget('package.json')); - await buildBundle({ - entry: 'src/index', - parallelism: getEnvironmentParallelism(), - statsJsonEnabled: opts.stats, - ...(await loadCliConfig({ - args: opts.config, - fromPackage: name, - })), - }); -}; diff --git a/packages/cli/src/commands/app/serve.ts b/packages/cli/src/commands/app/serve.ts deleted file mode 100644 index e41c2367da..0000000000 --- a/packages/cli/src/commands/app/serve.ts +++ /dev/null @@ -1,92 +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 fs from 'fs-extra'; -import chalk from 'chalk'; -import uniq from 'lodash/uniq'; -import { OptionValues } from 'commander'; -import { serveBundle } from '../../lib/bundler'; -import { loadCliConfig } from '../../lib/config'; -import { paths } from '../../lib/paths'; -import { Lockfile } from '../../lib/versioning'; -import { forbiddenDuplicatesFilter, includedFilter } from '../versions/lint'; - -export default async (opts: OptionValues) => { - const lockFilePath = paths.resolveTargetRoot('yarn.lock'); - if (fs.existsSync(lockFilePath)) { - try { - const lockfile = await Lockfile.load(lockFilePath); - const result = lockfile.analyze({ - filter: includedFilter, - }); - const problemPackages = [...result.newVersions, ...result.newRanges] - .map(({ name }) => name) - .filter(name => forbiddenDuplicatesFilter(name)); - - if (problemPackages.length > 0) { - console.log( - chalk.yellow( - `⚠️ Some of the following packages may be outdated or have duplicate installations: - - ${uniq(problemPackages).join(', ')} - `, - ), - ); - console.log( - chalk.yellow( - `⚠️ The following command may fix the issue, but it could also be an issue within one of your dependencies: - - yarn backstage-cli versions:check --fix - `, - ), - ); - } - } catch (error) { - console.log( - chalk.yellow( - `⚠️ Unable to parse yarn.lock file properly: - - ${error} - - skipping analyzer for outdated or duplicate installations - `, - ), - ); - } - } else { - console.log( - chalk.yellow( - `⚠️ Unable to find yarn.lock file: - - skipping analyzer for outdated or duplicate installations - `, - ), - ); - } - - const { name } = await fs.readJson(paths.resolveTarget('package.json')); - const waitForExit = await serveBundle({ - entry: 'src/index', - checksEnabled: opts.check, - ...(await loadCliConfig({ - args: opts.config, - fromPackage: name, - withFilteredKeys: true, - })), - }); - - await waitForExit(); -}; diff --git a/packages/cli/src/commands/backend/bundle.ts b/packages/cli/src/commands/backend/bundle.ts deleted file mode 100644 index 78d4d72d92..0000000000 --- a/packages/cli/src/commands/backend/bundle.ts +++ /dev/null @@ -1,72 +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 os from 'os'; -import fs from 'fs-extra'; -import { resolve as resolvePath } from 'path'; -import tar, { CreateOptions } from 'tar'; -import { OptionValues } from 'commander'; -import { createDistWorkspace } from '../../lib/packager'; -import { paths } from '../../lib/paths'; -import { getEnvironmentParallelism } from '../../lib/parallel'; -import { buildPackage, Output } from '../../lib/builder'; - -const BUNDLE_FILE = 'bundle.tar.gz'; -const SKELETON_FILE = 'skeleton.tar.gz'; - -export default async (opts: OptionValues) => { - const targetDir = paths.resolveTarget('dist'); - const pkg = await fs.readJson(paths.resolveTarget('package.json')); - - // We build the target package without generating type declarations. - await buildPackage({ outputs: new Set([Output.cjs]) }); - - const tmpDir = await fs.mkdtemp(resolvePath(os.tmpdir(), 'backstage-bundle')); - try { - await createDistWorkspace([pkg.name], { - targetDir: tmpDir, - buildDependencies: Boolean(opts.buildDependencies), - buildExcludes: [pkg.name], - parallelism: getEnvironmentParallelism(), - skeleton: SKELETON_FILE, - }); - - // 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); - - // 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), - ); - - // 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), - cwd: tmpDir, - portable: true, - noMtime: true, - gzip: true, - } as CreateOptions & { noMtime: boolean }, - [''], - ); - } finally { - await fs.remove(tmpDir); - } -}; diff --git a/packages/cli/src/commands/backend/dev.ts b/packages/cli/src/commands/backend/dev.ts deleted file mode 100644 index 2ee43958a2..0000000000 --- a/packages/cli/src/commands/backend/dev.ts +++ /dev/null @@ -1,36 +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 fs from 'fs-extra'; -import { OptionValues } from 'commander'; -import { paths } from '../../lib/paths'; -import { serveBackend } from '../../lib/bundler/backend'; - -export default async (opts: OptionValues) => { - // Cleaning dist/ before we start the dev process helps work around an issue - // where we end up with the entrypoint executing multiple times, causing - // a port bind conflict among other things. - await fs.remove(paths.resolveTarget('dist')); - - const waitForExit = await serveBackend({ - entry: 'src/index', - checksEnabled: opts.check, - inspectEnabled: opts.inspect, - inspectBrkEnabled: opts.inspectBrk, - }); - - await waitForExit(); -}; diff --git a/packages/cli/src/commands/index.ts b/packages/cli/src/commands/index.ts index 1a7b2c4f08..aca238a32b 100644 --- a/packages/cli/src/commands/index.ts +++ b/packages/cli/src/commands/index.ts @@ -183,53 +183,6 @@ export function registerMigrateCommand(program: Command) { } export function registerCommands(program: Command) { - // TODO(Rugvip): Deprecate in favor of package variant - program - .command('app:build') - .description('Build an app for a production release [DEPRECATED]') - .option('--stats', 'Write bundle stats to output directory') - .option(...configOption) - .action(lazy(() => import('./app/build').then(m => m.default))); - - // TODO(Rugvip): Deprecate in favor of package variant - program - .command('app:serve') - .description('Serve an app for local development [DEPRECATED]') - .option('--check', 'Enable type checking and linting') - .option(...configOption) - .action(lazy(() => import('./app/serve').then(m => m.default))); - - // TODO(Rugvip): Deprecate in favor of package variant - program - .command('backend:build') - .description('Build a backend plugin [DEPRECATED]') - .option('--minify', 'Minify the generated code') - .option('--experimental-type-build', 'Enable experimental type build') - .action(lazy(() => import('./backend/build').then(m => m.default))); - - // TODO(Rugvip): Deprecate in favor of package variant - program - .command('backend:bundle') - .description('Bundle the backend into a deployment archive [DEPRECATED]') - .option( - '--build-dependencies', - 'Build all local package dependencies before bundling the backend', - ) - .action(lazy(() => import('./backend/bundle').then(m => m.default))); - - // TODO(Rugvip): Deprecate in favor of package variant - program - .command('backend:dev') - .description( - 'Start local development server with HMR for the backend [DEPRECATED]', - ) - .option('--check', 'Enable type checking and linting') - .option('--inspect', 'Enable debugger') - .option('--inspect-brk', 'Enable debugger with await to attach debugger') - // We don't actually use the config in the CLI, just pass them on to the NodeJS process - .option(...configOption) - .action(lazy(() => import('./backend/dev').then(m => m.default))); - program .command('create') .storeOptionsAsProperties(false) @@ -268,22 +221,6 @@ export function registerCommands(program: Command) { lazy(() => import('./create-plugin/createPlugin').then(m => m.default)), ); - // TODO(Rugvip): Deprecate in favor of package variant - program - .command('plugin:build') - .description('Build a plugin [DEPRECATED]') - .option('--minify', 'Minify the generated code') - .option('--experimental-type-build', 'Enable experimental type build') - .action(lazy(() => import('./plugin/build').then(m => m.default))); - - // TODO(Rugvip): Deprecate in favor of package variant - program - .command('plugin:serve') - .description('Serves the dev/ folder of a plugin [DEPRECATED]') - .option('--check', 'Enable type checking and linting') - .option(...configOption) - .action(lazy(() => import('./plugin/serve').then(m => m.default))); - program .command('plugin:diff') .option('--check', 'Fail if changes are required') @@ -291,27 +228,6 @@ export function registerCommands(program: Command) { .description('Diff an existing plugin with the creation template') .action(lazy(() => import('./plugin/diff').then(m => m.default))); - // TODO(Rugvip): Deprecate in favor of package variant - program - .command('build') - .description('Build a package for publishing [DEPRECATED]') - .option('--outputs ', 'List of formats to output [types,cjs,esm]') - .option('--minify', 'Minify the generated code') - .option('--experimental-type-build', 'Enable experimental type build') - .action(lazy(() => import('./oldBuild').then(m => m.default))); - - // TODO(Rugvip): Deprecate in favor of package variant - program - .command('lint [directories...]') - .option( - '--format ', - 'Lint report output format', - 'eslint-formatter-friendly', - ) - .option('--fix', 'Attempt to automatically fix violations') - .description('Lint a package [DEPRECATED]') - .action(lazy(() => import('./lint').then(m => m.default))); - // TODO(Rugvip): Deprecate in favor of package variant program .command('test') @@ -400,22 +316,6 @@ export function registerCommands(program: Command) { .description('Check Backstage package versioning') .action(lazy(() => import('./versions/lint').then(m => m.default))); - // TODO(Rugvip): Deprecate in favor of package variant - program - .command('prepack') - .description( - 'Prepares a package for packaging before publishing [DEPRECATED]', - ) - .action(lazy(() => import('./pack').then(m => m.pre))); - - // TODO(Rugvip): Deprecate in favor of package variant - program - .command('postpack') - .description( - 'Restores the changes made by the prepack command [DEPRECATED]', - ) - .action(lazy(() => import('./pack').then(m => m.post))); - // TODO(Rugvip): Deprecate in favor of package variant program .command('clean') diff --git a/packages/cli/src/commands/oldBuild.ts b/packages/cli/src/commands/oldBuild.ts deleted file mode 100644 index c0899d4d02..0000000000 --- a/packages/cli/src/commands/oldBuild.ts +++ /dev/null @@ -1,41 +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 { buildPackage, Output } from '../lib/builder'; -import { OptionValues } from 'commander'; - -export default async (opts: OptionValues) => { - let outputs = new Set(); - - const { outputs: outputsStr } = opts as { outputs?: string }; - if (outputsStr) { - for (const output of outputsStr.split(',') as (keyof typeof Output)[]) { - if (output in Output) { - outputs.add(Output[output]); - } else { - throw new Error(`Unknown output format: ${output}`); - } - } - } else { - outputs = new Set([Output.types, Output.esm, Output.cjs]); - } - - await buildPackage({ - outputs, - minify: opts.minify, - useApiExtractor: opts.experimentalTypeBuild, - }); -}; diff --git a/packages/cli/src/commands/plugin/serve.ts b/packages/cli/src/commands/plugin/serve.ts deleted file mode 100644 index 891db190e0..0000000000 --- a/packages/cli/src/commands/plugin/serve.ts +++ /dev/null @@ -1,36 +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 fs from 'fs-extra'; -import { OptionValues } from 'commander'; -import { serveBundle } from '../../lib/bundler'; -import { loadCliConfig } from '../../lib/config'; -import { paths } from '../../lib/paths'; - -export default async (opts: OptionValues) => { - const { name } = await fs.readJson(paths.resolveTarget('package.json')); - const waitForExit = await serveBundle({ - entry: 'dev/index', - checksEnabled: opts.check, - ...(await loadCliConfig({ - args: opts.config, - fromPackage: name, - withFilteredKeys: true, - })), - }); - - await waitForExit(); -}; diff --git a/packages/cli/src/commands/test.ts b/packages/cli/src/commands/test.ts index f1bfcc356b..88769aec1a 100644 --- a/packages/cli/src/commands/test.ts +++ b/packages/cli/src/commands/test.ts @@ -78,6 +78,10 @@ export default async (_opts: OptionValues, cmd: Command) => { process.env.TZ = 'UTC'; } + if (args.includes('--help')) { + (process.stdout as any)._handle.setBlocking(true); + } + // eslint-disable-next-line jest/no-jest-import await require('jest').run(args); }; diff --git a/packages/cli/src/lib/bundler/server.ts b/packages/cli/src/lib/bundler/server.ts index e65e598106..d573f80e27 100644 --- a/packages/cli/src/lib/bundler/server.ts +++ b/packages/cli/src/lib/bundler/server.ts @@ -43,7 +43,6 @@ export async function serveBundle(options: ServeOptions) { const compiler = webpack(config); const server = new WebpackDevServer( - compiler as any, { hot: !process.env.CI, devMiddleware: { @@ -71,10 +70,11 @@ export async function serveBundle(options: ServeOptions) { webSocketURL: 'auto://0.0.0.0:0/ws', }, } as any, + compiler as any, ); await new Promise((resolve, reject) => { - server.listen(port, host, (err?: Error) => { + server.startCallback((err?: Error) => { if (err) { reject(err); return; diff --git a/packages/cli/templates/default-backend-plugin/package.json.hbs b/packages/cli/templates/default-backend-plugin/package.json.hbs index 2416fd75cb..4e8ee254b9 100644 --- a/packages/cli/templates/default-backend-plugin/package.json.hbs +++ b/packages/cli/templates/default-backend-plugin/package.json.hbs @@ -41,7 +41,7 @@ "@backstage/cli": "{{versionQuery '@backstage/cli'}}", "@types/supertest": "{{versionQuery '@types/supertest' '2.0.8'}}", "supertest": "{{versionQuery 'supertest' '4.0.2'}}", - "msw": "{{versionQuery 'msw' '0.42.0'}}" + "msw": "{{versionQuery 'msw' '0.43.0'}}" }, "files": [ "dist" diff --git a/packages/cli/templates/default-plugin/package.json.hbs b/packages/cli/templates/default-plugin/package.json.hbs index 34a0548b29..490f18d474 100644 --- a/packages/cli/templates/default-plugin/package.json.hbs +++ b/packages/cli/templates/default-plugin/package.json.hbs @@ -49,7 +49,7 @@ "@testing-library/user-event": "{{versionQuery '@testing-library/user-event' '14.0.0'}}", "@types/jest": "{{versionQuery '@types/jest' '26.0.7'}}", "@types/node": "{{versionQuery '@types/node' '16.11.26'}}", - "msw": "{{versionQuery 'msw' '0.42.0'}}", + "msw": "{{versionQuery 'msw' '0.43.0'}}", "cross-fetch": "{{versionQuery 'cross-fetch' '3.1.5'}}" }, "files": [ diff --git a/packages/codemods/cli-report.md b/packages/codemods/cli-report.md new file mode 100644 index 0000000000..57d2198141 --- /dev/null +++ b/packages/codemods/cli-report.md @@ -0,0 +1,61 @@ +## CLI Report file for "@backstage/codemods" + +> Do not edit this file. It is a report generated by `yarn build:api-reports` + +### `backstage-codemods` + +``` +Usage: backstage-codemods [options] [command] + +Options: + -V, --version + -h, --help + +Commands: + apply [target-dirs...] + list + help [command] +``` + +### `backstage-codemods apply` + +``` +Usage: backstage-codemods apply [options] [command] [target-dirs...] + +Options: + -h, --help + +Commands: + core-imports [options] [target-dirs...] + extension-names [options] [target-dirs...] + help [command] +``` + +### `backstage-codemods apply core-imports` + +``` +Usage: backstage-codemods apply core-imports [options] [target-dirs...] + +Options: + -d, --dry + -h, --help +``` + +### `backstage-codemods apply extension-names` + +``` +Usage: backstage-codemods apply extension-names [options] [target-dirs...] + +Options: + -d, --dry + -h, --help +``` + +### `backstage-codemods list` + +``` +Usage: backstage-codemods list [options] + +Options: + -h, --help +``` diff --git a/packages/config-loader/CHANGELOG.md b/packages/config-loader/CHANGELOG.md index d9228aa091..af297b1112 100644 --- a/packages/config-loader/CHANGELOG.md +++ b/packages/config-loader/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/config-loader +## 1.1.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.1.0-next.0 + ## 1.1.2 ### Patch Changes diff --git a/packages/config-loader/package.json b/packages/config-loader/package.json index 3448b336b7..3ca4b1455f 100644 --- a/packages/config-loader/package.json +++ b/packages/config-loader/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/config-loader", "description": "Config loading functionality used by Backstage backend, and CLI", - "version": "1.1.2", + "version": "1.1.3-next.0", "private": false, "publishConfig": { "access": "public", @@ -36,7 +36,7 @@ "dependencies": { "@backstage/cli-common": "^0.1.9", "@backstage/config": "^1.0.1", - "@backstage/errors": "^1.0.0", + "@backstage/errors": "^1.1.0-next.0", "@backstage/types": "^1.0.0", "@types/json-schema": "^7.0.6", "ajv": "^8.10.0", @@ -46,7 +46,7 @@ "json-schema-merge-allof": "^0.8.1", "json-schema-traverse": "^1.0.0", "node-fetch": "^2.6.7", - "typescript-json-schema": "^0.53.0", + "typescript-json-schema": "^0.54.0", "yaml": "^1.9.2", "yup": "^0.32.9" }, @@ -57,7 +57,7 @@ "@types/node": "^16.11.26", "@types/yup": "^0.29.13", "mock-fs": "^5.1.0", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/packages/config/package.json b/packages/config/package.json index bc0693fa73..fc99531bb4 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -37,7 +37,7 @@ "lodash": "^4.17.21" }, "devDependencies": { - "@backstage/test-utils": "^1.1.1-next.0", + "@backstage/test-utils": "^1.1.2-next.0", "@types/jest": "^26.0.7", "@types/node": "^16.0.0" }, diff --git a/packages/core-app-api/CHANGELOG.md b/packages/core-app-api/CHANGELOG.md index 8d78e51c62..c4d2f9d8fe 100644 --- a/packages/core-app-api/CHANGELOG.md +++ b/packages/core-app-api/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/core-app-api +## 1.0.4-next.0 + +### Patch Changes + +- 8fe2357101: The `signOut` method of the `IdentityApi` will now navigate the user back to the base URL of the app as indicated by the `app.baseUrl` config. + ## 1.0.3 ### Patch Changes diff --git a/packages/core-app-api/package.json b/packages/core-app-api/package.json index cbf9d7eb40..e7d530417a 100644 --- a/packages/core-app-api/package.json +++ b/packages/core-app-api/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/core-app-api", "description": "Core app API used by Backstage apps", - "version": "1.0.3", + "version": "1.0.4-next.0", "private": false, "publishConfig": { "access": "public", @@ -49,8 +49,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.1", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/react-hooks": "^8.0.0", @@ -59,7 +59,7 @@ "@types/node": "^16.11.26", "@types/zen-observable": "^0.8.0", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist", diff --git a/packages/core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy.test.ts b/packages/core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy.test.ts index aa15182499..3d4f83b05d 100644 --- a/packages/core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy.test.ts +++ b/packages/core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy.test.ts @@ -31,7 +31,7 @@ describe('AppIdentityProxy', () => { it('should forward user identities', async () => { const proxy = new AppIdentityProxy(); - proxy.setTarget(mockIdentityApi); + proxy.setTarget(mockIdentityApi, { signOutTargetUrl: '/' }); const logs = await withLogCollector(async () => { mockIdentityApi.getBackstageIdentity.mockResolvedValueOnce({ @@ -55,7 +55,7 @@ describe('AppIdentityProxy', () => { it('should warn about invalid user entity refs', async () => { const proxy = new AppIdentityProxy(); - proxy.setTarget(mockIdentityApi); + proxy.setTarget(mockIdentityApi, { signOutTargetUrl: '/' }); const logs = await withLogCollector(async () => { mockIdentityApi.getBackstageIdentity.mockResolvedValueOnce({ @@ -79,4 +79,16 @@ describe('AppIdentityProxy', () => { error: [], }); }); + + it('should navigate to target URL on sign out', async () => { + const proxy = new AppIdentityProxy(); + proxy.setTarget(mockIdentityApi, { signOutTargetUrl: '/foo' }); + Object.defineProperty(window, 'location', { + writable: true, + value: {}, + }); + + await proxy.signOut(); + expect(location.href).toBe('/foo'); + }); }); diff --git a/packages/core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy.ts b/packages/core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy.ts index 3ef3a1f6d3..2df351bc18 100644 --- a/packages/core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy.ts +++ b/packages/core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy.ts @@ -49,6 +49,7 @@ export class AppIdentityProxy implements IdentityApi { private target?: CompatibilityIdentityApi; private waitForTarget: Promise; private resolveTarget: (api: CompatibilityIdentityApi) => void = () => {}; + private signOutTargetUrl = '/'; constructor() { this.waitForTarget = new Promise(resolve => { @@ -57,8 +58,12 @@ export class AppIdentityProxy implements IdentityApi { } // This is called by the app manager once the sign-in page provides us with an implementation - setTarget(identityApi: CompatibilityIdentityApi) { + setTarget( + identityApi: CompatibilityIdentityApi, + targetOptions: { signOutTargetUrl: string }, + ) { this.target = identityApi; + this.signOutTargetUrl = targetOptions.signOutTargetUrl; this.resolveTarget(identityApi); } @@ -119,6 +124,6 @@ export class AppIdentityProxy implements IdentityApi { async signOut(): Promise { await this.waitForTarget.then(target => target.signOut()); - location.reload(); + location.href = this.signOutTargetUrl; } } diff --git a/packages/core-app-api/src/app/AppManager.tsx b/packages/core-app-api/src/app/AppManager.tsx index 75bab5c2df..f47ddf676a 100644 --- a/packages/core-app-api/src/app/AppManager.tsx +++ b/packages/core-app-api/src/app/AppManager.tsx @@ -334,41 +334,49 @@ export class AppManager implements BackstageApp { children: ReactElement; }) => { const [identityApi, setIdentityApi] = useState(); + const configApi = useApi(configApiRef); + const basePath = getBasePath(configApi); if (!identityApi) { return ; } - this.appIdentityProxy.setTarget(identityApi); + this.appIdentityProxy.setTarget(identityApi, { + signOutTargetUrl: basePath || '/', + }); return children; }; const AppRouter = ({ children }: PropsWithChildren<{}>) => { const configApi = useApi(configApiRef); - const mountPath = `${getBasePath(configApi)}/*`; + const basePath = getBasePath(configApi); + const mountPath = `${basePath}/*`; const { routeObjects } = useContext(InternalAppContext); // If the app hasn't configured a sign-in page, we just continue as guest. if (!SignInPageComponent) { - this.appIdentityProxy.setTarget({ - getUserId: () => 'guest', - getIdToken: async () => undefined, - getProfile: () => ({ - email: 'guest@example.com', - displayName: 'Guest', - }), - getProfileInfo: async () => ({ - email: 'guest@example.com', - displayName: 'Guest', - }), - getBackstageIdentity: async () => ({ - type: 'user', - userEntityRef: 'user:default/guest', - ownershipEntityRefs: ['user:default/guest'], - }), - getCredentials: async () => ({}), - signOut: async () => {}, - }); + this.appIdentityProxy.setTarget( + { + getUserId: () => 'guest', + getIdToken: async () => undefined, + getProfile: () => ({ + email: 'guest@example.com', + displayName: 'Guest', + }), + getProfileInfo: async () => ({ + email: 'guest@example.com', + displayName: 'Guest', + }), + getBackstageIdentity: async () => ({ + type: 'user', + userEntityRef: 'user:default/guest', + ownershipEntityRefs: ['user:default/guest'], + }), + getCredentials: async () => ({}), + signOut: async () => {}, + }, + { signOutTargetUrl: basePath || '/' }, + ); return ( diff --git a/packages/core-components/CHANGELOG.md b/packages/core-components/CHANGELOG.md index faec6d3d90..46a44394b3 100644 --- a/packages/core-components/CHANGELOG.md +++ b/packages/core-components/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/core-components +## 0.10.0-next.2 + +### Minor Changes + +- 32204fa794: Add `transformLinkUri` and `transformImageUri` to `MarkdownContent` + +### Patch Changes + +- b4b711bcc2: Fix the EntityLayout header style so that EntityContextMenu button can display in correct shape when user hover on it +- 15201b1032: Updated dependency `rc-progress` to `3.4.0`. +- 385389d23c: Updated to remove usage of the `bursts` object in the theme palette +- Updated dependencies + - @backstage/theme@0.2.16-next.1 + +## 0.9.6-next.1 + +### Patch Changes + +- 3c440ea77e: Change BackstageIconLinkVertical style to use pallette instead of explicit color +- 7e115d42f9: Support displaying subtitle text in `SidebarSubmenuItem` +- Updated dependencies + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + +## 0.9.6-next.0 + +### Patch Changes + +- c3cfc83af2: Updated JSDoc to be MDX compatible. + ## 0.9.5 ### Patch Changes diff --git a/packages/core-components/api-report.md b/packages/core-components/api-report.md index 911ef36867..302ef7ef7d 100644 --- a/packages/core-components/api-report.md +++ b/packages/core-components/api-report.md @@ -1110,6 +1110,7 @@ export type SidebarSubmenuItemDropdownItem = { // @public export type SidebarSubmenuItemProps = { title: string; + subtitle?: string; to?: string; icon?: IconComponent; dropdownItems?: SidebarSubmenuItemDropdownItem[]; diff --git a/packages/core-components/package.json b/packages/core-components/package.json index 867909b3cf..0d27c6419d 100644 --- a/packages/core-components/package.json +++ b/packages/core-components/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/core-components", "description": "Core components used by Backstage plugins and apps", - "version": "0.9.5", + "version": "0.10.0-next.2", "private": false, "publishConfig": { "access": "public", @@ -35,8 +35,8 @@ "dependencies": { "@backstage/config": "^1.0.1", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/errors": "^1.0.0", - "@backstage/theme": "^0.2.15", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/theme": "^0.2.16-next.1", "@backstage/version-bridge": "^1.0.1", "@material-table/core": "^3.1.0", "@material-ui/core": "^4.12.2", @@ -56,7 +56,7 @@ "pluralize": "^8.0.0", "prop-types": "^15.7.2", "qs": "^6.9.4", - "rc-progress": "3.3.3", + "rc-progress": "3.4.0", "react-helmet": "6.1.0", "react-hook-form": "^7.12.2", "react-markdown": "^8.0.0", @@ -79,9 +79,9 @@ "react-dom": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/core-app-api": "^1.0.3", - "@backstage/cli": "^0.17.2", - "@backstage/test-utils": "^1.1.1", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/react-hooks": "^8.0.0", @@ -101,7 +101,7 @@ "@types/react-window": "^1.8.5", "@types/zen-observable": "^0.8.0", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/packages/core-components/src/components/HeaderIconLinkRow/IconLinkVertical.tsx b/packages/core-components/src/components/HeaderIconLinkRow/IconLinkVertical.tsx index 2816603f7f..dda2782c45 100644 --- a/packages/core-components/src/components/HeaderIconLinkRow/IconLinkVertical.tsx +++ b/packages/core-components/src/components/HeaderIconLinkRow/IconLinkVertical.tsx @@ -47,7 +47,7 @@ const useIconStyles = makeStyles( textAlign: 'center', }, disabled: { - color: 'gray', + color: theme.palette.text.secondary, cursor: 'default', }, primary: { diff --git a/packages/core-components/src/components/Link/Link.test.tsx b/packages/core-components/src/components/Link/Link.test.tsx index 8c6ed54d76..5cfeaa4869 100644 --- a/packages/core-components/src/components/Link/Link.test.tsx +++ b/packages/core-components/src/components/Link/Link.test.tsx @@ -21,9 +21,11 @@ import { TestApiProvider, wrapInTestApp, } from '@backstage/test-utils'; -import { analyticsApiRef } from '@backstage/core-plugin-api'; -import { isExternalUri, Link } from './Link'; +import { analyticsApiRef, configApiRef } from '@backstage/core-plugin-api'; +import { isExternalUri, Link, useResolvedPath } from './Link'; import { Route, Routes } from 'react-router'; +import { renderHook, WrapperComponent } from '@testing-library/react-hooks'; +import { ConfigReader } from '@backstage/config'; describe('', () => { it('navigates using react-router', async () => { @@ -103,6 +105,58 @@ describe('', () => { }); }); + describe('resolves a sub-path correctly', () => { + it('when it starts with base path', async () => { + const testString = 'This is test string'; + const linkText = 'Navigate!'; + const configApi = new ConfigReader({ + app: { baseUrl: 'http://localhost:3000/example' }, + }); + + const { getByText } = render( + wrapInTestApp( + + + {linkText} + {testString}

} /> +
+
, + ), + ); + + expect(() => getByText(testString)).toThrow(); + fireEvent.click(getByText(linkText)); + await waitFor(() => { + expect(getByText(testString)).toBeInTheDocument(); + }); + }); + + it('when it does not start with base path', async () => { + const testString = 'This is test string'; + const linkText = 'Navigate!'; + const configApi = new ConfigReader({ + app: { baseUrl: 'http://localhost:3000/example' }, + }); + + const { getByText } = render( + wrapInTestApp( + + + {linkText} + {testString}

} /> +
+
, + ), + ); + + expect(() => getByText(testString)).toThrow(); + fireEvent.click(getByText(linkText)); + await waitFor(() => { + expect(getByText(testString)).toBeInTheDocument(); + }); + }); + }); + describe('isExternalUri', () => { it.each([ [true, 'http://'], @@ -128,4 +182,45 @@ describe('', () => { expect(isExternalUri(uri)).toBe(expected); }); }); + + describe('useResolvedPath', () => { + const wrapper: WrapperComponent<{}> = ({ children }) => { + const configApi = new ConfigReader({ + app: { baseUrl: 'http://localhost:3000/example' }, + }); + return ( + + {children} + + ); + }; + + describe('concatenate base path', () => { + it('when uri is internal and does not start with base path', () => { + const path = '/catalog/default/component/artist-lookup'; + const { result } = renderHook(() => useResolvedPath(path), { + wrapper, + }); + expect(result.current).toBe('/example'.concat(path)); + }); + }); + + describe('does not concatenate base path', () => { + it('when uri is external', () => { + const path = 'https://stackoverflow.com/questions/1/example'; + const { result } = renderHook(() => useResolvedPath(path), { + wrapper, + }); + expect(result.current).toBe(path); + }); + + it('when uri already starts with base path', () => { + const path = '/example/catalog/default/component/artist-lookup'; + const { result } = renderHook(() => useResolvedPath(path), { + wrapper, + }); + expect(result.current).toBe(path); + }); + }); + }); }); diff --git a/packages/core-components/src/components/Link/Link.tsx b/packages/core-components/src/components/Link/Link.tsx index 5809990b92..22b203d157 100644 --- a/packages/core-components/src/components/Link/Link.tsx +++ b/packages/core-components/src/components/Link/Link.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { useAnalytics } from '@backstage/core-plugin-api'; +import { configApiRef, useAnalytics, useApi } from '@backstage/core-plugin-api'; import classnames from 'classnames'; import MaterialLink, { LinkProps as MaterialLinkProps, @@ -25,6 +25,7 @@ import { Link as RouterLink, LinkProps as RouterLinkProps, } from 'react-router-dom'; +import { trimEnd } from 'lodash'; const useStyles = makeStyles( { @@ -52,6 +53,45 @@ export type LinkProps = MaterialLinkProps & noTrack?: boolean; }; +/** + * Returns the app base url that could be empty if the Config API is not properly implemented. + * The only cases there would be no Config API are in tests and in storybook stories, and in those cases, it's unlikely that callers would rely on this subpath behavior. + */ +const useBaseUrl = () => { + try { + const config = useApi(configApiRef); + return config.getOptionalString('app.baseUrl'); + } catch { + return undefined; + } +}; + +/** + * Get the app base path from the configured app baseUrl. + * The returned path does not have a trailing slash. + */ +const useBasePath = () => { + // baseUrl can be specified as just a path + const base = 'http://dummy.dev'; + const url = useBaseUrl() ?? '/'; + const { pathname } = new URL(url, base); + return trimEnd(pathname, '/'); +}; + +export const useResolvedPath = (uri: LinkProps['to']) => { + let resolvedPath = String(uri); + + const basePath = useBasePath(); + const external = isExternalUri(resolvedPath); + const startsWithBasePath = resolvedPath.startsWith(basePath); + + if (!external && !startsWithBasePath) { + resolvedPath = basePath.concat(resolvedPath); + } + + return resolvedPath; +}; + /** * Given a react node, try to retrieve its text content. */ @@ -84,7 +124,7 @@ export const Link = React.forwardRef( ({ onClick, noTrack, ...props }, ref) => { const classes = useStyles(); const analytics = useAnalytics(); - const to = String(props.to); + const to = useResolvedPath(props.to); const linkText = getNodeText(props.children) || to; const external = isExternalUri(to); const newWindow = external && !!/^https?:/.exec(to); @@ -99,11 +139,11 @@ export const Link = React.forwardRef( return external ? ( // External links {props.children} @@ -112,10 +152,11 @@ export const Link = React.forwardRef( ) : ( // Interact with React Router for internal links ); }, diff --git a/packages/core-components/src/components/MarkdownContent/MarkdownContent.test.tsx b/packages/core-components/src/components/MarkdownContent/MarkdownContent.test.tsx index 2e1550078f..9c08b83c40 100644 --- a/packages/core-components/src/components/MarkdownContent/MarkdownContent.test.tsx +++ b/packages/core-components/src/components/MarkdownContent/MarkdownContent.test.tsx @@ -62,4 +62,42 @@ describe('', () => { expect(fp2).toBeInTheDocument(); expect(rendered.getByText(');', { selector: 'span' })).toBeInTheDocument(); }); + + it('render MarkdownContent component with transformed link', async () => { + const rendered = await renderWithEffects( + wrapInTestApp( + { + return `${href}-modified`; + }} + />, + ), + ); + const fp1 = rendered.getByText('Title', { + selector: 'a', + }); + expect(fp1).toBeInTheDocument(); + expect(fp1.getAttribute('href')).toEqual( + 'https://backstage.io/link-modified', + ); + }); + + it('render MarkdownContent component with transformed image', async () => { + const rendered = await renderWithEffects( + wrapInTestApp( + { + return `https://example.com/blog/assets/6/header.png`; + }} + />, + ), + ); + const fp1 = rendered.getByAltText('Image'); + expect(fp1).toBeInTheDocument(); + expect(fp1.getAttribute('src')).toEqual( + 'https://example.com/blog/assets/6/header.png', + ); + }); }); diff --git a/packages/core-components/src/components/MarkdownContent/MarkdownContent.tsx b/packages/core-components/src/components/MarkdownContent/MarkdownContent.tsx index df4ad56776..0e5aedda90 100644 --- a/packages/core-components/src/components/MarkdownContent/MarkdownContent.tsx +++ b/packages/core-components/src/components/MarkdownContent/MarkdownContent.tsx @@ -68,6 +68,8 @@ type Props = { content: string; dialect?: 'gfm' | 'common-mark'; linkTarget?: Options['linkTarget']; + transformLinkUri?: (href: string) => string; + transformImageUri?: (href: string) => string; }; const components: Options['components'] = { @@ -91,7 +93,13 @@ const components: Options['components'] = { * If you just want to render to plain [CommonMark](https://commonmark.org/), set the dialect to `'common-mark'` */ export function MarkdownContent(props: Props) { - const { content, dialect = 'gfm', linkTarget } = props; + const { + content, + dialect = 'gfm', + linkTarget, + transformLinkUri, + transformImageUri, + } = props; const classes = useStyles(); return ( ); } diff --git a/packages/core-components/src/layout/Header/Header.tsx b/packages/core-components/src/layout/Header/Header.tsx index bb4d19b949..1badb4eb98 100644 --- a/packages/core-components/src/layout/Header/Header.tsx +++ b/packages/core-components/src/layout/Header/Header.tsx @@ -63,15 +63,16 @@ const useStyles = makeStyles( }, rightItemsBox: { width: 'auto', + alignItems: 'center', }, title: { - color: theme.palette.bursts.fontColor, + color: theme.page.fontColor, wordBreak: 'break-word', fontSize: theme.typography.h3.fontSize, marginBottom: 0, }, subtitle: { - color: theme.palette.bursts.fontColor, + color: theme.page.fontColor, opacity: 0.8, display: 'inline-block', // prevents margin collapse of adjacent siblings marginTop: theme.spacing(1), @@ -82,10 +83,10 @@ const useStyles = makeStyles( fontSize: 11, opacity: 0.8, marginBottom: theme.spacing(1), - color: theme.palette.bursts.fontColor, + color: theme.page.fontColor, }, breadcrumb: { - color: theme.palette.bursts.fontColor, + color: theme.page.fontColor, }, breadcrumbType: { fontSize: 'inherit', diff --git a/packages/core-components/src/layout/ItemCard/ItemCardHeader.tsx b/packages/core-components/src/layout/ItemCard/ItemCardHeader.tsx index a34d773ce3..d9443ffc9a 100644 --- a/packages/core-components/src/layout/ItemCard/ItemCardHeader.tsx +++ b/packages/core-components/src/layout/ItemCard/ItemCardHeader.tsx @@ -27,7 +27,7 @@ const styles = (theme: BackstageTheme) => root: { color: theme.palette.common.white, padding: theme.spacing(2, 2, 3), - backgroundImage: theme.palette.bursts.gradient.linear, + backgroundImage: theme.getPageTheme({ themeId: 'card' }).backgroundImage, backgroundPosition: 0, backgroundSize: 'inherit', }, diff --git a/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx b/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx index b51e3cbc0d..c85e6d11f2 100644 --- a/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx +++ b/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx @@ -85,14 +85,14 @@ const useStyles = makeStyles( overlayHeader: { display: 'flex', - color: theme.palette.bursts.fontColor, + color: theme.palette.text.primary, alignItems: 'center', justifyContent: 'space-between', padding: theme.spacing(2, 3), }, overlayHeaderClose: { - color: theme.palette.bursts.fontColor, + color: theme.palette.text.primary, }, marginMobileSidebar: props => ({ diff --git a/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx b/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx index 41f1a1e287..a1565a348f 100644 --- a/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx +++ b/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx @@ -59,6 +59,13 @@ const useStyles = makeStyles( whiteSpace: 'nowrap', overflow: 'hidden', 'text-overflow': 'ellipsis', + lineHeight: 1, + }, + subtitle: { + fontSize: 10, + whiteSpace: 'nowrap', + overflow: 'hidden', + 'text-overflow': 'ellipsis', }, dropdownArrow: { position: 'absolute', @@ -105,6 +112,7 @@ export type SidebarSubmenuItemDropdownItem = { * Holds submenu item content. * * title: Text content of submenu item + * subtitle: A subtitle displayed under the main title * to: Path to navigate to when item is clicked * icon: Icon displayed on the left of text content * dropdownItems: Optional array of dropdown items displayed when submenu item is clicked. @@ -113,6 +121,7 @@ export type SidebarSubmenuItemDropdownItem = { */ export type SidebarSubmenuItemProps = { title: string; + subtitle?: string; to?: string; icon?: IconComponent; dropdownItems?: SidebarSubmenuItemDropdownItem[]; @@ -124,7 +133,7 @@ export type SidebarSubmenuItemProps = { * @public */ export const SidebarSubmenuItem = (props: SidebarSubmenuItemProps) => { - const { title, to, icon: Icon, dropdownItems } = props; + const { title, subtitle, to, icon: Icon, dropdownItems } = props; const classes = useStyles(); const { setIsHoveredOn } = useContext(SidebarItemWithSubmenuContext); const closeSubmenu = () => { @@ -158,6 +167,12 @@ export const SidebarSubmenuItem = (props: SidebarSubmenuItemProps) => { {Icon && } {title} +
+ {subtitle && ( + + {subtitle} + + )}
{showDropDown ? ( @@ -210,6 +225,12 @@ export const SidebarSubmenuItem = (props: SidebarSubmenuItemProps) => { {Icon && } {title} +
+ {subtitle && ( + + {subtitle} + + )}
diff --git a/packages/core-plugin-api/package.json b/packages/core-plugin-api/package.json index 8d525b5f0f..37b69d74f7 100644 --- a/packages/core-plugin-api/package.json +++ b/packages/core-plugin-api/package.json @@ -46,9 +46,9 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.1", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/react-hooks": "^8.0.0", @@ -58,7 +58,7 @@ "@types/prop-types": "^15.7.3", "@types/zen-observable": "^0.8.0", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/packages/create-app/CHANGELOG.md b/packages/create-app/CHANGELOG.md index 775aed3faa..7f2fa483f0 100644 --- a/packages/create-app/CHANGELOG.md +++ b/packages/create-app/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/create-app +## 0.4.29-next.2 + +### Patch Changes + +- f281ad17c0: Adds the ability to define the Backstage app name using a `BACKSTAGE_APP_NAME` + environment variable when running `create-app`. + +## 0.4.29-next.1 + +### Patch Changes + +- Bumped create-app version. + +## 0.4.29-next.0 + +### Patch Changes + +- bc87604c26: Added an explicit `node-gyp` dependency to the root `package.json`. This is to work around a bug in older versions of `node-gyp` that causes Python execution to fail on macOS. + + You can add this workaround to your existing project by adding `node-gyp` as a `devDependency` in your root `package.json` file: + + ```diff + "devDependencies": { + + "node-gyp": "^9.0.0" + }, + ``` + ## 0.4.28 ### Patch Changes diff --git a/packages/create-app/cli-report.md b/packages/create-app/cli-report.md new file mode 100644 index 0000000000..1244432c6a --- /dev/null +++ b/packages/create-app/cli-report.md @@ -0,0 +1,15 @@ +## CLI Report file for "@backstage/create-app" + +> Do not edit this file. It is a report generated by `yarn build:api-reports` + +### `backstage-create-app` + +``` +Usage: backstage-create-app [options] + +Options: + -V, --version + --path [directory] + --skip-install + -h, --help +``` diff --git a/packages/create-app/package.json b/packages/create-app/package.json index bca9fe9b68..1fc0d17285 100644 --- a/packages/create-app/package.json +++ b/packages/create-app/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/create-app", "description": "A CLI that helps you create your own Backstage app", - "version": "0.4.28", + "version": "0.4.29-next.2", "private": false, "publishConfig": { "access": "public" diff --git a/packages/create-app/src/createApp.ts b/packages/create-app/src/createApp.ts index 824d1d967e..7cf589e5f8 100644 --- a/packages/create-app/src/createApp.ts +++ b/packages/create-app/src/createApp.ts @@ -49,6 +49,14 @@ export default async (opts: OptionValues): Promise => { } return true; }, + when: (a: Answers) => { + const envName = process.env.BACKSTAGE_APP_NAME; + if (envName) { + a.name = envName; + return false; + } + return true; + }, }, ]); diff --git a/packages/create-app/templates/default-app/package.json.hbs b/packages/create-app/templates/default-app/package.json.hbs index d4cf4fb5fe..47fb0d622f 100644 --- a/packages/create-app/templates/default-app/package.json.hbs +++ b/packages/create-app/templates/default-app/package.json.hbs @@ -35,7 +35,8 @@ "concurrently": "^6.0.0", "lerna": "^4.0.0", "prettier": "^2.3.2", - "typescript": "~4.6.4" + "typescript": "~4.6.4", + "node-gyp": "^9.0.0" }, "resolutions": { "@types/react": "^17", diff --git a/packages/dev-utils/CHANGELOG.md b/packages/dev-utils/CHANGELOG.md index 563de9fc44..b748970b06 100644 --- a/packages/dev-utils/CHANGELOG.md +++ b/packages/dev-utils/CHANGELOG.md @@ -1,5 +1,43 @@ # @backstage/dev-utils +## 1.0.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + - @backstage/app-defaults@1.0.4-next.2 + - @backstage/integration-react@1.1.2-next.2 + +## 1.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/app-defaults@1.0.4-next.1 + - @backstage/integration-react@1.1.2-next.1 + - @backstage/test-utils@1.1.2-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## 1.0.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/core-app-api@1.0.4-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + - @backstage/app-defaults@1.0.4-next.0 + - @backstage/integration-react@1.1.2-next.0 + - @backstage/test-utils@1.1.2-next.0 + ## 1.0.3 ### Patch Changes diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index 2da041d9b7..8d19bf9cb3 100644 --- a/packages/dev-utils/package.json +++ b/packages/dev-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/dev-utils", "description": "Utilities for developing Backstage plugins.", - "version": "1.0.3", + "version": "1.0.4-next.2", "private": false, "publishConfig": { "access": "public", @@ -33,15 +33,15 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/app-defaults": "^1.0.3", - "@backstage/core-app-api": "^1.0.3", - "@backstage/core-components": "^0.9.5", + "@backstage/app-defaults": "^1.0.4-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/catalog-model": "^1.0.3", - "@backstage/integration-react": "^1.1.1", - "@backstage/plugin-catalog-react": "^1.1.1", - "@backstage/test-utils": "^1.1.1", - "@backstage/theme": "^0.2.15", + "@backstage/catalog-model": "^1.1.0-next.2", + "@backstage/integration-react": "^1.1.2-next.2", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", + "@backstage/test-utils": "^1.1.2-next.1", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@testing-library/jest-dom": "^5.10.1", @@ -59,7 +59,7 @@ "react-dom": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", + "@backstage/cli": "^0.18.0-next.2", "@types/jest": "^26.0.7", "@types/node": "^16.0.0" }, diff --git a/packages/e2e-test/cli-report.md b/packages/e2e-test/cli-report.md new file mode 100644 index 0000000000..3a3912b8fc --- /dev/null +++ b/packages/e2e-test/cli-report.md @@ -0,0 +1,26 @@ +## CLI Report file for "e2e-test" + +> Do not edit this file. It is a report generated by `yarn build:api-reports` + +### `e2e-test` + +``` +Usage: e2e-test [options] [command] + +Options: + -V, --version + -h, --help + +Commands: + run + help [command] +``` + +### `e2e-test run` + +``` +Usage: e2e-test run [options] + +Options: + -h, --help +``` diff --git a/packages/e2e-test/package.json b/packages/e2e-test/package.json index 2de60f4db8..333ac09b23 100644 --- a/packages/e2e-test/package.json +++ b/packages/e2e-test/package.json @@ -30,7 +30,7 @@ }, "devDependencies": { "@backstage/cli-common": "^0.1.9-next.0", - "@backstage/errors": "^1.0.0", + "@backstage/errors": "^1.1.0-next.0", "@types/fs-extra": "^9.0.1", "@types/node": "^16.11.26", "@types/puppeteer": "^5.4.4", @@ -40,7 +40,7 @@ "fs-extra": "10.1.0", "handlebars": "^4.7.3", "pgtools": "^0.3.0", - "puppeteer": "^14.0.0", + "puppeteer": "^15.0.0", "tree-kill": "^1.2.2", "ts-node": "^10.0.0" }, diff --git a/packages/e2e-test/src/commands/run.ts b/packages/e2e-test/src/commands/run.ts index e1477d98d7..d324aeafaf 100644 --- a/packages/e2e-test/src/commands/run.ts +++ b/packages/e2e-test/src/commands/run.ts @@ -235,6 +235,18 @@ async function createApp( print('Rewriting module resolutions of app to use workspace packages'); await overrideModuleResolutions(appDir, workspaceDir); + // Yarn does not clean up node_module folders in the linked in dependencies by itself + print('Cleaning up node_modules in workspace'); + await fs.remove(resolvePath(workspaceDir, 'node_modules')); + for (const wsDir of ['packages', 'plugins']) { + for (const dir of await fs.readdir(resolvePath(workspaceDir, wsDir))) { + const moduleDir = resolvePath(workspaceDir, wsDir, dir, 'node_modules'); + if (await fs.pathExists(moduleDir)) { + await fs.remove(moduleDir); + } + } + } + print('Pinning yarn version and registry in app'); await pinYarnVersion(appDir); await fs.writeFile( diff --git a/packages/errors/CHANGELOG.md b/packages/errors/CHANGELOG.md index 20f938370b..b7d912f5ab 100644 --- a/packages/errors/CHANGELOG.md +++ b/packages/errors/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/errors +## 1.1.0-next.0 + +### Minor Changes + +- 6d61b44466: The `ResponseError.fromResponse` now accepts a more narrow response type, in order to avoid incompatibilities between different fetch implementations. + + The `response` property of `ResponseError` has also been narrowed to a new `ConsumedResponse` type that omits all the properties for consuming the body of the response. This is not considered a breaking change as it was always an error to try to consume the body of the response. + ## 1.0.0 ### Major Changes diff --git a/packages/errors/api-report.md b/packages/errors/api-report.md index a01581135b..aab4e9baec 100644 --- a/packages/errors/api-report.md +++ b/packages/errors/api-report.md @@ -14,6 +14,17 @@ export class AuthenticationError extends CustomErrorBase {} // @public export class ConflictError extends CustomErrorBase {} +// @public +export type ConsumedResponse = { + readonly headers: Headers; + readonly ok: boolean; + readonly redirected: boolean; + readonly status: number; + readonly statusText: string; + readonly type: ResponseType; + readonly url: string; +}; + // @public export class CustomErrorBase extends Error { constructor(message?: string, cause?: Error | unknown); @@ -67,15 +78,21 @@ export class NotModifiedError extends CustomErrorBase {} // @public export function parseErrorResponseBody( - response: Response, + response: ConsumedResponse & { + text(): Promise; + }, ): Promise; // @public export class ResponseError extends Error { readonly body: ErrorResponseBody; readonly cause: Error; - static fromResponse(response: Response): Promise; - readonly response: Response; + static fromResponse( + response: ConsumedResponse & { + text(): Promise; + }, + ): Promise; + readonly response: ConsumedResponse; } // @public diff --git a/packages/errors/package.json b/packages/errors/package.json index 8327246224..01f1137eeb 100644 --- a/packages/errors/package.json +++ b/packages/errors/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/errors", "description": "Common utilities for error handling within Backstage", - "version": "1.0.0", + "version": "1.1.0-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -38,7 +38,7 @@ "serialize-error": "^8.0.1" }, "devDependencies": { - "@backstage/cli": "^0.17.2-next.0", + "@backstage/cli": "^0.18.0-next.1", "@types/jest": "^26.0.7" }, "files": [ diff --git a/packages/errors/src/errors/ResponseError.ts b/packages/errors/src/errors/ResponseError.ts index 84c8137bb5..a26891ef6a 100644 --- a/packages/errors/src/errors/ResponseError.ts +++ b/packages/errors/src/errors/ResponseError.ts @@ -19,6 +19,7 @@ import { ErrorResponseBody, parseErrorResponseBody, } from '../serialization/response'; +import { ConsumedResponse } from './types'; /** * An error thrown as the result of a failed server request. @@ -34,7 +35,7 @@ export class ResponseError extends Error { * Note that the body of this response is always consumed. Its parsed form is * in the `body` field. */ - readonly response: Response; + readonly response: ConsumedResponse; /** * The parsed JSON error body, as sent by the server. @@ -59,7 +60,9 @@ export class ResponseError extends Error { * function consumes the body of the response, and assumes that it hasn't * been consumed before. */ - static async fromResponse(response: Response): Promise { + static async fromResponse( + response: ConsumedResponse & { text(): Promise }, + ): Promise { const data = await parseErrorResponseBody(response); const status = data.response.statusCode || response.status; @@ -77,7 +80,7 @@ export class ResponseError extends Error { private constructor(props: { message: string; - response: Response; + response: ConsumedResponse; data: ErrorResponseBody; cause: Error; }) { diff --git a/packages/errors/src/errors/index.ts b/packages/errors/src/errors/index.ts index bc2fb2aa4e..9e1c2408af 100644 --- a/packages/errors/src/errors/index.ts +++ b/packages/errors/src/errors/index.ts @@ -27,3 +27,4 @@ export { } from './common'; export { CustomErrorBase } from './CustomErrorBase'; export { ResponseError } from './ResponseError'; +export type { ConsumedResponse } from './types'; diff --git a/packages/errors/src/errors/types.ts b/packages/errors/src/errors/types.ts new file mode 100644 index 0000000000..a62975571f --- /dev/null +++ b/packages/errors/src/errors/types.ts @@ -0,0 +1,31 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * ConsumedResponse represents a Response that is known to have been consumed. + * The methods and properties used to read the body contents are therefore omitted. + * + * @public + */ +export type ConsumedResponse = { + readonly headers: Headers; + readonly ok: boolean; + readonly redirected: boolean; + readonly status: number; + readonly statusText: string; + readonly type: ResponseType; + readonly url: string; +}; diff --git a/packages/errors/src/serialization/response.ts b/packages/errors/src/serialization/response.ts index 3580220525..60894b243e 100644 --- a/packages/errors/src/serialization/response.ts +++ b/packages/errors/src/serialization/response.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import { ConsumedResponse } from '../errors/types'; import { SerializedError } from './error'; /** @@ -53,7 +54,7 @@ export type ErrorResponseBody = { * @param response - The response of a failed request */ export async function parseErrorResponseBody( - response: Response, + response: ConsumedResponse & { text(): Promise }, ): Promise { try { const text = await response.text(); diff --git a/packages/integration-react/CHANGELOG.md b/packages/integration-react/CHANGELOG.md index d03553f50d..644d6f7cc4 100644 --- a/packages/integration-react/CHANGELOG.md +++ b/packages/integration-react/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/integration-react +## 1.1.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/integration@1.2.2-next.2 + +## 1.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/integration@1.2.2-next.1 + +## 1.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + - @backstage/integration@1.2.2-next.0 + ## 1.1.1 ### Patch Changes diff --git a/packages/integration-react/package.json b/packages/integration-react/package.json index 580b91509f..bf0a3e471c 100644 --- a/packages/integration-react/package.json +++ b/packages/integration-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/integration-react", "description": "Frontend package for managing integrations towards external systems", - "version": "1.1.1", + "version": "1.1.2-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -25,10 +25,10 @@ }, "dependencies": { "@backstage/config": "^1.0.1", - "@backstage/core-components": "^0.9.5", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/integration": "^1.2.1", - "@backstage/theme": "^0.2.15", + "@backstage/integration": "^1.2.2-next.2", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -38,15 +38,15 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/jest": "^26.0.7", "@types/node": "^16.11.26", - "msw": "^0.42.0", + "msw": "^0.43.0", "cross-fetch": "^3.1.5" }, "files": [ diff --git a/packages/integration/CHANGELOG.md b/packages/integration/CHANGELOG.md index 736d9ff2a1..bf352f168f 100644 --- a/packages/integration/CHANGELOG.md +++ b/packages/integration/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/integration +## 1.2.2-next.2 + +### Patch Changes + +- e2d7b76f43: Upgrade git-url-parse to 12.0.0. + + Motivation for upgrade is transitively upgrading parse-url which is vulnerable + to several CVEs detected by Snyk. + + - SNYK-JS-PARSEURL-2935944 + - SNYK-JS-PARSEURL-2935947 + - SNYK-JS-PARSEURL-2936249 + +## 1.2.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.1.0-next.0 + +## 1.2.2-next.0 + +### Patch Changes + +- 8829e175f2: Allow frontend visibility for `integrations` itself. + ## 1.2.1 ### Patch Changes diff --git a/packages/integration/config.d.ts b/packages/integration/config.d.ts index c14f5c76cd..22acc5cd70 100644 --- a/packages/integration/config.d.ts +++ b/packages/integration/config.d.ts @@ -15,7 +15,10 @@ */ export interface Config { - /** Configuration for integrations towards various external repository provider systems */ + /** + * Configuration for integrations towards various external repository provider systems + * @visibility frontend + */ integrations?: { /** Integration configuration for Azure */ azure?: Array<{ diff --git a/packages/integration/package.json b/packages/integration/package.json index 06faef890d..532797aee8 100644 --- a/packages/integration/package.json +++ b/packages/integration/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/integration", "description": "Helpers for managing integrations towards external systems", - "version": "1.2.1", + "version": "1.2.2-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,21 +34,21 @@ }, "dependencies": { "@backstage/config": "^1.0.1", - "@backstage/errors": "^1.0.0", + "@backstage/errors": "^1.1.0-next.0", "cross-fetch": "^3.1.5", - "git-url-parse": "^11.6.0", + "git-url-parse": "^12.0.0", "@octokit/rest": "^18.5.3", "@octokit/auth-app": "^3.4.0", "luxon": "^2.0.2", "lodash": "^4.17.21" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/config-loader": "^1.1.2", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/config-loader": "^1.1.3-next.0", + "@backstage/test-utils": "^1.1.2-next.1", "@types/jest": "^26.0.7", "@types/luxon": "^2.0.4", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist", diff --git a/packages/integration/src/bitbucketServer/core.test.ts b/packages/integration/src/bitbucketServer/core.test.ts index 1c8f5d259c..076a2c7a4f 100644 --- a/packages/integration/src/bitbucketServer/core.test.ts +++ b/packages/integration/src/bitbucketServer/core.test.ts @@ -108,6 +108,20 @@ describe('bitbucketServer core', () => { ); }); + it('does not double encode the filepath', async () => { + const config: BitbucketServerIntegrationConfig = { + host: 'bitbucket.mycompany.net', + apiBaseUrl: 'https://api.bitbucket.mycompany.net/rest/api/1.0', + }; + const result = await getBitbucketServerDownloadUrl( + 'https://bitbucket.mycompany.net/projects/backstage/repos/mock/browse/%2Fdocs?at=some-branch', + config, + ); + expect(result).toEqual( + 'https://api.bitbucket.mycompany.net/rest/api/1.0/projects/backstage/repos/mock/archive?format=tgz&at=some-branch&prefix=backstage-mock&path=%2Fdocs', + ); + }); + it('do not add path param if no path is specified for Bitbucket Server', async () => { const defaultBranchResponse = { displayId: 'main', diff --git a/packages/integration/src/bitbucketServer/core.ts b/packages/integration/src/bitbucketServer/core.ts index 80dbc0443f..0c57b0d3ed 100644 --- a/packages/integration/src/bitbucketServer/core.ts +++ b/packages/integration/src/bitbucketServer/core.ts @@ -83,7 +83,9 @@ export async function getBitbucketServerDownloadUrl( // path will limit the downloaded content // /docs will only download the docs folder and everything below it // /docs/index.md will download the docs folder and everything below it - const path = filepath ? `&path=${encodeURIComponent(filepath)}` : ''; + const path = filepath + ? `&path=${encodeURIComponent(decodeURIComponent(filepath))}` + : ''; return `${config.apiBaseUrl}/projects/${project}/repos/${repoName}/archive?format=tgz&at=${branch}&prefix=${project}-${repoName}${path}`; } diff --git a/packages/release-manifests/package.json b/packages/release-manifests/package.json index f0627a9c95..3309b1b9f1 100644 --- a/packages/release-manifests/package.json +++ b/packages/release-manifests/package.json @@ -36,8 +36,8 @@ "cross-fetch": "^3.1.5" }, "devDependencies": { - "@backstage/test-utils": "^1.1.1", - "msw": "^0.42.0", + "@backstage/test-utils": "^1.1.2-next.0", + "msw": "^0.43.0", "@types/jest": "^26.0.7", "@types/node": "^16.0.0" }, diff --git a/packages/techdocs-cli-embedded-app/CHANGELOG.md b/packages/techdocs-cli-embedded-app/CHANGELOG.md index 58102369ed..af9f0ad09c 100644 --- a/packages/techdocs-cli-embedded-app/CHANGELOG.md +++ b/packages/techdocs-cli-embedded-app/CHANGELOG.md @@ -1,5 +1,51 @@ # techdocs-cli-embedded-app +## 0.2.72-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-techdocs@1.2.1-next.2 + - @backstage/plugin-catalog@1.4.0-next.2 + - @backstage/cli@0.18.0-next.2 + - @backstage/app-defaults@1.0.4-next.2 + - @backstage/integration-react@1.1.2-next.2 + - @backstage/plugin-techdocs-react@1.0.2-next.1 + +## 0.2.72-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/cli@0.18.0-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/plugin-catalog@1.3.1-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-techdocs@1.2.1-next.1 + - @backstage/app-defaults@1.0.4-next.1 + - @backstage/integration-react@1.1.2-next.1 + - @backstage/test-utils@1.1.2-next.1 + +## 0.2.72-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-techdocs-react@1.0.2-next.0 + - @backstage/plugin-catalog@1.3.1-next.0 + - @backstage/core-app-api@1.0.4-next.0 + - @backstage/cli@0.17.3-next.0 + - @backstage/plugin-techdocs@1.2.1-next.0 + - @backstage/app-defaults@1.0.4-next.0 + - @backstage/integration-react@1.1.2-next.0 + - @backstage/test-utils@1.1.2-next.0 + ## 0.2.71 ### Patch Changes diff --git a/packages/techdocs-cli-embedded-app/package.json b/packages/techdocs-cli-embedded-app/package.json index 8029d604db..60389b6596 100644 --- a/packages/techdocs-cli-embedded-app/package.json +++ b/packages/techdocs-cli-embedded-app/package.json @@ -1,25 +1,25 @@ { "name": "techdocs-cli-embedded-app", - "version": "0.2.71", + "version": "0.2.72-next.2", "private": true, "backstage": { "role": "frontend" }, "bundled": true, "dependencies": { - "@backstage/app-defaults": "^1.0.3", - "@backstage/catalog-model": "^1.0.3", - "@backstage/cli": "^0.17.2", + "@backstage/app-defaults": "^1.0.4-next.2", + "@backstage/catalog-model": "^1.1.0-next.2", + "@backstage/cli": "^0.18.0-next.2", "@backstage/config": "^1.0.1", - "@backstage/core-app-api": "^1.0.3", - "@backstage/core-components": "^0.9.5", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/integration-react": "^1.1.1", - "@backstage/plugin-catalog": "^1.3.0", - "@backstage/plugin-techdocs": "^1.2.0", - "@backstage/plugin-techdocs-react": "^1.0.1", - "@backstage/test-utils": "^1.1.1", - "@backstage/theme": "^0.2.15", + "@backstage/integration-react": "^1.1.2-next.2", + "@backstage/plugin-catalog": "^1.4.0-next.2", + "@backstage/plugin-techdocs": "^1.2.1-next.2", + "@backstage/plugin-techdocs-react": "^1.0.2-next.1", + "@backstage/test-utils": "^1.1.2-next.1", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "history": "^5.0.0", @@ -30,7 +30,7 @@ "react-use": "^17.2.4" }, "devDependencies": { - "@backstage/cli": "^0.17.2", + "@backstage/cli": "^0.18.0-next.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/packages/techdocs-cli/CHANGELOG.md b/packages/techdocs-cli/CHANGELOG.md index 21eb2393b7..3e66248276 100644 --- a/packages/techdocs-cli/CHANGELOG.md +++ b/packages/techdocs-cli/CHANGELOG.md @@ -1,5 +1,25 @@ # @techdocs/cli +## 1.1.3-next.1 + +### Patch Changes + +- a5d73da942: Fix the flag parsing for `legacyCopyReadmeMdToIndexMd` in `techdocs-cli generate` command, and decouple it's logic from the `techdocs-ref` flag. +- Updated dependencies + - @backstage/plugin-techdocs-node@1.2.0-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + +## 1.1.3-next.0 + +### Patch Changes + +- 14ce0d9347: Fixed a bug that prevented docker images from being pulled by default when generating TechDocs. +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/plugin-techdocs-node@1.1.3-next.0 + ## 1.1.2 ### Patch Changes diff --git a/packages/techdocs-cli/cli-report.md b/packages/techdocs-cli/cli-report.md new file mode 100644 index 0000000000..64b5e9c090 --- /dev/null +++ b/packages/techdocs-cli/cli-report.md @@ -0,0 +1,117 @@ +## CLI Report file for "@techdocs/cli" + +> Do not edit this file. It is a report generated by `yarn build:api-reports` + +### `techdocs-cli` + +``` +Usage: techdocs-cli [options] [command] + +Options: + -V, --version + -h, --help + +Commands: + generate|build [options] + migrate [options] + publish [options] + serve:mkdocs [options] + serve [options] + help [command] +``` + +### `techdocs-cli generate` + +``` +Usage: techdocs-cli generate|build [options] + +Options: + --source-dir + --output-dir + --docker-image + --no-pull + --no-docker + --techdocs-ref + --etag + -v --verbose + --omitTechdocsCoreMkdocsPlugin + --legacyCopyReadmeMdToIndexMd + -h, --help +``` + +### `techdocs-cli migrate` + +``` +Usage: techdocs-cli migrate [options] + +Options: + --publisher-type + --storage-name + --azureAccountName + --azureAccountKey + --awsRoleArn + --awsEndpoint + --awsS3ForcePathStyle + --awsBucketRootPath + --osCredentialId + --osSecret + --osAuthUrl + --osSwiftUrl + --removeOriginal + --concurrency + -v --verbose + -h, --help +``` + +### `techdocs-cli publish` + +``` +Usage: techdocs-cli publish [options] + +Options: + --publisher-type + --storage-name + --entity + --legacyUseCaseSensitiveTripletPaths + --azureAccountName + --azureAccountKey + --awsRoleArn + --awsEndpoint + --awsS3sse + --awsS3ForcePathStyle + --osCredentialId + --osSecret + --osAuthUrl + --osSwiftUrl + --gcsBucketRootPath + --directory + -h, --help +``` + +### `techdocs-cli serve` + +``` +Usage: techdocs-cli serve [options] + +Options: + -i, --docker-image + --docker-entrypoint + --no-docker + --mkdocs-port + -v --verbose + -h, --help +``` + +### `techdocs-cli serve:mkdocs` + +``` +Usage: techdocs-cli serve:mkdocs [options] + +Options: + -i, --docker-image + --docker-entrypoint + --no-docker + -p, --port + -v --verbose + -h, --help +``` diff --git a/packages/techdocs-cli/package.json b/packages/techdocs-cli/package.json index d1db470572..00e254d10f 100644 --- a/packages/techdocs-cli/package.json +++ b/packages/techdocs-cli/package.json @@ -1,7 +1,7 @@ { "name": "@techdocs/cli", "description": "Utility CLI for managing TechDocs sites in Backstage.", - "version": "1.1.2", + "version": "1.1.3-next.1", "private": false, "publishConfig": { "access": "public" @@ -37,7 +37,7 @@ "techdocs-cli": "bin/techdocs-cli" }, "devDependencies": { - "@backstage/cli": "^0.17.2", + "@backstage/cli": "^0.18.0-next.1", "@types/commander": "^2.12.2", "@types/fs-extra": "^9.0.6", "@types/http-proxy": "^1.17.4", @@ -62,11 +62,11 @@ "ext": "ts" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", - "@backstage/catalog-model": "^1.0.3", + "@backstage/backend-common": "^0.14.1-next.1", + "@backstage/catalog-model": "^1.1.0-next.1", "@backstage/cli-common": "^0.1.9", "@backstage/config": "^1.0.1", - "@backstage/plugin-techdocs-node": "^1.1.2", + "@backstage/plugin-techdocs-node": "^1.2.0-next.1", "@types/dockerode": "^3.3.0", "commander": "^9.1.0", "dockerode": "^3.3.1", diff --git a/packages/techdocs-cli/src/commands/generate/generate.ts b/packages/techdocs-cli/src/commands/generate/generate.ts index 309b9c7969..1e4ed220d9 100644 --- a/packages/techdocs-cli/src/commands/generate/generate.ts +++ b/packages/techdocs-cli/src/commands/generate/generate.ts @@ -57,8 +57,8 @@ export default async function generate(opts: OptionValues) { runIn: opts.docker ? 'docker' : 'local', dockerImage, pullImage, - legacyCopyReadmeMdToIndexMd, mkdocs: { + legacyCopyReadmeMdToIndexMd, omitTechdocsCorePlugin, }, }, diff --git a/packages/techdocs-cli/src/commands/index.ts b/packages/techdocs-cli/src/commands/index.ts index 85a218eb54..68e8f88c0b 100644 --- a/packages/techdocs-cli/src/commands/index.ts +++ b/packages/techdocs-cli/src/commands/index.ts @@ -38,7 +38,7 @@ export function registerCommands(program: Command) { 'The mkdocs docker container to use', defaultDockerImage, ) - .option('--no-pull', 'Do not pull the latest docker image', false) + .option('--no-pull', 'Do not pull the latest docker image') .option( '--no-docker', 'Do not use Docker, use MkDocs executable and plugins in current user environment.', diff --git a/packages/test-utils/CHANGELOG.md b/packages/test-utils/CHANGELOG.md index d8e9a8dd11..adbb3cd7ac 100644 --- a/packages/test-utils/CHANGELOG.md +++ b/packages/test-utils/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/test-utils +## 1.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-permission-common@0.6.3-next.0 + - @backstage/plugin-permission-react@0.4.3-next.0 + +## 1.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.0.4-next.0 + ## 1.1.1 ### Patch Changes diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index 0c52f47325..0918dcaaac 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/test-utils", "description": "Utilities to test Backstage plugins and apps.", - "version": "1.1.1", + "version": "1.1.2-next.1", "private": false, "publishConfig": { "access": "public", @@ -34,11 +34,11 @@ }, "dependencies": { "@backstage/config": "^1.0.1", - "@backstage/core-app-api": "^1.0.3", + "@backstage/core-app-api": "^1.0.4-next.0", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/plugin-permission-common": "^0.6.2", - "@backstage/plugin-permission-react": "^0.4.2", - "@backstage/theme": "^0.2.15", + "@backstage/plugin-permission-common": "^0.6.3-next.0", + "@backstage/plugin-permission-react": "^0.4.3-next.0", + "@backstage/theme": "^0.2.16-next.0", "@backstage/types": "^1.0.0", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.11.2", @@ -55,10 +55,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", + "@backstage/cli": "^0.18.0-next.1", "@types/jest": "^26.0.7", "@types/node": "^16.11.26", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/packages/theme/CHANGELOG.md b/packages/theme/CHANGELOG.md index 5c3e8cf5d6..93b79b0721 100644 --- a/packages/theme/CHANGELOG.md +++ b/packages/theme/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/theme +## 0.2.16-next.1 + +### Patch Changes + +- ff4f56eb49: **DEPRECATED**: The `bursts` object from `BackstagePaletteAdditions` has been depreciated and will be removed in a future release + + The `genPageTheme` function now includes an optional options object with an optional `fontColor` which defaults to white if not provided. + +## 0.2.16-next.0 + +### Patch Changes + +- 4c09c09102: Adds optional `htmlFontSize` property and also sets typography design tokens for h5 and h6 in base theme. + ## 0.2.15 ### Patch Changes diff --git a/packages/theme/api-report.md b/packages/theme/api-report.md index f650636710..92958c9c7e 100644 --- a/packages/theme/api-report.md +++ b/packages/theme/api-report.md @@ -116,7 +116,13 @@ export function createThemeOverrides(theme: BackstageTheme): Overrides; export const darkTheme: BackstageTheme; // @public -export function genPageTheme(colors: string[], shape: string): PageTheme; +export function genPageTheme(props: { + colors: string[]; + shape: string; + options?: { + fontColor?: string; + }; +}): PageTheme; // @public export const lightTheme: BackstageTheme; @@ -126,6 +132,7 @@ export type PageTheme = { colors: string[]; shape: string; backgroundImage: string; + fontColor: string; }; // @public @@ -145,5 +152,6 @@ export type SimpleThemeOptions = { defaultPageTheme: string; pageTheme?: Record; fontFamily?: string; + htmlFontSize?: number; }; ``` diff --git a/packages/theme/package.json b/packages/theme/package.json index d10999fefb..4cbd4d2205 100644 --- a/packages/theme/package.json +++ b/packages/theme/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/theme", "description": "material-ui theme for use with Backstage.", - "version": "0.2.15", + "version": "0.2.16-next.1", "private": false, "publishConfig": { "access": "public", @@ -36,7 +36,7 @@ "@material-ui/core": "^4.12.2" }, "devDependencies": { - "@backstage/cli": "^0.17.2-next.0" + "@backstage/cli": "^0.18.0-next.2" }, "files": [ "dist" diff --git a/packages/theme/src/baseTheme.ts b/packages/theme/src/baseTheme.ts index da663e3398..5e222c0c3e 100644 --- a/packages/theme/src/baseTheme.ts +++ b/packages/theme/src/baseTheme.ts @@ -24,6 +24,7 @@ import { } from './types'; import { pageTheme as defaultPageThemes } from './pageTheme'; +const DEFAULT_HTML_FONT_SIZE = 16; const DEFAULT_FONT_FAMILY = '"Helvetica Neue", Helvetica, Roboto, Arial, sans-serif'; @@ -37,6 +38,7 @@ export function createThemeOptions( ): BackstageThemeOptions { const { palette, + htmlFontSize = DEFAULT_HTML_FONT_SIZE, fontFamily = DEFAULT_FONT_FAMILY, defaultPageTheme, pageTheme = defaultPageThemes, @@ -57,9 +59,17 @@ export function createThemeOptions( }, }, typography: { + htmlFontSize, fontFamily, + h6: { + fontWeight: 700, + fontSize: 20, + marginBottom: 2, + }, h5: { fontWeight: 700, + fontSize: 24, + marginBottom: 4, }, h4: { fontWeight: 700, diff --git a/packages/theme/src/pageTheme.ts b/packages/theme/src/pageTheme.ts index ae81dc8534..5b5eb24be9 100644 --- a/packages/theme/src/pageTheme.ts +++ b/packages/theme/src/pageTheme.ts @@ -52,6 +52,7 @@ export const colorVariants: Record = { eveningSea: ['#00FFF2', '#035355'], teal: ['#005B4B'], pinkSea: ['#C8077A', '#C2297D'], + greens: ['#4BB8A5', '#187656'], }; /** @@ -63,12 +64,25 @@ export const colorVariants: Record = { * As the background shapes and colors are decorative, we place them onto the * page as a css background-image instead of an html element of its own. */ -export function genPageTheme(colors: string[], shape: string): PageTheme { +export function genPageTheme(props: { + colors: string[]; + shape: string; + options?: { + fontColor?: string; + }; +}): PageTheme { + const { colors, shape, options } = props; const gradientColors = colors.length === 1 ? [colors[0], colors[0]] : colors; const gradient = `linear-gradient(90deg, ${gradientColors.join(', ')})`; const backgroundImage = `${shape}, ${gradient}`; + const fontColor = options?.fontColor ?? '#FFFFFF'; - return { colors, shape, backgroundImage }; + return { + colors: colors, + shape: shape, + backgroundImage: backgroundImage, + fontColor: fontColor, + }; } /** @@ -77,13 +91,20 @@ export function genPageTheme(colors: string[], shape: string): PageTheme { * @public */ export const pageTheme: Record = { - home: genPageTheme(colorVariants.teal, shapes.wave), - documentation: genPageTheme(colorVariants.pinkSea, shapes.wave2), - tool: genPageTheme(colorVariants.purpleSky, shapes.round), - service: genPageTheme(colorVariants.marineBlue, shapes.wave), - website: genPageTheme(colorVariants.veryBlue, shapes.wave), - library: genPageTheme(colorVariants.rubyRed, shapes.wave), - other: genPageTheme(colorVariants.darkGrey, shapes.wave), - app: genPageTheme(colorVariants.toastyOrange, shapes.wave), - apis: genPageTheme(colorVariants.teal, shapes.wave2), + home: genPageTheme({ colors: colorVariants.teal, shape: shapes.wave }), + documentation: genPageTheme({ + colors: colorVariants.pinkSea, + shape: shapes.wave2, + }), + tool: genPageTheme({ colors: colorVariants.purpleSky, shape: shapes.round }), + service: genPageTheme({ + colors: colorVariants.marineBlue, + shape: shapes.wave, + }), + website: genPageTheme({ colors: colorVariants.veryBlue, shape: shapes.wave }), + library: genPageTheme({ colors: colorVariants.rubyRed, shape: shapes.wave }), + other: genPageTheme({ colors: colorVariants.darkGrey, shape: shapes.wave }), + app: genPageTheme({ colors: colorVariants.toastyOrange, shape: shapes.wave }), + apis: genPageTheme({ colors: colorVariants.teal, shape: shapes.wave2 }), + card: genPageTheme({ colors: colorVariants.greens, shape: shapes.wave }), }; diff --git a/packages/theme/src/types.ts b/packages/theme/src/types.ts index 3d1a64c38f..96b7c54f9b 100644 --- a/packages/theme/src/types.ts +++ b/packages/theme/src/types.ts @@ -63,6 +63,9 @@ export type BackstagePaletteAdditions = { tabbar: { indicator: string; }; + /** + * @deprecated The entire `bursts` section will be removed in a future release + */ bursts: { fontColor: string; slackChannelText: string; @@ -149,6 +152,7 @@ export type SimpleThemeOptions = { defaultPageTheme: string; pageTheme?: Record; fontFamily?: string; + htmlFontSize?: number; }; /** @@ -160,4 +164,5 @@ export type PageTheme = { colors: string[]; shape: string; backgroundImage: string; + fontColor: string; }; diff --git a/packages/types/package.json b/packages/types/package.json index 5ea10709ec..d1410631bd 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -34,7 +34,7 @@ }, "dependencies": {}, "devDependencies": { - "@backstage/cli": "^0.17.2-next.0", + "@backstage/cli": "^0.18.0-next.1", "@types/zen-observable": "^0.8.0", "zen-observable": "^0.8.15" }, diff --git a/packages/version-bridge/package.json b/packages/version-bridge/package.json index 81ec8017a1..4b9ce2ed11 100644 --- a/packages/version-bridge/package.json +++ b/packages/version-bridge/package.json @@ -37,7 +37,7 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2-next.0", + "@backstage/cli": "^0.18.0-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/react-hooks": "^8.0.0" diff --git a/plugins/adr-backend/CHANGELOG.md b/plugins/adr-backend/CHANGELOG.md index 946df67282..15a0519010 100644 --- a/plugins/adr-backend/CHANGELOG.md +++ b/plugins/adr-backend/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-adr-backend +## 0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/catalog-client@1.0.4-next.1 + - @backstage/integration@1.2.2-next.1 + - @backstage/plugin-adr-common@0.1.2-next.1 + - @backstage/plugin-search-common@0.3.6-next.0 + +## 0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/catalog-client@1.0.4-next.0 + - @backstage/plugin-adr-common@0.1.2-next.0 + ## 0.1.1 ### Patch Changes diff --git a/plugins/adr-backend/package.json b/plugins/adr-backend/package.json index c192e0cd85..be04a712cc 100644 --- a/plugins/adr-backend/package.json +++ b/plugins/adr-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-adr-backend", - "version": "0.1.1", + "version": "0.1.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -29,14 +29,14 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", - "@backstage/catalog-client": "^1.0.3", - "@backstage/catalog-model": "^1.0.3", + "@backstage/backend-common": "^0.14.1-next.1", + "@backstage/catalog-client": "^1.0.4-next.1", + "@backstage/catalog-model": "^1.1.0-next.1", "@backstage/config": "^1.0.1", - "@backstage/errors": "^1.0.0", - "@backstage/integration": "^1.2.1", - "@backstage/plugin-adr-common": "^0.1.1", - "@backstage/plugin-search-common": "^0.3.5", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/integration": "^1.2.2-next.1", + "@backstage/plugin-adr-common": "^0.1.2-next.1", + "@backstage/plugin-search-common": "^0.3.6-next.0", "luxon": "^2.0.2", "marked": "^4.0.14", "winston": "^3.2.1", @@ -44,11 +44,11 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", + "@backstage/cli": "^0.18.0-next.1", "@types/marked": "^4.0.0", "@types/supertest": "^2.0.8", "supertest": "^6.1.3", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/adr-common/CHANGELOG.md b/plugins/adr-common/CHANGELOG.md index d9a0207248..e07697118c 100644 --- a/plugins/adr-common/CHANGELOG.md +++ b/plugins/adr-common/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-adr-common +## 0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/integration@1.2.2-next.1 + - @backstage/plugin-search-common@0.3.6-next.0 + +## 0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/integration@1.2.2-next.0 + ## 0.1.1 ### Patch Changes diff --git a/plugins/adr-common/package.json b/plugins/adr-common/package.json index d3607f3a99..a0567fb5b8 100644 --- a/plugins/adr-common/package.json +++ b/plugins/adr-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-adr-common", "description": "Common functionalities for the adr plugin", - "version": "0.1.1", + "version": "0.1.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,12 +30,12 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", - "@backstage/integration": "^1.2.1", - "@backstage/plugin-search-common": "^0.3.5" + "@backstage/catalog-model": "^1.1.0-next.1", + "@backstage/integration": "^1.2.2-next.1", + "@backstage/plugin-search-common": "^0.3.6-next.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2" + "@backstage/cli": "^0.18.0-next.1" }, "files": [ "dist" diff --git a/plugins/adr/CHANGELOG.md b/plugins/adr/CHANGELOG.md index 61e28f3834..efad1034a8 100644 --- a/plugins/adr/CHANGELOG.md +++ b/plugins/adr/CHANGELOG.md @@ -1,5 +1,50 @@ # @backstage/plugin-adr +## 0.1.2-next.2 + +### Patch Changes + +- e2d7b76f43: Upgrade git-url-parse to 12.0.0. + + Motivation for upgrade is transitively upgrading parse-url which is vulnerable + to several CVEs detected by Snyk. + + - SNYK-JS-PARSEURL-2935944 + - SNYK-JS-PARSEURL-2935947 + - SNYK-JS-PARSEURL-2936249 + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/plugin-search-react@0.2.2-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + - @backstage/integration-react@1.1.2-next.2 + +## 0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/integration-react@1.1.2-next.1 + - @backstage/plugin-adr-common@0.1.2-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.1 + - @backstage/plugin-search-common@0.3.6-next.0 + - @backstage/plugin-search-react@0.2.2-next.1 + +## 0.1.2-next.0 + +### Patch Changes + +- 7d47e7e512: Track discover event and result rank for `AdrSearchResultListItem` +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-adr-common@0.1.2-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + - @backstage/integration-react@1.1.2-next.0 + - @backstage/plugin-search-react@0.2.2-next.0 + ## 0.1.1 ### Patch Changes diff --git a/plugins/adr/api-report.md b/plugins/adr/api-report.md index 61cf231784..fbe04b1dc4 100644 --- a/plugins/adr/api-report.md +++ b/plugins/adr/api-report.md @@ -47,10 +47,12 @@ export const AdrReader: { export const AdrSearchResultListItem: ({ lineClamp, highlight, + rank, result, }: { lineClamp?: number | undefined; highlight?: ResultHighlight | undefined; + rank?: number | undefined; result: AdrDocument; }) => JSX.Element; diff --git a/plugins/adr/package.json b/plugins/adr/package.json index 194cc44ae4..80d24e7223 100644 --- a/plugins/adr/package.json +++ b/plugins/adr/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-adr", - "version": "0.1.1", + "version": "0.1.2-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,18 +22,18 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/core-components": "^0.9.5", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/integration-react": "^1.1.1", - "@backstage/plugin-adr-common": "^0.1.1", - "@backstage/plugin-catalog-react": "^1.1.1", - "@backstage/plugin-search-common": "^0.3.5", - "@backstage/plugin-search-react": "^0.2.1", - "@backstage/theme": "^0.2.15", + "@backstage/integration-react": "^1.1.2-next.2", + "@backstage/plugin-adr-common": "^0.1.2-next.1", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", + "@backstage/plugin-search-common": "^0.3.6-next.0", + "@backstage/plugin-search-react": "^0.2.2-next.2", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", - "git-url-parse": "^11.6.0", + "git-url-parse": "^12.0.0", "octokit": "^1.7.1", "react-markdown": "^8.0.0", "react-router-dom": "6.0.0-beta.0", @@ -44,10 +44,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", @@ -55,7 +55,7 @@ "@types/jest": "*", "@types/node": "*", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/adr/src/search/AdrSearchResultListItem.tsx b/plugins/adr/src/search/AdrSearchResultListItem.tsx index 484bac336e..677e39fc11 100644 --- a/plugins/adr/src/search/AdrSearchResultListItem.tsx +++ b/plugins/adr/src/search/AdrSearchResultListItem.tsx @@ -24,6 +24,7 @@ import { makeStyles, } from '@material-ui/core'; import { Link } from '@backstage/core-components'; +import { useAnalytics } from '@backstage/core-plugin-api'; import { AdrDocument } from '@backstage/plugin-adr-common'; import { ResultHighlight } from '@backstage/plugin-search-common'; import { HighlightedSearchResultText } from '@backstage/plugin-search-react'; @@ -46,16 +47,26 @@ const useStyles = makeStyles({ export const AdrSearchResultListItem = ({ lineClamp = 5, highlight, + rank, result, }: { lineClamp?: number; highlight?: ResultHighlight; + rank?: number; result: AdrDocument; }) => { const classes = useStyles(); + const analytics = useAnalytics(); + + const handleClick = () => { + analytics.captureEvent('discover', result.title, { + attributes: { to: result.location }, + value: rank, + }); + }; return ( - + + +
+ ); +} +``` + ## Configuration For links to the Airflow instance, the `baseUrl` must be defined in diff --git a/plugins/apache-airflow/api-report.md b/plugins/apache-airflow/api-report.md index ca151f0734..333e4543cf 100644 --- a/plugins/apache-airflow/api-report.md +++ b/plugins/apache-airflow/api-report.md @@ -8,6 +8,13 @@ import { BackstagePlugin } from '@backstage/core-plugin-api'; import { RouteRef } from '@backstage/core-plugin-api'; +// @public +export const ApacheAirflowDagTable: ({ + dagIds, + }: { + dagIds?: string[] | undefined; +}) => JSX.Element; + // Warning: (ae-missing-release-tag) "ApacheAirflowPage" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) diff --git a/plugins/apache-airflow/package.json b/plugins/apache-airflow/package.json index 5455bd602b..657ecc7ad6 100644 --- a/plugins/apache-airflow/package.json +++ b/plugins/apache-airflow/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-apache-airflow", - "version": "0.1.14", + "version": "0.2.0-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,7 +23,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.9.5", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -36,16 +36,16 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/jest": "^26.0.7", "@types/node": "^16.11.26", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist", diff --git a/plugins/apache-airflow/src/api/ApacheAirflowApi.ts b/plugins/apache-airflow/src/api/ApacheAirflowApi.ts index dde8c57802..838292524a 100644 --- a/plugins/apache-airflow/src/api/ApacheAirflowApi.ts +++ b/plugins/apache-airflow/src/api/ApacheAirflowApi.ts @@ -25,6 +25,7 @@ export type ApacheAirflowApi = { discoveryApi: DiscoveryApi; baseUrl: string; listDags(options?: { objectsPerRequest: number }): Promise; + getDags(dagIds: string[]): Promise<{ dags: Dag[]; dagsNotFound: string[] }>; updateDag(dagId: string, isPaused: boolean): Promise; getInstanceStatus(): Promise; getInstanceVersion(): Promise; diff --git a/plugins/apache-airflow/src/api/ApacheAirflowClient.test.ts b/plugins/apache-airflow/src/api/ApacheAirflowClient.test.ts index 704b17eb34..b9bdb02283 100644 --- a/plugins/apache-airflow/src/api/ApacheAirflowClient.test.ts +++ b/plugins/apache-airflow/src/api/ApacheAirflowClient.test.ts @@ -107,6 +107,15 @@ describe('ApacheAirflowClient', () => { ); }), + rest.get(`${mockBaseUrl}/airflow/dags/:dag_id`, (req, res, ctx) => { + const { dag_id } = req.params; + const dag = dags.find(d => d.dag_id === dag_id); + if (dag) { + return res(ctx.json(dag)); + } + return res(ctx.status(404)); + }), + rest.patch(`${mockBaseUrl}/airflow/dags/:dag_id`, (req, res, ctx) => { const { dag_id } = req.params; const body = JSON.parse(req.body as string); @@ -160,4 +169,33 @@ describe('ApacheAirflowClient', () => { expect(response.dag_id).toEqual(dagId); expect(response.is_paused).toEqual(true); }); + + it('get only some dags', async () => { + setupHandlers(); + const client = new ApacheAirflowClient({ + discoveryApi: discoveryApi, + baseUrl: 'localhost:8080/', + }); + const dagIds = ['mock_dag_1', 'mock_dag_3']; + const response = await client.getDags(dagIds); + expect(response.dags.length).toEqual(dagIds.length); + response.dags.forEach((dag, index) => + expect(dag.dag_id).toEqual(dagIds[index]), + ); + expect(response.dagsNotFound.length).toEqual(0); + }); + + it('get dags but ignore NOT FOUND errors', async () => { + setupHandlers(); + const client = new ApacheAirflowClient({ + discoveryApi: discoveryApi, + baseUrl: 'localhost:8080/', + }); + const dagIds = ['mock_dag_1', 'a-random-DAG-id']; + const response = await client.getDags(dagIds); + expect(response.dags.length).toEqual(1); + expect(response.dags[0].dag_id).toEqual('mock_dag_1'); + expect(response.dagsNotFound.length).toEqual(1); + expect(response.dagsNotFound[0]).toEqual('a-random-DAG-id'); + }); }); diff --git a/plugins/apache-airflow/src/api/ApacheAirflowClient.ts b/plugins/apache-airflow/src/api/ApacheAirflowClient.ts index 847a1b1ca6..c722f5977d 100644 --- a/plugins/apache-airflow/src/api/ApacheAirflowClient.ts +++ b/plugins/apache-airflow/src/api/ApacheAirflowClient.ts @@ -75,6 +75,25 @@ export class ApacheAirflowClient implements ApacheAirflowApi { return dags; } + async getDags( + dagIds: string[], + ): Promise<{ dags: Dag[]; dagsNotFound: string[] }> { + const dagsNotFound: string[] = []; + const response = await Promise.all( + dagIds.map(id => { + return this.fetch(`/dags/${id}`).catch(e => { + if (e.message.toUpperCase('en-US') === 'NOT FOUND') { + dagsNotFound.push(id); + } else { + throw e; + } + }); + }), + ); + const dags = response.filter(Boolean) as Dag[]; + return { dags, dagsNotFound }; + } + async updateDag(dagId: string, isPaused: boolean): Promise { const init = { method: 'PATCH', diff --git a/plugins/apache-airflow/src/components/DagTableComponent/DagTableComponent.test.tsx b/plugins/apache-airflow/src/components/DagTableComponent/DagTableComponent.test.tsx new file mode 100644 index 0000000000..16ff3120be --- /dev/null +++ b/plugins/apache-airflow/src/components/DagTableComponent/DagTableComponent.test.tsx @@ -0,0 +1,62 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { ApacheAirflowApi, apacheAirflowApiRef } from '../../api'; +import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; +import React from 'react'; +import { DagTableComponent } from './DagTableComponent'; + +describe('DagTableComponent', () => { + const mockApi: jest.Mocked = { + listDags: jest.fn().mockResolvedValue([ + { + dag_id: 'mock_dag_1', + }, + { + dag_id: 'mock_dag_2', + }, + { + dag_id: 'mock_dag_3', + }, + ]), + getDags: jest.fn().mockResolvedValue({ + dags: [{ dag_id: 'mock_dag_1' }], + dagsNotFound: ['a-random-id'], + }), + } as any; + + it('should render all DAGs', async () => { + const { getByText } = await renderInTestApp( + + + , + ); + + ['mock_dag_1', 'mock_dag_2', 'mock_dag_3'].forEach(dagId => { + expect(getByText(dagId)).toBeInTheDocument(); + }); + }); + + it('should render only selected DAGs', async () => { + const { getByText } = await renderInTestApp( + + + , + ); + expect(getByText('mock_dag_1')).toBeInTheDocument(); + expect(getByText('Warning: 1 DAGs were not found')).toBeInTheDocument(); + expect(getByText('a-random-id')).toBeInTheDocument(); + }); +}); diff --git a/plugins/apache-airflow/src/components/DagTableComponent/DagTableComponent.tsx b/plugins/apache-airflow/src/components/DagTableComponent/DagTableComponent.tsx index cf343a596e..2514d70d45 100644 --- a/plugins/apache-airflow/src/components/DagTableComponent/DagTableComponent.tsx +++ b/plugins/apache-airflow/src/components/DagTableComponent/DagTableComponent.tsx @@ -20,6 +20,7 @@ import { StatusOK, Table, TableColumn, + WarningPanel, } from '@backstage/core-components'; import { useApi } from '@backstage/core-plugin-api'; import Box from '@material-ui/core/Box'; @@ -129,9 +130,18 @@ export const DenseTable = ({ dags }: DenseTableProps) => { ); }; -export const DagTableComponent = () => { +type DagTableComponentProps = { + dagIds?: string[]; +}; + +export const DagTableComponent = ({ dagIds }: DagTableComponentProps) => { const apiClient = useApi(apacheAirflowApiRef); + const { value, loading, error } = useAsync(async (): Promise => { + if (dagIds) { + const { dags } = await apiClient.getDags(dagIds); + return dags; + } return await apiClient.listDags(); }, []); @@ -146,6 +156,22 @@ export const DagTableComponent = () => { id: el.dag_id, // table records require `id` attribute dagUrl: `${apiClient.baseUrl}dag_details?dag_id=${el.dag_id}`, // construct path to DAG using `baseUrl` })); - - return ; + const dagsNotFound = + dagIds && value + ? dagIds.filter(id => !value.find(d => d.dag_id === id)) + : []; + return ( + <> + {dagsNotFound.length ? ( + + {dagsNotFound.map(dagId => ( + {dagId} + ))} + + ) : ( + '' + )} + + + ); }; diff --git a/plugins/apache-airflow/src/index.ts b/plugins/apache-airflow/src/index.ts index 7186839c0a..e8353c7760 100644 --- a/plugins/apache-airflow/src/index.ts +++ b/plugins/apache-airflow/src/index.ts @@ -20,4 +20,8 @@ * @packageDocumentation */ -export { apacheAirflowPlugin, ApacheAirflowPage } from './plugin'; +export { + apacheAirflowPlugin, + ApacheAirflowPage, + ApacheAirflowDagTable, +} from './plugin'; diff --git a/plugins/apache-airflow/src/plugin.ts b/plugins/apache-airflow/src/plugin.ts index 04ef1974d4..664cde36cc 100644 --- a/plugins/apache-airflow/src/plugin.ts +++ b/plugins/apache-airflow/src/plugin.ts @@ -17,11 +17,12 @@ import { rootRouteRef } from './routes'; import { apacheAirflowApiRef, ApacheAirflowClient } from './api'; import { + configApiRef, createApiFactory, + createComponentExtension, createPlugin, createRoutableExtension, discoveryApiRef, - configApiRef, } from '@backstage/core-plugin-api'; export const apacheAirflowPlugin = createPlugin({ @@ -49,3 +50,20 @@ export const ApacheAirflowPage = apacheAirflowPlugin.provide( mountPoint: rootRouteRef, }), ); + +/** + * Render the DAGs in a table + * If the dagIds is specified, only those DAGs are loaded. + * Otherwise, it's going to list all the DAGs + * @public + * @param dagIds - optional string[] of the DAGs to show in the table. If undefined, it will list all DAGs + */ +export const ApacheAirflowDagTable = apacheAirflowPlugin.provide( + createComponentExtension({ + name: 'ApacheAirflowDagTable', + component: { + lazy: () => + import('./components/DagTableComponent').then(m => m.DagTableComponent), + }, + }), +); diff --git a/plugins/api-docs-module-protoc-gen-doc/.eslintrc.js b/plugins/api-docs-module-protoc-gen-doc/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/api-docs-module-protoc-gen-doc/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/api-docs-module-protoc-gen-doc/CHANGELOG.md b/plugins/api-docs-module-protoc-gen-doc/CHANGELOG.md new file mode 100644 index 0000000000..c6ca346a62 --- /dev/null +++ b/plugins/api-docs-module-protoc-gen-doc/CHANGELOG.md @@ -0,0 +1,7 @@ +# @backstage/plugin-api-docs-module-protoc-gen-doc + +## 0.1.0-next.0 + +### Minor Changes + +- e0328f2107: Added the new `grpcDocsApiWidget` to render `protoc-gen-doc` generated descriptors by the `grpc-docs` package. diff --git a/plugins/api-docs-module-protoc-gen-doc/README.md b/plugins/api-docs-module-protoc-gen-doc/README.md new file mode 100644 index 0000000000..4d90cd74c2 --- /dev/null +++ b/plugins/api-docs-module-protoc-gen-doc/README.md @@ -0,0 +1,56 @@ +# @backstage/plugin-api-docs-module-protoc-gen-doc + +This package contains ApiDefinitionWidgets for the following projects: + +- [grpc-docs](https://github.com/gendocu-com/grpc-docs) + +## Setup + +``` +yarn add @backstage/plugin-api-docs-module-protoc-gen-doc +``` + +## Add the GrpcDocsApiWidget to your apis + +Add the widget to your `apiDocsConfigRef`. + +```ts +import { grpcDocsApiWidget } from '@backstage/plugin-api-docs-module-protoc-gen-doc'; +// packages/app/apis.ts +export const apis: AnyApiFactory[] = [ + createApiFactory({ + api: apiDocsConfigRef, + deps: {}, + factory: () => { + // load the default widgets + const definitionWidgets = defaultDefinitionWidgets(); + // add the grpc-docs api widget to the definition widgets + definitionWidgets.push(grpcDocsApiWidget); + return { + getApiDefinitionWidget: (apiEntity: ApiEntity) => { + // find the widget for the type of api entity + return definitionWidgets.find(d => d.type === apiEntity.spec.type); + }, + }; + }, + }), +]; +``` + +### Set the type in your api entities + +This widget will render the generated `protoc-gen-doc` descriptors with the `grpc-docs` package. For this make sure you use the `grpc-docs` as the type in the API catalog file. + +```yaml +apiVersion: backstage.io/v1alpha1 +kind: API +metadata: + name: hello-world + description: Hello World example for gRPC +spec: + type: grpc-docs + lifecycle: deprecated + owner: foo + definition: + $text: https://fetch-my-json.com/awesome-resource.json +``` diff --git a/plugins/api-docs-module-protoc-gen-doc/api-report.md b/plugins/api-docs-module-protoc-gen-doc/api-report.md new file mode 100644 index 0000000000..696fee2a20 --- /dev/null +++ b/plugins/api-docs-module-protoc-gen-doc/api-report.md @@ -0,0 +1,14 @@ +## API Report File for "@backstage/plugin-api-docs-module-protoc-gen-doc" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +/// + +// @public (undocumented) +export const grpcDocsApiWidget: { + type: string; + title: string; + component: (definition: string) => JSX.Element; +}; +``` diff --git a/plugins/api-docs-module-protoc-gen-doc/package.json b/plugins/api-docs-module-protoc-gen-doc/package.json new file mode 100644 index 0000000000..00409845d0 --- /dev/null +++ b/plugins/api-docs-module-protoc-gen-doc/package.json @@ -0,0 +1,47 @@ +{ + "name": "@backstage/plugin-api-docs-module-protoc-gen-doc", + "description": "Additional functionalities for the api-docs plugin that renders the output of the protoc-gen-doc", + "version": "0.1.0-next.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "main": "dist/index.esm.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "frontend-plugin-module" + }, + "homepage": "https://backstage.io", + "repository": { + "type": "git", + "url": "https://github.com/backstage/backstage", + "directory": "plugins/api-docs-module-protoc-gen-doc" + }, + "keywords": [ + "backstage" + ], + "scripts": { + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "grpc-docs": "^1.1.2" + }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, + "devDependencies": { + "@backstage/cli": "^0.18.0-next.1", + "@testing-library/jest-dom": "^5.16.4", + "@types/react": "^16.13.1 || ^17.0.0" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/api-docs-module-protoc-gen-doc/src/index.ts b/plugins/api-docs-module-protoc-gen-doc/src/index.ts new file mode 100644 index 0000000000..8cca60ac60 --- /dev/null +++ b/plugins/api-docs-module-protoc-gen-doc/src/index.ts @@ -0,0 +1,23 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Package encapsulating utilities to be shared by frontend TechDocs plugins. + * + * @packageDocumentation + */ + +export { grpcDocsApiWidget } from './widgets'; diff --git a/plugins/api-docs-module-protoc-gen-doc/src/setupTests.ts b/plugins/api-docs-module-protoc-gen-doc/src/setupTests.ts new file mode 100644 index 0000000000..7a459ed24e --- /dev/null +++ b/plugins/api-docs-module-protoc-gen-doc/src/setupTests.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import '@testing-library/jest-dom'; diff --git a/plugins/api-docs-module-protoc-gen-doc/src/widgets.tsx b/plugins/api-docs-module-protoc-gen-doc/src/widgets.tsx new file mode 100644 index 0000000000..5f35c8d9b3 --- /dev/null +++ b/plugins/api-docs-module-protoc-gen-doc/src/widgets.tsx @@ -0,0 +1,29 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { GRPCSelfGeneratedAPIReference } from 'grpc-docs'; + +/** + * @public + */ +export const grpcDocsApiWidget = { + type: 'grpc-docs', + title: 'gRPC', + component: (definition: string) => ( + + ), +}; diff --git a/plugins/api-docs/CHANGELOG.md b/plugins/api-docs/CHANGELOG.md index 2d61c19e62..6b2e54f018 100644 --- a/plugins/api-docs/CHANGELOG.md +++ b/plugins/api-docs/CHANGELOG.md @@ -1,5 +1,38 @@ # @backstage/plugin-api-docs +## 0.8.7-next.2 + +### Patch Changes + +- a274fe38b9: Add hidden title column to catalog and API table to enable filtering by title. +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog@1.4.0-next.2 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## 0.8.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/plugin-catalog@1.3.1-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## 0.8.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog@1.3.1-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + ## 0.8.6 ### Patch Changes diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index 9cd1e3aef0..b6d54ab952 100644 --- a/plugins/api-docs/package.json +++ b/plugins/api-docs/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-api-docs", "description": "A Backstage plugin that helps represent API entities in the frontend", - "version": "0.8.6", + "version": "0.8.7-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,13 +33,13 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@asyncapi/react-component": "1.0.0-next.38", - "@backstage/catalog-model": "^1.0.3", - "@backstage/core-components": "^0.9.5", + "@asyncapi/react-component": "1.0.0-next.39", + "@backstage/catalog-model": "^1.1.0-next.2", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/plugin-catalog": "^1.3.0", - "@backstage/plugin-catalog-react": "^1.1.1", - "@backstage/theme": "^0.2.15", + "@backstage/plugin-catalog": "^1.4.0-next.2", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -57,10 +57,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", @@ -68,7 +68,7 @@ "@types/node": "^16.11.26", "@types/swagger-ui-react": "^4.1.1", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/api-docs/src/components/ApiExplorerPage/DefaultApiExplorerPage.tsx b/plugins/api-docs/src/components/ApiExplorerPage/DefaultApiExplorerPage.tsx index 9fc6b2c3c2..b0acd3567c 100644 --- a/plugins/api-docs/src/components/ApiExplorerPage/DefaultApiExplorerPage.tsx +++ b/plugins/api-docs/src/components/ApiExplorerPage/DefaultApiExplorerPage.tsx @@ -40,6 +40,7 @@ import React from 'react'; import { registerComponentRouteRef } from '../../routes'; const defaultColumns: TableColumn[] = [ + CatalogTable.columns.createTitleColumn({ hidden: true }), CatalogTable.columns.createNameColumn({ defaultKind: 'API' }), CatalogTable.columns.createSystemColumn(), CatalogTable.columns.createOwnerColumn(), diff --git a/plugins/app-backend/CHANGELOG.md b/plugins/app-backend/CHANGELOG.md index 6e86ece20d..0282527437 100644 --- a/plugins/app-backend/CHANGELOG.md +++ b/plugins/app-backend/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-app-backend +## 0.3.34-next.2 + +### Patch Changes + +- 679b32172e: Updated dependency `knex` to `^2.0.0`. +- Updated dependencies + - @backstage/backend-common@0.14.1-next.2 + +## 0.3.34-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.1 + - @backstage/config-loader@1.1.3-next.0 + +## 0.3.34-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + ## 0.3.33 ### Patch Changes diff --git a/plugins/app-backend/package.json b/plugins/app-backend/package.json index 5efb839730..b25a162f4a 100644 --- a/plugins/app-backend/package.json +++ b/plugins/app-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-app-backend", "description": "A Backstage backend plugin that serves the Backstage frontend app", - "version": "0.3.33", + "version": "0.3.34-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,8 +33,8 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", - "@backstage/config-loader": "^1.1.2", + "@backstage/backend-common": "^0.14.1-next.2", + "@backstage/config-loader": "^1.1.3-next.0", "@backstage/config": "^1.0.1", "@backstage/types": "^1.0.0", "@types/express": "^4.17.6", @@ -43,19 +43,19 @@ "express-promise-router": "^4.1.0", "fs-extra": "10.1.0", "helmet": "^5.0.2", - "knex": "^1.0.2", + "knex": "^2.0.0", "lodash": "^4.17.21", "luxon": "^2.0.2", "winston": "^3.2.1", "yn": "^4.0.0" }, "devDependencies": { - "@backstage/backend-test-utils": "^0.1.25", - "@backstage/cli": "^0.17.2", + "@backstage/backend-test-utils": "^0.1.26-next.2", + "@backstage/cli": "^0.18.0-next.2", "@backstage/types": "^1.0.0", "@types/supertest": "^2.0.8", "mock-fs": "^5.1.0", - "msw": "^0.42.0", + "msw": "^0.43.0", "supertest": "^6.1.3" }, "files": [ diff --git a/plugins/auth-backend/CHANGELOG.md b/plugins/auth-backend/CHANGELOG.md index 0f69289de5..8e6e79d97e 100644 --- a/plugins/auth-backend/CHANGELOG.md +++ b/plugins/auth-backend/CHANGELOG.md @@ -1,5 +1,48 @@ # @backstage/plugin-auth-backend +## 0.15.0-next.2 + +### Patch Changes + +- 8e03db907a: Auth provider now also export createAuthProviderIntegration +- 679b32172e: Updated dependency `knex` to `^2.0.0`. +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/backend-common@0.14.1-next.2 + +## 0.15.0-next.1 + +### Minor Changes + +- 9d4040777e: **BREAKING**: Removed all directly exported auth provider factories, option types, and sign-in resolvers. For example: `AwsAlbProviderOptions`, `bitbucketUserIdSignInResolver`, `createGithubProvider`. These are all still accessible via the `providers` export. For example, use `providers.github.create()` rather than `createGithubProvider()`, and `providers.bitbucket.resolvers.userIdMatchingUserEntityAnnotation()` rather than `bitbucketUserIdSignInResolver`. + + **BREAKING**: Removed the exported `AuthProviderFactoryOptions` type as well as the deprecated option fields of the `AuthProviderFactory` callback. This includes the `tokenManager`, `tokenIssuer`, `discovery`, and `catalogApi` fields. Existing usage of these should be replaced with the new utilities in the `resolverContext` field. The deprecated `TokenIssuer` type is now also removed, since it is no longer used. + + **BREAKING**: Removed `getEntityClaims`, use `getDefaultOwnershipEntityRefs` instead. + + **DEPRECATION**: Deprecated `AtlassianAuthProvider` as it was unintentionally exported. + +### Patch Changes + +- f2cf79d62e: Added an option for the auth backend router to select the algorithm for the JWT token signing keys +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/catalog-client@1.0.4-next.1 + - @backstage/plugin-auth-node@0.2.3-next.1 + +## 0.14.2-next.0 + +### Patch Changes + +- 859346bfbb: Updated dependency `google-auth-library` to `^8.0.0`. +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/plugin-auth-node@0.2.3-next.0 + - @backstage/catalog-client@1.0.4-next.0 + ## 0.14.1 ### Patch Changes diff --git a/plugins/auth-backend/api-report.md b/plugins/auth-backend/api-report.md index bb25ff6d57..8c9ec14c9e 100644 --- a/plugins/auth-backend/api-report.md +++ b/plugins/auth-backend/api-report.md @@ -23,9 +23,7 @@ import { TokenSet } from 'openid-client'; import { UserEntity } from '@backstage/catalog-model'; import { UserinfoResponse } from 'openid-client'; -// Warning: (ae-missing-release-tag) "AtlassianAuthProvider" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) +// @public @deprecated (undocumented) export class AtlassianAuthProvider implements OAuthHandlers { // Warning: (ae-forgotten-export) The symbol "AtlassianAuthProviderOptions" needs to be exported by the entry point index.d.ts constructor(options: AtlassianAuthProviderOptions); @@ -45,22 +43,6 @@ export class AtlassianAuthProvider implements OAuthHandlers { start(req: OAuthStartRequest): Promise; } -// @public @deprecated (undocumented) -export type AtlassianProviderOptions = { - authHandler?: AuthHandler; - signIn?: { - resolver: SignInResolver; - }; -}; - -// @public @deprecated (undocumented) -export type Auth0ProviderOptions = { - authHandler?: AuthHandler; - signIn?: { - resolver: SignInResolver; - }; -}; - // @public export type AuthHandler = ( input: TAuthResult, @@ -89,26 +71,8 @@ export type AuthProviderFactory = (options: { config: Config; logger: Logger; resolverContext: AuthResolverContext; - tokenManager: TokenManager; - tokenIssuer: TokenIssuer; - discovery: PluginEndpointDiscovery; - catalogApi: CatalogApi; }) => AuthProviderRouteHandlers; -// Warning: (ae-missing-release-tag) "AuthProviderFactoryOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public @deprecated (undocumented) -export type AuthProviderFactoryOptions = { - providerId: string; - globalConfig: AuthProviderConfig; - config: Config; - logger: Logger; - tokenManager: TokenManager; - tokenIssuer: TokenIssuer; - discovery: PluginEndpointDiscovery; - catalogApi: CatalogApi; -}; - // Warning: (ae-missing-release-tag) "AuthProviderRouteHandlers" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public @@ -139,9 +103,6 @@ export type AuthResolverCatalogUserQuery = // @public export type AuthResolverContext = { - logger: Logger; - tokenIssuer: TokenIssuer; - catalogIdentityClient: CatalogIdentityClient; issueToken(params: TokenParams): Promise<{ token: string; }>; @@ -160,14 +121,6 @@ export type AuthResponse = { backstageIdentity?: BackstageIdentityResponse; }; -// @public @deprecated (undocumented) -export type AwsAlbProviderOptions = { - authHandler?: AuthHandler; - signIn: { - resolver: SignInResolver; - }; -}; - // @public (undocumented) export type AwsAlbResult = { fullProfile: Profile; @@ -206,20 +159,6 @@ export type BitbucketPassportProfile = Profile & { }; }; -// @public @deprecated (undocumented) -export type BitbucketProviderOptions = { - authHandler?: AuthHandler; - signIn?: { - resolver: SignInResolver; - }; -}; - -// @public @deprecated (undocumented) -export const bitbucketUserIdSignInResolver: SignInResolver; - -// @public @deprecated (undocumented) -export const bitbucketUsernameSignInResolver: SignInResolver; - // Warning: (ae-missing-release-tag) "CatalogIdentityClient" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public @@ -242,188 +181,21 @@ export type CookieConfigurer = (ctx: { secure: boolean; }; -// @public @deprecated (undocumented) -export const createAtlassianProvider: ( - options?: - | { - authHandler?: AuthHandler | undefined; - signIn?: - | { - resolver: SignInResolver; - } - | undefined; - } - | undefined, -) => AuthProviderFactory; - -// @public @deprecated (undocumented) -export const createAuth0Provider: ( - options?: - | { - authHandler?: AuthHandler | undefined; - signIn?: - | { - resolver: SignInResolver; - } - | undefined; - } - | undefined, -) => AuthProviderFactory; - -// @public @deprecated (undocumented) -export const createAwsAlbProvider: ( - options?: - | { - authHandler?: AuthHandler | undefined; - signIn: { - resolver: SignInResolver; - }; - } - | undefined, -) => AuthProviderFactory; - -// @public @deprecated (undocumented) -export const createBitbucketProvider: ( - options?: - | { - authHandler?: AuthHandler | undefined; - signIn?: - | { - resolver: SignInResolver; - } - | undefined; - } - | undefined, -) => AuthProviderFactory; - -// @public @deprecated (undocumented) -export const createGcpIapProvider: (options: { - authHandler?: AuthHandler | undefined; - signIn: { - resolver: SignInResolver; - }; -}) => AuthProviderFactory; - -// @public @deprecated (undocumented) -export const createGithubProvider: ( - options?: - | { - authHandler?: AuthHandler | undefined; - signIn?: - | { - resolver: SignInResolver; - } - | undefined; - stateEncoder?: StateEncoder | undefined; - } - | undefined, -) => AuthProviderFactory; - -// @public @deprecated (undocumented) -export const createGitlabProvider: ( - options?: - | { - authHandler?: AuthHandler | undefined; - signIn?: - | { - resolver: SignInResolver; - } - | undefined; - } - | undefined, -) => AuthProviderFactory; - -// @public @deprecated (undocumented) -export const createGoogleProvider: ( - options?: - | { - authHandler?: AuthHandler | undefined; - signIn?: - | { - resolver: SignInResolver; - } - | undefined; - } - | undefined, -) => AuthProviderFactory; - -// @public @deprecated (undocumented) -export const createMicrosoftProvider: ( - options?: - | { - authHandler?: AuthHandler | undefined; - signIn?: - | { - resolver: SignInResolver; - } - | undefined; - } - | undefined, -) => AuthProviderFactory; - -// @public @deprecated (undocumented) -export const createOAuth2Provider: ( - options?: - | { - authHandler?: AuthHandler | undefined; - signIn?: - | { - resolver: SignInResolver; - } - | undefined; - } - | undefined, -) => AuthProviderFactory; - -// @public @deprecated (undocumented) -export const createOauth2ProxyProvider: (options: { - authHandler?: AuthHandler> | undefined; - signIn: { - resolver: SignInResolver>; - }; -}) => AuthProviderFactory; - -// @public @deprecated (undocumented) -export const createOidcProvider: ( - options?: - | { - authHandler?: AuthHandler | undefined; - signIn?: - | { - resolver: SignInResolver; - } - | undefined; - } - | undefined, -) => AuthProviderFactory; - -// @public @deprecated (undocumented) -export const createOktaProvider: ( - options?: - | { - authHandler?: AuthHandler | undefined; - signIn?: - | { - resolver: SignInResolver; - } - | undefined; - } - | undefined, -) => AuthProviderFactory; - -// @public @deprecated (undocumented) -export const createOneLoginProvider: ( - options?: - | { - authHandler?: AuthHandler | undefined; - signIn?: - | { - resolver: SignInResolver; - } - | undefined; - } - | undefined, -) => AuthProviderFactory; +// Warning: (ae-missing-release-tag) "createAuthProviderIntegration" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export function createAuthProviderIntegration< + TCreateOptions extends unknown[], + TResolvers extends { + [name in string]: (...args: any[]) => SignInResolver; + }, +>(config: { + create: (...args: TCreateOptions) => AuthProviderFactory; + resolvers?: TResolvers; +}): Readonly<{ + create: (...args: TCreateOptions) => AuthProviderFactory; + resolvers: Readonly; +}>; // Warning: (ae-missing-release-tag) "createOriginFilter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -435,23 +207,7 @@ export function createOriginFilter(config: Config): (origin: string) => boolean; // @public (undocumented) export function createRouter(options: RouterOptions): Promise; -// @public @deprecated (undocumented) -export const createSamlProvider: ( - options?: - | { - authHandler?: AuthHandler | undefined; - signIn?: - | { - resolver: SignInResolver; - } - | undefined; - } - | undefined, -) => AuthProviderFactory; - -// Warning: (ae-missing-release-tag) "factories" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) +// @public export const defaultAuthProviderFactories: { [providerId: string]: AuthProviderFactory; }; @@ -466,14 +222,6 @@ export const encodeState: (state: OAuthState) => string; // @public (undocumented) export const ensuresXRequestedWith: (req: express.Request) => boolean; -// @public @deprecated (undocumented) -export type GcpIapProviderOptions = { - authHandler?: AuthHandler; - signIn: { - resolver: SignInResolver; - }; -}; - // @public export type GcpIapResult = { iapToken: GcpIapTokenInfo; @@ -489,11 +237,6 @@ export type GcpIapTokenInfo = { // @public export function getDefaultOwnershipEntityRefs(entity: Entity): string[]; -// Warning: (ae-missing-release-tag) "getEntityClaims" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public @deprecated (undocumented) -export function getEntityClaims(entity: UserEntity): TokenParams['claims']; - // Warning: (ae-missing-release-tag) "GithubOAuthResult" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -508,61 +251,6 @@ export type GithubOAuthResult = { refreshToken?: string; }; -// @public @deprecated (undocumented) -export type GithubProviderOptions = { - authHandler?: AuthHandler; - signIn?: { - resolver: SignInResolver; - }; - stateEncoder?: StateEncoder; -}; - -// @public @deprecated (undocumented) -export type GitlabProviderOptions = { - authHandler?: AuthHandler; - signIn?: { - resolver: SignInResolver; - }; -}; - -// @public @deprecated (undocumented) -export const googleEmailSignInResolver: SignInResolver; - -// @public @deprecated (undocumented) -export type GoogleProviderOptions = { - authHandler?: AuthHandler; - signIn?: { - resolver: SignInResolver; - }; -}; - -// @public @deprecated (undocumented) -export const microsoftEmailSignInResolver: SignInResolver; - -// @public @deprecated (undocumented) -export type MicrosoftProviderOptions = { - authHandler?: AuthHandler; - signIn?: { - resolver: SignInResolver; - }; -}; - -// @public @deprecated (undocumented) -export type OAuth2ProviderOptions = { - authHandler?: AuthHandler; - signIn?: { - resolver: SignInResolver; - }; -}; - -// @public @deprecated (undocumented) -export type Oauth2ProxyProviderOptions = { - authHandler: AuthHandler>; - signIn: { - resolver: SignInResolver>; - }; -}; - // @public export type OAuth2ProxyResult = { fullProfile: JWTPayload; @@ -584,10 +272,7 @@ export class OAuthAdapter implements AuthProviderRouteHandlers { static fromConfig( config: AuthProviderConfig, handlers: OAuthHandlers, - options: Pick< - Options, - 'providerId' | 'persistScopes' | 'tokenIssuer' | 'callbackUrl' - >, + options: Pick, ): OAuthAdapter; // (undocumented) logout(req: express.Request, res: express.Response): Promise; @@ -703,33 +388,6 @@ export type OidcAuthResult = { userinfo: UserinfoResponse; }; -// @public @deprecated (undocumented) -export type OidcProviderOptions = { - authHandler?: AuthHandler; - signIn?: { - resolver: SignInResolver; - }; -}; - -// @public @deprecated (undocumented) -export const oktaEmailSignInResolver: SignInResolver; - -// @public @deprecated (undocumented) -export type OktaProviderOptions = { - authHandler?: AuthHandler; - signIn?: { - resolver: SignInResolver; - }; -}; - -// @public @deprecated (undocumented) -export type OneLoginProviderOptions = { - authHandler?: AuthHandler; - signIn?: { - resolver: SignInResolver; - }; -}; - // Warning: (ae-missing-release-tag) "postMessageResponse" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -1008,6 +666,8 @@ export interface RouterOptions { // (undocumented) providerFactories?: ProviderFactories; // (undocumented) + tokenFactoryAlgorithm?: string; + // (undocumented) tokenManager: TokenManager; } @@ -1016,17 +676,6 @@ export type SamlAuthResult = { fullProfile: any; }; -// @public @deprecated (undocumented) -export const samlNameIdEntityNameSignInResolver: SignInResolver; - -// @public @deprecated (undocumented) -export type SamlProviderOptions = { - authHandler?: AuthHandler; - signIn?: { - resolver: SignInResolver; - }; -}; - // @public export type SignInInfo = { profile: ProfileInfo; @@ -1044,14 +693,6 @@ export type StateEncoder = (req: OAuthStartRequest) => Promise<{ encodedState: string; }>; -// @public @deprecated -export type TokenIssuer = { - issueToken(params: TokenParams): Promise; - listPublicKeys(): Promise<{ - keys: AnyJWK[]; - }>; -}; - // @public export type TokenParams = { claims: { @@ -1077,8 +718,4 @@ export type WebMessageResponse = type: 'authorization_response'; error: Error; }; - -// Warnings were encountered during analysis: -// -// src/identity/types.d.ts:38:9 - (ae-forgotten-export) The symbol "AnyJWK" needs to be exported by the entry point index.d.ts ``` diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index 8e142ba401..d6b027e6ea 100644 --- a/plugins/auth-backend/package.json +++ b/plugins/auth-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend", "description": "A Backstage backend plugin that handles authentication", - "version": "0.14.1", + "version": "0.15.0-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,12 +33,12 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/plugin-auth-node": "^0.2.2", - "@backstage/backend-common": "^0.14.0", - "@backstage/catalog-client": "^1.0.3", - "@backstage/catalog-model": "^1.0.3", + "@backstage/plugin-auth-node": "^0.2.3-next.1", + "@backstage/backend-common": "^0.14.1-next.2", + "@backstage/catalog-client": "^1.0.4-next.1", + "@backstage/catalog-model": "^1.1.0-next.2", "@backstage/config": "^1.0.1", - "@backstage/errors": "^1.0.0", + "@backstage/errors": "^1.1.0-next.0", "@backstage/types": "^1.0.0", "@google-cloud/firestore": "^5.0.2", "@types/express": "^4.17.6", @@ -50,10 +50,10 @@ "express-promise-router": "^4.1.0", "express-session": "^1.17.1", "fs-extra": "10.1.0", - "google-auth-library": "^7.6.1", + "google-auth-library": "^8.0.0", "jose": "^4.6.0", "jwt-decode": "^3.1.0", - "knex": "^1.0.2", + "knex": "^2.0.0", "lodash": "^4.17.21", "luxon": "^2.0.2", "minimatch": "^5.0.0", @@ -76,8 +76,8 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/backend-test-utils": "^0.1.25", - "@backstage/cli": "^0.17.2", + "@backstage/backend-test-utils": "^0.1.26-next.2", + "@backstage/cli": "^0.18.0-next.2", "@types/body-parser": "^1.19.0", "@types/cookie-parser": "^1.4.2", "@types/express-session": "^1.17.2", @@ -88,7 +88,7 @@ "@types/passport-saml": "^1.1.3", "@types/passport-strategy": "^0.2.35", "@types/xml2js": "^0.4.7", - "msw": "^0.42.0", + "msw": "^0.43.0", "supertest": "^6.1.3" }, "files": [ diff --git a/plugins/auth-backend/src/identity/index.ts b/plugins/auth-backend/src/identity/index.ts index cb2f369668..a5e0dd4b80 100644 --- a/plugins/auth-backend/src/identity/index.ts +++ b/plugins/auth-backend/src/identity/index.ts @@ -20,4 +20,4 @@ export { DatabaseKeyStore } from './DatabaseKeyStore'; export { MemoryKeyStore } from './MemoryKeyStore'; export { FirestoreKeyStore } from './FirestoreKeyStore'; export { KeyStores } from './KeyStores'; -export type { KeyStore, TokenIssuer, TokenParams } from './types'; +export type { KeyStore, TokenParams } from './types'; diff --git a/plugins/auth-backend/src/identity/types.ts b/plugins/auth-backend/src/identity/types.ts index 5a350284e5..4765b50d7d 100644 --- a/plugins/auth-backend/src/identity/types.ts +++ b/plugins/auth-backend/src/identity/types.ts @@ -37,12 +37,8 @@ export type TokenParams = { }; }; -// TODO(Rugvip): This should at least be made internal /** * A TokenIssuer is able to issue verifiable ID Tokens on demand. - * - * @public - * @deprecated This interface is deprecated and will be removed in a future release. */ export type TokenIssuer = { /** diff --git a/plugins/auth-backend/src/index.ts b/plugins/auth-backend/src/index.ts index d51cb3f1eb..f8a8580359 100644 --- a/plugins/auth-backend/src/index.ts +++ b/plugins/auth-backend/src/index.ts @@ -21,7 +21,7 @@ */ export * from './service/router'; -export type { TokenIssuer, TokenParams } from './identity'; +export type { TokenParams } from './identity'; export * from './providers'; // flow package provides 2 functions diff --git a/plugins/auth-backend/src/lib/catalog/index.ts b/plugins/auth-backend/src/lib/catalog/index.ts index 0d1aa4a6f7..f0f5b10808 100644 --- a/plugins/auth-backend/src/lib/catalog/index.ts +++ b/plugins/auth-backend/src/lib/catalog/index.ts @@ -15,4 +15,3 @@ */ export { CatalogIdentityClient } from './CatalogIdentityClient'; -export { getEntityClaims } from './helpers'; diff --git a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts index 5be4b7e3c0..9c28ed8fad 100644 --- a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts +++ b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts @@ -31,7 +31,6 @@ import { isError, NotAllowedError, } from '@backstage/errors'; -import { TokenIssuer } from '../../identity/types'; import { defaultCookieConfigurer, readState, verifyNonce } from './helpers'; import { postMessageResponse, ensuresXRequestedWith } from '../flow'; import { @@ -52,8 +51,6 @@ export type Options = { cookieDomain: string; cookiePath: string; appOrigin: string; - /** @deprecated This option is no longer needed */ - tokenIssuer?: TokenIssuer; isOriginAllowed: (origin: string) => boolean; callbackUrl: string; }; @@ -61,10 +58,7 @@ export class OAuthAdapter implements AuthProviderRouteHandlers { static fromConfig( config: AuthProviderConfig, handlers: OAuthHandlers, - options: Pick< - Options, - 'providerId' | 'persistScopes' | 'tokenIssuer' | 'callbackUrl' - >, + options: Pick, ): OAuthAdapter { const { origin: appOrigin } = new URL(config.appUrl); diff --git a/plugins/auth-backend/src/lib/resolvers/CatalogAuthResolverContext.ts b/plugins/auth-backend/src/lib/resolvers/CatalogAuthResolverContext.ts index 1a1fdd7a36..cbc2439563 100644 --- a/plugins/auth-backend/src/lib/resolvers/CatalogAuthResolverContext.ts +++ b/plugins/auth-backend/src/lib/resolvers/CatalogAuthResolverContext.ts @@ -25,8 +25,7 @@ import { } from '@backstage/catalog-model'; import { ConflictError, InputError, NotFoundError } from '@backstage/errors'; import { Logger } from 'winston'; -import { TokenIssuer } from '../..'; -import { TokenParams } from '../../identity'; +import { TokenIssuer, TokenParams } from '../../identity/types'; import { AuthResolverContext } from '../../providers'; import { AuthResolverCatalogUserQuery } from '../../providers/types'; import { CatalogIdentityClient } from '../catalog'; diff --git a/plugins/auth-backend/src/providers/atlassian/index.ts b/plugins/auth-backend/src/providers/atlassian/index.ts index cf3eb901d9..8dff0197a3 100644 --- a/plugins/auth-backend/src/providers/atlassian/index.ts +++ b/plugins/auth-backend/src/providers/atlassian/index.ts @@ -14,8 +14,4 @@ * limitations under the License. */ -export { createAtlassianProvider } from './provider'; -export type { - AtlassianAuthProvider, - AtlassianProviderOptions, -} from './provider'; +export { atlassian, AtlassianAuthProvider } from './provider'; diff --git a/plugins/auth-backend/src/providers/atlassian/provider.ts b/plugins/auth-backend/src/providers/atlassian/provider.ts index 2aa85dab96..b693d226a2 100644 --- a/plugins/auth-backend/src/providers/atlassian/provider.ts +++ b/plugins/auth-backend/src/providers/atlassian/provider.ts @@ -58,6 +58,10 @@ export const atlassianDefaultAuthHandler: AuthHandler = async ({ profile: makeProfileInfo(fullProfile, params.id_token), }); +/** + * @public + * @deprecated This export is deprecated and will be removed in the future. + */ export class AtlassianAuthProvider implements OAuthHandlers { private readonly _strategy: AtlassianStrategy; private readonly signInResolver?: SignInResolver; @@ -161,25 +165,6 @@ export class AtlassianAuthProvider implements OAuthHandlers { } } -/** - * @public - * @deprecated This type has been inlined into the create method and will be removed. - */ -export type AtlassianProviderOptions = { - /** - * The profile transformation function used to verify and convert the auth response - * into the profile that will be presented to the user. - */ - authHandler?: AuthHandler; - - /** - * Configure sign-in for this provider, without it the provider can not be used to sign users in. - */ - signIn?: { - resolver: SignInResolver; - }; -}; - /** * Auth provider integration for atlassian auth * @@ -230,9 +215,3 @@ export const atlassian = createAuthProviderIntegration({ }); }, }); - -/** - * @public - * @deprecated Use `providers.atlassian.create` instead - */ -export const createAtlassianProvider = atlassian.create; diff --git a/plugins/auth-backend/src/providers/auth0/index.ts b/plugins/auth-backend/src/providers/auth0/index.ts index b201177d69..94a08a5809 100644 --- a/plugins/auth-backend/src/providers/auth0/index.ts +++ b/plugins/auth-backend/src/providers/auth0/index.ts @@ -14,5 +14,4 @@ * limitations under the License. */ -export { createAuth0Provider } from './provider'; -export type { Auth0ProviderOptions } from './provider'; +export { auth0 } from './provider'; diff --git a/plugins/auth-backend/src/providers/auth0/provider.ts b/plugins/auth-backend/src/providers/auth0/provider.ts index 9ddd587508..a53f504f50 100644 --- a/plugins/auth-backend/src/providers/auth0/provider.ts +++ b/plugins/auth-backend/src/providers/auth0/provider.ts @@ -169,28 +169,6 @@ export class Auth0AuthProvider implements OAuthHandlers { } } -/** - * @public - * @deprecated This type has been inlined into the create method and will be removed. - */ -export type Auth0ProviderOptions = { - /** - * The profile transformation function used to verify and convert the auth response - * into the profile that will be presented to the user. - */ - authHandler?: AuthHandler; - - /** - * Configure sign-in for this provider, without it the provider can not be used to sign users in. - */ - signIn?: { - /** - * Maps an auth result to a Backstage identity for the user. - */ - resolver: SignInResolver; - }; -}; - /** * Auth provider integration for auth0 auth * @@ -249,9 +227,3 @@ export const auth0 = createAuthProviderIntegration({ }); }, }); - -/** - * @public - * @deprecated Use `providers.auth0.create` instead. - */ -export const createAuth0Provider = auth0.create; diff --git a/plugins/auth-backend/src/providers/aws-alb/index.ts b/plugins/auth-backend/src/providers/aws-alb/index.ts index 710d86ca3d..9b3e8920ac 100644 --- a/plugins/auth-backend/src/providers/aws-alb/index.ts +++ b/plugins/auth-backend/src/providers/aws-alb/index.ts @@ -14,5 +14,5 @@ * limitations under the License. */ -export { createAwsAlbProvider } from './provider'; -export type { AwsAlbProviderOptions, AwsAlbResult } from './provider'; +export { awsAlb } from './provider'; +export type { AwsAlbResult } from './provider'; diff --git a/plugins/auth-backend/src/providers/aws-alb/provider.ts b/plugins/auth-backend/src/providers/aws-alb/provider.ts index b8d43a11e6..5af606539e 100644 --- a/plugins/auth-backend/src/providers/aws-alb/provider.ts +++ b/plugins/auth-backend/src/providers/aws-alb/provider.ts @@ -211,28 +211,6 @@ export class AwsAlbAuthProvider implements AuthProviderRouteHandlers { }; } -/** - * @public - * @deprecated This type has been inlined into the create method and will be removed. - */ -export type AwsAlbProviderOptions = { - /** - * The profile transformation function used to verify and convert the auth response - * into the profile that will be presented to the user. - */ - authHandler?: AuthHandler; - - /** - * Configure sign-in for this provider, without it the provider can not be used to sign users in. - */ - signIn: { - /** - * Maps an auth result to a Backstage identity for the user. - */ - resolver: SignInResolver; - }; -}; - /** * Auth provider integration for AWS ALB auth * @@ -282,9 +260,3 @@ export const awsAlb = createAuthProviderIntegration({ }; }, }); - -/** - * @public - * @deprecated Use `providers.awsAlb.create` instead - */ -export const createAwsAlbProvider = awsAlb.create; diff --git a/plugins/auth-backend/src/providers/bitbucket/index.ts b/plugins/auth-backend/src/providers/bitbucket/index.ts index 55a5735655..9d82c1066c 100644 --- a/plugins/auth-backend/src/providers/bitbucket/index.ts +++ b/plugins/auth-backend/src/providers/bitbucket/index.ts @@ -14,13 +14,8 @@ * limitations under the License. */ -export { - createBitbucketProvider, - bitbucketUsernameSignInResolver, - bitbucketUserIdSignInResolver, -} from './provider'; +export { bitbucket } from './provider'; export type { - BitbucketProviderOptions, BitbucketPassportProfile, BitbucketOAuthResult, } from './provider'; diff --git a/plugins/auth-backend/src/providers/bitbucket/provider.ts b/plugins/auth-backend/src/providers/bitbucket/provider.ts index 5b9919764b..e3bd044466 100644 --- a/plugins/auth-backend/src/providers/bitbucket/provider.ts +++ b/plugins/auth-backend/src/providers/bitbucket/provider.ts @@ -190,28 +190,6 @@ export class BitbucketAuthProvider implements OAuthHandlers { } } -/** - * @public - * @deprecated This type has been inlined into the create method and will be removed. - */ -export type BitbucketProviderOptions = { - /** - * The profile transformation function used to verify and convert the auth response - * into the profile that will be presented to the user. - */ - authHandler?: AuthHandler; - - /** - * Configure sign-in for this provider, without it the provider can not be used to sign users in. - */ - signIn?: { - /** - * Maps an auth result to a Backstage identity for the user. - */ - resolver: SignInResolver; - }; -}; - /** * Auth provider integration for BitBucket auth * @@ -305,23 +283,3 @@ export const bitbucket = createAuthProviderIntegration({ }, }, }); - -/** - * @public - * @deprecated Use `providers.bitbucket.create` instead - */ -export const createBitbucketProvider = bitbucket.create; - -/** - * @public - * @deprecated Use `providers.bitbucket.resolvers.usernameMatchingUserEntityAnnotation()` instead. - */ -export const bitbucketUsernameSignInResolver = - bitbucket.resolvers.usernameMatchingUserEntityAnnotation(); - -/** - * @public - * @deprecated Use `providers.bitbucket.resolvers.userIdMatchingUserEntityAnnotation()` instead. - */ -export const bitbucketUserIdSignInResolver = - bitbucket.resolvers.userIdMatchingUserEntityAnnotation(); diff --git a/plugins/auth-backend/src/providers/factories.ts b/plugins/auth-backend/src/providers/factories.ts deleted file mode 100644 index 42d3569815..0000000000 --- a/plugins/auth-backend/src/providers/factories.ts +++ /dev/null @@ -1,46 +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 { createGithubProvider } from './github'; -import { createGitlabProvider } from './gitlab'; -import { createGoogleProvider } from './google'; -import { createOAuth2Provider } from './oauth2'; -import { createOidcProvider } from './oidc'; -import { createOktaProvider } from './okta'; -import { createSamlProvider } from './saml'; -import { createAuth0Provider } from './auth0'; -import { createMicrosoftProvider } from './microsoft'; -import { createOneLoginProvider } from './onelogin'; -import { AuthProviderFactory } from './types'; -import { createAwsAlbProvider } from './aws-alb'; -import { createBitbucketProvider } from './bitbucket'; -import { createAtlassianProvider } from './atlassian'; - -export const factories: { [providerId: string]: AuthProviderFactory } = { - google: createGoogleProvider(), - github: createGithubProvider(), - gitlab: createGitlabProvider(), - saml: createSamlProvider(), - okta: createOktaProvider(), - auth0: createAuth0Provider(), - microsoft: createMicrosoftProvider(), - oauth2: createOAuth2Provider(), - oidc: createOidcProvider(), - onelogin: createOneLoginProvider(), - awsalb: createAwsAlbProvider(), - bitbucket: createBitbucketProvider(), - atlassian: createAtlassianProvider(), -}; diff --git a/plugins/auth-backend/src/providers/gcp-iap/index.ts b/plugins/auth-backend/src/providers/gcp-iap/index.ts index 97e31b0051..12f76ec142 100644 --- a/plugins/auth-backend/src/providers/gcp-iap/index.ts +++ b/plugins/auth-backend/src/providers/gcp-iap/index.ts @@ -14,9 +14,5 @@ * limitations under the License. */ -export { createGcpIapProvider } from './provider'; -export type { - GcpIapProviderOptions, - GcpIapResult, - GcpIapTokenInfo, -} from './types'; +export { gcpIap } from './provider'; +export type { GcpIapResult, GcpIapTokenInfo } from './types'; diff --git a/plugins/auth-backend/src/providers/gcp-iap/provider.ts b/plugins/auth-backend/src/providers/gcp-iap/provider.ts index cb5d5979cd..500b062d5b 100644 --- a/plugins/auth-backend/src/providers/gcp-iap/provider.ts +++ b/plugins/auth-backend/src/providers/gcp-iap/provider.ts @@ -117,9 +117,3 @@ export const gcpIap = createAuthProviderIntegration({ }; }, }); - -/** - * @public - * @deprecated Use `providers.gcpIap.create` instead - */ -export const createGcpIapProvider = gcpIap.create; diff --git a/plugins/auth-backend/src/providers/gcp-iap/types.ts b/plugins/auth-backend/src/providers/gcp-iap/types.ts index 6e5a022a3d..25828b7d51 100644 --- a/plugins/auth-backend/src/providers/gcp-iap/types.ts +++ b/plugins/auth-backend/src/providers/gcp-iap/types.ts @@ -15,7 +15,7 @@ */ import { JsonValue } from '@backstage/types'; -import { AuthHandler, AuthResponse, SignInResolver } from '../types'; +import { AuthResponse } from '../types'; /** * The header name used by the IAP. @@ -69,27 +69,3 @@ export type GcpIapProviderInfo = { * The shape of the response to return to callers. */ export type GcpIapResponse = AuthResponse; - -/** - * @public - * @deprecated This type has been inlined into the create method and will be removed. - */ -export type GcpIapProviderOptions = { - /** - * The profile transformation function used to verify and convert the auth - * response into the profile that will be presented to the user. The default - * implementation just provides the authenticated email that the IAP - * presented. - */ - authHandler?: AuthHandler; - - /** - * Configures sign-in for this provider. - */ - signIn: { - /** - * Maps an auth result to a Backstage identity for the user. - */ - resolver: SignInResolver; - }; -}; diff --git a/plugins/auth-backend/src/providers/github/index.ts b/plugins/auth-backend/src/providers/github/index.ts index a855b13b83..2f4bb1f6cd 100644 --- a/plugins/auth-backend/src/providers/github/index.ts +++ b/plugins/auth-backend/src/providers/github/index.ts @@ -14,5 +14,5 @@ * limitations under the License. */ -export { createGithubProvider } from './provider'; -export type { GithubOAuthResult, GithubProviderOptions } from './provider'; +export { github } from './provider'; +export type { GithubOAuthResult } from './provider'; diff --git a/plugins/auth-backend/src/providers/github/provider.ts b/plugins/auth-backend/src/providers/github/provider.ts index e018a6cf99..9c115b5eb8 100644 --- a/plugins/auth-backend/src/providers/github/provider.ts +++ b/plugins/auth-backend/src/providers/github/provider.ts @@ -227,46 +227,6 @@ export class GithubAuthProvider implements OAuthHandlers { } } -/** - * @public - * @deprecated This type has been inlined into the create method and will be removed. - */ -export type GithubProviderOptions = { - /** - * The profile transformation function used to verify and convert the auth response - * into the profile that will be presented to the user. - */ - authHandler?: AuthHandler; - - /** - * Configure sign-in for this provider, without it the provider can not be used to sign users in. - */ - signIn?: { - /** - * Maps an auth result to a Backstage identity for the user. - */ - resolver: SignInResolver; - }; - - /** - * The state encoder used to encode the 'state' parameter on the OAuth request. - * - * It should return a string that takes the state params (from the request), url encodes the params - * and finally base64 encodes them. - * - * Providing your own stateEncoder will allow you to add addition parameters to the state field. - * - * It is typed as follows: - * `export type StateEncoder = (input: OAuthState) => Promise<{encodedState: string}>;` - * - * Note: the stateEncoder must encode a 'nonce' value and an 'env' value. Without this, the OAuth flow will fail - * (These two values will be set by the req.state by default) - * - * For more information, please see the helper module in ../../oauth/helpers #readState - */ - stateEncoder?: StateEncoder; -}; - /** * Auth provider integration for GitHub auth * @@ -381,9 +341,3 @@ export const github = createAuthProviderIntegration({ }, }, }); - -/** - * @public - * @deprecated Use `providers.github.create` instead - */ -export const createGithubProvider = github.create; diff --git a/plugins/auth-backend/src/providers/gitlab/index.ts b/plugins/auth-backend/src/providers/gitlab/index.ts index 52ede48756..9b60d1f18a 100644 --- a/plugins/auth-backend/src/providers/gitlab/index.ts +++ b/plugins/auth-backend/src/providers/gitlab/index.ts @@ -14,5 +14,4 @@ * limitations under the License. */ -export { createGitlabProvider } from './provider'; -export type { GitlabProviderOptions } from './provider'; +export { gitlab } from './provider'; diff --git a/plugins/auth-backend/src/providers/gitlab/provider.ts b/plugins/auth-backend/src/providers/gitlab/provider.ts index 868357bcda..c24c2e128d 100644 --- a/plugins/auth-backend/src/providers/gitlab/provider.ts +++ b/plugins/auth-backend/src/providers/gitlab/provider.ts @@ -178,31 +178,6 @@ export class GitlabAuthProvider implements OAuthHandlers { } } -/** - * @public - * @deprecated This type has been inlined into the create method and will be removed. - */ -export type GitlabProviderOptions = { - /** - * The profile transformation function used to verify and convert the auth response - * into the profile that will be presented to the user. - */ - authHandler?: AuthHandler; - - /** - * Configure sign-in for this provider, without it the provider can not be used to sign users in. - */ - /** - * Maps an auth result to a Backstage identity for the user. - * - * Set to `'email'` to use the default email-based sign in resolver, which will search - * the catalog for a single user entity that has a matching `microsoft.com/email` annotation. - */ - signIn?: { - resolver: SignInResolver; - }; -}; - /** * Auth provider integration for GitLab auth * @@ -254,9 +229,3 @@ export const gitlab = createAuthProviderIntegration({ }); }, }); - -/** - * @public - * @deprecated Use `providers.gitlab.create` instead - */ -export const createGitlabProvider = gitlab.create; diff --git a/plugins/auth-backend/src/providers/google/index.ts b/plugins/auth-backend/src/providers/google/index.ts index 209484ad04..5e8c3236e4 100644 --- a/plugins/auth-backend/src/providers/google/index.ts +++ b/plugins/auth-backend/src/providers/google/index.ts @@ -14,5 +14,4 @@ * limitations under the License. */ -export { createGoogleProvider, googleEmailSignInResolver } from './provider'; -export type { GoogleProviderOptions } from './provider'; +export { google } from './provider'; diff --git a/plugins/auth-backend/src/providers/google/provider.ts b/plugins/auth-backend/src/providers/google/provider.ts index 2d58bc2aa6..f60d4e9947 100644 --- a/plugins/auth-backend/src/providers/google/provider.ts +++ b/plugins/auth-backend/src/providers/google/provider.ts @@ -168,28 +168,6 @@ export class GoogleAuthProvider implements OAuthHandlers { } } -/** - * @public - * @deprecated This type has been inlined into the create method and will be removed. - */ -export type GoogleProviderOptions = { - /** - * The profile transformation function used to verify and convert the auth response - * into the profile that will be presented to the user. - */ - authHandler?: AuthHandler; - - /** - * Configure sign-in for this provider, without it the provider can not be used to sign users in. - */ - signIn?: { - /** - * Maps an auth result to a Backstage identity for the user. - */ - resolver: SignInResolver; - }; -}; - /** * Auth provider integration for Google auth * @@ -272,16 +250,3 @@ export const google = createAuthProviderIntegration({ }, }, }); - -/** - * @public - * @deprecated Use `providers.google.create` instead. - */ -export const createGoogleProvider = google.create; - -/** - * @public - * @deprecated Use `providers.google.resolvers.emailMatchingUserEntityAnnotation()` instead. - */ -export const googleEmailSignInResolver = - google.resolvers.emailMatchingUserEntityAnnotation(); diff --git a/plugins/auth-backend/src/providers/index.ts b/plugins/auth-backend/src/providers/index.ts index 1f33a60e55..41ee44beae 100644 --- a/plugins/auth-backend/src/providers/index.ts +++ b/plugins/auth-backend/src/providers/index.ts @@ -14,30 +14,25 @@ * limitations under the License. */ -export * from './atlassian'; -export * from './auth0'; -export * from './aws-alb'; -export * from './bitbucket'; -export * from './github'; -export * from './gitlab'; -export * from './google'; -export * from './microsoft'; -export * from './oauth2'; -export * from './oauth2-proxy'; -export * from './oidc'; -export * from './okta'; -export * from './onelogin'; -export * from './saml'; -export * from './gcp-iap'; +export { AtlassianAuthProvider } from './atlassian'; +export type { AwsAlbResult } from './aws-alb'; +export type { + BitbucketOAuthResult, + BitbucketPassportProfile, +} from './bitbucket'; +export type { GithubOAuthResult } from './github'; +export type { OAuth2ProxyResult } from './oauth2-proxy'; +export type { OidcAuthResult } from './oidc'; +export type { SamlAuthResult } from './saml'; +export type { GcpIapResult, GcpIapTokenInfo } from './gcp-iap'; -export { providers } from './providers'; +export { providers, defaultAuthProviderFactories } from './providers'; -export { factories as defaultAuthProviderFactories } from './factories'; +export { createAuthProviderIntegration } from './createAuthProviderIntegration'; export type { AuthProviderConfig, AuthProviderRouteHandlers, - AuthProviderFactoryOptions, AuthProviderFactory, AuthHandler, AuthResolverCatalogUserQuery, diff --git a/plugins/auth-backend/src/providers/microsoft/index.ts b/plugins/auth-backend/src/providers/microsoft/index.ts index 3167de5d0d..16dadc3bb0 100644 --- a/plugins/auth-backend/src/providers/microsoft/index.ts +++ b/plugins/auth-backend/src/providers/microsoft/index.ts @@ -14,8 +14,4 @@ * limitations under the License. */ -export { - createMicrosoftProvider, - microsoftEmailSignInResolver, -} from './provider'; -export type { MicrosoftProviderOptions } from './provider'; +export { microsoft } from './provider'; diff --git a/plugins/auth-backend/src/providers/microsoft/provider.ts b/plugins/auth-backend/src/providers/microsoft/provider.ts index 0c58049619..db79dba225 100644 --- a/plugins/auth-backend/src/providers/microsoft/provider.ts +++ b/plugins/auth-backend/src/providers/microsoft/provider.ts @@ -190,28 +190,6 @@ export class MicrosoftAuthProvider implements OAuthHandlers { } } -/** - * @public - * @deprecated This type has been inlined into the create method and will be removed. - */ -export type MicrosoftProviderOptions = { - /** - * The profile transformation function used to verify and convert the auth response - * into the profile that will be presented to the user. - */ - authHandler?: AuthHandler; - - /** - * Configure sign-in for this provider, without it the provider can not be used to sign users in. - */ - signIn?: { - /** - * Maps an auth result to a Backstage identity for the user. - */ - resolver: SignInResolver; - }; -}; - /** * Auth provider integration for Microsoft auth * @@ -301,16 +279,3 @@ export const microsoft = createAuthProviderIntegration({ }, }, }); - -/** - * @public - * @deprecated Use `providers.microsoft.create` instead - */ -export const createMicrosoftProvider = microsoft.create; - -/** - * @public - * @deprecated Use `providers.microsoft.resolvers.emailMatchingUserEntityAnnotation()` instead. - */ -export const microsoftEmailSignInResolver = - microsoft.resolvers.emailMatchingUserEntityAnnotation(); diff --git a/plugins/auth-backend/src/providers/oauth2-proxy/index.ts b/plugins/auth-backend/src/providers/oauth2-proxy/index.ts index 62304b1d1f..d3004f31e4 100644 --- a/plugins/auth-backend/src/providers/oauth2-proxy/index.ts +++ b/plugins/auth-backend/src/providers/oauth2-proxy/index.ts @@ -14,5 +14,5 @@ * limitations under the License. */ -export { createOauth2ProxyProvider } from './provider'; -export type { Oauth2ProxyProviderOptions, OAuth2ProxyResult } from './provider'; +export { oauth2Proxy } from './provider'; +export type { OAuth2ProxyResult } from './provider'; diff --git a/plugins/auth-backend/src/providers/oauth2-proxy/provider.ts b/plugins/auth-backend/src/providers/oauth2-proxy/provider.ts index 625c9e3d62..3ac7d09000 100644 --- a/plugins/auth-backend/src/providers/oauth2-proxy/provider.ts +++ b/plugins/auth-backend/src/providers/oauth2-proxy/provider.ts @@ -80,27 +80,6 @@ export type OAuth2ProxyResult = { getHeader(name: string): string | undefined; }; -/** - * @public - * @deprecated This type has been inlined into the create method and will be removed. - */ -export type Oauth2ProxyProviderOptions = { - /** - * Configure an auth handler to generate a profile for the user. - */ - authHandler: AuthHandler>; - - /** - * Configure sign-in for this provider, without it the provider can not be used to sign users in. - */ - signIn: { - /** - * Maps an auth result to a Backstage identity for the user. - */ - resolver: SignInResolver>; - }; -}; - interface Options { resolverContext: AuthResolverContext; signInResolver: SignInResolver>; @@ -231,9 +210,3 @@ export const oauth2Proxy = createAuthProviderIntegration({ }; }, }); - -/** - * @public - * @deprecated Use `providers.oauth2Proxy.create` instead - */ -export const createOauth2ProxyProvider = oauth2Proxy.create; diff --git a/plugins/auth-backend/src/providers/oauth2/index.ts b/plugins/auth-backend/src/providers/oauth2/index.ts index d68208a148..14485e04ff 100644 --- a/plugins/auth-backend/src/providers/oauth2/index.ts +++ b/plugins/auth-backend/src/providers/oauth2/index.ts @@ -14,5 +14,4 @@ * limitations under the License. */ -export { createOAuth2Provider } from './provider'; -export type { OAuth2ProviderOptions } from './provider'; +export { oauth2 } from './provider'; diff --git a/plugins/auth-backend/src/providers/oauth2/provider.ts b/plugins/auth-backend/src/providers/oauth2/provider.ts index 6b4787e985..6fa649c421 100644 --- a/plugins/auth-backend/src/providers/oauth2/provider.ts +++ b/plugins/auth-backend/src/providers/oauth2/provider.ts @@ -192,18 +192,6 @@ export class OAuth2AuthProvider implements OAuthHandlers { } } -/** - * @public - * @deprecated This type has been inlined into the create method and will be removed. - */ -export type OAuth2ProviderOptions = { - authHandler?: AuthHandler; - - signIn?: { - resolver: SignInResolver; - }; -}; - /** * Auth provider integration for generic OAuth2 auth * @@ -260,9 +248,3 @@ export const oauth2 = createAuthProviderIntegration({ }); }, }); - -/** - * @public - * @deprecated Use `providers.oauth2.create` instead - */ -export const createOAuth2Provider = oauth2.create; diff --git a/plugins/auth-backend/src/providers/oidc/index.ts b/plugins/auth-backend/src/providers/oidc/index.ts index e63c9920df..6b2282411c 100644 --- a/plugins/auth-backend/src/providers/oidc/index.ts +++ b/plugins/auth-backend/src/providers/oidc/index.ts @@ -14,5 +14,5 @@ * limitations under the License. */ -export type { OidcAuthResult, OidcProviderOptions } from './provider'; -export { createOidcProvider } from './provider'; +export { oidc } from './provider'; +export type { OidcAuthResult } from './provider'; diff --git a/plugins/auth-backend/src/providers/oidc/provider.test.ts b/plugins/auth-backend/src/providers/oidc/provider.test.ts index 59a717f132..ee8aa50b01 100644 --- a/plugins/auth-backend/src/providers/oidc/provider.test.ts +++ b/plugins/auth-backend/src/providers/oidc/provider.test.ts @@ -23,7 +23,7 @@ import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { ClientMetadata, IssuerMetadata } from 'openid-client'; import { OAuthAdapter } from '../../lib/oauth'; -import { createOidcProvider, OidcAuthProvider, Options } from './provider'; +import { oidc, OidcAuthProvider, Options } from './provider'; import { AuthResolverContext } from '../types'; const issuerMetadata = { @@ -155,7 +155,7 @@ describe('OidcAuthProvider', () => { expect(requestSequence).toEqual([0, 1, 2].map(i => requests[i].url)); }); - it('createOidcProvider', async () => { + it('oidc.create', async () => { const handler = jest.fn((_req, res, ctx) => { return res( ctx.status(200), @@ -172,7 +172,7 @@ describe('OidcAuthProvider', () => { metadataUrl: 'https://oidc.test/.well-known/openid-configuration', }, } as any); - const provider = createOidcProvider()({ + const provider = oidc.create()({ globalConfig: { appUrl: 'https://oidc.test', baseUrl: 'https://oidc.test', diff --git a/plugins/auth-backend/src/providers/oidc/provider.ts b/plugins/auth-backend/src/providers/oidc/provider.ts index 69a65d1cae..eb963a3711 100644 --- a/plugins/auth-backend/src/providers/oidc/provider.ts +++ b/plugins/auth-backend/src/providers/oidc/provider.ts @@ -198,18 +198,6 @@ export class OidcAuthProvider implements OAuthHandlers { } } -/** - * @public - * @deprecated This type has been inlined into the create method and will be removed. - */ -export type OidcProviderOptions = { - authHandler?: AuthHandler; - - signIn?: { - resolver: SignInResolver; - }; -}; - /** * Auth provider integration for generic OpenID Connect auth * @@ -268,9 +256,3 @@ export const oidc = createAuthProviderIntegration({ }); }, }); - -/** - * @public - * @deprecated Use `providers.oidc.create` instead - */ -export const createOidcProvider = oidc.create; diff --git a/plugins/auth-backend/src/providers/okta/index.ts b/plugins/auth-backend/src/providers/okta/index.ts index fd9ebf46da..3387fa3668 100644 --- a/plugins/auth-backend/src/providers/okta/index.ts +++ b/plugins/auth-backend/src/providers/okta/index.ts @@ -14,5 +14,4 @@ * limitations under the License. */ -export { createOktaProvider, oktaEmailSignInResolver } from './provider'; -export type { OktaProviderOptions } from './provider'; +export { okta } from './provider'; diff --git a/plugins/auth-backend/src/providers/okta/provider.ts b/plugins/auth-backend/src/providers/okta/provider.ts index 98cec6df3a..de9d128641 100644 --- a/plugins/auth-backend/src/providers/okta/provider.ts +++ b/plugins/auth-backend/src/providers/okta/provider.ts @@ -192,28 +192,6 @@ export class OktaAuthProvider implements OAuthHandlers { } } -/** - * @public - * @deprecated This type has been inlined into the create method and will be removed. - */ -export type OktaProviderOptions = { - /** - * The profile transformation function used to verify and convert the auth response - * into the profile that will be presented to the user. - */ - authHandler?: AuthHandler; - - /** - * Configure sign-in for this provider, without it the provider can not be used to sign users in. - */ - signIn?: { - /** - * Maps an auth result to a Backstage identity for the user. - */ - resolver: SignInResolver; - }; -}; - /** * Auth provider integration for Okta auth * @@ -305,16 +283,3 @@ export const okta = createAuthProviderIntegration({ }, }, }); - -/** - * @public - * @deprecated Use `providers.okta.create` instead - */ -export const createOktaProvider = okta.create; - -/** - * @public - * @deprecated Use `providers.okta.resolvers.emailMatchingUserEntityAnnotation()` instead. - */ -export const oktaEmailSignInResolver = - okta.resolvers.emailMatchingUserEntityAnnotation(); diff --git a/plugins/auth-backend/src/providers/onelogin/index.ts b/plugins/auth-backend/src/providers/onelogin/index.ts index 63cf0be3cd..3f356029fb 100644 --- a/plugins/auth-backend/src/providers/onelogin/index.ts +++ b/plugins/auth-backend/src/providers/onelogin/index.ts @@ -14,5 +14,4 @@ * limitations under the License. */ -export { createOneLoginProvider } from './provider'; -export type { OneLoginProviderOptions } from './provider'; +export { onelogin } from './provider'; diff --git a/plugins/auth-backend/src/providers/onelogin/provider.ts b/plugins/auth-backend/src/providers/onelogin/provider.ts index d81eb3d83c..59b57b3851 100644 --- a/plugins/auth-backend/src/providers/onelogin/provider.ts +++ b/plugins/auth-backend/src/providers/onelogin/provider.ts @@ -166,28 +166,6 @@ export class OneLoginProvider implements OAuthHandlers { } } -/** - * @public - * @deprecated This type has been inlined into the create method and will be removed. - */ -export type OneLoginProviderOptions = { - /** - * The profile transformation function used to verify and convert the auth response - * into the profile that will be presented to the user. - */ - authHandler?: AuthHandler; - - /** - * Configure sign-in for this provider, without it the provider can not be used to sign users in. - */ - signIn?: { - /** - * Maps an auth result to a Backstage identity for the user. - */ - resolver: SignInResolver; - }; -}; - /** * Auth provider integration for OneLogin auth * @@ -244,9 +222,3 @@ export const onelogin = createAuthProviderIntegration({ }); }, }); - -/** - * @public - * @deprecated Use `providers.onelogin.create` instead - */ -export const createOneLoginProvider = onelogin.create; diff --git a/plugins/auth-backend/src/providers/providers.ts b/plugins/auth-backend/src/providers/providers.ts index 3d49e2bbbb..71df8223ef 100644 --- a/plugins/auth-backend/src/providers/providers.ts +++ b/plugins/auth-backend/src/providers/providers.ts @@ -14,21 +14,22 @@ * limitations under the License. */ -import { atlassian } from './atlassian/provider'; -import { auth0 } from './auth0/provider'; -import { awsAlb } from './aws-alb/provider'; -import { bitbucket } from './bitbucket/provider'; -import { gcpIap } from './gcp-iap/provider'; -import { github } from './github/provider'; -import { gitlab } from './gitlab/provider'; -import { google } from './google/provider'; -import { microsoft } from './microsoft/provider'; -import { oauth2 } from './oauth2/provider'; -import { oauth2Proxy } from './oauth2-proxy/provider'; -import { oidc } from './oidc/provider'; -import { okta } from './okta/provider'; -import { onelogin } from './onelogin/provider'; -import { saml } from './saml/provider'; +import { atlassian } from './atlassian'; +import { auth0 } from './auth0'; +import { awsAlb } from './aws-alb'; +import { bitbucket } from './bitbucket'; +import { gcpIap } from './gcp-iap'; +import { github } from './github'; +import { gitlab } from './gitlab'; +import { google } from './google'; +import { microsoft } from './microsoft'; +import { oauth2 } from './oauth2'; +import { oauth2Proxy } from './oauth2-proxy'; +import { oidc } from './oidc'; +import { okta } from './okta'; +import { onelogin } from './onelogin'; +import { saml } from './saml'; +import { AuthProviderFactory } from './types'; /** * All built-in auth provider integrations. @@ -52,3 +53,26 @@ export const providers = Object.freeze({ onelogin, saml, }); + +/** + * All auth provider factories that are installed by default. + * + * @public + */ +export const defaultAuthProviderFactories: { + [providerId: string]: AuthProviderFactory; +} = { + google: google.create(), + github: github.create(), + gitlab: gitlab.create(), + saml: saml.create(), + okta: okta.create(), + auth0: auth0.create(), + microsoft: microsoft.create(), + oauth2: oauth2.create(), + oidc: oidc.create(), + onelogin: onelogin.create(), + awsalb: awsAlb.create(), + bitbucket: bitbucket.create(), + atlassian: atlassian.create(), +}; diff --git a/plugins/auth-backend/src/providers/saml/index.ts b/plugins/auth-backend/src/providers/saml/index.ts index 8d36e17d29..d59f7bf0a7 100644 --- a/plugins/auth-backend/src/providers/saml/index.ts +++ b/plugins/auth-backend/src/providers/saml/index.ts @@ -14,8 +14,5 @@ * limitations under the License. */ -export { - createSamlProvider, - samlNameIdEntityNameSignInResolver, -} from './provider'; -export type { SamlProviderOptions, SamlAuthResult } from './provider'; +export { saml } from './provider'; +export type { SamlAuthResult } from './provider'; diff --git a/plugins/auth-backend/src/providers/saml/provider.ts b/plugins/auth-backend/src/providers/saml/provider.ts index 4f5076b410..3d35f46628 100644 --- a/plugins/auth-backend/src/providers/saml/provider.ts +++ b/plugins/auth-backend/src/providers/saml/provider.ts @@ -132,28 +132,6 @@ export class SamlAuthProvider implements AuthProviderRouteHandlers { type SignatureAlgorithm = 'sha1' | 'sha256' | 'sha512'; -/** - * @public - * @deprecated This type has been inlined into the create method and will be removed. - */ -export type SamlProviderOptions = { - /** - * The profile transformation function used to verify and convert the auth response - * into the profile that will be presented to the user. - */ - authHandler?: AuthHandler; - - /** - * Configure sign-in for this provider, without it the provider can not be used to sign users in. - */ - signIn?: { - /** - * Maps an auth result to a Backstage identity for the user. - */ - resolver: SignInResolver; - }; -}; - /** * Auth provider integration for SAML auth * @@ -230,16 +208,3 @@ export const saml = createAuthProviderIntegration({ }, }, }); - -/** - * @public - * @deprecated Use `providers.saml.create` instead - */ -export const createSamlProvider = saml.create; - -/** - * @public - * @deprecated Use `providers.saml.resolvers.nameIdMatchingUserEntityName()` instead. - */ -export const samlNameIdEntityNameSignInResolver = - saml.resolvers.nameIdMatchingUserEntityName(); diff --git a/plugins/auth-backend/src/providers/types.ts b/plugins/auth-backend/src/providers/types.ts index 128dea12ef..c99bdfbadb 100644 --- a/plugins/auth-backend/src/providers/types.ts +++ b/plugins/auth-backend/src/providers/types.ts @@ -14,11 +14,8 @@ * limitations under the License. */ -import { - PluginEndpointDiscovery, - TokenManager, -} from '@backstage/backend-common'; -import { CatalogApi, GetEntitiesRequest } from '@backstage/catalog-client'; +import { GetEntitiesRequest } from '@backstage/catalog-client'; +import { Entity } from '@backstage/catalog-model'; import { Config } from '@backstage/config'; import { BackstageIdentityResponse, @@ -26,10 +23,8 @@ import { } from '@backstage/plugin-auth-node'; import express from 'express'; import { Logger } from 'winston'; -import { TokenIssuer, TokenParams } from '../identity/types'; +import { TokenParams } from '../identity/types'; import { OAuthStartRequest } from '../lib/oauth/types'; -import { CatalogIdentityClient } from '../lib/catalog'; -import { Entity } from '@backstage/catalog-model'; /** * A query for a single user in the catalog. @@ -69,13 +64,6 @@ export type AuthResolverCatalogUserQuery = * @public */ export type AuthResolverContext = { - /** @deprecated Will be removed from the context, access it via a closure instead if needed */ - logger: Logger; - /** @deprecated Use the `issueToken` method instead */ - tokenIssuer: TokenIssuer; - /** @deprecated Use the `findCatalogUser` and `signInWithCatalogUser` methods instead, and the `getDefaultOwnershipEntityRefs` helper */ - catalogIdentityClient: CatalogIdentityClient; - /** * Issues a Backstage token using the provided parameters. */ @@ -204,35 +192,12 @@ export interface AuthProviderRouteHandlers { logout?(req: express.Request, res: express.Response): Promise; } -/** - * @deprecated This type is deprecated and will be removed in a future release. - */ -export type AuthProviderFactoryOptions = { - providerId: string; - globalConfig: AuthProviderConfig; - config: Config; - logger: Logger; - tokenManager: TokenManager; - tokenIssuer: TokenIssuer; - discovery: PluginEndpointDiscovery; - catalogApi: CatalogApi; -}; - export type AuthProviderFactory = (options: { providerId: string; globalConfig: AuthProviderConfig; config: Config; logger: Logger; resolverContext: AuthResolverContext; - - /** @deprecated This field has been deprecated and needs to be passed directly to the auth provider instead */ - tokenManager: TokenManager; - /** @deprecated This field has been deprecated and needs to be passed directly to the auth provider instead */ - tokenIssuer: TokenIssuer; - /** @deprecated This field has been deprecated and needs to be passed directly to the auth provider instead */ - discovery: PluginEndpointDiscovery; - /** @deprecated This field has been deprecated and needs to be passed directly to the auth provider instead */ - catalogApi: CatalogApi; }) => AuthProviderRouteHandlers; /** @public */ diff --git a/plugins/auth-backend/src/service/router.ts b/plugins/auth-backend/src/service/router.ts index 80b8a24022..e4fa5eeea4 100644 --- a/plugins/auth-backend/src/service/router.ts +++ b/plugins/auth-backend/src/service/router.ts @@ -44,6 +44,7 @@ export interface RouterOptions { config: Config; discovery: PluginEndpointDiscovery; tokenManager: TokenManager; + tokenFactoryAlgorithm?: string; providerFactories?: ProviderFactories; } @@ -56,6 +57,7 @@ export async function createRouter( discovery, database, tokenManager, + tokenFactoryAlgorithm, providerFactories, } = options; const router = Router(); @@ -71,6 +73,7 @@ export async function createRouter( keyStore, keyDurationSeconds, logger: logger.child({ component: 'token-factory' }), + algorithm: tokenFactoryAlgorithm, }); const catalogApi = new CatalogClient({ discoveryApi: discovery }); @@ -119,10 +122,6 @@ export async function createRouter( }, config: providersConfig.getConfig(providerId), logger, - tokenManager, - tokenIssuer, - discovery, - catalogApi, resolverContext: CatalogAuthResolverContext.create({ logger, catalogApi, @@ -141,6 +140,7 @@ export async function createRouter( } if (provider.refresh) { r.get('/refresh', provider.refresh.bind(provider)); + r.post('/refresh', provider.refresh.bind(provider)); } router.use(`/${providerId}`, r); diff --git a/plugins/auth-node/CHANGELOG.md b/plugins/auth-node/CHANGELOG.md index 4381303915..43bf44ac8e 100644 --- a/plugins/auth-node/CHANGELOG.md +++ b/plugins/auth-node/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-auth-node +## 0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + +## 0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + ## 0.2.2 ### Patch Changes diff --git a/plugins/auth-node/package.json b/plugins/auth-node/package.json index 2281d2d35e..011aade178 100644 --- a/plugins/auth-node/package.json +++ b/plugins/auth-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-node", - "version": "0.2.2", + "version": "0.2.3-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,17 +23,17 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", + "@backstage/backend-common": "^0.14.1-next.1", "@backstage/config": "^1.0.1", - "@backstage/errors": "^1.0.0", + "@backstage/errors": "^1.1.0-next.0", "jose": "^4.6.0", "node-fetch": "^2.6.7", "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.17.2", + "@backstage/cli": "^0.18.0-next.1", "lodash": "^4.17.21", - "msw": "^0.42.0", + "msw": "^0.43.0", "uuid": "^8.0.0" }, "files": [ diff --git a/plugins/azure-devops-backend/CHANGELOG.md b/plugins/azure-devops-backend/CHANGELOG.md index f9d414bef9..95fb110ed8 100644 --- a/plugins/azure-devops-backend/CHANGELOG.md +++ b/plugins/azure-devops-backend/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-azure-devops-backend +## 0.3.13-next.0 + +### Patch Changes + +- 13a232ec22: Added comments to example to help avoid confusion as to where lines need to be added +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + ## 0.3.12 ### Patch Changes diff --git a/plugins/azure-devops-backend/README.md b/plugins/azure-devops-backend/README.md index e71021471b..5dc0570bd2 100644 --- a/plugins/azure-devops-backend/README.md +++ b/plugins/azure-devops-backend/README.md @@ -60,7 +60,10 @@ Here's how to get the backend up and running: // ... async function main() { // ... + // Add this line under the other lines that follow the useHotMemoize pattern const azureDevOpsEnv = useHotMemoize(module, () => createEnv('azure-devops')); + // ... + // Insert this line under the other lines that add their routers to apiRouter in the same way apiRouter.use('/azure-devops', await azureDevOps(azureDevOpsEnv)); ``` diff --git a/plugins/azure-devops-backend/package.json b/plugins/azure-devops-backend/package.json index e85ba907c6..cff9eaf07e 100644 --- a/plugins/azure-devops-backend/package.json +++ b/plugins/azure-devops-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-azure-devops-backend", - "version": "0.3.12", + "version": "0.3.13-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,7 +23,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", + "@backstage/backend-common": "^0.14.1-next.1", "@backstage/config": "^1.0.1", "@backstage/plugin-azure-devops-common": "^0.2.3", "@types/express": "^4.17.6", @@ -35,10 +35,10 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", + "@backstage/cli": "^0.18.0-next.1", "@types/supertest": "^2.0.8", "supertest": "^6.1.6", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist", diff --git a/plugins/azure-devops-common/package.json b/plugins/azure-devops-common/package.json index 0f52082db6..f0f137ac52 100644 --- a/plugins/azure-devops-common/package.json +++ b/plugins/azure-devops-common/package.json @@ -32,7 +32,7 @@ "clean": "backstage-cli package clean" }, "devDependencies": { - "@backstage/cli": "^0.17.2-next.0" + "@backstage/cli": "^0.18.0-next.1" }, "files": [ "dist" diff --git a/plugins/azure-devops/CHANGELOG.md b/plugins/azure-devops/CHANGELOG.md index 8de9bd00a8..79a58574f3 100644 --- a/plugins/azure-devops/CHANGELOG.md +++ b/plugins/azure-devops/CHANGELOG.md @@ -1,5 +1,36 @@ # @backstage/plugin-azure-devops +## 0.1.23-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## 0.1.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## 0.1.23-next.0 + +### Patch Changes + +- e049e41048: Exporting azureDevOpsApiRef, AzureGitTagsIcon, and all hooks for the benefit of other plugins. +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + ## 0.1.22 ### Patch Changes diff --git a/plugins/azure-devops/api-report.md b/plugins/azure-devops/api-report.md index 9760340771..b366166d95 100644 --- a/plugins/azure-devops/api-report.md +++ b/plugins/azure-devops/api-report.md @@ -5,10 +5,21 @@ ```ts /// +import { ApiRef } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/core-plugin-api'; +import { BuildRun } from '@backstage/plugin-azure-devops-common'; +import { BuildRunOptions } from '@backstage/plugin-azure-devops-common'; import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common'; +import { DiscoveryApi } from '@backstage/core-plugin-api'; import { Entity } from '@backstage/catalog-model'; +import { GitTag } from '@backstage/plugin-azure-devops-common'; +import { IdentityApi } from '@backstage/core-plugin-api'; +import { PullRequest } from '@backstage/plugin-azure-devops-common'; +import { PullRequestOptions } from '@backstage/plugin-azure-devops-common'; +import { RepoBuild } from '@backstage/plugin-azure-devops-common'; +import { RepoBuildOptions } from '@backstage/plugin-azure-devops-common'; import { SvgIconProps } from '@material-ui/core'; +import { Team } from '@backstage/plugin-azure-devops-common'; // Warning: (ae-missing-release-tag) "AllFilter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -55,6 +66,107 @@ export type AssignedToUserFilter = BaseFilter & } ); +// Warning: (ae-missing-release-tag) "AzureDevOpsApi" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface AzureDevOpsApi { + // (undocumented) + getAllTeams(): Promise; + // (undocumented) + getBuildRuns( + projectName: string, + repoName?: string, + definitionName?: string, + options?: BuildRunOptions, + ): Promise<{ + items: BuildRun[]; + }>; + // (undocumented) + getDashboardPullRequests( + projectName: string, + ): Promise; + // (undocumented) + getGitTags( + projectName: string, + repoName: string, + ): Promise<{ + items: GitTag[]; + }>; + // (undocumented) + getPullRequests( + projectName: string, + repoName: string, + options?: PullRequestOptions, + ): Promise<{ + items: PullRequest[]; + }>; + // (undocumented) + getRepoBuilds( + projectName: string, + repoName: string, + options?: RepoBuildOptions, + ): Promise<{ + items: RepoBuild[]; + }>; + // (undocumented) + getUserTeamIds(userId: string): Promise; +} + +// Warning: (ae-missing-release-tag) "azureDevOpsApiRef" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const azureDevOpsApiRef: ApiRef; + +// Warning: (ae-missing-release-tag) "AzureDevOpsClient" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export class AzureDevOpsClient implements AzureDevOpsApi { + constructor(options: { + discoveryApi: DiscoveryApi; + identityApi: IdentityApi; + }); + // (undocumented) + getAllTeams(): Promise; + // (undocumented) + getBuildRuns( + projectName: string, + repoName?: string, + definitionName?: string, + options?: BuildRunOptions, + ): Promise<{ + items: BuildRun[]; + }>; + // (undocumented) + getDashboardPullRequests( + projectName: string, + ): Promise; + // (undocumented) + getGitTags( + projectName: string, + repoName: string, + ): Promise<{ + items: GitTag[]; + }>; + // (undocumented) + getPullRequests( + projectName: string, + repoName: string, + options?: PullRequestOptions, + ): Promise<{ + items: PullRequest[]; + }>; + // (undocumented) + getRepoBuilds( + projectName: string, + repoName: string, + options?: RepoBuildOptions, + ): Promise<{ + items: RepoBuild[]; + }>; + // (undocumented) + getUserTeamIds(userId: string): Promise; +} + // Warning: (ae-missing-release-tag) "azureDevOpsPlugin" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) diff --git a/plugins/azure-devops/package.json b/plugins/azure-devops/package.json index 8fad3a8697..6ab9760f66 100644 --- a/plugins/azure-devops/package.json +++ b/plugins/azure-devops/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-azure-devops", - "version": "0.1.22", + "version": "0.1.23-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,13 +30,13 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", - "@backstage/core-components": "^0.9.5", + "@backstage/catalog-model": "^1.1.0-next.2", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/errors": "^1.0.0", + "@backstage/errors": "^1.1.0-next.0", "@backstage/plugin-azure-devops-common": "^0.2.3", - "@backstage/plugin-catalog-react": "^1.1.1", - "@backstage/theme": "^0.2.15", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -49,17 +49,17 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/jest": "^26.0.7", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/azure-devops/src/index.ts b/plugins/azure-devops/src/index.ts index 48177ee830..e65c1d02a3 100644 --- a/plugins/azure-devops/src/index.ts +++ b/plugins/azure-devops/src/index.ts @@ -26,6 +26,8 @@ export { export { AzurePullRequestsIcon } from './components/AzurePullRequestsIcon'; +export * from './api'; + export { FilterType } from './components/PullRequestsPage'; export type { PullRequestColumnConfig, diff --git a/plugins/badges-backend/CHANGELOG.md b/plugins/badges-backend/CHANGELOG.md index 3b80f26ca1..779625184e 100644 --- a/plugins/badges-backend/CHANGELOG.md +++ b/plugins/badges-backend/CHANGELOG.md @@ -1,5 +1,33 @@ # @backstage/plugin-badges-backend +## 0.1.28-next.2 + +### Patch Changes + +- 58fd5ee9d5: Add missing installation instructions +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/backend-common@0.14.1-next.2 + +## 0.1.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/catalog-client@1.0.4-next.1 + +## 0.1.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/catalog-client@1.0.4-next.0 + ## 0.1.27 ### Patch Changes diff --git a/plugins/badges-backend/README.md b/plugins/badges-backend/README.md index bdbfac3fa5..63e43c6692 100644 --- a/plugins/badges-backend/README.md +++ b/plugins/badges-backend/README.md @@ -11,8 +11,14 @@ endpoint. ## Installation -Install the `@backstage/plugin-badges-backend` package in your backend package, -and then integrate the plugin using the following default setup for +Install the `@backstage/plugin-badges-backend` package in your backend package: + +```bash +# From your Backstage root directory +yarn add --cwd packages/backend @backstage/plugin-badges-backend +``` + +Add the plugin using the following default setup for `src/plugins/badges.ts`: ```ts @@ -39,6 +45,34 @@ the badges-backend `createRouter()` to forward to the default badge builder. To customize the available badges, provide a custom set of badge factories. See further down for an example of a custom badge factories function. +Finally, you have to make the following changes in `src/index.ts`: + +```ts +// 1. import the plugin +import badges from './plugins/badges'; + +... + +const config = await loadBackendConfig({ + argv: process.argv, + logger: rootLogger, +}); +const createEnv = makeCreateEnv(config); + + ... + // 2. Create a PluginEnvironment for the Badges plugin + const badgesEnv = useHotMemoize(module, () => createEnv('badges')); + + ... + + const apiRouter = Router(); + ... + // 3. Register the badges plugin in the router + apiRouter.use('/badges', await badges(badgesEnv)); + ... + apiRouter.use(notFoundHandler()); +``` + ## Badge builder Badges are created by classes implementing the `BadgeBuilder` type. The default diff --git a/plugins/badges-backend/package.json b/plugins/badges-backend/package.json index d1b5d094d9..1e0bc62b15 100644 --- a/plugins/badges-backend/package.json +++ b/plugins/badges-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-badges-backend", "description": "A Backstage backend plugin that generates README badges for your entities", - "version": "0.1.27", + "version": "0.1.28-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,11 +34,11 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", - "@backstage/catalog-client": "^1.0.3", - "@backstage/catalog-model": "^1.0.3", + "@backstage/backend-common": "^0.14.1-next.2", + "@backstage/catalog-client": "^1.0.4-next.1", + "@backstage/catalog-model": "^1.1.0-next.2", "@backstage/config": "^1.0.1", - "@backstage/errors": "^1.0.0", + "@backstage/errors": "^1.1.0-next.0", "@types/express": "^4.17.6", "badge-maker": "^3.3.0", "cors": "^2.8.5", @@ -48,7 +48,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", + "@backstage/cli": "^0.18.0-next.2", "@types/supertest": "^2.0.8", "supertest": "^6.1.3" }, diff --git a/plugins/badges/CHANGELOG.md b/plugins/badges/CHANGELOG.md index ff7b290b68..b6fc662c3a 100644 --- a/plugins/badges/CHANGELOG.md +++ b/plugins/badges/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-badges +## 0.2.31-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## 0.2.31-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## 0.2.31-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + ## 0.2.30 ### Patch Changes diff --git a/plugins/badges/package.json b/plugins/badges/package.json index aeade2c50a..6972ba80ae 100644 --- a/plugins/badges/package.json +++ b/plugins/badges/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-badges", "description": "A Backstage plugin that generates README badges for your entities", - "version": "0.2.30", + "version": "0.2.31-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,12 +30,12 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", - "@backstage/core-components": "^0.9.5", + "@backstage/catalog-model": "^1.1.0-next.2", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/errors": "^1.0.0", - "@backstage/plugin-catalog-react": "^1.1.1", - "@backstage/theme": "^0.2.15", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -46,17 +46,17 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/jest": "^26.0.7", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/bazaar-backend/CHANGELOG.md b/plugins/bazaar-backend/CHANGELOG.md index 4b0cb04530..81358cfc7f 100644 --- a/plugins/bazaar-backend/CHANGELOG.md +++ b/plugins/bazaar-backend/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-bazaar-backend +## 0.1.18-next.1 + +### Patch Changes + +- 679b32172e: Updated dependency `knex` to `^2.0.0`. +- Updated dependencies + - @backstage/backend-common@0.14.1-next.2 + - @backstage/backend-test-utils@0.1.26-next.2 + +## 0.1.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/backend-test-utils@0.1.26-next.0 + ## 0.1.17 ### Patch Changes diff --git a/plugins/bazaar-backend/package.json b/plugins/bazaar-backend/package.json index 5f723a9dfb..351535e544 100644 --- a/plugins/bazaar-backend/package.json +++ b/plugins/bazaar-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-bazaar-backend", - "version": "0.1.17", + "version": "0.1.18-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,18 +23,18 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", - "@backstage/backend-test-utils": "^0.1.25", + "@backstage/backend-common": "^0.14.1-next.2", + "@backstage/backend-test-utils": "^0.1.26-next.2", "@backstage/config": "^1.0.1", "@types/express": "^4.17.6", "express": "^4.17.1", "express-promise-router": "^4.1.0", - "knex": "^1.0.2", + "knex": "^2.0.0", "winston": "^3.2.1", "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2" + "@backstage/cli": "^0.18.0-next.2" }, "files": [ "dist", diff --git a/plugins/bazaar/CHANGELOG.md b/plugins/bazaar/CHANGELOG.md index 911390ee28..e70e0db58b 100644 --- a/plugins/bazaar/CHANGELOG.md +++ b/plugins/bazaar/CHANGELOG.md @@ -1,5 +1,40 @@ # @backstage/plugin-bazaar +## 0.1.22-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/plugin-catalog@1.4.0-next.2 + - @backstage/cli@0.18.0-next.2 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## 0.1.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/cli@0.18.0-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/plugin-catalog@1.3.1-next.1 + - @backstage/catalog-client@1.0.4-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## 0.1.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog@1.3.1-next.0 + - @backstage/cli@0.17.3-next.0 + - @backstage/catalog-client@1.0.4-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + ## 0.1.21 ### Patch Changes diff --git a/plugins/bazaar/package.json b/plugins/bazaar/package.json index cb3318b4e9..aa44986a79 100644 --- a/plugins/bazaar/package.json +++ b/plugins/bazaar/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-bazaar", - "version": "0.1.21", + "version": "0.1.22-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -24,13 +24,13 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-client": "^1.0.3", - "@backstage/catalog-model": "^1.0.3", - "@backstage/cli": "^0.17.2", - "@backstage/core-components": "^0.9.5", + "@backstage/catalog-client": "^1.0.4-next.1", + "@backstage/catalog-model": "^1.1.0-next.2", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/plugin-catalog": "^1.3.0", - "@backstage/plugin-catalog-react": "^1.1.1", + "@backstage/plugin-catalog": "^1.4.0-next.2", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", "@date-io/luxon": "1.x", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -47,8 +47,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/dev-utils": "^1.0.3", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/dev-utils": "^1.0.4-next.2", "@testing-library/jest-dom": "^5.10.1", "cross-fetch": "^3.1.5" }, diff --git a/plugins/bitbucket-cloud-common/CHANGELOG.md b/plugins/bitbucket-cloud-common/CHANGELOG.md index 62100f2e0b..f066706277 100644 --- a/plugins/bitbucket-cloud-common/CHANGELOG.md +++ b/plugins/bitbucket-cloud-common/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-bitbucket-cloud-common +## 0.1.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.2.2-next.0 + ## 0.1.0 ### Minor Changes diff --git a/plugins/bitbucket-cloud-common/package.json b/plugins/bitbucket-cloud-common/package.json index a02196bc39..d5a686a1cd 100644 --- a/plugins/bitbucket-cloud-common/package.json +++ b/plugins/bitbucket-cloud-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-bitbucket-cloud-common", "description": "Common functionalities for bitbucket-cloud plugins", - "version": "0.1.0", + "version": "0.1.1-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -28,13 +28,13 @@ "update-models": "yarn refresh-schema && yarn generate-models && yarn reduce-models" }, "dependencies": { - "@backstage/integration": "^1.2.1", + "@backstage/integration": "^1.2.2-next.1", "cross-fetch": "^3.1.5" }, "devDependencies": { - "@backstage/cli": "^0.17.2", + "@backstage/cli": "^0.18.0-next.1", "@openapitools/openapi-generator-cli": "^2.4.26", - "msw": "^0.42.0", + "msw": "^0.43.0", "ts-morph": "^15.0.0" }, "files": [ diff --git a/plugins/bitrise/CHANGELOG.md b/plugins/bitrise/CHANGELOG.md index 0badfe894d..9058f5c15a 100644 --- a/plugins/bitrise/CHANGELOG.md +++ b/plugins/bitrise/CHANGELOG.md @@ -1,5 +1,34 @@ # @backstage/plugin-bitrise +## 0.1.34-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## 0.1.34-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## 0.1.34-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + ## 0.1.33 ### Patch Changes diff --git a/plugins/bitrise/package.json b/plugins/bitrise/package.json index 1d17b5a4b5..07ac2ca46e 100644 --- a/plugins/bitrise/package.json +++ b/plugins/bitrise/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-bitrise", "description": "A Backstage plugin that integrates towards Bitrise", - "version": "0.1.33", + "version": "0.1.34-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -24,11 +24,11 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", - "@backstage/core-components": "^0.9.5", + "@backstage/catalog-model": "^1.1.0-next.2", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/plugin-catalog-react": "^1.1.1", - "@backstage/theme": "^0.2.15", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -43,17 +43,17 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/jest": "^26.0.7", "@types/node": "^16.11.26", "@types/recharts": "^1.8.15", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/catalog-backend-module-aws/CHANGELOG.md b/plugins/catalog-backend-module-aws/CHANGELOG.md index d246ae9677..2f200dd9b1 100644 --- a/plugins/catalog-backend-module-aws/CHANGELOG.md +++ b/plugins/catalog-backend-module-aws/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-catalog-backend-module-aws +## 0.1.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.1 + - @backstage/backend-tasks@0.3.3-next.1 + - @backstage/integration@1.2.2-next.1 + +## 0.1.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/backend-tasks@0.3.3-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.0 + ## 0.1.6 ### Patch Changes diff --git a/plugins/catalog-backend-module-aws/package.json b/plugins/catalog-backend-module-aws/package.json index 53ed33c47d..c768bbe9e4 100644 --- a/plugins/catalog-backend-module-aws/package.json +++ b/plugins/catalog-backend-module-aws/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-aws", "description": "A Backstage catalog backend module that helps integrate towards AWS", - "version": "0.1.6", + "version": "0.1.7-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,13 +33,13 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", - "@backstage/backend-tasks": "^0.3.2", - "@backstage/catalog-model": "^1.0.3", + "@backstage/backend-common": "^0.14.1-next.1", + "@backstage/backend-tasks": "^0.3.3-next.1", + "@backstage/catalog-model": "^1.1.0-next.1", "@backstage/config": "^1.0.1", - "@backstage/errors": "^1.0.0", - "@backstage/integration": "^1.2.1", - "@backstage/plugin-catalog-backend": "^1.2.0", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/integration": "^1.2.2-next.1", + "@backstage/plugin-catalog-backend": "^1.2.1-next.1", "@backstage/types": "^1.0.0", "aws-sdk": "^2.840.0", "lodash": "^4.17.21", @@ -48,7 +48,7 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.17.2", + "@backstage/cli": "^0.18.0-next.1", "@types/lodash": "^4.14.151", "aws-sdk-mock": "^5.2.1", "yaml": "^1.9.2" diff --git a/plugins/catalog-backend-module-azure/CHANGELOG.md b/plugins/catalog-backend-module-azure/CHANGELOG.md index fcc8126ad0..f9c2eeb6ce 100644 --- a/plugins/catalog-backend-module-azure/CHANGELOG.md +++ b/plugins/catalog-backend-module-azure/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-catalog-backend-module-azure +## 0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.1 + - @backstage/backend-tasks@0.3.3-next.1 + - @backstage/integration@1.2.2-next.1 + +## 0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/backend-tasks@0.3.3-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.0 + ## 0.1.4 ### Patch Changes diff --git a/plugins/catalog-backend-module-azure/package.json b/plugins/catalog-backend-module-azure/package.json index 5b0966f960..6256a01a72 100644 --- a/plugins/catalog-backend-module-azure/package.json +++ b/plugins/catalog-backend-module-azure/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-azure", "description": "A Backstage catalog backend module that helps integrate towards Azure", - "version": "0.1.4", + "version": "0.1.5-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,23 +33,23 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", - "@backstage/catalog-model": "^1.0.3", - "@backstage/backend-tasks": "^0.3.2", + "@backstage/backend-common": "^0.14.1-next.1", + "@backstage/catalog-model": "^1.1.0-next.1", + "@backstage/backend-tasks": "^0.3.3-next.1", "@backstage/config": "^1.0.1", - "@backstage/errors": "^1.0.0", - "@backstage/integration": "^1.2.1", - "@backstage/plugin-catalog-backend": "^1.2.0", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/integration": "^1.2.2-next.1", + "@backstage/plugin-catalog-backend": "^1.2.1-next.1", "@backstage/types": "^1.0.0", "lodash": "^4.17.21", - "msw": "^0.42.0", + "msw": "^0.43.0", "uuid": "^8.0.0", "node-fetch": "^2.6.7", "winston": "^3.2.1" }, "devDependencies": { - "@backstage/backend-test-utils": "^0.1.25", - "@backstage/cli": "^0.17.2", + "@backstage/backend-test-utils": "^0.1.26-next.1", + "@backstage/cli": "^0.18.0-next.1", "@types/lodash": "^4.14.151" }, "files": [ diff --git a/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md index 4f83b02e1f..c0d71dd190 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-catalog-backend-module-bitbucket-cloud +## 0.1.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.2.2-next.0 + - @backstage/backend-tasks@0.3.3-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.1.1-next.0 + ## 0.1.0 ### Minor Changes diff --git a/plugins/catalog-backend-module-bitbucket-cloud/package.json b/plugins/catalog-backend-module-bitbucket-cloud/package.json index aea92c3b56..b272cb8c29 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/package.json +++ b/plugins/catalog-backend-module-bitbucket-cloud/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-bitbucket-cloud", "description": "A Backstage catalog backend module that helps integrate towards Bitbucket Cloud", - "version": "0.1.0", + "version": "0.1.1-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,19 +33,19 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/backend-tasks": "^0.3.2", + "@backstage/backend-tasks": "^0.3.3-next.1", "@backstage/config": "^1.0.1", - "@backstage/integration": "^1.2.1", - "@backstage/plugin-bitbucket-cloud-common": "^0.1.0", - "@backstage/plugin-catalog-backend": "^1.2.0", + "@backstage/integration": "^1.2.2-next.1", + "@backstage/plugin-bitbucket-cloud-common": "^0.1.1-next.0", + "@backstage/plugin-catalog-backend": "^1.2.1-next.1", "uuid": "^8.0.0", "winston": "^3.2.1" }, "devDependencies": { - "@backstage/backend-common": "^0.14.0", - "@backstage/backend-test-utils": "^0.1.25", - "@backstage/cli": "^0.17.2", - "msw": "^0.42.0" + "@backstage/backend-common": "^0.14.1-next.1", + "@backstage/backend-test-utils": "^0.1.26-next.1", + "@backstage/cli": "^0.18.0-next.1", + "msw": "^0.43.0" }, "files": [ "dist", diff --git a/plugins/catalog-backend-module-bitbucket/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket/CHANGELOG.md index 8c3b2c6ad5..a920827973 100644 --- a/plugins/catalog-backend-module-bitbucket/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-catalog-backend-module-bitbucket +## 0.2.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.1 + - @backstage/integration@1.2.2-next.1 + +## 0.2.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.1.1-next.0 + ## 0.2.0 ### Minor Changes diff --git a/plugins/catalog-backend-module-bitbucket/package.json b/plugins/catalog-backend-module-bitbucket/package.json index 8b9c3b4e91..4eb2a85e0e 100644 --- a/plugins/catalog-backend-module-bitbucket/package.json +++ b/plugins/catalog-backend-module-bitbucket/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-bitbucket", "description": "A Backstage catalog backend module that helps integrate towards Bitbucket", - "version": "0.2.0", + "version": "0.2.1-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,22 +33,22 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", - "@backstage/catalog-model": "^1.0.3", + "@backstage/backend-common": "^0.14.1-next.1", + "@backstage/catalog-model": "^1.1.0-next.1", "@backstage/config": "^1.0.1", - "@backstage/errors": "^1.0.0", - "@backstage/integration": "^1.2.1", - "@backstage/plugin-bitbucket-cloud-common": "^0.1.0", - "@backstage/plugin-catalog-backend": "^1.2.0", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/integration": "^1.2.2-next.1", + "@backstage/plugin-bitbucket-cloud-common": "^0.1.1-next.0", + "@backstage/plugin-catalog-backend": "^1.2.1-next.1", "@backstage/types": "^1.0.0", "lodash": "^4.17.21", - "msw": "^0.42.0", + "msw": "^0.43.0", "node-fetch": "^2.6.7", "winston": "^3.2.1" }, "devDependencies": { - "@backstage/backend-test-utils": "^0.1.25", - "@backstage/cli": "^0.17.2", + "@backstage/backend-test-utils": "^0.1.26-next.1", + "@backstage/cli": "^0.18.0-next.1", "@types/lodash": "^4.14.151" }, "files": [ diff --git a/plugins/catalog-backend-module-gerrit/CHANGELOG.md b/plugins/catalog-backend-module-gerrit/CHANGELOG.md index 8654556d28..c55973d568 100644 --- a/plugins/catalog-backend-module-gerrit/CHANGELOG.md +++ b/plugins/catalog-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-catalog-backend-module-gerrit +## 0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.1 + - @backstage/backend-tasks@0.3.3-next.1 + - @backstage/integration@1.2.2-next.1 + +## 0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/backend-tasks@0.3.3-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.0 + ## 0.1.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-gerrit/package.json b/plugins/catalog-backend-module-gerrit/package.json index 55c33d2578..6c4bd63659 100644 --- a/plugins/catalog-backend-module-gerrit/package.json +++ b/plugins/catalog-backend-module-gerrit/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-gerrit", - "version": "0.1.1", + "version": "0.1.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -28,22 +28,22 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", - "@backstage/backend-tasks": "^0.3.2", - "@backstage/catalog-model": "^1.0.3", + "@backstage/backend-common": "^0.14.1-next.1", + "@backstage/backend-tasks": "^0.3.3-next.1", + "@backstage/catalog-model": "^1.1.0-next.1", "@backstage/config": "^1.0.1", - "@backstage/errors": "^1.0.0", - "@backstage/integration": "^1.2.1", - "@backstage/plugin-catalog-backend": "^1.2.0", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/integration": "^1.2.2-next.1", + "@backstage/plugin-catalog-backend": "^1.2.1-next.1", "fs-extra": "10.1.0", - "msw": "^0.42.0", + "msw": "^0.43.0", "node-fetch": "^2.6.7", "uuid": "^8.0.0", "winston": "^3.2.1" }, "devDependencies": { - "@backstage/backend-test-utils": "^0.1.25", - "@backstage/cli": "^0.17.2", + "@backstage/backend-test-utils": "^0.1.26-next.1", + "@backstage/cli": "^0.18.0-next.1", "@types/fs-extra": "^9.0.1" }, "files": [ diff --git a/plugins/catalog-backend-module-github/CHANGELOG.md b/plugins/catalog-backend-module-github/CHANGELOG.md index 553504c46f..42aa26afdf 100644 --- a/plugins/catalog-backend-module-github/CHANGELOG.md +++ b/plugins/catalog-backend-module-github/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-catalog-backend-module-github +## 0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.1 + - @backstage/backend-tasks@0.3.3-next.1 + - @backstage/integration@1.2.2-next.1 + +## 0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/backend-tasks@0.3.3-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.0 + ## 0.1.4 ### Patch Changes diff --git a/plugins/catalog-backend-module-github/package.json b/plugins/catalog-backend-module-github/package.json index 680c812c4c..eae503c507 100644 --- a/plugins/catalog-backend-module-github/package.json +++ b/plugins/catalog-backend-module-github/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-github", "description": "A Backstage catalog backend module that helps integrate towards GitHub", - "version": "0.1.4", + "version": "0.1.5-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,24 +33,24 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", - "@backstage/backend-tasks": "^0.3.2", - "@backstage/catalog-model": "^1.0.3", + "@backstage/backend-common": "^0.14.1-next.1", + "@backstage/backend-tasks": "^0.3.3-next.1", + "@backstage/catalog-model": "^1.1.0-next.1", "@backstage/config": "^1.0.1", - "@backstage/errors": "^1.0.0", - "@backstage/integration": "^1.2.1", - "@backstage/plugin-catalog-backend": "^1.2.0", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/integration": "^1.2.2-next.1", + "@backstage/plugin-catalog-backend": "^1.2.1-next.1", "@backstage/types": "^1.0.0", "@octokit/graphql": "^4.5.8", "lodash": "^4.17.21", - "msw": "^0.42.0", + "msw": "^0.43.0", "node-fetch": "^2.6.7", "uuid": "^8.0.0", "winston": "^3.2.1" }, "devDependencies": { - "@backstage/backend-test-utils": "^0.1.25", - "@backstage/cli": "^0.17.2", + "@backstage/backend-test-utils": "^0.1.26-next.1", + "@backstage/cli": "^0.18.0-next.1", "@types/lodash": "^4.14.151" }, "files": [ diff --git a/plugins/catalog-backend-module-gitlab/CHANGELOG.md b/plugins/catalog-backend-module-gitlab/CHANGELOG.md index f785a935e6..95fa6ddbda 100644 --- a/plugins/catalog-backend-module-gitlab/CHANGELOG.md +++ b/plugins/catalog-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,40 @@ # @backstage/plugin-catalog-backend-module-gitlab +## 0.1.5-next.1 + +### Patch Changes + +- 49ff472c0b: Add the possibility in the `GitlabDiscoveryEntityProvider` to scan the whole project instead of concrete groups. For that, use a configuration like this one, where the group parameter is omitted (not mandatory anymore): + + ```yaml + catalog: + providers: + gitlab: + yourProviderId: + host: gitlab-host # Identifies one of the hosts set up in the integrations + branch: main # Optional. Uses `master` as default + entityFilename: catalog-info.yaml # Optional. Defaults to `catalog-info.yaml` + ``` + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.1 + - @backstage/backend-tasks@0.3.3-next.1 + - @backstage/integration@1.2.2-next.1 + +## 0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/backend-tasks@0.3.3-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.0 + ## 0.1.4 ### Patch Changes diff --git a/plugins/catalog-backend-module-gitlab/config.d.ts b/plugins/catalog-backend-module-gitlab/config.d.ts index 5b0d42c81d..82f1a5db7c 100644 --- a/plugins/catalog-backend-module-gitlab/config.d.ts +++ b/plugins/catalog-backend-module-gitlab/config.d.ts @@ -32,10 +32,11 @@ export interface Config { */ host: string; /** - * (Required) Gitlab's group[/subgroup] where the discovery is done. + * (Optional) Gitlab's group[/subgroup] where the discovery is done. + * If not defined the whole project will be scanned. * @visibility backend */ - group: string; + group?: string; /** * (Optional) Default branch to read the catalog-info.yaml file. * If not set, 'master' will be used. diff --git a/plugins/catalog-backend-module-gitlab/package.json b/plugins/catalog-backend-module-gitlab/package.json index 4780d86530..47f48af481 100644 --- a/plugins/catalog-backend-module-gitlab/package.json +++ b/plugins/catalog-backend-module-gitlab/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-gitlab", "description": "A Backstage catalog backend module that helps integrate towards GitLab", - "version": "0.1.4", + "version": "0.1.5-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,23 +33,23 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", - "@backstage/catalog-model": "^1.0.3", - "@backstage/backend-tasks": "^0.3.2", + "@backstage/backend-common": "^0.14.1-next.1", + "@backstage/catalog-model": "^1.1.0-next.1", + "@backstage/backend-tasks": "^0.3.3-next.1", "@backstage/config": "^1.0.1", - "@backstage/errors": "^1.0.0", - "@backstage/integration": "^1.2.1", - "@backstage/plugin-catalog-backend": "^1.2.0", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/integration": "^1.2.2-next.1", + "@backstage/plugin-catalog-backend": "^1.2.1-next.1", "@backstage/types": "^1.0.0", "lodash": "^4.17.21", - "msw": "^0.42.0", + "msw": "^0.43.0", "node-fetch": "^2.6.7", "winston": "^3.2.1", "uuid": "^8.0.0" }, "devDependencies": { - "@backstage/backend-test-utils": "^0.1.25", - "@backstage/cli": "^0.17.2", + "@backstage/backend-test-utils": "^0.1.26-next.1", + "@backstage/cli": "^0.18.0-next.1", "@types/lodash": "^4.14.151", "@types/uuid": "^8.0.0" }, diff --git a/plugins/catalog-backend-module-gitlab/src/providers/config.test.ts b/plugins/catalog-backend-module-gitlab/src/providers/config.test.ts index d28930b151..892ce5f25c 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/config.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/config.test.ts @@ -100,7 +100,26 @@ describe('config', () => { }); expect(() => readGitlabConfigs(config)).toThrow( - "Missing required config value at 'catalog.providers.gitlab.test.group'", + "Missing required config value at 'catalog.providers.gitlab.test.host'", ); }); + + it('read full gitlab project', () => { + const config = new ConfigReader({ + catalog: { + providers: { + gitlab: { + test: { + host: 'host', + branch: 'main', + }, + }, + }, + }, + }); + + const result = readGitlabConfigs(config); + expect(result).toHaveLength(1); + expect(result[0].group).toEqual(''); + }); }); diff --git a/plugins/catalog-backend-module-gitlab/src/providers/config.ts b/plugins/catalog-backend-module-gitlab/src/providers/config.ts index f7eb316997..d6ad28b2ca 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/config.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/config.ts @@ -25,7 +25,7 @@ import { GitlabProviderConfig } from '../lib/types'; * @param config - The config object to extract from */ function readGitlabConfig(id: string, config: Config): GitlabProviderConfig { - const group = config.getString('group'); + const group = config.getOptionalString('group') ?? ''; const host = config.getString('host'); const branch = config.getOptionalString('branch') ?? 'master'; const catalogFile = diff --git a/plugins/catalog-backend-module-ldap/CHANGELOG.md b/plugins/catalog-backend-module-ldap/CHANGELOG.md index 072ef991d4..e906e40631 100644 --- a/plugins/catalog-backend-module-ldap/CHANGELOG.md +++ b/plugins/catalog-backend-module-ldap/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-catalog-backend-module-ldap +## 0.5.1-next.1 + +### Patch Changes + +- fbfbff6bf7: Add possibility to resolve relations by RDN, in addition to UUID and DN +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.1 + - @backstage/backend-tasks@0.3.3-next.1 + +## 0.5.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/backend-tasks@0.3.3-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.0 + ## 0.5.0 ### Minor Changes diff --git a/plugins/catalog-backend-module-ldap/package.json b/plugins/catalog-backend-module-ldap/package.json index 288fccf7a5..7232ea24c3 100644 --- a/plugins/catalog-backend-module-ldap/package.json +++ b/plugins/catalog-backend-module-ldap/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-ldap", "description": "A Backstage catalog backend module that helps integrate towards LDAP", - "version": "0.5.0", + "version": "0.5.1-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,11 +33,11 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/backend-tasks": "^0.3.2", - "@backstage/catalog-model": "^1.0.3", + "@backstage/backend-tasks": "^0.3.3-next.1", + "@backstage/catalog-model": "^1.1.0-next.1", "@backstage/config": "^1.0.1", - "@backstage/errors": "^1.0.0", - "@backstage/plugin-catalog-backend": "^1.2.0", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/plugin-catalog-backend": "^1.2.1-next.1", "@backstage/types": "^1.0.0", "@types/ldapjs": "^2.2.0", "ldapjs": "^2.2.0", @@ -46,7 +46,7 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.17.2", + "@backstage/cli": "^0.18.0-next.1", "@types/lodash": "^4.14.151" }, "files": [ diff --git a/plugins/catalog-backend-module-ldap/src/ldap/read.test.ts b/plugins/catalog-backend-module-ldap/src/ldap/read.test.ts index 410ac847b3..49803b9c39 100644 --- a/plugins/catalog-backend-module-ldap/src/ldap/read.test.ts +++ b/plugins/catalog-backend-module-ldap/src/ldap/read.test.ts @@ -345,206 +345,128 @@ describe('readLdapGroups', () => { describe('resolveRelations', () => { describe('lookup', () => { - it('matches by DN', () => { - const parent = group({ - metadata: { - name: 'parent', - annotations: { [LDAP_DN_ANNOTATION]: 'pa' }, - }, - }); - const child = group({ - metadata: { - name: 'child', - annotations: { [LDAP_DN_ANNOTATION]: 'ca' }, - }, - }); - const groupMember = new Map>([ - ['pa', new Set(['ca'])], - ]); - resolveRelations([parent, child], [], new Map(), new Map(), groupMember); - expect(parent.spec.children).toEqual(['group:default/child']); - expect(child.spec.parent).toEqual('group:default/parent'); - }); - - it('matches by UUID', () => { - const parent = group({ - metadata: { - name: 'parent', - annotations: { [LDAP_UUID_ANNOTATION]: 'pa' }, - }, - }); - const child = group({ - metadata: { - name: 'child', - annotations: { [LDAP_UUID_ANNOTATION]: 'ca' }, - }, - }); - const groupMember = new Map>([ - ['pa', new Set(['ca'])], - ]); - resolveRelations([parent, child], [], new Map(), new Map(), groupMember); - expect(parent.spec.children).toEqual(['group:default/child']); - expect(child.spec.parent).toEqual('group:default/parent'); - }); + it.each([LDAP_DN_ANNOTATION, LDAP_RDN_ANNOTATION, LDAP_UUID_ANNOTATION])( + 'matches by %s', + annotation => { + const parent = group({ + metadata: { + name: 'parent', + annotations: { [annotation]: 'pa' }, + }, + }); + const child = group({ + metadata: { + name: 'child', + annotations: { [annotation]: 'ca' }, + }, + }); + const groupMember = new Map>([ + ['pa', new Set(['ca'])], + ]); + resolveRelations( + [parent, child], + [], + new Map(), + new Map(), + groupMember, + ); + expect(parent.spec.children).toEqual(['group:default/child']); + expect(child.spec.parent).toEqual('group:default/parent'); + }, + ); }); describe('userMemberOf', () => { - it('populates relations by dn', () => { - const host = group({ - metadata: { name: 'host', annotations: { [LDAP_DN_ANNOTATION]: 'ha' } }, - }); - const member = user({ - metadata: { - name: 'member', - annotations: { [LDAP_DN_ANNOTATION]: 'ma' }, - }, - }); - const userMemberOf = new Map>([ - ['ma', new Set(['ha'])], - ]); - resolveRelations([host], [member], userMemberOf, new Map(), new Map()); - expect(member.spec.memberOf).toEqual(['group:default/host']); - }); - - it('populates relations by uuid', () => { - const host = group({ - metadata: { - name: 'host', - annotations: { [LDAP_UUID_ANNOTATION]: 'ha' }, - }, - }); - const member = user({ - metadata: { - name: 'member', - annotations: { [LDAP_DN_ANNOTATION]: 'ma' }, - }, - }); - const userMemberOf = new Map>([ - ['ma', new Set(['ha'])], - ]); - resolveRelations([host], [member], userMemberOf, new Map(), new Map()); - expect(member.spec.memberOf).toEqual(['group:default/host']); - }); + it.each([LDAP_DN_ANNOTATION, LDAP_RDN_ANNOTATION, LDAP_UUID_ANNOTATION])( + 'populates relations by %s', + annotation => { + const host = group({ + metadata: { name: 'host', annotations: { [annotation]: 'ha' } }, + }); + const member = user({ + metadata: { + name: 'member', + annotations: { [annotation]: 'ma' }, + }, + }); + const userMemberOf = new Map>([ + ['ma', new Set(['ha'])], + ]); + resolveRelations([host], [member], userMemberOf, new Map(), new Map()); + expect(member.spec.memberOf).toEqual(['group:default/host']); + }, + ); }); describe('groupMemberOf', () => { - it('populates relations by dn', () => { - const parent = group({ - metadata: { - name: 'parent', - annotations: { [LDAP_DN_ANNOTATION]: 'pa' }, - }, - }); - const child = group({ - metadata: { - name: 'child', - annotations: { [LDAP_DN_ANNOTATION]: 'ca' }, - }, - }); - const groupMemberOf = new Map>([ - ['ca', new Set(['pa'])], - ]); - resolveRelations( - [parent, child], - [], - new Map(), - groupMemberOf, - new Map(), - ); - expect(parent.spec.children).toEqual(['group:default/child']); - expect(child.spec.parent).toEqual('group:default/parent'); - }); - }); - - it('populates relations by uuid', () => { - const parent = group({ - metadata: { - name: 'parent', - annotations: { [LDAP_UUID_ANNOTATION]: 'pa' }, + it.each([LDAP_DN_ANNOTATION, LDAP_RDN_ANNOTATION, LDAP_UUID_ANNOTATION])( + 'populates relations by %s', + annotation => { + const parent = group({ + metadata: { + name: 'parent', + annotations: { [annotation]: 'pa' }, + }, + }); + const child = group({ + metadata: { + name: 'child', + annotations: { [annotation]: 'ca' }, + }, + }); + const groupMemberOf = new Map>([ + ['ca', new Set(['pa'])], + ]); + resolveRelations( + [parent, child], + [], + new Map(), + groupMemberOf, + new Map(), + ); + expect(parent.spec.children).toEqual(['group:default/child']); + expect(child.spec.parent).toEqual('group:default/parent'); }, - }); - const child = group({ - metadata: { - name: 'child', - annotations: { [LDAP_UUID_ANNOTATION]: 'ca' }, - }, - }); - const groupMemberOf = new Map>([ - ['ca', new Set(['pa'])], - ]); - resolveRelations([parent, child], [], new Map(), groupMemberOf, new Map()); - expect(parent.spec.children).toEqual(['group:default/child']); - expect(child.spec.parent).toEqual('group:default/parent'); + ); }); describe('groupMember', () => { - it('populates relations by dn', () => { - const parent = group({ - metadata: { - name: 'parent', - annotations: { [LDAP_DN_ANNOTATION]: 'pa' }, - }, - }); - const child = group({ - metadata: { - name: 'child', - annotations: { [LDAP_DN_ANNOTATION]: 'ca' }, - }, - }); - const member = user({ - metadata: { - name: 'member', - annotations: { [LDAP_DN_ANNOTATION]: 'ma' }, - }, - }); - const groupMember = new Map>([ - ['pa', new Set(['ca', 'ma'])], - ]); - resolveRelations( - [parent, child], - [member], - new Map(), - new Map(), - groupMember, - ); - expect(parent.spec.children).toEqual(['group:default/child']); - expect(child.spec.parent).toEqual('group:default/parent'); - expect(member.spec.memberOf).toEqual(['group:default/parent']); - }); - - it('populates relations by uuid', () => { - const parent = group({ - metadata: { - name: 'parent', - annotations: { [LDAP_UUID_ANNOTATION]: 'pa' }, - }, - }); - const child = group({ - metadata: { - name: 'child', - annotations: { [LDAP_UUID_ANNOTATION]: 'ca' }, - }, - }); - const member = user({ - metadata: { - name: 'member', - annotations: { [LDAP_UUID_ANNOTATION]: 'ma' }, - }, - }); - const groupMember = new Map>([ - ['pa', new Set(['ca', 'ma'])], - ]); - resolveRelations( - [parent, child], - [member], - new Map(), - new Map(), - groupMember, - ); - expect(parent.spec.children).toEqual(['group:default/child']); - expect(child.spec.parent).toEqual('group:default/parent'); - expect(member.spec.memberOf).toEqual(['group:default/parent']); - }); + it.each([LDAP_DN_ANNOTATION, LDAP_RDN_ANNOTATION, LDAP_UUID_ANNOTATION])( + 'populates relations by %s', + annotation => { + const parent = group({ + metadata: { + name: 'parent', + annotations: { [annotation]: 'pa' }, + }, + }); + const child = group({ + metadata: { + name: 'child', + annotations: { [annotation]: 'ca' }, + }, + }); + const member = user({ + metadata: { + name: 'member', + annotations: { [annotation]: 'ma' }, + }, + }); + const groupMember = new Map>([ + ['pa', new Set(['ca', 'ma'])], + ]); + resolveRelations( + [parent, child], + [member], + new Map(), + new Map(), + groupMember, + ); + expect(parent.spec.children).toEqual(['group:default/child']); + expect(child.spec.parent).toEqual('group:default/parent'); + expect(member.spec.memberOf).toEqual(['group:default/parent']); + }, + ); }); }); diff --git a/plugins/catalog-backend-module-ldap/src/ldap/read.ts b/plugins/catalog-backend-module-ldap/src/ldap/read.ts index d0fe30e0e6..420ba141fc 100644 --- a/plugins/catalog-backend-module-ldap/src/ldap/read.ts +++ b/plugins/catalog-backend-module-ldap/src/ldap/read.ts @@ -365,11 +365,13 @@ export function resolveRelations( for (const user of users) { userMap.set(stringifyEntityRef(user), user); userMap.set(user.metadata.annotations![LDAP_DN_ANNOTATION], user); + userMap.set(user.metadata.annotations![LDAP_RDN_ANNOTATION], user); userMap.set(user.metadata.annotations![LDAP_UUID_ANNOTATION], user); } for (const group of groups) { groupMap.set(stringifyEntityRef(group), group); groupMap.set(group.metadata.annotations![LDAP_DN_ANNOTATION], group); + groupMap.set(group.metadata.annotations![LDAP_RDN_ANNOTATION], group); groupMap.set(group.metadata.annotations![LDAP_UUID_ANNOTATION], group); } diff --git a/plugins/catalog-backend-module-msgraph/CHANGELOG.md b/plugins/catalog-backend-module-msgraph/CHANGELOG.md index d6a0f7c7b7..a86663d6d1 100644 --- a/plugins/catalog-backend-module-msgraph/CHANGELOG.md +++ b/plugins/catalog-backend-module-msgraph/CHANGELOG.md @@ -1,5 +1,113 @@ # @backstage/plugin-catalog-backend-module-msgraph +## 0.4.0-next.1 + +### Minor Changes + +- a145672f0f: Align `msgraph` plugin's entity provider config with other providers. **Deprecated** entity processor as well as previous config. + + You will see warning at the log output until you migrate to the new setup. + All deprecated parts will be removed eventually after giving some time to migrate. + + Please find information on how to migrate your current setup to the new one below. + + **Migration Guide:** + + There were two different way on how to use the msgraph plugin: processor or provider. + + Previous registration for the processor: + + ```typescript + // packages/backend/src/plugins/catalog.ts + builder.addProcessor( + MicrosoftGraphOrgReaderProcessor.fromConfig(env.config, { + logger: env.logger, + // [...] + }), + ); + ``` + + Previous registration when using the provider: + + ```typescript + // packages/backend/src/plugins/catalog.ts + builder.addEntityProvider( + MicrosoftGraphOrgEntityProvider.fromConfig(env.config, { + id: 'https://graph.microsoft.com/v1.0', + target: 'https://graph.microsoft.com/v1.0', + logger: env.logger, + schedule: env.scheduler.createScheduledTaskRunner({ + frequency: { minutes: 30 }, + timeout: { minutes: 3 }, + }), + // [...] + }), + ); + ``` + + Previous configuration as used for both: + + ```yaml + # app-config.yaml + catalog: + processors: + microsoftGraphOrg: + providers: + - target: https://graph.microsoft.com/v1.0 + # [...] + ``` + + **Replacement:** + + Please check https://github.com/backstage/backstage/blob/master/plugins/catalog-backend-module-msgraph/README.md for the complete documentation of all configuration options (config as well as registration of the provider). + + ```yaml + # app-config.yaml + catalog: + providers: + microsoftGraphOrg: + # In case you used the deprecated configuration with the entity provider + # using the value of `target` will keep the same location key for all + providerId: # some stable ID which will be used as part of the location key for all ingested data + target: https://graph.microsoft.com/v1.0 + # [...] + ``` + + ```typescript + // packages/backend/src/plugins/catalog.ts + builder.addEntityProvider( + MicrosoftGraphOrgEntityProvider.fromConfig(env.config, { + logger: env.logger, + schedule: env.scheduler.createScheduledTaskRunner({ + frequency: { minutes: 30 }, + timeout: { minutes: 3 }, + }), + // [...] + }), + ); + ``` + + In case you've used multiple entity providers before + **and** you had different transformers for each of them + you can provide these directly at the one `fromConfig` call + by passing a Record with the provider ID as key. + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/backend-tasks@0.3.3-next.2 + - @backstage/plugin-catalog-backend@1.2.1-next.2 + +## 0.3.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/backend-tasks@0.3.3-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.0 + ## 0.3.3 ### Patch Changes diff --git a/plugins/catalog-backend-module-msgraph/README.md b/plugins/catalog-backend-module-msgraph/README.md index e6429152e4..6132d5abc6 100644 --- a/plugins/catalog-backend-module-msgraph/README.md +++ b/plugins/catalog-backend-module-msgraph/README.md @@ -1,85 +1,86 @@ # Catalog Backend Module for Microsoft Graph -This is an extension module to the `plugin-catalog-backend` plugin, providing a -`MicrosoftGraphOrgReaderProcessor` and a `MicrosoftGraphOrgEntityProvider` that -can be used to ingest organization data from the Microsoft Graph API. This -processor is useful if you want to import users and groups from Azure Active -Directory or Office 365. +This is an extension module to the `plugin-catalog-backend` plugin, providing a `MicrosoftGraphOrgEntityProvider` +that can be used to ingest organization data from the Microsoft Graph API. +This provider is useful if you want to import users and groups from Azure Active Directory or Office 365. ## Getting Started -First you need to decide whether you want to use an [entity provider or a processor](https://backstage.io/docs/features/software-catalog/life-of-an-entity#stitching) to ingest the organization data. -If you want groups and users deleted from the source to be automatically deleted -from Backstage, choose the entity provider. - 1. Create or use an existing App registration in the [Microsoft Azure Portal](https://portal.azure.com/). The App registration requires at least the API permissions `Group.Read.All`, `GroupMember.Read.All`, `User.Read` and `User.Read.All` for Microsoft Graph (if you still run into errors about insufficient privileges, add `Team.ReadBasic.All` and `TeamMember.Read.All` too). -2. Configure the processor or entity provider: +2. Configure the entity provider: ```yaml # app-config.yaml catalog: - processors: + providers: microsoftGraphOrg: - providers: - - target: https://graph.microsoft.com/v1.0 - authority: https://login.microsoftonline.com - # If you don't know you tenantId, you can use Microsoft Graph Explorer - # to query it - tenantId: ${MICROSOFT_GRAPH_TENANT_ID} - # Client Id and Secret can be created under Certificates & secrets in - # the App registration in the Microsoft Azure Portal. - clientId: ${MICROSOFT_GRAPH_CLIENT_ID} - clientSecret: ${MICROSOFT_GRAPH_CLIENT_SECRET_TOKEN} - # Optional mode for querying which defaults to "basic". - # By default, the Microsoft Graph API only provides the basic feature set - # for querying. Certain features are limited to advanced querying capabilities. - # (See https://docs.microsoft.com/en-us/graph/aad-advanced-queries) - queryMode: basic # basic | advanced + providerId: + target: https://graph.microsoft.com/v1.0 + authority: https://login.microsoftonline.com + # If you don't know you tenantId, you can use Microsoft Graph Explorer + # to query it + tenantId: ${MICROSOFT_GRAPH_TENANT_ID} + # Client Id and Secret can be created under Certificates & secrets in + # the App registration in the Microsoft Azure Portal. + clientId: ${MICROSOFT_GRAPH_CLIENT_ID} + clientSecret: ${MICROSOFT_GRAPH_CLIENT_SECRET_TOKEN} + # Optional mode for querying which defaults to "basic". + # By default, the Microsoft Graph API only provides the basic feature set + # for querying. Certain features are limited to advanced querying capabilities. + # (See https://docs.microsoft.com/en-us/graph/aad-advanced-queries) + queryMode: basic # basic | advanced + # Optional configuration block + user: # Optional parameter to include the expanded resource or collection referenced # by a single relationship (navigation property) in your results. # Only one relationship can be expanded in a single request. # See https://docs.microsoft.com/en-us/graph/query-parameters#expand-parameter # Can be combined with userGroupMember[...] instead of userFilter. - userExpand: manager + expand: manager # Optional filter for user, see Microsoft Graph API for the syntax # See https://docs.microsoft.com/en-us/graph/api/resources/user?view=graph-rest-1.0#properties # and for the syntax https://docs.microsoft.com/en-us/graph/query-parameters#filter-parameter # This and userGroupMemberFilter are mutually exclusive, only one can be specified - userFilter: accountEnabled eq true and userType eq 'member' + filter: accountEnabled eq true and userType eq 'member' + # Optional configuration block + userGroupMember: # Optional filter for users, use group membership to get users. # (Filtered groups and fetch their members.) # This and userFilter are mutually exclusive, only one can be specified # See https://docs.microsoft.com/en-us/graph/search-query-parameter - userGroupMemberFilter: "displayName eq 'Backstage Users'" + filter: "displayName eq 'Backstage Users'" + # Optional search for users, use group membership to get users. + # (Search for groups and fetch their members.) + # This and userFilter are mutually exclusive, only one can be specified + search: '"description:One" AND ("displayName:Video" OR "displayName:Drive")' + # Optional configuration block + group: # Optional parameter to include the expanded resource or collection referenced # by a single relationship (navigation property) in your results. # Only one relationship can be expanded in a single request. # See https://docs.microsoft.com/en-us/graph/query-parameters#expand-parameter # Can be combined with userGroupMember[...] instead of userFilter. - groupExpand: member - # Optional search for users, use group membership to get users. - # (Search for groups and fetch their members.) - # This and userFilter are mutually exclusive, only one can be specified - userGroupMemberSearch: '"description:One" AND ("displayName:Video" OR "displayName:Drive")' + expand: member # Optional filter for group, see Microsoft Graph API for the syntax # See https://docs.microsoft.com/en-us/graph/api/resources/group?view=graph-rest-1.0#properties - groupFilter: securityEnabled eq false and mailEnabled eq true and groupTypes/any(c:c+eq+'Unified') + filter: securityEnabled eq false and mailEnabled eq true and groupTypes/any(c:c+eq+'Unified') # Optional search for groups, see Microsoft Graph API for the syntax # See https://docs.microsoft.com/en-us/graph/search-query-parameter - groupSearch: '"description:One" AND ("displayName:Video" OR "displayName:Drive")' - # Optional select for groups, this will allow you work with schemaExtensions in order to add extra information to your groups that can be used on you custom groupTransformers + search: '"description:One" AND ("displayName:Video" OR "displayName:Drive")' + # Optional select for groups, this will allow you work with schemaExtensions + # in order to add extra information to your groups that can be used on you custom groupTransformers # See https://docs.microsoft.com/en-us/graph/api/resources/schemaextension?view=graph-rest-1.0 - groupSelect: ['id', 'displayName', 'description'] + select: ['id', 'displayName', 'description'] ``` -`userFilter` and `userGroupMemberFilter` are mutually exclusive, only one can be provided. If both are provided, an error will be thrown. +`user.filter` and `userGroupMember.filter` are mutually exclusive, only one can be provided. If both are provided, an error will be thrown. -By default, all users are loaded. If you want to filter users based on their attributes, use `userFilter`. `userGroupMemberFilter` can be used if you want to load users based on their group membership. +By default, all users are loaded. If you want to filter users based on their attributes, use `user.filter`. `userGroupMember.filter` can be used if you want to load users based on their group membership. 3. The package is not installed by default, therefore you have to add a dependency to `@backstage/plugin-catalog-backend-module-msgraph` to your @@ -90,15 +91,12 @@ By default, all users are loaded. If you want to filter users based on their att yarn add --cwd packages/backend @backstage/plugin-catalog-backend-module-msgraph ``` -### Using the Entity Provider - 4. The `MicrosoftGraphOrgEntityProvider` is not registered by default, so you have to register it in the catalog plugin. Pass the target to reference a provider from the configuration. ```diff // packages/backend/src/plugins/catalog.ts -+import { Duration } from 'luxon'; +import { MicrosoftGraphOrgEntityProvider } from '@backstage/plugin-catalog-backend-module-msgraph'; export default async function createPlugin( @@ -106,53 +104,21 @@ yarn add --cwd packages/backend @backstage/plugin-catalog-backend-module-msgraph ): Promise { const builder = await CatalogBuilder.create(env); -+ // The target parameter below needs to match one of the providers' target -+ // value specified in your app-config (see above). + builder.addEntityProvider( + MicrosoftGraphOrgEntityProvider.fromConfig(env.config, { -+ id: 'production', -+ target: 'https://graph.microsoft.com/v1.0', + logger: env.logger, + schedule: env.scheduler.createScheduledTaskRunner({ -+ frequency: Duration.fromObject({ minutes: 5 }), -+ timeout: Duration.fromObject({ minutes: 3 }), ++ frequency: { minutes: 5 }, ++ timeout: { minutes: 3 }, + }), + }), + ); ``` -### Using the Processor - -4. The `MicrosoftGraphOrgReaderProcessor` is not registered by default, so you - have to register it in the catalog plugin: - -```typescript -// packages/backend/src/plugins/catalog.ts -builder.addProcessor( - MicrosoftGraphOrgReaderProcessor.fromConfig(env.config, { - logger: env.logger, - }), -); -``` - -5. Add a location that ingests from Microsoft Graph: - -```yaml -# app-config.yaml -catalog: - locations: - - type: microsoft-graph-org - target: https://graph.microsoft.com/v1.0 - rules: - - allow: [Group, User] - … -``` - ## Customize the Processor or Entity Provider -In case you want to customize the ingested entities, both the `MicrosoftGraphOrgReaderProcessor` -and the `MicrosoftGraphOrgEntityProvider` allows to pass transformers for users, -groups and the organization. +In case you want to customize the ingested entities, the `MicrosoftGraphOrgEntityProvider` +allows to pass transformers for users, groups and the organization. 1. Create a transformer: @@ -179,13 +145,17 @@ export async function myGroupTransformer( } ``` -2. Configure the processor with the transformer: +2. Add the transformer: -```ts -builder.addProcessor( - MicrosoftGraphOrgReaderProcessor.fromConfig(env.config, { - logger: env.logger, - groupTransformer: myGroupTransformer, - }), -); +```diff + builder.addEntityProvider( + MicrosoftGraphOrgEntityProvider.fromConfig(env.config, { + logger: env.logger, + schedule: env.scheduler.createScheduledTaskRunner({ + frequency: { minutes: 5 }, + timeout: { minutes: 3 }, + }), ++ groupTransformer: myGroupTransformer, + }), + ); ``` diff --git a/plugins/catalog-backend-module-msgraph/api-report.md b/plugins/catalog-backend-module-msgraph/api-report.md index 31a22b0bc4..a4083b1d9e 100644 --- a/plugins/catalog-backend-module-msgraph/api-report.md +++ b/plugins/catalog-backend-module-msgraph/api-report.md @@ -125,14 +125,14 @@ export class MicrosoftGraphOrgEntityProvider implements EntityProvider { static fromConfig( configRoot: Config, options: MicrosoftGraphOrgEntityProviderOptions, - ): MicrosoftGraphOrgEntityProvider; + ): MicrosoftGraphOrgEntityProvider[]; // (undocumented) getProviderName(): string; read(options?: { logger?: Logger }): Promise; } -// @public -export interface MicrosoftGraphOrgEntityProviderOptions { +// @public @deprecated +export interface MicrosoftGraphOrgEntityProviderLegacyOptions { groupTransformer?: GroupTransformer; id: string; logger: Logger; @@ -143,6 +143,19 @@ export interface MicrosoftGraphOrgEntityProviderOptions { } // @public +export type MicrosoftGraphOrgEntityProviderOptions = + | MicrosoftGraphOrgEntityProviderLegacyOptions + | { + logger: Logger; + schedule: 'manual' | TaskRunner; + userTransformer?: UserTransformer | Record; + groupTransformer?: GroupTransformer | Record; + organizationTransformer?: + | OrganizationTransformer + | Record; + }; + +// @public @deprecated export class MicrosoftGraphOrgReaderProcessor implements CatalogProcessor { constructor(options: { providers: MicrosoftGraphProviderConfig[]; @@ -173,6 +186,7 @@ export class MicrosoftGraphOrgReaderProcessor implements CatalogProcessor { // @public export type MicrosoftGraphProviderConfig = { + id: string; target: string; authority?: string; tenantId: string; @@ -206,7 +220,7 @@ export type OrganizationTransformer = ( organization: MicrosoftGraph.Organization, ) => Promise; -// @public +// @public @deprecated export function readMicrosoftGraphConfig( config: Config, ): MicrosoftGraphProviderConfig[]; diff --git a/plugins/catalog-backend-module-msgraph/config.d.ts b/plugins/catalog-backend-module-msgraph/config.d.ts index cf00713e72..564ccbb10a 100644 --- a/plugins/catalog-backend-module-msgraph/config.d.ts +++ b/plugins/catalog-backend-module-msgraph/config.d.ts @@ -25,6 +25,7 @@ export interface Config { processors?: { /** * MicrosoftGraphOrgReaderProcessor configuration + * @deprecated Use `catalog.providers.microsoftGraphOrg` instead. */ microsoftGraphOrg?: { /** @@ -102,5 +103,173 @@ export interface Config { }>; }; }; + /** + * List of provider-specific options and attributes + */ + providers?: { + /** + * MicrosoftGraphOrgEntityProvider configuration. + */ + microsoftGraphOrg?: + | { + /** + * The prefix of the target that this matches on, e.g. + * "https://graph.microsoft.com/v1.0", with no trailing slash. + */ + target: string; + /** + * The auth authority used. + * + * Default value "https://login.microsoftonline.com" + */ + authority?: string; + /** + * The tenant whose org data we are interested in. + */ + tenantId: string; + /** + * The OAuth client ID to use for authenticating requests. + */ + clientId: string; + /** + * The OAuth client secret to use for authenticating requests. + * + * @visibility secret + */ + clientSecret: string; + + user?: { + /** + * The "expand" argument to apply to users. + * + * E.g. "manager". + */ + expand?: string; + /** + * The filter to apply to extract users. + * + * E.g. "accountEnabled eq true and userType eq 'member'" + */ + filter?: string; + }; + + group?: { + /** + * The "expand" argument to apply to groups. + * + * E.g. "member". + */ + expand?: string; + /** + * The filter to apply to extract groups. + * + * E.g. "securityEnabled eq false and mailEnabled eq true" + */ + filter?: string; + /** + * The search criteria to apply to extract users by groups memberships. + * + * E.g. "\"displayName:-team\"" would only match groups which contain '-team' + */ + search?: string; + /** + * The fields to be fetched on query. + * + * E.g. ["id", "displayName", "description"] + */ + select?: string[]; + }; + + userGroupMember?: { + /** + * The filter to apply to extract users by groups memberships. + * + * E.g. "displayName eq 'Backstage Users'" + */ + filter?: string; + /** + * The search criteria to apply to extract groups. + * + * E.g. "\"displayName:-team\"" would only match groups which contain '-team' + */ + search?: string; + }; + } + | Record< + string, + { + /** + * The prefix of the target that this matches on, e.g. + * "https://graph.microsoft.com/v1.0", with no trailing slash. + */ + target: string; + /** + * The auth authority used. + * + * Default value "https://login.microsoftonline.com" + */ + authority?: string; + /** + * The tenant whose org data we are interested in. + */ + tenantId: string; + /** + * The OAuth client ID to use for authenticating requests. + */ + clientId: string; + /** + * The OAuth client secret to use for authenticating requests. + * + * @visibility secret + */ + clientSecret: string; + + user?: { + /** + * The filter to apply to extract users. + * + * E.g. "accountEnabled eq true and userType eq 'member'" + */ + filter?: string; + }; + + group?: { + /** + * The filter to apply to extract groups. + * + * E.g. "securityEnabled eq false and mailEnabled eq true" + */ + filter?: string; + /** + * The search criteria to apply to extract users by groups memberships. + * + * E.g. "\"displayName:-team\"" would only match groups which contain '-team' + */ + search?: string; + /** + * The fields to be fetched on query. + * + * E.g. ["id", "displayName", "description"] + */ + select?: string[]; + }; + + userGroupMember?: { + /** + * The filter to apply to extract users by groups memberships. + * + * E.g. "displayName eq 'Backstage Users'" + */ + filter?: string; + /** + * The search criteria to apply to extract groups. + * + * E.g. "\"displayName:-team\"" would only match groups which contain '-team' + */ + search?: string; + }; + } + >; + }; }; } diff --git a/plugins/catalog-backend-module-msgraph/package.json b/plugins/catalog-backend-module-msgraph/package.json index 3131dc6daa..921d198b8b 100644 --- a/plugins/catalog-backend-module-msgraph/package.json +++ b/plugins/catalog-backend-module-msgraph/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-msgraph", "description": "A Backstage catalog backend module that helps integrate towards Microsoft Graph", - "version": "0.3.3", + "version": "0.4.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,10 +34,10 @@ }, "dependencies": { "@azure/msal-node": "^1.1.0", - "@backstage/backend-tasks": "^0.3.2", - "@backstage/catalog-model": "^1.0.3", + "@backstage/backend-tasks": "^0.3.3-next.2", + "@backstage/catalog-model": "^1.1.0-next.2", "@backstage/config": "^1.0.1", - "@backstage/plugin-catalog-backend": "^1.2.0", + "@backstage/plugin-catalog-backend": "^1.2.1-next.2", "@microsoft/microsoft-graph-types": "^2.6.0", "@types/node-fetch": "^2.5.12", "lodash": "^4.17.21", @@ -48,11 +48,11 @@ "qs": "^6.9.4" }, "devDependencies": { - "@backstage/backend-common": "^0.14.0", - "@backstage/backend-test-utils": "^0.1.25", - "@backstage/cli": "^0.17.2", + "@backstage/backend-common": "^0.14.1-next.2", + "@backstage/backend-test-utils": "^0.1.26-next.2", + "@backstage/cli": "^0.18.0-next.2", "@types/lodash": "^4.14.151", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist", diff --git a/plugins/catalog-backend-module-msgraph/src/microsoftGraph/config.test.ts b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/config.test.ts index e310fa544f..8239090249 100644 --- a/plugins/catalog-backend-module-msgraph/src/microsoftGraph/config.test.ts +++ b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/config.test.ts @@ -15,13 +15,14 @@ */ import { ConfigReader } from '@backstage/config'; -import { readMicrosoftGraphConfig } from './config'; +import { readMicrosoftGraphConfig, readProviderConfigs } from './config'; describe('readMicrosoftGraphConfig', () => { it('applies all of the defaults', () => { const config = { providers: [ { + id: 'target', target: 'target', tenantId: 'tenantId', clientId: 'clientId', @@ -32,6 +33,7 @@ describe('readMicrosoftGraphConfig', () => { const actual = readMicrosoftGraphConfig(new ConfigReader(config)); const expected = [ { + id: 'target', target: 'target', tenantId: 'tenantId', clientId: 'clientId', @@ -48,6 +50,7 @@ describe('readMicrosoftGraphConfig', () => { const config = { providers: [ { + id: 'target', target: 'target', tenantId: 'tenantId', clientId: 'clientId', @@ -64,6 +67,7 @@ describe('readMicrosoftGraphConfig', () => { const actual = readMicrosoftGraphConfig(new ConfigReader(config)); const expected = [ { + id: 'target', target: 'target', tenantId: 'tenantId', clientId: 'clientId', @@ -83,6 +87,7 @@ describe('readMicrosoftGraphConfig', () => { const config = { providers: [ { + id: 'target', target: 'target', tenantId: 'tenantId', clientId: 'clientId', @@ -100,6 +105,7 @@ describe('readMicrosoftGraphConfig', () => { const config = { providers: [ { + id: 'target', target: 'target', tenantId: 'tenantId', clientId: 'clientId', @@ -113,3 +119,128 @@ describe('readMicrosoftGraphConfig', () => { expect(() => readMicrosoftGraphConfig(new ConfigReader(config))).toThrow(); }); }); + +describe('readProviderConfigs', () => { + it('applies all of the defaults', () => { + const config = { + catalog: { + providers: { + microsoftGraphOrg: { + customProviderId: { + target: 'target', + tenantId: 'tenantId', + clientId: 'clientId', + clientSecret: 'clientSecret', + }, + }, + }, + }, + }; + const actual = readProviderConfigs(new ConfigReader(config)); + const expected = [ + { + id: 'customProviderId', + target: 'target', + tenantId: 'tenantId', + clientId: 'clientId', + clientSecret: 'clientSecret', + authority: 'https://login.microsoftonline.com', + }, + ]; + expect(actual).toEqual(expected); + }); + + it('reads all the values', () => { + const config = { + catalog: { + providers: { + microsoftGraphOrg: { + customProviderId: { + target: 'target', + tenantId: 'tenantId', + clientId: 'clientId', + clientSecret: 'clientSecret', + authority: 'https://login.example.com/', + user: { + expand: 'manager', + filter: 'accountEnabled eq true', + }, + group: { + expand: 'member', + filter: 'securityEnabled eq false', + select: ['id', 'displayName', 'description'], + }, + }, + }, + }, + }, + }; + const actual = readProviderConfigs(new ConfigReader(config)); + const expected = [ + { + id: 'customProviderId', + target: 'target', + tenantId: 'tenantId', + clientId: 'clientId', + clientSecret: 'clientSecret', + authority: 'https://login.example.com', + userExpand: 'manager', + userFilter: 'accountEnabled eq true', + groupExpand: 'member', + groupSelect: ['id', 'displayName', 'description'], + groupFilter: 'securityEnabled eq false', + }, + ]; + expect(actual).toEqual(expected); + }); + + it('should fail if both userFilter and userGroupMemberFilter are set', () => { + const config = { + catalog: { + providers: { + microsoftGraphOrg: { + customProviderId: { + target: 'target', + tenantId: 'tenantId', + clientId: 'clientId', + clientSecret: 'clientSecret', + authority: 'https://login.example.com/', + user: { + filter: 'accountEnabled eq true', + }, + userGroupMember: { + filter: 'any', + }, + }, + }, + }, + }, + }; + expect(() => readProviderConfigs(new ConfigReader(config))).toThrow(); + }); + + it('should fail if both userFilter and userGroupMemberSearch are set', () => { + const config = { + catalog: { + providers: { + microsoftGraphOrg: { + customProviderId: { + target: 'target', + tenantId: 'tenantId', + clientId: 'clientId', + clientSecret: 'clientSecret', + authority: 'https://login.example.com/', + user: { + filter: 'accountEnabled eq true', + }, + userGroupMember: { + search: 'any', + }, + }, + }, + }, + }, + }; + expect(() => readProviderConfigs(new ConfigReader(config))).toThrow(); + }); +}); diff --git a/plugins/catalog-backend-module-msgraph/src/microsoftGraph/config.ts b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/config.ts index aa2f2d6ee2..30e3a9a4d2 100644 --- a/plugins/catalog-backend-module-msgraph/src/microsoftGraph/config.ts +++ b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/config.ts @@ -17,12 +17,21 @@ import { Config } from '@backstage/config'; import { trimEnd } from 'lodash'; +const DEFAULT_AUTHORITY = 'https://login.microsoftonline.com'; +const DEFAULT_PROVIDER_ID = 'default'; +const DEFAULT_TARGET = 'https://graph.microsoft.com/v1.0'; + /** * The configuration parameters for a single Microsoft Graph provider. * * @public */ export type MicrosoftGraphProviderConfig = { + /** + * Identifier of the provider which will be used i.e. at the location key for ingested entities. + */ + id: string; + /** * The prefix of the target that this matches on, e.g. * "https://graph.microsoft.com/v1.0", with no trailing slash. @@ -55,7 +64,7 @@ export type MicrosoftGraphProviderConfig = { /** * The "expand" argument to apply to users. * - * E.g. "manager" + * E.g. "manager". */ userExpand?: string; /** @@ -73,7 +82,7 @@ export type MicrosoftGraphProviderConfig = { /** * The "expand" argument to apply to groups. * - * E.g. "member" + * E.g. "member". */ groupExpand?: string; /** @@ -113,6 +122,7 @@ export type MicrosoftGraphProviderConfig = { * @param config - The root of the msgraph config hierarchy * * @public + * @deprecated Replaced by not exported `readProviderConfigs` and kept for backwards compatibility only. */ export function readMicrosoftGraphConfig( config: Config, @@ -125,7 +135,7 @@ export function readMicrosoftGraphConfig( const authority = providerConfig.getOptionalString('authority') ? trimEnd(providerConfig.getOptionalString('authority'), '/') - : 'https://login.microsoftonline.com'; + : DEFAULT_AUTHORITY; const tenantId = providerConfig.getString('tenantId'); const clientId = providerConfig.getString('clientId'); const clientSecret = providerConfig.getString('clientSecret'); @@ -164,6 +174,7 @@ export function readMicrosoftGraphConfig( } providers.push({ + id: target, target, authority, tenantId, @@ -183,3 +194,86 @@ export function readMicrosoftGraphConfig( return providers; } + +export function readProviderConfigs( + config: Config, +): MicrosoftGraphProviderConfig[] { + const providersConfig = config.getOptionalConfig( + 'catalog.providers.microsoftGraphOrg', + ); + if (!providersConfig) { + return []; + } + + if (providersConfig.has('clientId')) { + // simple/single config variant + return [readProviderConfig(DEFAULT_PROVIDER_ID, providersConfig)]; + } + + return providersConfig.keys().map(id => { + const providerConfig = providersConfig.getConfig(id); + + return readProviderConfig(id, providerConfig); + }); +} + +export function readProviderConfig( + id: string, + config: Config, +): MicrosoftGraphProviderConfig { + const target = trimEnd( + config.getOptionalString('target') ?? DEFAULT_TARGET, + '/', + ); + const authority = trimEnd( + config.getOptionalString('authority') ?? DEFAULT_AUTHORITY, + '/', + ); + + const clientId = config.getString('clientId'); + const clientSecret = config.getString('clientSecret'); + const tenantId = config.getString('tenantId'); + + const userExpand = config.getOptionalString('user.expand'); + const userFilter = config.getOptionalString('user.filter'); + + const groupExpand = config.getOptionalString('group.expand'); + const groupFilter = config.getOptionalString('group.filter'); + const groupSearch = config.getOptionalString('group.search'); + const groupSelect = config.getOptionalStringArray('group.select'); + + const userGroupMemberFilter = config.getOptionalString( + 'userGroupMember.filter', + ); + const userGroupMemberSearch = config.getOptionalString( + 'userGroupMember.search', + ); + + if (userFilter && userGroupMemberFilter) { + throw new Error( + `userFilter and userGroupMemberFilter are mutually exclusive, only one can be specified.`, + ); + } + if (userFilter && userGroupMemberSearch) { + throw new Error( + `userGroupMemberSearch cannot be specified when userFilter is defined.`, + ); + } + + return { + id, + target, + authority, + clientId, + clientSecret, + tenantId, + userExpand, + userFilter, + groupExpand, + groupFilter, + groupSearch, + groupSelect, + userGroupMemberFilter, + userGroupMemberSearch, + }; +} 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 456afda550..26b4f80765 100644 --- a/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgEntityProvider.test.ts +++ b/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgEntityProvider.test.ts @@ -14,6 +14,7 @@ * limitations under the License. */ import { getVoidLogger } from '@backstage/backend-common'; +import { ConfigReader } from '@backstage/config'; import { ANNOTATION_LOCATION, ANNOTATION_ORIGIN_LOCATION, @@ -78,19 +79,30 @@ describe('MicrosoftGraphOrgEntityProvider', () => { ], }); + const config = { + catalog: { + providers: { + microsoftGraphOrg: { + customProviderId: { + target: 'target', + tenantId: 'tenantId', + clientId: 'clientId', + clientSecret: 'clientSecret', + }, + }, + }, + }, + }; const entityProviderConnection: EntityProviderConnection = { applyMutation: jest.fn(), }; - const provider = new MicrosoftGraphOrgEntityProvider({ - id: 'test', - logger: getVoidLogger(), - provider: { - target: 'https://example.com', - tenantId: 'tenant', - clientId: 'clientid', - clientSecret: 'clientsecret', + const provider = MicrosoftGraphOrgEntityProvider.fromConfig( + new ConfigReader(config), + { + logger: getVoidLogger(), + schedule: 'manual', }, - }); + )[0]; provider.connect(entityProviderConnection); @@ -104,8 +116,10 @@ describe('MicrosoftGraphOrgEntityProvider', () => { kind: 'User', metadata: { annotations: { - 'backstage.io/managed-by-location': 'msgraph:test/u1', - 'backstage.io/managed-by-origin-location': 'msgraph:test/u1', + 'backstage.io/managed-by-location': + 'msgraph:customProviderId/u1', + 'backstage.io/managed-by-origin-location': + 'msgraph:customProviderId/u1', }, name: 'u1', }, @@ -113,7 +127,7 @@ describe('MicrosoftGraphOrgEntityProvider', () => { memberOf: [], }, }, - locationKey: 'msgraph-org-provider:test', + locationKey: 'msgraph-org-provider:customProviderId', }, { entity: { @@ -121,8 +135,10 @@ describe('MicrosoftGraphOrgEntityProvider', () => { kind: 'Group', metadata: { annotations: { - 'backstage.io/managed-by-location': 'msgraph:test/g1', - 'backstage.io/managed-by-origin-location': 'msgraph:test/g1', + 'backstage.io/managed-by-location': + 'msgraph:customProviderId/g1', + 'backstage.io/managed-by-origin-location': + 'msgraph:customProviderId/g1', }, name: 'g1', }, @@ -131,7 +147,7 @@ describe('MicrosoftGraphOrgEntityProvider', () => { type: 'team', }, }, - locationKey: 'msgraph-org-provider:test', + locationKey: 'msgraph-org-provider:customProviderId', }, ], type: 'full', diff --git a/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgEntityProvider.ts b/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgEntityProvider.ts index d96faf8e03..4a52ddc665 100644 --- a/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgEntityProvider.ts +++ b/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgEntityProvider.ts @@ -40,13 +40,64 @@ import { readMicrosoftGraphOrg, UserTransformer, } from '../microsoftGraph'; +import { readProviderConfigs } from '../microsoftGraph/config'; /** * Options for {@link MicrosoftGraphOrgEntityProvider}. * * @public */ -export interface MicrosoftGraphOrgEntityProviderOptions { +export type MicrosoftGraphOrgEntityProviderOptions = + | MicrosoftGraphOrgEntityProviderLegacyOptions + | { + /** + * The logger to use. + */ + logger: Logger; + + /** + * The refresh schedule to use. + * + * @remarks + * + * If you pass in 'manual', you are responsible for calling the `read` method + * manually at some interval. + * + * But more commonly you will pass in the result of + * {@link @backstage/backend-tasks#PluginTaskScheduler.createScheduledTaskRunner} + * to enable automatic scheduling of tasks. + */ + schedule: 'manual' | TaskRunner; + + /** + * The function that transforms a user entry in msgraph to an entity. + * Optionally, you can pass separate transformers per provider ID. + */ + userTransformer?: UserTransformer | Record; + + /** + * The function that transforms a group entry in msgraph to an entity. + * Optionally, you can pass separate transformers per provider ID. + */ + groupTransformer?: GroupTransformer | Record; + + /** + * The function that transforms an organization entry in msgraph to an entity. + * Optionally, you can pass separate transformers per provider ID. + */ + organizationTransformer?: + | OrganizationTransformer + | Record; + }; + +/** + * Legacy options for {@link MicrosoftGraphOrgEntityProvider} + * based on `catalog.processors.microsoftGraphOrg`. + * + * @public + * @deprecated This interface exists for backwards compatibility only and will be removed in the future. + */ +export interface MicrosoftGraphOrgEntityProviderLegacyOptions { /** * A unique, stable identifier for this provider. * @@ -57,7 +108,7 @@ export interface MicrosoftGraphOrgEntityProviderOptions { /** * The target that this provider should consume. * - * Should exactly match the "target" field of one of the providers + * Should exactly match the "target" field of one of the provider * configuration entries. */ target: string; @@ -110,7 +161,58 @@ export class MicrosoftGraphOrgEntityProvider implements EntityProvider { static fromConfig( configRoot: Config, options: MicrosoftGraphOrgEntityProviderOptions, - ) { + ): MicrosoftGraphOrgEntityProvider[] { + if ('id' in options) { + return [ + MicrosoftGraphOrgEntityProvider.fromLegacyConfig(configRoot, options), + ]; + } + + function getTransformer( + id: string, + transformers?: T | Record, + ): T | undefined { + if (['undefined', 'function'].includes(typeof transformers)) { + return transformers as T; + } + + return (transformers as Record)[id]; + } + + return readProviderConfigs(configRoot).map(providerConfig => { + const provider = new MicrosoftGraphOrgEntityProvider({ + id: providerConfig.id, + provider: providerConfig, + logger: options.logger, + userTransformer: getTransformer( + providerConfig.id, + options.userTransformer, + ), + groupTransformer: getTransformer( + providerConfig.id, + options.groupTransformer, + ), + organizationTransformer: getTransformer( + providerConfig.id, + options.organizationTransformer, + ), + }); + provider.schedule(options.schedule); + + return provider; + }); + } + + /** + * @deprecated Exists for backwards compatibility only and will be removed in the future. + */ + private static fromLegacyConfig( + configRoot: Config, + options: MicrosoftGraphOrgEntityProviderLegacyOptions, + ): MicrosoftGraphOrgEntityProvider { + options.logger.warn( + 'Deprecated msgraph config "catalog.processors.microsoftGraphOrg" used. Use "catalog.providers.microsoftGraphOrg" instead. More info at https://github.com/backstage/backstage/blob/master/.changeset/long-bananas-rescue.md', + ); const config = configRoot.getOptionalConfig( 'catalog.processors.microsoftGraphOrg', ); diff --git a/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgReaderProcessor.test.ts b/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgReaderProcessor.test.ts index 8236dc52e1..bcf76e9482 100644 --- a/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgReaderProcessor.test.ts +++ b/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgReaderProcessor.test.ts @@ -38,6 +38,7 @@ describe('MicrosoftGraphOrgReaderProcessor', () => { processor = new MicrosoftGraphOrgReaderProcessor({ providers: [ { + id: 'https://example.com', target: 'https://example.com', tenantId: 'tenant', clientId: 'clientid', diff --git a/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgReaderProcessor.ts b/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgReaderProcessor.ts index 5d0e6b2ec7..decd84ec1f 100644 --- a/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgReaderProcessor.ts +++ b/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgReaderProcessor.ts @@ -33,9 +33,10 @@ import { } from '../microsoftGraph'; /** - * Extracts teams and users out of a the Microsoft Graph API. + * Extracts teams and users out of the Microsoft Graph API. * * @public + * @deprecated Use the MicrosoftGraphOrgEntityProvider instead. */ export class MicrosoftGraphOrgReaderProcessor implements CatalogProcessor { private readonly providers: MicrosoftGraphProviderConfig[]; @@ -67,6 +68,9 @@ export class MicrosoftGraphOrgReaderProcessor implements CatalogProcessor { groupTransformer?: GroupTransformer; organizationTransformer?: OrganizationTransformer; }) { + options.logger.warn( + 'MicrosoftGraphOrgReaderProcessor is deprecated. Please use MicrosoftGraphOrgEntityProvider instead. More info at https://github.com/backstage/backstage/blob/master/.changeset/long-bananas-rescue.md', + ); this.providers = options.providers; this.logger = options.logger; this.userTransformer = options.userTransformer; diff --git a/plugins/catalog-backend-module-msgraph/src/processors/index.ts b/plugins/catalog-backend-module-msgraph/src/processors/index.ts index 7bc3559c8b..7e74ca1d8b 100644 --- a/plugins/catalog-backend-module-msgraph/src/processors/index.ts +++ b/plugins/catalog-backend-module-msgraph/src/processors/index.ts @@ -15,5 +15,8 @@ */ export { MicrosoftGraphOrgEntityProvider } from './MicrosoftGraphOrgEntityProvider'; -export type { MicrosoftGraphOrgEntityProviderOptions } from './MicrosoftGraphOrgEntityProvider'; +export type { + MicrosoftGraphOrgEntityProviderOptions, + MicrosoftGraphOrgEntityProviderLegacyOptions, +} from './MicrosoftGraphOrgEntityProvider'; export { MicrosoftGraphOrgReaderProcessor } from './MicrosoftGraphOrgReaderProcessor'; diff --git a/plugins/catalog-backend-module-openapi/.eslintrc.js b/plugins/catalog-backend-module-openapi/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/catalog-backend-module-openapi/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/catalog-backend-module-openapi/CHANGELOG.md b/plugins/catalog-backend-module-openapi/CHANGELOG.md new file mode 100644 index 0000000000..657238efda --- /dev/null +++ b/plugins/catalog-backend-module-openapi/CHANGELOG.md @@ -0,0 +1,28 @@ +# @backstage/plugin-catalog-backend-module-openapi + +## 0.1.0-next.1 + +### Patch Changes + +- 4881dc4c84: Updated dependency `openapi-types` to `^12.0.0`. +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/backend-common@0.14.1-next.2 + - @backstage/plugin-catalog-backend@1.2.1-next.2 + - @backstage/integration@1.2.2-next.2 + +## 0.1.0-next.0 + +### Minor Changes + +- 67503d159e: Add basic OpenAPI \$ref support. + + For more information see [here](https://github.com/backstage/backstage/tree/master/plugins/catalog-backend-module-openapi). + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/plugin-catalog-backend@1.2.1-next.1 + - @backstage/integration@1.2.2-next.1 diff --git a/plugins/catalog-backend-module-openapi/README.md b/plugins/catalog-backend-module-openapi/README.md new file mode 100644 index 0000000000..1a133521c6 --- /dev/null +++ b/plugins/catalog-backend-module-openapi/README.md @@ -0,0 +1,27 @@ +# Catalog Backend Module for OpenAPI specifications + +This is an extension module to the plugin-catalog-backend plugin, providing extensions targeted at OpenAPI specifications. + +With this you can split your OpenAPI definition into multiple files and reference them. They will be bundled, using an UrlReader, during processing and stored as a single specification. + +## Installation + +### Install the package + +```bash +# From your Backstage root directory +yarn add --cwd packages/backend @backstage/plugin-catalog-backend-module-openapi +``` + +### Adding the plugin to your `packages/backend` + +The processor can be added by importing `OpenApiRefProcessor` in `src/plugins/catalog.ts` in your `backend` package and adding the following. + +```ts +builder.addProcessor( + OpenApiRefProcessor.fromConfig(env.config, { + logger: env.logger, + reader: env.reader, + }), +); +``` diff --git a/plugins/catalog-backend-module-openapi/api-report.md b/plugins/catalog-backend-module-openapi/api-report.md new file mode 100644 index 0000000000..92ddd1e3cd --- /dev/null +++ b/plugins/catalog-backend-module-openapi/api-report.md @@ -0,0 +1,36 @@ +## API Report File for "@backstage/plugin-catalog-backend-module-openapi" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { CatalogProcessor } from '@backstage/plugin-catalog-backend'; +import { Config } from '@backstage/config'; +import { Entity } from '@backstage/catalog-model'; +import { LocationSpec } from '@backstage/plugin-catalog-backend'; +import { Logger } from 'winston'; +import { ScmIntegrations } from '@backstage/integration'; +import { UrlReader } from '@backstage/backend-common'; + +// @public (undocumented) +export class OpenApiRefProcessor implements CatalogProcessor { + constructor(options: { + integrations: ScmIntegrations; + logger: Logger; + reader: UrlReader; + }); + // (undocumented) + static fromConfig( + config: Config, + options: { + logger: Logger; + reader: UrlReader; + }, + ): OpenApiRefProcessor; + // (undocumented) + getProcessorName(): string; + // (undocumented) + preProcessEntity(entity: Entity, location: LocationSpec): Promise; +} + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/catalog-backend-module-openapi/package.json b/plugins/catalog-backend-module-openapi/package.json new file mode 100644 index 0000000000..0b9c24369c --- /dev/null +++ b/plugins/catalog-backend-module-openapi/package.json @@ -0,0 +1,53 @@ +{ + "name": "@backstage/plugin-catalog-backend-module-openapi", + "description": "A Backstage catalog backend module that helps with OpenAPI specifications", + "version": "0.1.0-next.1", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "private": false, + "publishConfig": { + "access": "public", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "backend-plugin-module" + }, + "homepage": "https://backstage.io", + "repository": { + "type": "git", + "url": "https://github.com/backstage/backstage", + "directory": "plugins/catalog-backend-module-openapi" + }, + "keywords": [ + "backstage" + ], + "scripts": { + "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": { + "@apidevtools/swagger-parser": "^10.1.0", + "@backstage/backend-common": "^0.14.1-next.2", + "@backstage/catalog-model": "^1.1.0-next.2", + "@backstage/config": "^1.0.1", + "@backstage/integration": "^1.2.2-next.2", + "@backstage/plugin-catalog-backend": "^1.2.1-next.2", + "winston": "^3.2.1", + "yaml": "^2.1.1" + }, + "devDependencies": { + "@backstage/backend-test-utils": "^0.1.26-next.2", + "@backstage/cli": "^0.18.0-next.2", + "openapi-types": "^12.0.0" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/catalog-backend-module-openapi/src/OpenApiRefProcessor.test.ts b/plugins/catalog-backend-module-openapi/src/OpenApiRefProcessor.test.ts new file mode 100644 index 0000000000..8f2cc571c2 --- /dev/null +++ b/plugins/catalog-backend-module-openapi/src/OpenApiRefProcessor.test.ts @@ -0,0 +1,101 @@ +/* + * 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 { getVoidLogger } from '@backstage/backend-common'; +import { ConfigReader } from '@backstage/config'; +import { LocationSpec } from '@backstage/plugin-catalog-backend'; +import { OpenApiRefProcessor } from './OpenApiRefProcessor'; +import { bundleOpenApiSpecification } from './lib'; + +jest.mock('./lib', () => ({ + bundleOpenApiSpecification: jest.fn(), +})); + +const bundledSpecification = ''; + +describe('OpenApiRefProcessor', () => { + const mockLocation = (): LocationSpec => ({ + type: 'url', + target: `https://github.com/owner/repo/blob/main/catalog-info.yaml`, + }); + + beforeEach(() => { + (bundleOpenApiSpecification as any).mockResolvedValue(bundledSpecification); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + describe('preProcessEntity', () => { + const setupTest = ({ kind = 'API', spec = {} } = {}) => { + const entity = { + kind, + spec: { definition: '', ...spec }, + }; + const config = new ConfigReader({}); + const reader = { + read: jest.fn(), + readTree: jest.fn(), + search: jest.fn(), + }; + const processor = OpenApiRefProcessor.fromConfig(config, { + logger: getVoidLogger(), + reader, + }); + + return { entity, processor }; + }; + + it('should bundle OpenAPI specifications', async () => { + const { entity, processor } = setupTest({ + kind: 'API', + spec: { type: 'openapi' }, + }); + + const result = await processor.preProcessEntity( + entity as any, + mockLocation(), + ); + + expect(result.spec?.definition).toEqual(bundledSpecification); + }); + + it('should ignore other kinds', async () => { + const { entity, processor } = setupTest({ kind: 'Group' }); + + const result = await processor.preProcessEntity( + entity as any, + mockLocation(), + ); + + expect(result).toEqual(entity); + }); + + it('should ignore other specification types', async () => { + const { entity, processor } = setupTest({ + kind: 'Group', + spec: { type: 'asyncapi' }, + }); + + const result = await processor.preProcessEntity( + entity as any, + mockLocation(), + ); + + expect(result).toEqual(entity); + }); + }); +}); diff --git a/plugins/catalog-backend-module-openapi/src/OpenApiRefProcessor.ts b/plugins/catalog-backend-module-openapi/src/OpenApiRefProcessor.ts new file mode 100644 index 0000000000..01875e0779 --- /dev/null +++ b/plugins/catalog-backend-module-openapi/src/OpenApiRefProcessor.ts @@ -0,0 +1,94 @@ +/* + * 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 { UrlReader } from '@backstage/backend-common'; +import { Entity } from '@backstage/catalog-model'; +import { Config } from '@backstage/config'; +import { ScmIntegrations } from '@backstage/integration'; +import { + CatalogProcessor, + LocationSpec, +} from '@backstage/plugin-catalog-backend'; +import { bundleOpenApiSpecification } from './lib'; +import { Logger } from 'winston'; + +/** @public */ +export class OpenApiRefProcessor implements CatalogProcessor { + private readonly integrations: ScmIntegrations; + private readonly logger: Logger; + private readonly reader: UrlReader; + + static fromConfig( + config: Config, + options: { logger: Logger; reader: UrlReader }, + ) { + const integrations = ScmIntegrations.fromConfig(config); + + return new OpenApiRefProcessor({ + ...options, + integrations, + }); + } + + constructor(options: { + integrations: ScmIntegrations; + logger: Logger; + reader: UrlReader; + }) { + this.integrations = options.integrations; + this.logger = options.logger; + this.reader = options.reader; + } + + getProcessorName(): string { + return 'OpenApiRefProcessor'; + } + + async preProcessEntity( + entity: Entity, + location: LocationSpec, + ): Promise { + if ( + !entity || + entity.kind !== 'API' || + (entity.spec && entity.spec.type !== 'openapi') + ) { + return entity; + } + + const scmIntegration = this.integrations.byUrl(location.target); + if (!scmIntegration) { + return entity; + } + + this.logger.debug(`Bundling OpenAPI specification from ${location.target}`); + try { + const bundledSpec = await bundleOpenApiSpecification( + entity.spec!.definition?.toString(), + location.target, + this.reader, + scmIntegration, + ); + + return { + ...entity, + spec: { ...entity.spec, definition: bundledSpec }, + }; + } catch (error) { + this.logger.error(`Unable to bundle OpenAPI specification`, error); + return entity; + } + } +} diff --git a/plugins/catalog-backend-module-openapi/src/index.ts b/plugins/catalog-backend-module-openapi/src/index.ts new file mode 100644 index 0000000000..f98bee6bac --- /dev/null +++ b/plugins/catalog-backend-module-openapi/src/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { OpenApiRefProcessor } from './OpenApiRefProcessor'; diff --git a/plugins/catalog-backend-module-openapi/src/lib/bundle.test.ts b/plugins/catalog-backend-module-openapi/src/lib/bundle.test.ts new file mode 100644 index 0000000000..4505f158b5 --- /dev/null +++ b/plugins/catalog-backend-module-openapi/src/lib/bundle.test.ts @@ -0,0 +1,117 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { ConfigReader } from '@backstage/config'; +import { ScmIntegrations } from '@backstage/integration'; +import { bundleOpenApiSpecification } from './bundle'; + +const specification = ` +openapi: "3.0.0" +info: + version: 1.0.0 + title: Swagger Petstore + license: + name: MIT +servers: + - url: http://petstore.swagger.io/v1 +paths: + /pets: + get: + $ref: "./paths/pets/list.yaml" +`; + +const list = ` +--- +summary: List all pets +operationId: listPets +tags: + - pets +responses: + '200': + description: A paged array of pets + content: + application/json: + schema: + type: string +`; + +const expectedResult = ` +openapi: 3.0.0 +info: + version: 1.0.0 + title: Swagger Petstore + license: + name: MIT +servers: + - url: http://petstore.swagger.io/v1 +paths: + /pets: + get: + summary: List all pets + operationId: listPets + tags: + - pets + responses: + "200": + description: A paged array of pets + content: + application/json: + schema: + type: string +`; + +describe('bundleOpenApiSpecification', () => { + const readUrl = jest.fn(); + const reader = { + readUrl, + read: jest.fn(), + readTree: jest.fn(), + search: jest.fn(), + }; + + const scmIntegration = ScmIntegrations.fromConfig(new ConfigReader({})).byUrl( + 'https://github.com/owner/repo/blob/main/openapi.yaml', + ); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should return undefined if no specification is supplied', async () => { + expect( + await bundleOpenApiSpecification( + undefined, + 'https://github.com/owner/repo/blob/main/openapi.yaml', + reader, + scmIntegration as any, + ), + ).toBeUndefined(); + }); + + it('should return the bundled specification', async () => { + readUrl.mockResolvedValue({ + buffer: jest.fn().mockResolvedValue(list), + }); + + const result = await bundleOpenApiSpecification( + specification, + 'https://github.com/owner/repo/blob/main/openapi.yaml', + reader, + scmIntegration as any, + ); + + expect(result).toEqual(expectedResult.trimStart()); + }); +}); diff --git a/plugins/catalog-backend-module-openapi/src/lib/bundle.ts b/plugins/catalog-backend-module-openapi/src/lib/bundle.ts new file mode 100644 index 0000000000..3d35429d8b --- /dev/null +++ b/plugins/catalog-backend-module-openapi/src/lib/bundle.ts @@ -0,0 +1,69 @@ +/* + * 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 { UrlReader } from '@backstage/backend-common'; +import { ScmIntegration } from '@backstage/integration'; +import SwaggerParser from '@apidevtools/swagger-parser'; +import { parse, stringify } from 'yaml'; +import * as path from 'path'; + +const protocolPattern = /^(\w{2,}):\/\//i; +const getProtocol = (refPath: string) => { + const match = protocolPattern.exec(refPath); + if (match) { + return match[1].toLowerCase(); + } + return undefined; +}; + +export async function bundleOpenApiSpecification( + specification: string | undefined, + targetUrl: string, + reader: UrlReader, + scmIntegration: ScmIntegration, +): Promise { + const fileUrlReaderResolver: SwaggerParser.ResolverOptions = { + canRead: file => { + const protocol = getProtocol(file.url); + return protocol === undefined || protocol === 'file'; + }, + read: async file => { + const relativePath = path.relative('.', file.url); + const url = scmIntegration.resolveUrl({ + base: targetUrl, + url: relativePath, + }); + if (reader.readUrl) { + const data = await reader.readUrl(url); + return data.buffer(); + } + throw new Error('UrlReader has no readUrl method defined'); + }, + }; + + if (!specification) { + return undefined; + } + + const options: SwaggerParser.Options = { + resolve: { + file: fileUrlReaderResolver, + http: true, + }, + }; + const specObject = parse(specification); + const bundledSpec = await SwaggerParser.bundle(specObject, options); + return stringify(bundledSpec); +} diff --git a/plugins/catalog-backend-module-openapi/src/lib/index.ts b/plugins/catalog-backend-module-openapi/src/lib/index.ts new file mode 100644 index 0000000000..805569181a --- /dev/null +++ b/plugins/catalog-backend-module-openapi/src/lib/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export * from './bundle'; diff --git a/packages/cli/src/commands/backend/build.ts b/plugins/catalog-backend-module-openapi/src/setupTests.ts similarity index 66% rename from packages/cli/src/commands/backend/build.ts rename to plugins/catalog-backend-module-openapi/src/setupTests.ts index c85eecfed3..d3232290a7 100644 --- a/packages/cli/src/commands/backend/build.ts +++ b/plugins/catalog-backend-module-openapi/src/setupTests.ts @@ -14,13 +14,4 @@ * limitations under the License. */ -import { OptionValues } from 'commander'; -import { buildPackage, Output } from '../../lib/builder'; - -export default async (opts: OptionValues) => { - await buildPackage({ - outputs: new Set([Output.cjs, Output.types]), - minify: opts.minify, - useApiExtractor: opts.experimentalTypeBuild, - }); -}; +export {}; diff --git a/plugins/catalog-backend/CHANGELOG.md b/plugins/catalog-backend/CHANGELOG.md index f235285617..a228308681 100644 --- a/plugins/catalog-backend/CHANGELOG.md +++ b/plugins/catalog-backend/CHANGELOG.md @@ -1,5 +1,52 @@ # @backstage/plugin-catalog-backend +## 1.2.1-next.2 + +### Patch Changes + +- 679b32172e: Updated dependency `knex` to `^2.0.0`. +- e2d7b76f43: Upgrade git-url-parse to 12.0.0. + + Motivation for upgrade is transitively upgrading parse-url which is vulnerable + to several CVEs detected by Snyk. + + - SNYK-JS-PARSEURL-2935944 + - SNYK-JS-PARSEURL-2935947 + - SNYK-JS-PARSEURL-2936249 + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/backend-common@0.14.1-next.2 + - @backstage/integration@1.2.2-next.2 + +## 1.2.1-next.1 + +### Patch Changes + +- f1dcc6f3c6: Use entity type predicates from catalog-model +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/catalog-client@1.0.4-next.1 + - @backstage/integration@1.2.2-next.1 + - @backstage/plugin-catalog-common@1.0.4-next.0 + - @backstage/plugin-permission-common@0.6.3-next.0 + - @backstage/plugin-permission-node@0.6.3-next.1 + - @backstage/plugin-search-common@0.3.6-next.0 + +## 1.2.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/plugin-permission-node@0.6.3-next.0 + - @backstage/catalog-client@1.0.4-next.0 + - @backstage/plugin-scaffolder-common@1.1.2-next.0 + ## 1.2.0 ### Minor Changes diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index c33dccd8a7..ebed76ca90 100644 --- a/plugins/catalog-backend/package.json +++ b/plugins/catalog-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend", "description": "The Backstage backend plugin that provides the Backstage catalog", - "version": "1.2.0", + "version": "1.2.1-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,17 +34,17 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", - "@backstage/catalog-client": "^1.0.3", - "@backstage/catalog-model": "^1.0.3", + "@backstage/backend-common": "^0.14.1-next.2", + "@backstage/catalog-client": "^1.0.4-next.1", + "@backstage/catalog-model": "^1.1.0-next.2", "@backstage/config": "^1.0.1", - "@backstage/errors": "^1.0.0", - "@backstage/integration": "^1.2.1", - "@backstage/plugin-catalog-common": "^1.0.3", - "@backstage/plugin-permission-common": "^0.6.2", - "@backstage/plugin-permission-node": "^0.6.2", - "@backstage/plugin-scaffolder-common": "^1.1.1", - "@backstage/plugin-search-common": "^0.3.5", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/integration": "^1.2.2-next.2", + "@backstage/plugin-catalog-common": "^1.0.4-next.0", + "@backstage/plugin-permission-common": "^0.6.3-next.0", + "@backstage/plugin-permission-node": "^0.6.3-next.1", + "@backstage/plugin-scaffolder-common": "^1.1.2-next.0", + "@backstage/plugin-search-common": "^0.3.6-next.0", "@backstage/types": "^1.0.0", "@types/express": "^4.17.6", "codeowners-utils": "^1.0.2", @@ -53,9 +53,9 @@ "express-promise-router": "^4.1.0", "fast-json-stable-stringify": "^2.1.0", "fs-extra": "10.1.0", - "git-url-parse": "^11.6.0", + "git-url-parse": "^12.0.0", "glob": "^7.1.6", - "knex": "^1.0.2", + "knex": "^2.0.0", "lodash": "^4.17.21", "luxon": "^2.0.2", "node-fetch": "^2.6.7", @@ -68,17 +68,17 @@ "zod": "^3.11.6" }, "devDependencies": { - "@backstage/backend-test-utils": "^0.1.25", - "@backstage/cli": "^0.17.2", - "@backstage/plugin-permission-common": "^0.6.2", - "@backstage/plugin-search-backend-node": "0.6.2", + "@backstage/backend-test-utils": "^0.1.26-next.2", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/plugin-permission-common": "^0.6.3-next.0", + "@backstage/plugin-search-backend-node": "0.6.3-next.1", "@types/core-js": "^2.5.4", "@types/git-url-parse": "^9.0.0", "@types/lodash": "^4.14.151", "@types/supertest": "^2.0.8", "@types/uuid": "^8.0.0", "better-sqlite3": "^7.5.0", - "msw": "^0.42.0", + "msw": "^0.43.0", "supertest": "^6.1.3", "wait-for-expect": "^3.0.2", "luxon": "^2.0.2" diff --git a/plugins/catalog-backend/src/search/DefaultCatalogCollator.ts b/plugins/catalog-backend/src/search/DefaultCatalogCollator.ts index f895ded85e..70ec0ee948 100644 --- a/plugins/catalog-backend/src/search/DefaultCatalogCollator.ts +++ b/plugins/catalog-backend/src/search/DefaultCatalogCollator.ts @@ -20,8 +20,8 @@ import { } from '@backstage/backend-common'; import { Entity, + isUserEntity, stringifyEntityRef, - UserEntity, } from '@backstage/catalog-model'; import { Config } from '@backstage/config'; import { @@ -93,13 +93,9 @@ export class DefaultCatalogCollator { return formatted.toLowerCase(); } - private isUserEntity(entity: Entity): entity is UserEntity { - return entity.kind.toLocaleUpperCase('en-US') === 'USER'; - } - private getDocumentText(entity: Entity): string { let documentText = entity.metadata.description || ''; - if (this.isUserEntity(entity)) { + if (isUserEntity(entity)) { if (entity.spec?.profile?.displayName && documentText) { // combine displayName and description const displayName = entity.spec?.profile?.displayName; diff --git a/plugins/catalog-backend/src/search/util.ts b/plugins/catalog-backend/src/search/util.ts index b5df2a28a7..fd54d397c9 100644 --- a/plugins/catalog-backend/src/search/util.ts +++ b/plugins/catalog-backend/src/search/util.ts @@ -14,15 +14,7 @@ * limitations under the License. */ -import { Entity, UserEntity, GroupEntity } from '@backstage/catalog-model'; - -function isUserEntity(entity: Entity): entity is UserEntity { - return entity.kind.toLocaleUpperCase('en-US') === 'USER'; -} - -function isGroupEntity(entity: Entity): entity is GroupEntity { - return entity.kind.toLocaleUpperCase('en-US') === 'GROUP'; -} +import { Entity, isUserEntity, isGroupEntity } from '@backstage/catalog-model'; export function getDocumentText(entity: Entity): string { const documentTexts: string[] = []; diff --git a/plugins/catalog-common/CHANGELOG.md b/plugins/catalog-common/CHANGELOG.md index 72002894c4..7fa70e5859 100644 --- a/plugins/catalog-common/CHANGELOG.md +++ b/plugins/catalog-common/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-catalog-common +## 1.0.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.6.3-next.0 + - @backstage/plugin-search-common@0.3.6-next.0 + ## 1.0.3 ### Patch Changes diff --git a/plugins/catalog-common/package.json b/plugins/catalog-common/package.json index 27e7764812..82c0d72855 100644 --- a/plugins/catalog-common/package.json +++ b/plugins/catalog-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-common", "description": "Common functionalities for the catalog plugin", - "version": "1.0.3", + "version": "1.0.4-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,11 +34,11 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/plugin-permission-common": "^0.6.2", - "@backstage/plugin-search-common": "^0.3.5" + "@backstage/plugin-permission-common": "^0.6.3-next.0", + "@backstage/plugin-search-common": "^0.3.6-next.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2" + "@backstage/cli": "^0.18.0-next.1" }, "files": [ "dist", diff --git a/plugins/catalog-graph/CHANGELOG.md b/plugins/catalog-graph/CHANGELOG.md index 2afbca45c5..f497b35628 100644 --- a/plugins/catalog-graph/CHANGELOG.md +++ b/plugins/catalog-graph/CHANGELOG.md @@ -1,5 +1,36 @@ # @backstage/plugin-catalog-graph +## 0.2.19-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## 0.2.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/catalog-client@1.0.4-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## 0.2.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/catalog-client@1.0.4-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + ## 0.2.18 ### Patch Changes diff --git a/plugins/catalog-graph/package.json b/plugins/catalog-graph/package.json index 508453b387..c61d388f0b 100644 --- a/plugins/catalog-graph/package.json +++ b/plugins/catalog-graph/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-graph", - "version": "0.2.18", + "version": "0.2.19-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -24,12 +24,12 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-client": "^1.0.3", - "@backstage/catalog-model": "^1.0.3", - "@backstage/core-components": "^0.9.5", + "@backstage/catalog-client": "^1.0.4-next.1", + "@backstage/catalog-model": "^1.1.0-next.2", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/plugin-catalog-react": "^1.1.1", - "@backstage/theme": "^0.2.15", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -45,11 +45,11 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/plugin-catalog": "^1.3.0", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/plugin-catalog": "^1.4.0-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@backstage/types": "^1.0.0", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", diff --git a/plugins/catalog-graphql/CHANGELOG.md b/plugins/catalog-graphql/CHANGELOG.md index b7c6aa5723..16f0bb50d9 100644 --- a/plugins/catalog-graphql/CHANGELOG.md +++ b/plugins/catalog-graphql/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-catalog-graphql +## 0.3.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + ## 0.3.10 ### Patch Changes diff --git a/plugins/catalog-graphql/package.json b/plugins/catalog-graphql/package.json index 3e631906a6..81b31ffe51 100644 --- a/plugins/catalog-graphql/package.json +++ b/plugins/catalog-graphql/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-graphql", "description": "An experimental Backstage catalog GraphQL module", - "version": "0.3.10", + "version": "0.3.11-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,7 +34,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", + "@backstage/catalog-model": "^1.1.0-next.1", "@backstage/config": "^1.0.1", "@backstage/types": "^1.0.0", "apollo-server": "^3.0.0", @@ -46,14 +46,14 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.1", + "@backstage/test-utils": "^1.1.2-next.1", "@graphql-codegen/cli": "^2.3.1", "@graphql-codegen/graphql-modules-preset": "^2.3.2", "@graphql-codegen/typescript": "^2.4.2", "@graphql-codegen/typescript-resolvers": "^2.4.3", "@graphql-tools/schema": "^8.3.1", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/catalog-import/CHANGELOG.md b/plugins/catalog-import/CHANGELOG.md index 5ee8857f18..7de1bd72d0 100644 --- a/plugins/catalog-import/CHANGELOG.md +++ b/plugins/catalog-import/CHANGELOG.md @@ -1,5 +1,51 @@ # @backstage/plugin-catalog-import +## 0.8.10-next.2 + +### Patch Changes + +- e2d7b76f43: Upgrade git-url-parse to 12.0.0. + + Motivation for upgrade is transitively upgrading parse-url which is vulnerable + to several CVEs detected by Snyk. + + - SNYK-JS-PARSEURL-2935944 + - SNYK-JS-PARSEURL-2935947 + - SNYK-JS-PARSEURL-2936249 + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/integration@1.2.2-next.2 + - @backstage/plugin-catalog-react@1.1.2-next.2 + - @backstage/integration-react@1.1.2-next.2 + +## 0.8.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/catalog-client@1.0.4-next.1 + - @backstage/integration@1.2.2-next.1 + - @backstage/integration-react@1.1.2-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## 0.8.10-next.0 + +### Patch Changes + +- 272106fdad: Support use without `integrations` or only integrations without frontend visible properties (e.g., `bitbucketCloud`) being configured by checking `integrations.github` directly without attempting to load `integrations`. +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/catalog-client@1.0.4-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + - @backstage/integration-react@1.1.2-next.0 + ## 0.8.9 ### Patch Changes diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json index 0c72baaf9f..042e85f792 100644 --- a/plugins/catalog-import/package.json +++ b/plugins/catalog-import/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-import", "description": "A Backstage plugin the helps you import entities into your catalog", - "version": "0.8.9", + "version": "0.8.10-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,20 +34,20 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-client": "^1.0.3", - "@backstage/catalog-model": "^1.0.3", + "@backstage/catalog-client": "^1.0.4-next.1", + "@backstage/catalog-model": "^1.1.0-next.2", "@backstage/config": "^1.0.1", - "@backstage/core-components": "^0.9.5", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/errors": "^1.0.0", - "@backstage/integration": "^1.2.1", - "@backstage/integration-react": "^1.1.1", - "@backstage/plugin-catalog-react": "^1.1.1", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/integration": "^1.2.2-next.2", + "@backstage/integration-react": "^1.1.2-next.2", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", "@octokit/rest": "^18.5.3", - "git-url-parse": "^11.6.0", + "git-url-parse": "^12.0.0", "js-base64": "^3.6.0", "lodash": "^4.17.21", "react-hook-form": "^7.12.2", @@ -60,17 +60,17 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/react-hooks": "^8.0.0", "@testing-library/user-event": "^14.0.0", "@types/jest": "^26.0.7", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist", diff --git a/plugins/catalog-import/src/components/ImportInfoCard/ImportInfoCard.tsx b/plugins/catalog-import/src/components/ImportInfoCard/ImportInfoCard.tsx index 7fa6b13a82..4779e2d64b 100644 --- a/plugins/catalog-import/src/components/ImportInfoCard/ImportInfoCard.tsx +++ b/plugins/catalog-import/src/components/ImportInfoCard/ImportInfoCard.tsx @@ -46,8 +46,7 @@ export const ImportInfoCard = (props: ImportInfoCardProps) => { const appTitle = configApi.getOptional('app.title') || 'Backstage'; const catalogImportApi = useApi(catalogImportApiRef); - const integrations = configApi.getConfig('integrations'); - const hasGithubIntegration = integrations.has('github'); + const hasGithubIntegration = configApi.has('integrations.github'); const catalogFilename = useCatalogFilename(); diff --git a/plugins/catalog-react/CHANGELOG.md b/plugins/catalog-react/CHANGELOG.md index ba7f7deb6d..0df99a1bb9 100644 --- a/plugins/catalog-react/CHANGELOG.md +++ b/plugins/catalog-react/CHANGELOG.md @@ -1,5 +1,79 @@ # @backstage/plugin-catalog-react +## 1.1.2-next.2 + +### Patch Changes + +- be26d95141: Added new `EntityProcessingStatusPicker` that will filter for entities with orphans and/or errors. + + If you are using the default Catalog page this picker will be added automatically. For those who have customized their Catalog page you'll need to add this manually by doing something like this: + + ```diff + ... + import { + CatalogFilterLayout, + EntityTypePicker, + UserListPicker, + EntityTagPicker + + EntityProcessingStatusPicker, + } from '@backstage/plugin-catalog-react'; + ... + export const CustomCatalogPage = ({ + columns, + actions, + initiallySelectedFilter = 'owned', + }: CatalogPageProps) => { + return ( + ... + + + + + + ... + }; + ``` + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/integration@1.2.2-next.2 + +## 1.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + - @backstage/catalog-client@1.0.4-next.1 + - @backstage/integration@1.2.2-next.1 + - @backstage/plugin-catalog-common@1.0.4-next.0 + - @backstage/plugin-permission-common@0.6.3-next.0 + - @backstage/plugin-permission-react@0.4.3-next.0 + +## 1.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/catalog-client@1.0.4-next.0 + ## 1.1.1 ### Patch Changes diff --git a/plugins/catalog-react/api-report.md b/plugins/catalog-react/api-report.md index 285ecafd70..5232c49150 100644 --- a/plugins/catalog-react/api-report.md +++ b/plugins/catalog-react/api-report.md @@ -78,6 +78,7 @@ export type CatalogReactComponentsNameToClassKey = { CatalogReactEntitySearchBar: CatalogReactEntitySearchBarClassKey; CatalogReactEntityTagPicker: CatalogReactEntityTagPickerClassKey; CatalogReactEntityOwnerPicker: CatalogReactEntityOwnerPickerClassKey; + CatalogReactEntityProcessingStatusPicker: CatalogReactEntityProcessingStatusPickerClassKey; }; // @public (undocumented) @@ -86,6 +87,9 @@ export type CatalogReactEntityLifecyclePickerClassKey = 'input'; // @public (undocumented) export type CatalogReactEntityOwnerPickerClassKey = 'input'; +// @public (undocumented) +export type CatalogReactEntityProcessingStatusPickerClassKey = 'input'; + // @public (undocumented) export type CatalogReactEntitySearchBarClassKey = 'searchToolbar' | 'input'; @@ -137,8 +141,19 @@ export type DefaultEntityFilters = { lifecycles?: EntityLifecycleFilter; tags?: EntityTagFilter; text?: EntityTextFilter; + orphan?: EntityOrphanFilter; + error?: EntityErrorFilter; }; +// @public +export class EntityErrorFilter implements EntityFilter { + constructor(value: boolean); + // (undocumented) + filterEntity(entity: Entity): boolean; + // (undocumented) + readonly value: boolean; +} + // @public (undocumented) export type EntityFilter = { getCatalogFilters?: () => Record< @@ -222,6 +237,15 @@ export type EntityLoadingStatus = { refresh?: VoidFunction; }; +// @public +export class EntityOrphanFilter implements EntityFilter { + constructor(value: boolean); + // (undocumented) + filterEntity(entity: Entity): boolean; + // (undocumented) + readonly value: boolean; +} + // @public export class EntityOwnerFilter implements EntityFilter { constructor(values: string[]); @@ -236,6 +260,9 @@ export class EntityOwnerFilter implements EntityFilter { // @public (undocumented) export const EntityOwnerPicker: () => JSX.Element | null; +// @public (undocumented) +export const EntityProcessingStatusPicker: () => JSX.Element; + // @public export const EntityProvider: (props: EntityProviderProps) => JSX.Element; diff --git a/plugins/catalog-react/package.json b/plugins/catalog-react/package.json index 47e99f23d8..3f3ee5f402 100644 --- a/plugins/catalog-react/package.json +++ b/plugins/catalog-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-react", "description": "A frontend library that helps other Backstage plugins interact with the catalog", - "version": "1.1.1", + "version": "1.1.2-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,16 +34,16 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/catalog-client": "^1.0.3", - "@backstage/catalog-model": "^1.0.3", - "@backstage/core-components": "^0.9.5", + "@backstage/catalog-client": "^1.0.4-next.1", + "@backstage/catalog-model": "^1.1.0-next.2", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/errors": "^1.0.0", - "@backstage/integration": "^1.2.1", - "@backstage/plugin-catalog-common": "^1.0.3", - "@backstage/plugin-permission-common": "^0.6.2", - "@backstage/plugin-permission-react": "^0.4.2", - "@backstage/theme": "^0.2.15", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/integration": "^1.2.2-next.2", + "@backstage/plugin-catalog-common": "^1.0.4-next.0", + "@backstage/plugin-permission-common": "^0.6.3-next.0", + "@backstage/plugin-permission-react": "^0.4.3-next.0", + "@backstage/theme": "^0.2.16-next.1", "@backstage/types": "^1.0.0", "@backstage/version-bridge": "^1.0.1", "@material-ui/core": "^4.12.2", @@ -63,11 +63,11 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/plugin-catalog-common": "^1.0.3", - "@backstage/plugin-scaffolder-common": "^1.1.1", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/plugin-catalog-common": "^1.0.4-next.0", + "@backstage/plugin-scaffolder-common": "^1.1.2-next.0", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/react-hooks": "^8.0.0", diff --git a/plugins/catalog-react/src/components/EntityProcessingStatusPicker/EntityProcessingStatusPicker.test.tsx b/plugins/catalog-react/src/components/EntityProcessingStatusPicker/EntityProcessingStatusPicker.test.tsx new file mode 100644 index 0000000000..8e90e04148 --- /dev/null +++ b/plugins/catalog-react/src/components/EntityProcessingStatusPicker/EntityProcessingStatusPicker.test.tsx @@ -0,0 +1,152 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Entity } from '@backstage/catalog-model'; +import { fireEvent, render } from '@testing-library/react'; +import React from 'react'; +import { EntityErrorFilter, EntityOrphanFilter } from '../../filters'; +import { MockEntityListContextProvider } from '../../testUtils/providers'; +import { EntityProcessingStatusPicker } from './EntityProcessingStatusPicker'; + +const orphanAnnotation: Record = {}; +orphanAnnotation['backstage.io/orphan'] = 'true'; + +const sampleEntities: Entity[] = [ + { + apiVersion: '1', + kind: 'Component', + metadata: { + name: 'valid-component', + }, + }, + { + apiVersion: '1', + kind: 'Component', + metadata: { + name: 'orphan-component', + annotations: orphanAnnotation, + }, + }, + { + apiVersion: '1', + kind: 'Component', + metadata: { + name: 'error-component', + tags: ['Invalid Tag'], + }, + }, +]; + +describe('', () => { + it('renders all processing status options', () => { + const rendered = render( + + + , + ); + expect(rendered.getByText('Processing Status')).toBeInTheDocument(); + + fireEvent.click(rendered.getByTestId('processing-status-picker-expand')); + expect(rendered.getByText('Is Orphan')).toBeInTheDocument(); + expect(rendered.getByText('Has Error')).toBeInTheDocument(); + }); + + it('adds orphan to orphan filter', () => { + const updateFilters = jest.fn(); + const rendered = render( + + + , + ); + + fireEvent.click(rendered.getByTestId('processing-status-picker-expand')); + fireEvent.click(rendered.getByText('Is Orphan')); + expect(updateFilters).toHaveBeenCalledWith({ + orphan: new EntityOrphanFilter(true), + }); + }); + + it('adds error to error filter', () => { + const updateFilters = jest.fn(); + const rendered = render( + + + , + ); + + fireEvent.click(rendered.getByTestId('processing-status-picker-expand')); + fireEvent.click(rendered.getByText('Has Error')); + expect(updateFilters).toHaveBeenCalledWith({ + error: new EntityErrorFilter(true), + }); + }); + + it('remove orphan from orphan filter', () => { + const updateFilters = jest.fn(); + const rendered = render( + + + , + ); + + fireEvent.click(rendered.getByTestId('processing-status-picker-expand')); + fireEvent.click(rendered.getByText('Is Orphan')); + expect(updateFilters).toHaveBeenCalledWith({ + orphan: undefined, + }); + }); + + it('remove error from error filter', () => { + const updateFilters = jest.fn(); + const rendered = render( + + + , + ); + + fireEvent.click(rendered.getByTestId('processing-status-picker-expand')); + fireEvent.click(rendered.getByText('Has Error')); + expect(updateFilters).toHaveBeenCalledWith({ + error: undefined, + }); + }); +}); diff --git a/plugins/catalog-react/src/components/EntityProcessingStatusPicker/EntityProcessingStatusPicker.tsx b/plugins/catalog-react/src/components/EntityProcessingStatusPicker/EntityProcessingStatusPicker.tsx new file mode 100644 index 0000000000..3fe3b60e25 --- /dev/null +++ b/plugins/catalog-react/src/components/EntityProcessingStatusPicker/EntityProcessingStatusPicker.tsx @@ -0,0 +1,111 @@ +/* + * 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 { EntityErrorFilter, EntityOrphanFilter } from '../../filters'; +import { + Box, + Checkbox, + FormControlLabel, + makeStyles, + TextField, + Typography, +} from '@material-ui/core'; +import CheckBoxIcon from '@material-ui/icons/CheckBox'; +import CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank'; +import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; +import React, { useState } from 'react'; +import { useEntityList } from '../../hooks'; +import { Autocomplete } from '@material-ui/lab'; + +/** @public */ +export type CatalogReactEntityProcessingStatusPickerClassKey = 'input'; + +const useStyles = makeStyles( + { + input: {}, + }, + { + name: 'CatalogReactEntityProcessingStatusPickerPicker', + }, +); + +const icon = ; +const checkedIcon = ; + +/** @public */ +export const EntityProcessingStatusPicker = () => { + const classes = useStyles(); + const { updateFilters } = useEntityList(); + + const [selectedAdvancedItems, setSelectedAdvancedItems] = useState( + [], + ); + + function orphanChange(value: boolean) { + updateFilters({ + orphan: value ? new EntityOrphanFilter(value) : undefined, + }); + } + + function errorChange(value: boolean) { + updateFilters({ + error: value ? new EntityErrorFilter(value) : undefined, + }); + } + + const availableAdvancedItems = ['Is Orphan', 'Has Error']; + + return ( + + + Processing Status + { + setSelectedAdvancedItems(value); + orphanChange(value.includes('Is Orphan')); + errorChange(value.includes('Has Error')); + }} + renderOption={(option, { selected }) => ( + + } + label={option} + /> + )} + size="small" + popupIcon={ + + } + renderInput={params => ( + + )} + /> + + + ); +}; diff --git a/plugins/catalog-react/src/components/EntityProcessingStatusPicker/index.ts b/plugins/catalog-react/src/components/EntityProcessingStatusPicker/index.ts new file mode 100644 index 0000000000..55daeaecc0 --- /dev/null +++ b/plugins/catalog-react/src/components/EntityProcessingStatusPicker/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { EntityProcessingStatusPicker as EntityProcessingStatusPicker } from './EntityProcessingStatusPicker'; +export type { CatalogReactEntityProcessingStatusPickerClassKey } from './EntityProcessingStatusPicker'; diff --git a/plugins/catalog-react/src/components/index.ts b/plugins/catalog-react/src/components/index.ts index 7a26a72bf9..c604306ead 100644 --- a/plugins/catalog-react/src/components/index.ts +++ b/plugins/catalog-react/src/components/index.ts @@ -27,3 +27,4 @@ export * from './FavoriteEntity'; export * from './InspectEntityDialog'; export * from './UnregisterEntityDialog'; export * from './UserListPicker'; +export * from './EntityProcessingStatusPicker'; diff --git a/plugins/catalog-react/src/filters.test.ts b/plugins/catalog-react/src/filters.test.ts index ba31e21122..c2c92e033e 100644 --- a/plugins/catalog-react/src/filters.test.ts +++ b/plugins/catalog-react/src/filters.test.ts @@ -14,9 +14,13 @@ * limitations under the License. */ -import { Entity } from '@backstage/catalog-model'; +import { AlphaEntity, Entity } from '@backstage/catalog-model'; import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; -import { EntityTextFilter } from './filters'; +import { + EntityErrorFilter, + EntityOrphanFilter, + EntityTextFilter, +} from './filters'; const entities: Entity[] = [ { @@ -91,3 +95,50 @@ describe('EntityTextFilter', () => { expect(filter.filterEntity(entities[1])).toBeTruthy(); }); }); + +describe('EntityOrphanFilter', () => { + const orphanAnnotation: Record = {}; + orphanAnnotation['backstage.io/orphan'] = 'true'; + + const orphan: Entity = { + apiVersion: '1', + kind: 'Component', + metadata: { + name: 'orphaned-service', + annotations: orphanAnnotation, + }, + }; + + it('should find orphans', () => { + const filter = new EntityOrphanFilter(true); + expect(filter.filterEntity(orphan)).toBeTruthy(); + expect(filter.filterEntity(entities[1])).toBeFalsy(); + }); +}); + +describe('EntityErrorFilter', () => { + const error: AlphaEntity = { + apiVersion: '1', + kind: 'Component', + metadata: { + name: 'service-with-error', + tags: ['Invalid Tag'], + }, + status: { + items: [ + { + type: 'invalid-tag', + level: 'error', + message: 'Tag is not valid', + error: undefined, + }, + ], + }, + }; + + it('should find errors', () => { + const filter = new EntityErrorFilter(true); + expect(filter.filterEntity(error)).toBeTruthy(); + expect(filter.filterEntity(entities[1])).toBeFalsy(); + }); +}); diff --git a/plugins/catalog-react/src/filters.ts b/plugins/catalog-react/src/filters.ts index 9fb057a01c..a828015f0e 100644 --- a/plugins/catalog-react/src/filters.ts +++ b/plugins/catalog-react/src/filters.ts @@ -14,7 +14,11 @@ * limitations under the License. */ -import { Entity, RELATION_OWNED_BY } from '@backstage/catalog-model'; +import { + AlphaEntity, + Entity, + RELATION_OWNED_BY, +} from '@backstage/catalog-model'; import { humanizeEntityRef } from './components/EntityRefLink'; import { EntityFilter, UserListFilterKind } from './types'; import { getEntityRelations } from './utils'; @@ -159,3 +163,28 @@ export class UserListFilter implements EntityFilter { return this.value; } } + +/** + * Filters entities based if it is an orphan or not. + * @public + */ +export class EntityOrphanFilter implements EntityFilter { + constructor(readonly value: boolean) {} + filterEntity(entity: Entity): boolean { + const orphan = entity.metadata.annotations?.['backstage.io/orphan']; + return orphan !== undefined && this.value.toString() === orphan; + } +} + +/** + * Filters entities based on if it has errors or not. + * @public + */ +export class EntityErrorFilter implements EntityFilter { + constructor(readonly value: boolean) {} + filterEntity(entity: Entity): boolean { + const error = + ((entity as AlphaEntity)?.status?.items?.length as number) > 0; + return error !== undefined && this.value === error; + } +} diff --git a/plugins/catalog-react/src/hooks/useEntityListProvider.tsx b/plugins/catalog-react/src/hooks/useEntityListProvider.tsx index ccac475ae8..089701d8b4 100644 --- a/plugins/catalog-react/src/hooks/useEntityListProvider.tsx +++ b/plugins/catalog-react/src/hooks/useEntityListProvider.tsx @@ -31,8 +31,10 @@ import useDebounce from 'react-use/lib/useDebounce'; import useMountedState from 'react-use/lib/useMountedState'; import { catalogApiRef } from '../api'; import { + EntityErrorFilter, EntityKindFilter, EntityLifecycleFilter, + EntityOrphanFilter, EntityOwnerFilter, EntityTagFilter, EntityTextFilter, @@ -52,6 +54,8 @@ export type DefaultEntityFilters = { lifecycles?: EntityLifecycleFilter; tags?: EntityTagFilter; text?: EntityTextFilter; + orphan?: EntityOrphanFilter; + error?: EntityErrorFilter; }; /** @public */ diff --git a/plugins/catalog-react/src/overridableComponents.ts b/plugins/catalog-react/src/overridableComponents.ts index 1e654988e4..c3b392fcfe 100644 --- a/plugins/catalog-react/src/overridableComponents.ts +++ b/plugins/catalog-react/src/overridableComponents.ts @@ -22,6 +22,7 @@ import { CatalogReactEntitySearchBarClassKey, CatalogReactEntityTagPickerClassKey, CatalogReactEntityOwnerPickerClassKey, + CatalogReactEntityProcessingStatusPickerClassKey, } from './components'; /** @public */ @@ -31,6 +32,7 @@ export type CatalogReactComponentsNameToClassKey = { CatalogReactEntitySearchBar: CatalogReactEntitySearchBarClassKey; CatalogReactEntityTagPicker: CatalogReactEntityTagPickerClassKey; CatalogReactEntityOwnerPicker: CatalogReactEntityOwnerPickerClassKey; + CatalogReactEntityProcessingStatusPicker: CatalogReactEntityProcessingStatusPickerClassKey; }; /** @public */ diff --git a/plugins/catalog/CHANGELOG.md b/plugins/catalog/CHANGELOG.md index 5f4e9809c0..5e00cd2661 100644 --- a/plugins/catalog/CHANGELOG.md +++ b/plugins/catalog/CHANGELOG.md @@ -1,5 +1,114 @@ # @backstage/plugin-catalog +## 1.4.0-next.2 + +### Minor Changes + +- a274fe38b9: Add hidden title column to catalog and API table to enable filtering by title. + +### Patch Changes + +- 258057a4b9: Adding ability to customize the "unregister entity" menu item in the entity context menu on the entity page with options 'visible','hidden','disabled'.With this three new options, one can hide the "unregister entity" menu item from the list, disable or keep it enabled. + + The boolean input for "unregister entity" will be deprecated later in favour of the above three options. + +- 385389d23c: Updated to remove usage of the `bursts` object in the theme palette +- be26d95141: Added new `EntityProcessingStatusPicker` that will filter for entities with orphans and/or errors. + + If you are using the default Catalog page this picker will be added automatically. For those who have customized their Catalog page you'll need to add this manually by doing something like this: + + ```diff + ... + import { + CatalogFilterLayout, + EntityTypePicker, + UserListPicker, + EntityTagPicker + + EntityProcessingStatusPicker, + } from '@backstage/plugin-catalog-react'; + ... + export const CustomCatalogPage = ({ + columns, + actions, + initiallySelectedFilter = 'owned', + }: CatalogPageProps) => { + return ( + ... + + + + + + ... + }; + ``` + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/plugin-search-react@0.2.2-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + - @backstage/integration-react@1.1.2-next.2 + +## 1.3.1-next.1 + +### Patch Changes + +- f1dcc6f3c6: Use entity type predicates from catalog-model +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + - @backstage/catalog-client@1.0.4-next.1 + - @backstage/integration-react@1.1.2-next.1 + - @backstage/plugin-catalog-common@1.0.4-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + - @backstage/plugin-search-common@0.3.6-next.0 + - @backstage/plugin-search-react@0.2.2-next.1 + +## 1.3.1-next.0 + +### Patch Changes + +- dcaf1cb418: Previously, the color of the Entity Context Menu (in the Entity Page Header) was hardcoded as `white`. + + This was an issue for themes that use a header with a white background. By default, the color of the icon is now `theme.palette.bursts.fontColor`. + + It can now also be overridden in the theme, which is only necessary if the header title, subtitle and three-dots icon need to have different colors. For example: + + ```typescript + export function createThemeOverrides(theme: BackstageTheme): Overrides { + return { + PluginCatalogEntityContextMenu: { + button: { + color: 'blue', + }, + }, + ... + }, + ... + } + ``` + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/catalog-client@1.0.4-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + - @backstage/integration-react@1.1.2-next.0 + - @backstage/plugin-search-react@0.2.2-next.0 + ## 1.3.0 ### Minor Changes diff --git a/plugins/catalog/api-report.md b/plugins/catalog/api-report.md index 34bb5dfcec..bfdf62bdb0 100644 --- a/plugins/catalog/api-report.md +++ b/plugins/catalog/api-report.md @@ -136,6 +136,13 @@ export const CatalogTable: { createSpecLifecycleColumn(): TableColumn; createMetadataDescriptionColumn(): TableColumn; createTagsColumn(): TableColumn; + createTitleColumn( + options?: + | { + hidden?: boolean | undefined; + } + | undefined, + ): TableColumn; }>; }; @@ -211,6 +218,9 @@ export interface DependsOnResourcesCardProps { // @public (undocumented) export const EntityAboutCard: (props: AboutCardProps) => JSX.Element; +// @public (undocumented) +export type EntityContextMenuClassKey = 'button'; + // @public (undocumented) export const EntityDependencyOfComponentsCard: ( props: DependencyOfComponentsCardProps, @@ -256,10 +266,10 @@ export interface EntityLayoutProps { children?: React_2.ReactNode; // (undocumented) NotFoundComponent?: React_2.ReactNode; - // Warning: (ae-forgotten-export) The symbol "contextMenuOptions" needs to be exported by the entry point index.d.ts + // Warning: (ae-forgotten-export) The symbol "EntityContextMenuOptions" needs to be exported by the entry point index.d.ts // // (undocumented) - UNSTABLE_contextMenuOptions?: contextMenuOptions; + UNSTABLE_contextMenuOptions?: EntityContextMenuOptions; // Warning: (ae-forgotten-export) The symbol "ExtraContextMenuItem" needs to be exported by the entry point index.d.ts // // (undocumented) @@ -394,6 +404,7 @@ export function isOrphan(entity: Entity): boolean; export type PluginCatalogComponentsNameToClassKey = { PluginCatalogEntityLinksEmptyState: EntityLinksEmptyStateClassKey; PluginCatalogSystemDiagramCard: SystemDiagramCardClassKey; + PluginCatalogEntityContextMenu: EntityContextMenuClassKey; }; // @public (undocumented) diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index 792df94e18..a294e64d29 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog", "description": "The Backstage plugin for browsing the Backstage catalog", - "version": "1.3.0", + "version": "1.4.0-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,17 +34,17 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-client": "^1.0.3", - "@backstage/catalog-model": "^1.0.3", - "@backstage/core-components": "^0.9.5", + "@backstage/catalog-client": "^1.0.4-next.1", + "@backstage/catalog-model": "^1.1.0-next.2", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/errors": "^1.0.0", - "@backstage/integration-react": "^1.1.1", - "@backstage/plugin-catalog-common": "^1.0.3", - "@backstage/plugin-catalog-react": "^1.1.1", - "@backstage/plugin-search-common": "^0.3.5", - "@backstage/plugin-search-react": "^0.2.1", - "@backstage/theme": "^0.2.15", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/integration-react": "^1.1.2-next.2", + "@backstage/plugin-catalog-common": "^1.0.4-next.0", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", + "@backstage/plugin-search-common": "^0.3.6-next.0", + "@backstage/plugin-search-react": "^0.2.2-next.2", + "@backstage/theme": "^0.2.16-next.1", "@backstage/types": "^1.0.0", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -61,11 +61,11 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/plugin-permission-react": "^0.4.2", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/plugin-permission-react": "^0.4.3-next.0", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", diff --git a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx index 5250dcec0d..51ef12ac74 100644 --- a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx +++ b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx @@ -28,6 +28,7 @@ import { CatalogFilterLayout, EntityLifecyclePicker, EntityListProvider, + EntityProcessingStatusPicker, EntityOwnerPicker, EntityTagPicker, EntityTypePicker, @@ -84,6 +85,7 @@ export function DefaultCatalogPage(props: DefaultCatalogPageProps) { + { const defaultColumns: TableColumn[] = useMemo(() => { return [ + columnFactories.createTitleColumn({ hidden: true }), columnFactories.createNameColumn({ defaultKind: filters.kind?.value }), ...createEntitySpecificColumns(), columnFactories.createMetadataDescriptionColumn(), diff --git a/plugins/catalog/src/components/CatalogTable/columns.tsx b/plugins/catalog/src/components/CatalogTable/columns.tsx index 0fb91d4f3f..d8b52e276e 100644 --- a/plugins/catalog/src/components/CatalogTable/columns.tsx +++ b/plugins/catalog/src/components/CatalogTable/columns.tsx @@ -131,4 +131,14 @@ export const columnFactories = Object.freeze({ ), }; }, + createTitleColumn(options?: { + hidden?: boolean; + }): TableColumn { + return { + title: 'Title', + field: 'entity.metadata.title', + hidden: options?.hidden, + searchable: true, + }; + }, }); diff --git a/plugins/catalog/src/components/EntityContextMenu/EntityContextMenu.test.tsx b/plugins/catalog/src/components/EntityContextMenu/EntityContextMenu.test.tsx index eb920aaa20..0e981bb1fc 100644 --- a/plugins/catalog/src/components/EntityContextMenu/EntityContextMenu.test.tsx +++ b/plugins/catalog/src/components/EntityContextMenu/EntityContextMenu.test.tsx @@ -42,7 +42,6 @@ function render(children: React.ReactNode) { describe('ComponentContextMenu', () => { it('should call onUnregisterEntity on button click', async () => { const mockCallback = jest.fn(); - await render( { expect(mockCallback).toBeCalled(); }); + it('check Unregister entity button is disabled', async () => { + const mockCallback = jest.fn(); + + const { getByText } = await render( + {}} + />, + ); + + const button = await screen.findByTestId('menu-button'); + expect(button).toBeInTheDocument(); + fireEvent.click(button); + + const unregister = await screen.getByText('Unregister entity'); + expect(unregister).toBeInTheDocument(); + + const unregisterSpanItem = getByText(/Unregister entity/); + const unregisterMenuListItem = + unregisterSpanItem?.parentElement?.parentElement; + expect(unregisterMenuListItem).toHaveAttribute('aria-disabled'); + }); + it('should call onInspectEntity on button click', async () => { const mockCallback = jest.fn(); diff --git a/plugins/catalog/src/components/EntityContextMenu/EntityContextMenu.tsx b/plugins/catalog/src/components/EntityContextMenu/EntityContextMenu.tsx index 5664186ab1..41610ed13c 100644 --- a/plugins/catalog/src/components/EntityContextMenu/EntityContextMenu.tsx +++ b/plugins/catalog/src/components/EntityContextMenu/EntityContextMenu.tsx @@ -24,20 +24,28 @@ import { Popover, } from '@material-ui/core'; import { makeStyles } from '@material-ui/core/styles'; -import CancelIcon from '@material-ui/icons/Cancel'; import BugReportIcon from '@material-ui/icons/BugReport'; import MoreVert from '@material-ui/icons/MoreVert'; import React, { useState } from 'react'; import { IconComponent } from '@backstage/core-plugin-api'; import { useEntityPermission } from '@backstage/plugin-catalog-react'; import { catalogEntityDeletePermission } from '@backstage/plugin-catalog-common'; +import { BackstageTheme } from '@backstage/theme'; +import { UnregisterEntity, UnregisterEntityOptions } from './UnregisterEntity'; -// TODO(freben): It should probably instead be the case that Header sets the theme text color to white inside itself unconditionally instead -const useStyles = makeStyles({ - button: { - color: 'white', +/** @public */ +export type EntityContextMenuClassKey = 'button'; + +const useStyles = makeStyles( + (theme: BackstageTheme) => { + return { + button: { + color: theme.page.fontColor, + }, + }; }, -}); + { name: 'PluginCatalogEntityContextMenu' }, +); // NOTE(freben): Intentionally not exported at this point, since it's part of // the unstable extra context menu items concept below @@ -47,14 +55,9 @@ interface ExtraContextMenuItem { onClick: () => void; } -// unstable context menu option, eg: disable the unregister entity menu -interface contextMenuOptions { - disableUnregister: boolean; -} - interface EntityContextMenuProps { UNSTABLE_extraContextMenuItems?: ExtraContextMenuItem[]; - UNSTABLE_contextMenuOptions?: contextMenuOptions; + UNSTABLE_contextMenuOptions?: UnregisterEntityOptions; onUnregisterEntity: () => void; onInspectEntity: () => void; } @@ -71,6 +74,7 @@ export function EntityContextMenu(props: EntityContextMenuProps) { const unregisterPermission = useEntityPermission( catalogEntityDeletePermission, ); + const isAllowed = unregisterPermission.allowed; const onOpen = (event: React.SyntheticEvent) => { setAnchorEl(event.currentTarget); @@ -98,11 +102,6 @@ export function EntityContextMenu(props: EntityContextMenuProps) { , ]; - const disableUnregister = - (!unregisterPermission.allowed || - UNSTABLE_contextMenuOptions?.disableUnregister) ?? - false; - return ( <> {extraItems} - { - onClose(); - onUnregisterEntity(); - }} - disabled={disableUnregister} - > - - - - - + { onClose(); diff --git a/plugins/catalog/src/components/EntityContextMenu/UnregisterEntity.test.tsx b/plugins/catalog/src/components/EntityContextMenu/UnregisterEntity.test.tsx new file mode 100644 index 0000000000..70b75c7bae --- /dev/null +++ b/plugins/catalog/src/components/EntityContextMenu/UnregisterEntity.test.tsx @@ -0,0 +1,80 @@ +/* + * 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 { EntityProvider } from '@backstage/plugin-catalog-react'; +import { permissionApiRef } from '@backstage/plugin-permission-react'; +import { + MockPermissionApi, + renderInTestApp, + TestApiProvider, +} from '@backstage/test-utils'; +import { fireEvent, screen } from '@testing-library/react'; +import * as React from 'react'; +import { UnregisterEntity } from './UnregisterEntity'; + +const mockPermissionApi = new MockPermissionApi(); + +function render(children: React.ReactNode) { + return renderInTestApp( + + + , + ); +} + +describe('ComponentContextMenu', () => { + it('should call onUnregisterEntity on button click', async () => { + const mockCallback = jest.fn(); + await render( + {}} + />, + ); + + const unregister = await screen.findByText('Unregister entity'); + expect(unregister).toBeInTheDocument(); + fireEvent.click(unregister); + + expect(mockCallback).toBeCalled(); + }); + + it('check Unregister entity button is disabled', async () => { + const mockCallback = jest.fn(); + + const { getByText } = await render( + {}} + />, + ); + + const unregister = await screen.getByText('Unregister entity'); + expect(unregister).toBeInTheDocument(); + + const unregisterSpanItem = getByText(/Unregister entity/); + const unregisterMenuListItem = + unregisterSpanItem?.parentElement?.parentElement; + expect(unregisterMenuListItem).toHaveAttribute('aria-disabled'); + }); +}); diff --git a/plugins/catalog/src/components/EntityContextMenu/UnregisterEntity.tsx b/plugins/catalog/src/components/EntityContextMenu/UnregisterEntity.tsx new file mode 100644 index 0000000000..05044bf935 --- /dev/null +++ b/plugins/catalog/src/components/EntityContextMenu/UnregisterEntity.tsx @@ -0,0 +1,72 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { ListItemIcon, ListItemText, MenuItem } from '@material-ui/core'; +import CancelIcon from '@material-ui/icons/Cancel'; + +type VisibleType = 'visible' | 'hidden' | 'disable'; + +export type UnregisterEntityOptions = { + disableUnregister: boolean | VisibleType; +}; + +interface UnregisterEntityProps { + unregisterEntityOptions?: UnregisterEntityOptions; + isUnregisterAllowed: boolean; + onUnregisterEntity: () => void; + onClose: () => void; +} + +export function UnregisterEntity(props: UnregisterEntityProps) { + const { + unregisterEntityOptions, + isUnregisterAllowed, + onUnregisterEntity, + onClose, + } = props; + + const isBoolean = + typeof unregisterEntityOptions?.disableUnregister === 'boolean'; + + const isDisabled = + (!isUnregisterAllowed || + (isBoolean + ? !!unregisterEntityOptions?.disableUnregister + : unregisterEntityOptions?.disableUnregister === 'disable')) ?? + false; + + let unregisterButton = <>; + + if (unregisterEntityOptions?.disableUnregister !== 'hidden') { + unregisterButton = ( + { + onClose(); + onUnregisterEntity(); + }} + disabled={isDisabled} + > + + + + + + ); + } + + return <>{unregisterButton}; +} diff --git a/plugins/catalog/src/components/EntityContextMenu/index.ts b/plugins/catalog/src/components/EntityContextMenu/index.ts new file mode 100644 index 0000000000..4a2deb20b4 --- /dev/null +++ b/plugins/catalog/src/components/EntityContextMenu/index.ts @@ -0,0 +1,18 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { EntityContextMenu } from './EntityContextMenu'; +export type { EntityContextMenuClassKey } from './EntityContextMenu'; diff --git a/plugins/catalog/src/components/EntityLayout/EntityLayout.tsx b/plugins/catalog/src/components/EntityLayout/EntityLayout.tsx index 693137fe21..2295034905 100644 --- a/plugins/catalog/src/components/EntityLayout/EntityLayout.tsx +++ b/plugins/catalog/src/components/EntityLayout/EntityLayout.tsx @@ -142,15 +142,18 @@ interface ExtraContextMenuItem { onClick: () => void; } +type VisibleType = 'visible' | 'hidden' | 'disable'; + +// NOTE(blam): Intentionally not exported at this point, since it's part of // unstable context menu option, eg: disable the unregister entity menu -interface contextMenuOptions { - disableUnregister: boolean; +interface EntityContextMenuOptions { + disableUnregister: boolean | VisibleType; } /** @public */ export interface EntityLayoutProps { UNSTABLE_extraContextMenuItems?: ExtraContextMenuItem[]; - UNSTABLE_contextMenuOptions?: contextMenuOptions; + UNSTABLE_contextMenuOptions?: EntityContextMenuOptions; children?: React.ReactNode; NotFoundComponent?: React.ReactNode; } diff --git a/plugins/catalog/src/components/EntitySwitch/conditions.ts b/plugins/catalog/src/components/EntitySwitch/conditions.ts index 5f50fde5c9..86fd38a900 100644 --- a/plugins/catalog/src/components/EntitySwitch/conditions.ts +++ b/plugins/catalog/src/components/EntitySwitch/conditions.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { Entity, ComponentEntity } from '@backstage/catalog-model'; +import { ComponentEntity, Entity } from '@backstage/catalog-model'; function strCmp(a: string | undefined, b: string | undefined): boolean { return Boolean( diff --git a/plugins/catalog/src/index.ts b/plugins/catalog/src/index.ts index cfe4851d09..f0f94656d5 100644 --- a/plugins/catalog/src/index.ts +++ b/plugins/catalog/src/index.ts @@ -62,6 +62,7 @@ export type { } from './components/EntityLinksCard'; export type { SystemDiagramCardClassKey } from './components/SystemDiagramCard'; export type { DefaultCatalogPageProps } from './components/CatalogPage'; +export type { EntityContextMenuClassKey } from './components/EntityContextMenu'; export type { HasComponentsCardProps } from './components/HasComponentsCard'; export type { HasResourcesCardProps } from './components/HasResourcesCard'; export type { HasSubcomponentsCardProps } from './components/HasSubcomponentsCard'; diff --git a/plugins/catalog/src/overridableComponents.ts b/plugins/catalog/src/overridableComponents.ts index e76aafbb68..5cd82202d5 100644 --- a/plugins/catalog/src/overridableComponents.ts +++ b/plugins/catalog/src/overridableComponents.ts @@ -18,11 +18,13 @@ import { StyleRules } from '@material-ui/core/styles/withStyles'; import { EntityLinksEmptyStateClassKey } from './components/EntityLinksCard'; import { SystemDiagramCardClassKey } from './components/SystemDiagramCard'; +import { EntityContextMenuClassKey } from './components/EntityContextMenu'; /** @public */ export type PluginCatalogComponentsNameToClassKey = { PluginCatalogEntityLinksEmptyState: EntityLinksEmptyStateClassKey; PluginCatalogSystemDiagramCard: SystemDiagramCardClassKey; + PluginCatalogEntityContextMenu: EntityContextMenuClassKey; }; /** @public */ diff --git a/plugins/cicd-statistics-module-gitlab/CHANGELOG.md b/plugins/cicd-statistics-module-gitlab/CHANGELOG.md index de73c87469..14d234e35c 100644 --- a/plugins/cicd-statistics-module-gitlab/CHANGELOG.md +++ b/plugins/cicd-statistics-module-gitlab/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-cicd-statistics-module-gitlab +## 0.1.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/plugin-cicd-statistics@0.1.9-next.0 + ## 0.1.2 ### Patch Changes diff --git a/plugins/cicd-statistics-module-gitlab/package.json b/plugins/cicd-statistics-module-gitlab/package.json index dd48ad7719..749c77d1c5 100644 --- a/plugins/cicd-statistics-module-gitlab/package.json +++ b/plugins/cicd-statistics-module-gitlab/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-cicd-statistics-module-gitlab", "description": "CI/CD Statistics plugin module; Gitlab CICD", - "version": "0.1.2", + "version": "0.1.3-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -29,16 +29,16 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/plugin-cicd-statistics": "^0.1.8", + "@backstage/plugin-cicd-statistics": "^0.1.9-next.0", "@gitbeaker/browser": "^35.6.0", "@gitbeaker/core": "^35.6.0", "luxon": "^2.0.2", "p-limit": "^4.0.0", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/catalog-model": "^1.0.3" + "@backstage/catalog-model": "^1.1.0-next.1" }, "devDependencies": { - "@backstage/cli": "^0.17.2" + "@backstage/cli": "^0.18.0-next.1" }, "files": [ "dist" diff --git a/plugins/cicd-statistics/CHANGELOG.md b/plugins/cicd-statistics/CHANGELOG.md index 498cfa47a3..e8856187c9 100644 --- a/plugins/cicd-statistics/CHANGELOG.md +++ b/plugins/cicd-statistics/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-cicd-statistics +## 0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + ## 0.1.8 ### Patch Changes diff --git a/plugins/cicd-statistics/package.json b/plugins/cicd-statistics/package.json index 0859afd945..c09dc7c995 100644 --- a/plugins/cicd-statistics/package.json +++ b/plugins/cicd-statistics/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-cicd-statistics", "description": "A frontend plugin visualizing CI/CD pipeline statistics (build time)", - "version": "0.1.8", + "version": "0.1.9-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -37,9 +37,9 @@ "@types/luxon": "^2.0.5" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", + "@backstage/catalog-model": "^1.1.0-next.0", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/plugin-catalog-react": "^1.1.1", + "@backstage/plugin-catalog-react": "^1.1.2-next.0", "@date-io/luxon": "^1.3.13", "@material-ui/core": "^4.9.13", "@material-ui/icons": "^4.11.2", diff --git a/plugins/circleci/CHANGELOG.md b/plugins/circleci/CHANGELOG.md index 39cfcea568..4df5655c52 100644 --- a/plugins/circleci/CHANGELOG.md +++ b/plugins/circleci/CHANGELOG.md @@ -1,5 +1,34 @@ # @backstage/plugin-circleci +## 0.3.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## 0.3.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## 0.3.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + ## 0.3.6 ### Patch Changes diff --git a/plugins/circleci/package.json b/plugins/circleci/package.json index 3e00add228..c17569db13 100644 --- a/plugins/circleci/package.json +++ b/plugins/circleci/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-circleci", "description": "A Backstage plugin that integrates towards Circle CI", - "version": "0.3.6", + "version": "0.3.7-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,11 +35,11 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", - "@backstage/core-components": "^0.9.5", + "@backstage/catalog-model": "^1.1.0-next.2", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/plugin-catalog-react": "^1.1.1", - "@backstage/theme": "^0.2.15", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -55,10 +55,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", @@ -66,7 +66,7 @@ "@types/jest": "^26.0.7", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/cloudbuild/CHANGELOG.md b/plugins/cloudbuild/CHANGELOG.md index 8454cc5cd4..94b16aafdd 100644 --- a/plugins/cloudbuild/CHANGELOG.md +++ b/plugins/cloudbuild/CHANGELOG.md @@ -1,5 +1,34 @@ # @backstage/plugin-cloudbuild +## 0.3.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## 0.3.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## 0.3.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + ## 0.3.6 ### Patch Changes diff --git a/plugins/cloudbuild/package.json b/plugins/cloudbuild/package.json index b1f14356e0..2348693d58 100644 --- a/plugins/cloudbuild/package.json +++ b/plugins/cloudbuild/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-cloudbuild", "description": "A Backstage plugin that integrates towards Google Cloud Build", - "version": "0.3.6", + "version": "0.3.7-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,11 +34,11 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", - "@backstage/core-components": "^0.9.5", + "@backstage/catalog-model": "^1.1.0-next.2", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/plugin-catalog-react": "^1.1.1", - "@backstage/theme": "^0.2.15", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -52,17 +52,17 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/jest": "^26.0.7", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/code-climate/CHANGELOG.md b/plugins/code-climate/CHANGELOG.md index 7cc1362a4d..cd2e824758 100644 --- a/plugins/code-climate/CHANGELOG.md +++ b/plugins/code-climate/CHANGELOG.md @@ -1,5 +1,34 @@ # @backstage/plugin-code-climate +## 0.1.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## 0.1.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## 0.1.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + ## 0.1.6 ### Patch Changes diff --git a/plugins/code-climate/package.json b/plugins/code-climate/package.json index 193fc71f3c..40c0861f17 100644 --- a/plugins/code-climate/package.json +++ b/plugins/code-climate/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-code-climate", - "version": "0.1.6", + "version": "0.1.7-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,11 +23,11 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", - "@backstage/core-components": "^0.9.5", + "@backstage/catalog-model": "^1.1.0-next.2", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/plugin-catalog-react": "^1.1.1", - "@backstage/theme": "^0.2.15", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -40,9 +40,9 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", @@ -51,7 +51,7 @@ "@types/luxon": "^2.0.9", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/code-coverage-backend/CHANGELOG.md b/plugins/code-coverage-backend/CHANGELOG.md index ebf82cc984..6fccd225cb 100644 --- a/plugins/code-coverage-backend/CHANGELOG.md +++ b/plugins/code-coverage-backend/CHANGELOG.md @@ -1,5 +1,36 @@ # @backstage/plugin-code-coverage-backend +## 0.1.32-next.2 + +### Patch Changes + +- 679b32172e: Updated dependency `knex` to `^2.0.0`. +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/backend-common@0.14.1-next.2 + - @backstage/integration@1.2.2-next.2 + +## 0.1.32-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/catalog-client@1.0.4-next.1 + - @backstage/integration@1.2.2-next.1 + +## 0.1.32-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/catalog-client@1.0.4-next.0 + ## 0.1.31 ### Patch Changes diff --git a/plugins/code-coverage-backend/api-report.md b/plugins/code-coverage-backend/api-report.md index 437c48227f..c33874064b 100644 --- a/plugins/code-coverage-backend/api-report.md +++ b/plugins/code-coverage-backend/api-report.md @@ -10,27 +10,10 @@ import { PluginDatabaseManager } from '@backstage/backend-common'; import { PluginEndpointDiscovery } from '@backstage/backend-common'; import { UrlReader } from '@backstage/backend-common'; -// Warning: (ae-missing-release-tag) "CodeCoverageApi" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export interface CodeCoverageApi { - // (undocumented) - name: string; -} - -// Warning: (ae-missing-release-tag) "createRouter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) +// @public export function createRouter(options: RouterOptions): Promise; -// Warning: (ae-missing-release-tag) "makeRouter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const makeRouter: (options: RouterOptions) => Promise; - -// Warning: (ae-missing-release-tag) "RouterOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) +// @public export interface RouterOptions { // (undocumented) config: Config; diff --git a/plugins/code-coverage-backend/package.json b/plugins/code-coverage-backend/package.json index 0bc5281648..017b96122e 100644 --- a/plugins/code-coverage-backend/package.json +++ b/plugins/code-coverage-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-code-coverage-backend", "description": "A Backstage backend plugin that helps you keep track of your code coverage", - "version": "0.1.31", + "version": "0.1.32-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,26 +23,26 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", - "@backstage/catalog-client": "^1.0.3", - "@backstage/catalog-model": "^1.0.3", + "@backstage/backend-common": "^0.14.1-next.2", + "@backstage/catalog-client": "^1.0.4-next.1", + "@backstage/catalog-model": "^1.1.0-next.2", "@backstage/config": "^1.0.1", - "@backstage/errors": "^1.0.0", - "@backstage/integration": "^1.2.1", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/integration": "^1.2.2-next.2", "@types/express": "^4.17.6", "express": "^4.17.1", "express-promise-router": "^4.1.0", "express-xml-bodyparser": "^0.3.0", - "knex": "^1.0.2", + "knex": "^2.0.0", "uuid": "^8.3.2", "winston": "^3.2.1", "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", + "@backstage/cli": "^0.18.0-next.2", "@types/express-xml-bodyparser": "^0.3.2", "@types/supertest": "^2.0.8", - "msw": "^0.42.0", + "msw": "^0.43.0", "supertest": "^6.1.6", "xml2js": "^0.4.23" }, diff --git a/plugins/code-coverage-backend/src/index.ts b/plugins/code-coverage-backend/src/index.ts index 3b1b536ac7..8511c9b71e 100644 --- a/plugins/code-coverage-backend/src/index.ts +++ b/plugins/code-coverage-backend/src/index.ts @@ -20,4 +20,5 @@ * @packageDocumentation */ -export * from './service/router'; +export { createRouter } from './service/router'; +export type { RouterOptions } from './service/router'; diff --git a/plugins/code-coverage-backend/src/service/router.ts b/plugins/code-coverage-backend/src/service/router.ts index 488103c835..37279b549f 100644 --- a/plugins/code-coverage-backend/src/service/router.ts +++ b/plugins/code-coverage-backend/src/service/router.ts @@ -35,6 +35,11 @@ import { Jacoco } from './converter/jacoco'; import { Converter } from './converter'; import { getEntitySourceLocation } from '@backstage/catalog-model'; +/** + * Options for {@link createRouter}. + * + * @public + */ export interface RouterOptions { config: Config; discovery: PluginEndpointDiscovery; @@ -211,6 +216,11 @@ export const makeRouter = async ( return router; }; +/** + * Creates a code-coverage plugin backend router. + * + * @public + */ export async function createRouter( options: RouterOptions, ): Promise { diff --git a/plugins/code-coverage/CHANGELOG.md b/plugins/code-coverage/CHANGELOG.md index 474c324e98..b2b64aa993 100644 --- a/plugins/code-coverage/CHANGELOG.md +++ b/plugins/code-coverage/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-code-coverage +## 0.1.34-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## 0.1.34-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## 0.1.34-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + ## 0.1.33 ### Patch Changes diff --git a/plugins/code-coverage/api-report.md b/plugins/code-coverage/api-report.md index 0e675dec04..152cc93103 100644 --- a/plugins/code-coverage/api-report.md +++ b/plugins/code-coverage/api-report.md @@ -9,8 +9,6 @@ import { BackstagePlugin } from '@backstage/core-plugin-api'; import { Entity } from '@backstage/catalog-model'; import { RouteRef } from '@backstage/core-plugin-api'; -// Warning: (ae-missing-release-tag) "codeCoveragePlugin" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// // @public (undocumented) export const codeCoveragePlugin: BackstagePlugin< { @@ -19,20 +17,12 @@ export const codeCoveragePlugin: BackstagePlugin< {} >; -// Warning: (ae-missing-release-tag) "EntityCodeCoverageContent" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) +// @public export const EntityCodeCoverageContent: () => JSX.Element; -// Warning: (ae-missing-release-tag) "isCodeCoverageAvailable" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -const isCodeCoverageAvailable: (entity: Entity) => boolean; -export { isCodeCoverageAvailable }; -export { isCodeCoverageAvailable as isPluginApplicableToEntity }; +// @public +export function isCodeCoverageAvailable(entity: Entity): boolean; -// Warning: (ae-missing-release-tag) "Router" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const Router: () => JSX.Element; +// @public @deprecated (undocumented) +export const isPluginApplicableToEntity: typeof isCodeCoverageAvailable; ``` diff --git a/plugins/code-coverage/package.json b/plugins/code-coverage/package.json index f72d73d293..68cd7d7990 100644 --- a/plugins/code-coverage/package.json +++ b/plugins/code-coverage/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-code-coverage", "description": "A Backstage plugin that helps you keep track of your code coverage", - "version": "0.1.33", + "version": "0.1.34-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -24,13 +24,13 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", + "@backstage/catalog-model": "^1.1.0-next.2", "@backstage/config": "^1.0.1", - "@backstage/core-components": "^0.9.5", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/errors": "^1.0.0", - "@backstage/plugin-catalog-react": "^1.1.1", - "@backstage/theme": "^0.2.15", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -46,10 +46,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", @@ -58,7 +58,7 @@ "@types/node": "^16.11.26", "@types/recharts": "^1.8.15", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/code-coverage/src/components/FileExplorer/Highlighter.ts b/plugins/code-coverage/src/components/FileExplorer/Highlighter.ts index 225ca96175..d97d147da3 100644 --- a/plugins/code-coverage/src/components/FileExplorer/Highlighter.ts +++ b/plugins/code-coverage/src/components/FileExplorer/Highlighter.ts @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import 'highlight.js/styles/atom-one-dark.css'; import highlight from 'highlight.js'; diff --git a/plugins/code-coverage/src/components/Router.tsx b/plugins/code-coverage/src/components/Router.tsx index d3342b86eb..190b441c7a 100644 --- a/plugins/code-coverage/src/components/Router.tsx +++ b/plugins/code-coverage/src/components/Router.tsx @@ -13,16 +13,26 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import React from 'react'; import { Entity } from '@backstage/catalog-model'; import { useEntity } from '@backstage/plugin-catalog-react'; import { CodeCoveragePage } from './CodeCoveragePage'; import { MissingAnnotationEmptyState } from '@backstage/core-components'; -export const isCodeCoverageAvailable = (entity: Entity) => - Boolean(entity.metadata.annotations?.['backstage.io/code-coverage']); +/** + * Returns true if the given entity has code coverage enabled. + * + * @public + */ +export function isCodeCoverageAvailable(entity: Entity) { + return Boolean(entity.metadata.annotations?.['backstage.io/code-coverage']); +} -export const Router = () => { +/** + * @public + */ +export const Router = (): JSX.Element => { const { entity } = useEntity(); if (!isCodeCoverageAvailable(entity)) { @@ -30,5 +40,6 @@ export const Router = () => { ); } + return ; }; diff --git a/plugins/code-coverage/src/index.ts b/plugins/code-coverage/src/index.ts index 2ece7ed1e8..06c10026ff 100644 --- a/plugins/code-coverage/src/index.ts +++ b/plugins/code-coverage/src/index.ts @@ -20,9 +20,13 @@ * @packageDocumentation */ +import { isCodeCoverageAvailable } from './components/Router'; + export { codeCoveragePlugin, EntityCodeCoverageContent } from './plugin'; -export { - Router, - isCodeCoverageAvailable, - isCodeCoverageAvailable as isPluginApplicableToEntity, -} from './components/Router'; +export { isCodeCoverageAvailable }; + +/** + * @public + * @deprecated Use `isPluginApplicableToEntity` instead. + */ +export const isPluginApplicableToEntity = isCodeCoverageAvailable; diff --git a/plugins/code-coverage/src/plugin.ts b/plugins/code-coverage/src/plugin.ts index 1202c4e4b3..f137e9d488 100644 --- a/plugins/code-coverage/src/plugin.ts +++ b/plugins/code-coverage/src/plugin.ts @@ -23,6 +23,9 @@ import { discoveryApiRef, } from '@backstage/core-plugin-api'; +/** + * @public + */ export const codeCoveragePlugin = createPlugin({ id: 'code-coverage', routes: { @@ -37,6 +40,11 @@ export const codeCoveragePlugin = createPlugin({ ], }); +/** + * An entity code coverage page. + * + * @public + */ export const EntityCodeCoverageContent = codeCoveragePlugin.provide( createRoutableExtension({ name: 'EntityCodeCoverageContent', diff --git a/plugins/codescene/CHANGELOG.md b/plugins/codescene/CHANGELOG.md index 2443fda056..e3f98725c3 100644 --- a/plugins/codescene/CHANGELOG.md +++ b/plugins/codescene/CHANGELOG.md @@ -1,5 +1,30 @@ # @backstage/plugin-codescene +## 0.1.2-next.2 + +### Patch Changes + +- 15201b1032: Updated dependency `rc-progress` to `3.4.0`. +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + +## 0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + +## 0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + ## 0.1.1 ### Patch Changes diff --git a/plugins/codescene/package.json b/plugins/codescene/package.json index 47006c25c7..85f7096f69 100644 --- a/plugins/codescene/package.json +++ b/plugins/codescene/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-codescene", - "version": "0.1.1", + "version": "0.1.2-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,14 +23,14 @@ }, "dependencies": { "@backstage/config": "^1.0.1", - "@backstage/core-components": "^0.9.5", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/errors": "^1.0.0", - "@backstage/theme": "^0.2.15", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.9.10", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "^4.0.0-alpha.57", - "rc-progress": "3.3.3", + "rc-progress": "3.4.0", "react-router-dom": "6.0.0-beta.0", "react-use": "^17.2.4" }, @@ -38,16 +38,16 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/jest": "*", "@types/node": "*", - "msw": "^0.42.0", + "msw": "^0.43.0", "cross-fetch": "^3.1.5" }, "files": [ diff --git a/plugins/config-schema/CHANGELOG.md b/plugins/config-schema/CHANGELOG.md index 1128a525fe..b6a43ed858 100644 --- a/plugins/config-schema/CHANGELOG.md +++ b/plugins/config-schema/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-config-schema +## 0.1.30-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + +## 0.1.30-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + +## 0.1.30-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + ## 0.1.29 ### Patch Changes diff --git a/plugins/config-schema/package.json b/plugins/config-schema/package.json index 0a6c6f2d88..c33e7adac3 100644 --- a/plugins/config-schema/package.json +++ b/plugins/config-schema/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-config-schema", "description": "A Backstage plugin that lets you browse the configuration schema of your app", - "version": "0.1.29", + "version": "0.1.30-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -25,10 +25,10 @@ }, "dependencies": { "@backstage/config": "^1.0.1", - "@backstage/core-components": "^0.9.5", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/errors": "^1.0.0", - "@backstage/theme": "^0.2.15", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/theme": "^0.2.16-next.1", "@backstage/types": "^1.0.0", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -41,17 +41,17 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/jest": "^26.0.7", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/cost-insights-common/.eslintrc.js b/plugins/cost-insights-common/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/cost-insights-common/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/cost-insights-common/CHANGELOG.md b/plugins/cost-insights-common/CHANGELOG.md new file mode 100644 index 0000000000..0a55b342fc --- /dev/null +++ b/plugins/cost-insights-common/CHANGELOG.md @@ -0,0 +1,7 @@ +# @backstage/plugin-cost-insights-common + +## 0.1.0-next.0 + +### Minor Changes + +- 81dd5ea989: Introduces a new isomorphic @backstage/plugin-cost-insight-common package to contain shared types across all other cost insights packages and modules. diff --git a/plugins/cost-insights-common/README.md b/plugins/cost-insights-common/README.md new file mode 100644 index 0000000000..5140701987 --- /dev/null +++ b/plugins/cost-insights-common/README.md @@ -0,0 +1,8 @@ +# Cost Insights Common + +Shared isomorphic code for the cost-insights plugin. + +## Links + +- [Frontend part of the plugin](https://github.com/backstage/backstage/tree/master/plugins/cost-insights) +- [The Backstage homepage](https://backstage.io) diff --git a/plugins/cost-insights-common/api-report.md b/plugins/cost-insights-common/api-report.md new file mode 100644 index 0000000000..a5f7045854 --- /dev/null +++ b/plugins/cost-insights-common/api-report.md @@ -0,0 +1,92 @@ +## API Report File for "@backstage/plugin-cost-insights-common" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +// @public (undocumented) +export interface ChangeStatistic { + amount: number; + ratio?: number; +} + +// @public (undocumented) +export interface Cost { + // (undocumented) + aggregation: DateAggregation[]; + // (undocumented) + change?: ChangeStatistic; + // (undocumented) + groupedCosts?: Record; + // (undocumented) + id: string; + // (undocumented) + trendline?: Trendline; +} + +// @public (undocumented) +export type DateAggregation = { + date: string; + amount: number; +}; + +// @public +export interface Entity { + // (undocumented) + aggregation: [number, number]; + // (undocumented) + change: ChangeStatistic; + // (undocumented) + entities: Record; + // (undocumented) + id: Maybe; +} + +// @public (undocumented) +export type Group = { + id: string; +}; + +// @public (undocumented) +export type Maybe = T | null; + +// @public (undocumented) +export type Metric = { + kind: string; + name: string; + default: boolean; +}; + +// @public (undocumented) +export interface MetricData { + // (undocumented) + aggregation: DateAggregation[]; + // (undocumented) + change: ChangeStatistic; + // (undocumented) + format: 'number' | 'currency'; + // (undocumented) + id: string; +} + +// @public (undocumented) +export interface Product { + // (undocumented) + kind: string; + // (undocumented) + name: string; +} + +// @public (undocumented) +export interface Project { + // (undocumented) + id: string; + // (undocumented) + name?: string; +} + +// @public (undocumented) +export type Trendline = { + slope: number; + intercept: number; +}; +``` diff --git a/plugins/cost-insights-common/package.json b/plugins/cost-insights-common/package.json new file mode 100644 index 0000000000..2918462e09 --- /dev/null +++ b/plugins/cost-insights-common/package.json @@ -0,0 +1,42 @@ +{ + "name": "@backstage/plugin-cost-insights-common", + "description": "Common functionalities for the cost-insights plugin", + "version": "0.1.0-next.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "private": false, + "publishConfig": { + "access": "public", + "main": "dist/index.cjs.js", + "module": "dist/index.esm.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "common-library" + }, + "homepage": "https://backstage.io", + "repository": { + "type": "git", + "url": "https://github.com/backstage/backstage", + "directory": "plugins/cost-insights-common" + }, + "keywords": [ + "backstage" + ], + "scripts": { + "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": { + "@backstage/cli": "^0.18.0-next.2" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/cost-insights-common/src/index.ts b/plugins/cost-insights-common/src/index.ts new file mode 100644 index 0000000000..c3c76ccf17 --- /dev/null +++ b/plugins/cost-insights-common/src/index.ts @@ -0,0 +1,23 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Provides shared objects useful for interacting with the cost-insights plugin. + * + * @packageDocumentation + */ + +export * from './types'; diff --git a/plugins/cost-insights-common/src/setupTests.ts b/plugins/cost-insights-common/src/setupTests.ts new file mode 100644 index 0000000000..813cdeaae3 --- /dev/null +++ b/plugins/cost-insights-common/src/setupTests.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export {}; diff --git a/plugins/cost-insights-common/src/types/ChangeStatistic.ts b/plugins/cost-insights-common/src/types/ChangeStatistic.ts new file mode 100644 index 0000000000..8d64fb47f9 --- /dev/null +++ b/plugins/cost-insights-common/src/types/ChangeStatistic.ts @@ -0,0 +1,32 @@ +/* + * 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. + */ + +/** + * @public + */ +export interface ChangeStatistic { + /** + * The ratio of change from one duration to another, expressed as: (newSum - oldSum) / oldSum + * If a ratio cannot be calculated - such as when a new or old sum is zero, + * the ratio can be omitted and where applicable, ∞ or -∞ will display based on amount. + */ + ratio?: number; + + /** + * The actual USD change between time periods (can be negative if costs decreased) + */ + amount: number; +} diff --git a/plugins/cost-insights/src/types/Cost.ts b/plugins/cost-insights-common/src/types/Cost.ts similarity index 97% rename from plugins/cost-insights/src/types/Cost.ts rename to plugins/cost-insights-common/src/types/Cost.ts index 2ae4755bc7..90ccbe17c0 100644 --- a/plugins/cost-insights/src/types/Cost.ts +++ b/plugins/cost-insights-common/src/types/Cost.ts @@ -18,6 +18,9 @@ import { DateAggregation } from './DateAggregation'; import { ChangeStatistic } from './ChangeStatistic'; import { Trendline } from './Trendline'; +/** + * @public + */ export interface Cost { id: string; aggregation: DateAggregation[]; diff --git a/plugins/cost-insights/src/types/DateAggregation.ts b/plugins/cost-insights-common/src/types/DateAggregation.ts similarity index 85% rename from plugins/cost-insights/src/types/DateAggregation.ts rename to plugins/cost-insights-common/src/types/DateAggregation.ts index 72a2514006..edc867a7bf 100644 --- a/plugins/cost-insights/src/types/DateAggregation.ts +++ b/plugins/cost-insights-common/src/types/DateAggregation.ts @@ -14,7 +14,15 @@ * limitations under the License. */ +/** + * @public + */ export type DateAggregation = { - date: string; // YYYY-MM-DD + /** + * The date aggregation as string. + * @example YYYY-MM-DD + */ + date: string; + amount: number; }; diff --git a/plugins/cost-insights-common/src/types/Entity.ts b/plugins/cost-insights-common/src/types/Entity.ts new file mode 100644 index 0000000000..9a6d6746aa --- /dev/null +++ b/plugins/cost-insights-common/src/types/Entity.ts @@ -0,0 +1,124 @@ +/* + * 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 { ChangeStatistic } from './ChangeStatistic'; +import { Maybe } from './Maybe'; + +/** + * + * An entity is a tree-like structure that represents any unique + * product or service that generates cost over a fixed period of time. + * An entity could be atomic or composite. An atomic entity is indivisible + * and cannot be broken into sub-entities. + * + * A composite entity is divided into sub-entities that account for portions + * of the total cost **over the same time period**. The root entity is + * expected to only have _one_ Record consisting of the sub-entities to display + * in the product panel (keyed by the entity type, such as "service" for + * compute entities). + * + * The root sub-entities may have multiple breakdowns - for example, a + * breakdown of an entity cost by SKU vs deployment environment. The sum + * aggregated cost of each keyed breakdown should equal the sub-entity's cost. + * + * Entities with null ids are considered "unlabeled" - costs without attribution. + * If an entity is a composite, it may only have one (1) null child but may have any number of + * null grandchildren. + * + * @public + * + * @example + * Here's an example composite entity: + * ``` + * const compositeEntity = { + * id: 'product', + * aggregation: [0, 200], + * change: { + * ratio: 2000, + * amount: 200 + * }, + * entities: { + * service: [ + * { + * id: 'service-a', + * aggregation: [0, 100], + * change: { + * ratio: 100, + * amount: 100 + * }, + * entities: {} + * }, + * { + * id: 'service-b', + * aggregation: [0, 100], + * change: { + * ratio: 100, + * amount: 100 + * }, + * entities: { + * SKU: [ + * { + * id: 'service-b-sku-a', + * aggregation: [0, 25], + * change: { + * ratio: 25, + * amount: 25 + * }, + * entities: {} + * }, + * { + * id: null, // Unlabeled cost for service-b + * aggregation: [0, 75], + * change: { + * ratio: 75, + * amount: 75 + * }, + * entities: {} + * }, + * ], + * deployment: [ + * { + * id: 'service-b-env-a', + * aggregation: [0, 50], + * change: { + * ratio: 50, + * amount: 50 + * }, + * entities: {} + * }, + * { + * id: 'service-b-env-b', + * aggregation: [0, 50], + * change: { + * ratio: 50, + * amount: 50 + * }, + * entities: {} + * }, + * ] + * } + * }, + * ] + * } + * } + * ``` + */ +export interface Entity { + id: Maybe; + aggregation: [number, number]; + entities: Record; + change: ChangeStatistic; +} diff --git a/plugins/cost-insights/src/types/Group.ts b/plugins/cost-insights-common/src/types/Group.ts similarity index 97% rename from plugins/cost-insights/src/types/Group.ts rename to plugins/cost-insights-common/src/types/Group.ts index 8e0c768924..b34cac083f 100644 --- a/plugins/cost-insights/src/types/Group.ts +++ b/plugins/cost-insights-common/src/types/Group.ts @@ -14,6 +14,9 @@ * limitations under the License. */ +/** + * @public + */ export type Group = { id: string; }; diff --git a/plugins/cost-insights/src/types/Maybe.ts b/plugins/cost-insights-common/src/types/Maybe.ts similarity index 97% rename from plugins/cost-insights/src/types/Maybe.ts rename to plugins/cost-insights-common/src/types/Maybe.ts index 461c31f6a5..824c64c334 100644 --- a/plugins/cost-insights/src/types/Maybe.ts +++ b/plugins/cost-insights-common/src/types/Maybe.ts @@ -14,4 +14,7 @@ * limitations under the License. */ +/** + * @public + */ export type Maybe = T | null; diff --git a/plugins/cost-insights/src/types/Metric.ts b/plugins/cost-insights-common/src/types/Metric.ts similarity index 97% rename from plugins/cost-insights/src/types/Metric.ts rename to plugins/cost-insights-common/src/types/Metric.ts index 107513b80d..901d40f106 100644 --- a/plugins/cost-insights/src/types/Metric.ts +++ b/plugins/cost-insights-common/src/types/Metric.ts @@ -14,6 +14,9 @@ * limitations under the License. */ +/** + * @public + */ export type Metric = { kind: string; name: string; diff --git a/plugins/cost-insights/src/types/MetricData.ts b/plugins/cost-insights-common/src/types/MetricData.ts similarity index 97% rename from plugins/cost-insights/src/types/MetricData.ts rename to plugins/cost-insights-common/src/types/MetricData.ts index 225da185f8..56742e76e9 100644 --- a/plugins/cost-insights/src/types/MetricData.ts +++ b/plugins/cost-insights-common/src/types/MetricData.ts @@ -17,6 +17,9 @@ import { DateAggregation } from './DateAggregation'; import { ChangeStatistic } from './ChangeStatistic'; +/** + * @public + */ export interface MetricData { id: string; format: 'number' | 'currency'; diff --git a/plugins/cost-insights/src/types/Product.ts b/plugins/cost-insights-common/src/types/Product.ts similarity index 97% rename from plugins/cost-insights/src/types/Product.ts rename to plugins/cost-insights-common/src/types/Product.ts index 9920841223..7ed49c18da 100644 --- a/plugins/cost-insights/src/types/Product.ts +++ b/plugins/cost-insights-common/src/types/Product.ts @@ -14,6 +14,9 @@ * limitations under the License. */ +/** + * @public + */ export interface Product { kind: string; name: string; diff --git a/plugins/cost-insights/src/types/Project.ts b/plugins/cost-insights-common/src/types/Project.ts similarity index 97% rename from plugins/cost-insights/src/types/Project.ts rename to plugins/cost-insights-common/src/types/Project.ts index c12a3f1fa2..6cad92ed46 100644 --- a/plugins/cost-insights/src/types/Project.ts +++ b/plugins/cost-insights-common/src/types/Project.ts @@ -14,6 +14,9 @@ * limitations under the License. */ +/** + * @public + */ export interface Project { id: string; name?: string; diff --git a/plugins/cost-insights/src/types/Trendline.ts b/plugins/cost-insights-common/src/types/Trendline.ts similarity index 97% rename from plugins/cost-insights/src/types/Trendline.ts rename to plugins/cost-insights-common/src/types/Trendline.ts index 64405678f1..3a7e372880 100644 --- a/plugins/cost-insights/src/types/Trendline.ts +++ b/plugins/cost-insights-common/src/types/Trendline.ts @@ -13,6 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +/** + * @public + */ export type Trendline = { slope: number; intercept: number; diff --git a/plugins/cost-insights-common/src/types/index.ts b/plugins/cost-insights-common/src/types/index.ts new file mode 100644 index 0000000000..86e7af33aa --- /dev/null +++ b/plugins/cost-insights-common/src/types/index.ts @@ -0,0 +1,27 @@ +/* + * 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 * from './ChangeStatistic'; +export * from './Cost'; +export * from './DateAggregation'; +export * from './Entity'; +export * from './Group'; +export * from './Maybe'; +export * from './MetricData'; +export * from './Metric'; +export * from './Product'; +export * from './Project'; +export * from './Trendline'; diff --git a/plugins/cost-insights/CHANGELOG.md b/plugins/cost-insights/CHANGELOG.md index 5b726f558c..a5824d1cc9 100644 --- a/plugins/cost-insights/CHANGELOG.md +++ b/plugins/cost-insights/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-cost-insights +## 0.11.29-next.2 + +### Patch Changes + +- 3e032a5de2: Move cost-insights data specific API types (non react) into an @backstage/plugin-cost-insights-common + isomorphic package. This allows these types to be shared in any backend packages or other cost-insight + modules. +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/plugin-cost-insights-common@0.1.0-next.0 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + +## 0.11.29-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + +## 0.11.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + ## 0.11.28 ### Patch Changes diff --git a/plugins/cost-insights/api-report.md b/plugins/cost-insights/api-report.md index 75e1315502..5a9024de5a 100644 --- a/plugins/cost-insights/api-report.md +++ b/plugins/cost-insights/api-report.md @@ -9,9 +9,12 @@ import { ApiRef } from '@backstage/core-plugin-api'; import { BackstagePalette } from '@backstage/theme'; import { BackstagePlugin } from '@backstage/core-plugin-api'; import { BackstageTheme } from '@backstage/theme'; +import { ChangeStatistic as ChangeStatistic_2 } from '@backstage/plugin-cost-insights-common'; +import * as common from '@backstage/plugin-cost-insights-common'; import { ContentRenderer } from 'recharts'; import { Dispatch } from 'react'; import { ForwardRefExoticComponent } from 'react'; +import { Maybe as Maybe_2 } from '@backstage/plugin-cost-insights-common'; import { PaletteOptions } from '@material-ui/core/styles/createPalette'; import { PropsWithChildren } from 'react'; import { ReactNode } from 'react'; @@ -32,9 +35,9 @@ export type Alert = { status?: AlertStatus; url?: string; buttonText?: string; - SnoozeForm?: Maybe; - AcceptForm?: Maybe; - DismissForm?: Maybe; + SnoozeForm?: Maybe_2; + AcceptForm?: Maybe_2; + DismissForm?: Maybe_2; onSnoozed?(options: AlertOptions): Promise; onAccepted?(options: AlertOptions): Promise; onDismissed?(options: AlertOptions): Promise; @@ -55,9 +58,9 @@ export interface AlertCost { // @public (undocumented) export interface AlertDismissFormData { // (undocumented) - feedback: Maybe; + feedback: Maybe_2; // (undocumented) - other: Maybe; + other: Maybe_2; // (undocumented) reason: AlertDismissReason; } @@ -271,13 +274,8 @@ export type BarChartTooltipProps = { // Warning: (ae-missing-release-tag) "ChangeStatistic" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // -// @public (undocumented) -export interface ChangeStatistic { - // (undocumented) - amount: number; - // (undocumented) - ratio?: number; -} +// @public @deprecated (undocumented) +export type ChangeStatistic = common.ChangeStatistic; // Warning: (ae-missing-release-tag) "ChangeThreshold" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -289,8 +287,6 @@ export enum ChangeThreshold { upper = 0.05, } -// Warning: (ae-missing-release-tag) "ChartData" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// // @public (undocumented) export type ChartData = { date: number; @@ -301,19 +297,8 @@ export type ChartData = { // Warning: (ae-missing-release-tag) "Cost" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // -// @public (undocumented) -export interface Cost { - // (undocumented) - aggregation: DateAggregation[]; - // (undocumented) - change?: ChangeStatistic; - // (undocumented) - groupedCosts?: Record; - // (undocumented) - id: string; - // (undocumented) - trendline?: Trendline; -} +// @public @deprecated (undocumented) +export type Cost = common.Cost; // Warning: (ae-missing-release-tag) "CostGrowth" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -423,8 +408,6 @@ export interface CostInsightsThemeOptions extends PaletteOptions { palette: CostInsightsPaletteOptions; } -// Warning: (ae-missing-release-tag) "Currency" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// // @public (undocumented) export interface Currency { // (undocumented) @@ -467,19 +450,14 @@ export enum DataKey { // Warning: (ae-missing-release-tag) "DateAggregation" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // -// @public (undocumented) -export type DateAggregation = { - date: string; - amount: number; -}; +// @public @deprecated (undocumented) +export type DateAggregation = common.DateAggregation; // Warning: (ae-missing-release-tag) "DEFAULT_DATE_FORMAT" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) export const DEFAULT_DATE_FORMAT = 'yyyy-LL-dd'; -// Warning: (ae-missing-release-tag) "Duration" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// // @public export enum Duration { // (undocumented) @@ -499,17 +477,8 @@ export const EngineerThreshold = 0.5; // Warning: (ae-missing-release-tag) "Entity" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // -// @public (undocumented) -export interface Entity { - // (undocumented) - aggregation: [number, number]; - // (undocumented) - change: ChangeStatistic; - // (undocumented) - entities: Record; - // (undocumented) - id: Maybe; -} +// @public @deprecated (undocumented) +export type Entity = common.Entity; // Warning: (ae-missing-release-tag) "ExampleCostInsightsClient" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -535,10 +504,8 @@ export class ExampleCostInsightsClient implements CostInsightsApi { // Warning: (ae-missing-release-tag) "Group" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // -// @public (undocumented) -export type Group = { - id: string; -}; +// @public @deprecated (undocumented) +export type Group = common.Group; // Warning: (ae-missing-release-tag) "GrowthType" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -604,31 +571,18 @@ export type Loading = Record; // Warning: (ae-missing-release-tag) "Maybe" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // -// @public (undocumented) -export type Maybe = T | null; +// @public @deprecated (undocumented) +export type Maybe = common.Maybe; // Warning: (ae-missing-release-tag) "Metric" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // -// @public (undocumented) -export type Metric = { - kind: string; - name: string; - default: boolean; -}; +// @public @deprecated (undocumented) +export type Metric = common.Metric; // Warning: (ae-missing-release-tag) "MetricData" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // -// @public (undocumented) -export interface MetricData { - // (undocumented) - aggregation: DateAggregation[]; - // (undocumented) - change: ChangeStatistic; - // (undocumented) - format: 'number' | 'currency'; - // (undocumented) - id: string; -} +// @public @deprecated (undocumented) +export type MetricData = common.MetricData; // Warning: (ae-forgotten-export) The symbol "MockConfigProviderProps" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "MockConfigProvider" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -648,32 +602,23 @@ export const MockCurrencyProvider: ({ ...context }: MockCurrencyProviderProps) => JSX.Element; -// Warning: (ae-missing-release-tag) "PageFilters" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// // @public (undocumented) export interface PageFilters { // (undocumented) duration: Duration; // (undocumented) - group: Maybe; + group: Maybe_2; // (undocumented) metric: string | null; // (undocumented) - project: Maybe; + project: Maybe_2; } // Warning: (ae-missing-release-tag) "Product" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // -// @public (undocumented) -export interface Product { - // (undocumented) - kind: string; - // (undocumented) - name: string; -} +// @public @deprecated (undocumented) +export type Product = common.Product; -// Warning: (ae-missing-release-tag) "ProductFilters" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// // @public (undocumented) export type ProductFilters = Array; @@ -687,8 +632,6 @@ export type ProductInsightsOptions = { project: Maybe; }; -// Warning: (ae-missing-release-tag) "ProductPeriod" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// // @public (undocumented) export interface ProductPeriod { // (undocumented) @@ -699,13 +642,8 @@ export interface ProductPeriod { // Warning: (ae-missing-release-tag) "Project" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // -// @public (undocumented) -export interface Project { - // (undocumented) - id: string; - // (undocumented) - name?: string; -} +// @public @deprecated (undocumented) +export type Project = common.Project; // Warning: (ae-missing-release-tag) "ProjectGrowthAlert" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -731,7 +669,7 @@ export interface ProjectGrowthData { // (undocumented) aggregation: [number, number]; // (undocumented) - change: ChangeStatistic; + change: ChangeStatistic_2; // (undocumented) periodEnd: string; // (undocumented) @@ -749,7 +687,7 @@ export interface ResourceData { // (undocumented) current: number; // (undocumented) - name: Maybe; + name: Maybe_2; // (undocumented) previous: number; } @@ -765,11 +703,8 @@ export type TooltipItem = { // Warning: (ae-missing-release-tag) "Trendline" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // -// @public (undocumented) -export type Trendline = { - slope: number; - intercept: number; -}; +// @public @deprecated (undocumented) +export type Trendline = common.Trendline; // Warning: (ae-missing-release-tag) "UnlabeledDataflowAlert" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // diff --git a/plugins/cost-insights/contrib/aws-cost-explorer-api.md b/plugins/cost-insights/contrib/aws-cost-explorer-api.md index caa7b72e10..1e3f4e9de6 100644 --- a/plugins/cost-insights/contrib/aws-cost-explorer-api.md +++ b/plugins/cost-insights/contrib/aws-cost-explorer-api.md @@ -77,7 +77,7 @@ We can use the data provided by the Cost Explorer API to implement CostInsightsA ### 1. [getGroupDailyCost](https://github.com/backstage/backstage/blob/master/plugins/cost-insights/src/api/CostInsightsApi.ts#L93) -The `getGroupDailyCost` method is expected to return daily cost aggregations for a given group and interval time frame as a [`Cost`](https://github.com/backstage/backstage/blob/master/plugins/cost-insights/src/types/Cost.ts). +The `getGroupDailyCost` method is expected to return daily cost aggregations for a given group and interval time frame as a [`Cost`](https://github.com/backstage/backstage/blob/master/plugins/cost-insights-common/src/types/Cost.ts). #### Total Daily cost @@ -208,13 +208,13 @@ Sample `groupedCosts` based on the response: ### 2. [getProjectDailyCost](https://github.com/backstage/backstage/blob/master/plugins/cost-insights/src/api/CostInsightsApi.ts#L111) -The `getProjectDailyCost` method is expected to return daily cost aggregations for a given billing entity and interval time frame as a [`Cost`](https://github.com/backstage/backstage/blob/master/plugins/cost-insights/src/types/Cost.ts). +The `getProjectDailyCost` method is expected to return daily cost aggregations for a given billing entity and interval time frame as a [`Cost`](https://github.com/backstage/backstage/blob/master/plugins/cost-insights-common/src/types/Cost.ts). This should be similar to the `getGroupDailyCost` method implementation, but with an updated `LINKED_ACCOUNT` filter to get narrower cost data for a lower-level linked account. ### 3. [getProductInsights](https://github.com/backstage/backstage/blob/master/plugins/cost-insights/src/api/CostInsightsApi.ts#L111) -The `getProductInsights` method is expected to return cost aggregations for a particular cloud product and interval time frame as an [`Entity`](https://github.com/backstage/backstage/blob/master/plugins/cost-insights/src/types/Entity.ts). +The `getProductInsights` method is expected to return cost aggregations for a particular cloud product and interval time frame as an [`Entity`](https://github.com/backstage/backstage/blob/master/plugins/cost-insights-common/src/types/Entity.ts). #### Cloud product cost by resource diff --git a/plugins/cost-insights/package.json b/plugins/cost-insights/package.json index 9cb8d22db9..beb28546b6 100644 --- a/plugins/cost-insights/package.json +++ b/plugins/cost-insights/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-cost-insights", "description": "A Backstage plugin that helps you keep track of your cloud spend", - "version": "0.11.28", + "version": "0.11.29-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,11 +34,12 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", + "@backstage/catalog-model": "^1.1.0-next.2", "@backstage/config": "^1.0.1", - "@backstage/core-components": "^0.9.5", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/theme": "^0.2.15", + "@backstage/plugin-cost-insights-common": "^0.1.0-next.0", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -60,10 +61,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", @@ -75,7 +76,7 @@ "@types/yup": "^0.29.13", "canvas": "^2.6.1", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist", diff --git a/plugins/cost-insights/src/types/Alert.ts b/plugins/cost-insights/src/types/Alert.ts index 2f220be0e6..483b9a654d 100644 --- a/plugins/cost-insights/src/types/Alert.ts +++ b/plugins/cost-insights/src/types/Alert.ts @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { ForwardRefExoticComponent, RefAttributes } from 'react'; -import { ChangeStatistic } from './ChangeStatistic'; +import { ChangeStatistic, Maybe } from '@backstage/plugin-cost-insights-common'; import { Duration } from './Duration'; -import { Maybe } from './Maybe'; /** * Generic alert type with required fields for display. The `element` field will be rendered in diff --git a/plugins/cost-insights/src/types/ChangeStatistic.ts b/plugins/cost-insights/src/types/ChangeStatistic.ts index 6e85335a67..8264b23c8d 100644 --- a/plugins/cost-insights/src/types/ChangeStatistic.ts +++ b/plugins/cost-insights/src/types/ChangeStatistic.ts @@ -14,15 +14,6 @@ * limitations under the License. */ -export interface ChangeStatistic { - // The ratio of change from one duration to another, expressed as: (newSum - oldSum) / oldSum - // If a ratio cannot be calculated - such as when a new or old sum is zero, - // the ratio can be omitted and where applicable, ∞ or -∞ will display based on amount. - ratio?: number; - // The actual USD change between time periods (can be negative if costs decreased) - amount: number; -} - export const EngineerThreshold = 0.5; export enum ChangeThreshold { diff --git a/plugins/cost-insights/src/types/ChartData.tsx b/plugins/cost-insights/src/types/ChartData.ts similarity index 97% rename from plugins/cost-insights/src/types/ChartData.tsx rename to plugins/cost-insights/src/types/ChartData.ts index 9de8af496d..f4ae204a22 100644 --- a/plugins/cost-insights/src/types/ChartData.tsx +++ b/plugins/cost-insights/src/types/ChartData.ts @@ -14,6 +14,9 @@ * limitations under the License. */ +/** + * @public + */ export type ChartData = { date: number; trend: number; diff --git a/plugins/cost-insights/src/types/Currency.ts b/plugins/cost-insights/src/types/Currency.ts index 5cc5756dfc..4bd1490a69 100644 --- a/plugins/cost-insights/src/types/Currency.ts +++ b/plugins/cost-insights/src/types/Currency.ts @@ -14,6 +14,9 @@ * limitations under the License. */ +/** + * @public + */ export interface Currency { kind: string | null; label: string; @@ -21,10 +24,3 @@ export interface Currency { prefix?: string; rate?: number; } - -export enum CurrencyType { - USD = 'USD', - CarbonOffsetTons = 'CARBON_OFFSET_TONS', - Beers = 'BEERS', - IceCream = 'PINTS_OF_ICE_CREAM', -} diff --git a/plugins/cost-insights/src/types/CurrencyType.ts b/plugins/cost-insights/src/types/CurrencyType.ts new file mode 100644 index 0000000000..0316e8f90e --- /dev/null +++ b/plugins/cost-insights/src/types/CurrencyType.ts @@ -0,0 +1,22 @@ +/* + * 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 enum CurrencyType { + USD = 'USD', + CarbonOffsetTons = 'CARBON_OFFSET_TONS', + Beers = 'BEERS', + IceCream = 'PINTS_OF_ICE_CREAM', +} diff --git a/plugins/cost-insights/src/types/DateFormat.ts b/plugins/cost-insights/src/types/DateFormat.ts new file mode 100644 index 0000000000..c5d9c83f6e --- /dev/null +++ b/plugins/cost-insights/src/types/DateFormat.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export const DEFAULT_DATE_FORMAT = 'yyyy-LL-dd'; diff --git a/plugins/cost-insights/src/types/Duration.ts b/plugins/cost-insights/src/types/Duration.ts index 94297ac00a..dbb226df24 100644 --- a/plugins/cost-insights/src/types/Duration.ts +++ b/plugins/cost-insights/src/types/Duration.ts @@ -19,6 +19,8 @@ * 'last completed quarter', and P30D/P90D to be '[month|quarter] relative to today'. So if * it's September 15, P3M represents costs for Q2 and P30D represents August 16 - * September 15. + * + * @public */ export enum Duration { P7D = 'P7D', @@ -26,5 +28,3 @@ export enum Duration { P90D = 'P90D', P3M = 'P3M', } - -export const DEFAULT_DATE_FORMAT = 'yyyy-LL-dd'; diff --git a/plugins/cost-insights/src/types/Entity.ts b/plugins/cost-insights/src/types/Entity.ts deleted file mode 100644 index ccfea6667e..0000000000 --- a/plugins/cost-insights/src/types/Entity.ts +++ /dev/null @@ -1,118 +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 { ChangeStatistic } from './ChangeStatistic'; -import { Maybe } from './Maybe'; - -export interface Entity { - id: Maybe; - aggregation: [number, number]; - entities: Record; - change: ChangeStatistic; -} - -/* - An entity is a tree-like structure that represents any unique - product or service that generates cost over a fixed period of time. - An entity could be atomic or composite. An atomic entity is indivisible - and cannot be broken into sub-entities. - - A composite entity is divided into sub-entities that account for portions - of the total cost **over the same time period**. The root entity is - expected to only have _one_ Record consisting of the sub-entities to display - in the product panel (keyed by the entity type, such as "service" for - compute entities). - - The root sub-entities may have multiple breakdowns - for example, a - breakdown of an entity cost by SKU vs deployment environment. The sum - aggregated cost of each keyed breakdown should equal the sub-entity's cost. - - Entities with null ids are considered "unlabeled" - costs without attribution. - If an entity is a composite, it may only have one (1) null child but may have any number of - null grandchildren. - - { - id: 'product', - aggregation: [0, 200], - change: { - ratio: 2000, - amount: 200 - }, - entities: { - service: [ - { - id: 'service-a', - aggregation: [0, 100], - change: { - ratio: 100, - amount: 100 - }, - entities: {} - }, - { - id: 'service-b', - aggregation: [0, 100], - change: { - ratio: 100, - amount: 100 - }, - entities: { - SKU: [ - { - id: 'service-b-sku-a', - aggregation: [0, 25], - change: { - ratio: 25, - amount: 25 - }, - entities: {} - }, - { - id: null, // Unlabeled cost for service-b - aggregation: [0, 75], - change: { - ratio: 75, - amount: 75 - }, - entities: {} - }, - ], - deployment: [ - { - id: 'service-b-env-a', - aggregation: [0, 50], - change: { - ratio: 50, - amount: 50 - }, - entities: {} - }, - { - id: 'service-b-env-b', - aggregation: [0, 50], - change: { - ratio: 50, - amount: 50 - }, - entities: {} - }, - ] - } - }, - ] - } - } -*/ diff --git a/plugins/cost-insights/src/types/Filters.ts b/plugins/cost-insights/src/types/Filters.ts index 6beef5cacc..d307243ad0 100644 --- a/plugins/cost-insights/src/types/Filters.ts +++ b/plugins/cost-insights/src/types/Filters.ts @@ -14,9 +14,12 @@ * limitations under the License. */ -import { Maybe } from './Maybe'; +import { Maybe } from '@backstage/plugin-cost-insights-common'; import { Duration } from './Duration'; +/** + * @public + */ export interface PageFilters { group: Maybe; project: Maybe; @@ -24,8 +27,14 @@ export interface PageFilters { metric: string | null; } +/** + * @public + */ export type ProductFilters = Array; +/** + * @public + */ export interface ProductPeriod { duration: Duration; productType: string; diff --git a/plugins/cost-insights/src/types/index.ts b/plugins/cost-insights/src/types/index.ts index 5f090cc7eb..b836914e73 100644 --- a/plugins/cost-insights/src/types/index.ts +++ b/plugins/cost-insights/src/types/index.ts @@ -14,22 +14,66 @@ * limitations under the License. */ +// TODO: Split some of these up into `@backstage/plugin-cost-insights-react` for presentation types +// and `@backstage/plugin-cost-insights-common` for data transfer object types. export * from './Alert'; export * from './ChangeStatistic'; export * from './ChartData'; -export * from './Cost'; -export * from './DateAggregation'; -export * from './Duration'; export * from './Currency'; -export * from './Entity'; -export * from './Icon'; +export * from './CurrencyType'; +export * from './DateFormat'; +export * from './Duration'; export * from './Filters'; -export * from './Group'; +export * from './Icon'; export * from './Loading'; -export * from './Maybe'; -export * from './MetricData'; -export * from './Metric'; -export * from './Product'; -export * from './Project'; export * from './Theme'; -export * from './Trendline'; + +/** + * Deprecated types moved to `@backstage/plugin-cost-insights-common` + */ +import * as common from '@backstage/plugin-cost-insights-common'; + +/** + * @deprecated use the same type from `@backstage/plugin-cost-insights-common` instead + */ +export type ChangeStatistic = common.ChangeStatistic; +/** + * @deprecated use the same type from `@backstage/plugin-cost-insights-common` instead + */ +export type Cost = common.Cost; +/** + * @deprecated use the same type from `@backstage/plugin-cost-insights-common` instead + */ +export type DateAggregation = common.DateAggregation; +/** + * @deprecated use the same type from `@backstage/plugin-cost-insights-common` instead + */ +export type Entity = common.Entity; +/** + * @deprecated use the same type from `@backstage/plugin-cost-insights-common` instead + */ +export type Group = common.Group; +/** + * @deprecated use the same type from `@backstage/plugin-cost-insights-common` instead + */ +export type Maybe = common.Maybe; +/** + * @deprecated use the same type from `@backstage/plugin-cost-insights-common` instead + */ +export type Metric = common.Metric; +/** + * @deprecated use the same type from `@backstage/plugin-cost-insights-common` instead + */ +export type MetricData = common.MetricData; +/** + * @deprecated use the same type from `@backstage/plugin-cost-insights-common` instead + */ +export type Product = common.Product; +/** + * @deprecated use the same type from `@backstage/plugin-cost-insights-common` instead + */ +export type Project = common.Project; +/** + * @deprecated use the same type from `@backstage/plugin-cost-insights-common` instead + */ +export type Trendline = common.Trendline; diff --git a/plugins/dynatrace/CHANGELOG.md b/plugins/dynatrace/CHANGELOG.md index fddf3667af..ffe12d4991 100644 --- a/plugins/dynatrace/CHANGELOG.md +++ b/plugins/dynatrace/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/plugin-dynatrace +## 0.1.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + +## 0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + +## 0.1.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + ## 0.1.0 ### Minor Changes diff --git a/plugins/dynatrace/package.json b/plugins/dynatrace/package.json index 9ee59f38a3..0bf3c2f26c 100644 --- a/plugins/dynatrace/package.json +++ b/plugins/dynatrace/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-dynatrace", - "version": "0.1.0", + "version": "0.1.1-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,10 +22,10 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", - "@backstage/core-components": "^0.9.5", + "@backstage/catalog-model": "^1.1.0-next.2", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/theme": "^0.2.15", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.9.13", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -33,14 +33,14 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "@backstage/plugin-catalog-react": "^1.1.1-next.1", + "@backstage/plugin-catalog-react": "^1.1.2-next.0", "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", @@ -48,7 +48,7 @@ "@types/node": "*", "cross-fetch": "^3.1.5", "express": "^4.18.1", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist", diff --git a/plugins/example-todo-list-backend/CHANGELOG.md b/plugins/example-todo-list-backend/CHANGELOG.md index 46a980fbe3..4609c6c4ea 100644 --- a/plugins/example-todo-list-backend/CHANGELOG.md +++ b/plugins/example-todo-list-backend/CHANGELOG.md @@ -1,5 +1,22 @@ # @internal/plugin-todo-list-backend +## 1.0.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/plugin-auth-node@0.2.3-next.1 + +## 1.0.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/plugin-auth-node@0.2.3-next.0 + ## 1.0.2 ### Patch Changes diff --git a/plugins/example-todo-list-backend/package.json b/plugins/example-todo-list-backend/package.json index 7aaed0532b..67fc049267 100644 --- a/plugins/example-todo-list-backend/package.json +++ b/plugins/example-todo-list-backend/package.json @@ -1,10 +1,13 @@ { "name": "@internal/plugin-todo-list-backend", - "version": "1.0.2", + "version": "1.0.3-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", "private": true, + "backstage": { + "role": "backend-plugin" + }, "publishConfig": { "access": "public", "main": "dist/index.cjs.js", @@ -20,10 +23,10 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", + "@backstage/backend-common": "^0.14.1-next.1", "@backstage/config": "^1.0.1", - "@backstage/errors": "^1.0.0", - "@backstage/plugin-auth-node": "^0.2.2", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/plugin-auth-node": "^0.2.3-next.1", "@types/express": "^4.17.6", "cross-fetch": "^3.1.5", "express": "^4.17.1", @@ -33,10 +36,10 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", + "@backstage/cli": "^0.18.0-next.1", "@types/supertest": "^2.0.8", "@types/uuid": "^8.0.0", - "msw": "^0.42.0", + "msw": "^0.43.0", "supertest": "^6.1.6" }, "files": [ diff --git a/plugins/example-todo-list-common/CHANGELOG.md b/plugins/example-todo-list-common/CHANGELOG.md index 564b1f57eb..ba6a7bcf3d 100644 --- a/plugins/example-todo-list-common/CHANGELOG.md +++ b/plugins/example-todo-list-common/CHANGELOG.md @@ -1,5 +1,12 @@ # @internal/plugin-todo-list-common +## 1.0.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.6.3-next.0 + ## 1.0.2 ### Patch Changes diff --git a/plugins/example-todo-list-common/package.json b/plugins/example-todo-list-common/package.json index 596a37b210..b06328608a 100644 --- a/plugins/example-todo-list-common/package.json +++ b/plugins/example-todo-list-common/package.json @@ -1,6 +1,6 @@ { "name": "@internal/plugin-todo-list-common", - "version": "1.0.2", + "version": "1.0.3-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -11,7 +11,7 @@ "types": "dist/index.d.ts" }, "backstage": { - "role": "frontend-plugin" + "role": "common-library" }, "scripts": { "start": "backstage-cli package start", @@ -23,15 +23,15 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/plugin-permission-common": "^0.6.2" + "@backstage/plugin-permission-common": "^0.6.3-next.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.1", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.1", + "@backstage/test-utils": "^1.1.2-next.1", "@types/node": "^16.11.26", - "msw": "^0.42.0", + "msw": "^0.43.0", "cross-fetch": "^3.1.5" }, "files": [ diff --git a/plugins/example-todo-list/CHANGELOG.md b/plugins/example-todo-list/CHANGELOG.md index 31404fa73d..e73d0d6474 100644 --- a/plugins/example-todo-list/CHANGELOG.md +++ b/plugins/example-todo-list/CHANGELOG.md @@ -1,5 +1,28 @@ # @internal/plugin-todo-list +## 1.0.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + +## 1.0.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/theme@0.2.16-next.0 + +## 1.0.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + ## 1.0.2 ### Patch Changes diff --git a/plugins/example-todo-list/package.json b/plugins/example-todo-list/package.json index c80b9a48ea..3531995880 100644 --- a/plugins/example-todo-list/package.json +++ b/plugins/example-todo-list/package.json @@ -1,10 +1,13 @@ { "name": "@internal/plugin-todo-list", - "version": "1.0.2", + "version": "1.0.3-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", "private": true, + "backstage": { + "role": "frontend-plugin" + }, "publishConfig": { "access": "public", "main": "dist/index.esm.js", @@ -21,9 +24,9 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.9.5", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/theme": "^0.2.15", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -33,16 +36,16 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/jest": "^26.0.7", "@types/node": "^16.11.26", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/explore-react/package.json b/plugins/explore-react/package.json index 00ec76258d..b23867d8a7 100644 --- a/plugins/explore-react/package.json +++ b/plugins/explore-react/package.json @@ -36,16 +36,16 @@ "@backstage/core-plugin-api": "^1.0.3" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.1", + "@backstage/dev-utils": "^1.0.4-next.1", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/jest": "^26.0.7", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/explore/CHANGELOG.md b/plugins/explore/CHANGELOG.md index 712e3203fb..ecb1209c85 100644 --- a/plugins/explore/CHANGELOG.md +++ b/plugins/explore/CHANGELOG.md @@ -1,5 +1,34 @@ # @backstage/plugin-explore +## 0.3.38-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## 0.3.38-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## 0.3.38-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + ## 0.3.37 ### Patch Changes diff --git a/plugins/explore/package.json b/plugins/explore/package.json index 201be77085..729aee7322 100644 --- a/plugins/explore/package.json +++ b/plugins/explore/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-explore", "description": "A Backstage plugin for building an exploration page of your software ecosystem", - "version": "0.3.37", + "version": "0.3.38-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,12 +34,12 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", - "@backstage/core-components": "^0.9.5", + "@backstage/catalog-model": "^1.1.0-next.2", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/plugin-catalog-react": "^1.1.1", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", "@backstage/plugin-explore-react": "^0.0.18", - "@backstage/theme": "^0.2.15", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -53,17 +53,17 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/jest": "^26.0.7", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/firehydrant/CHANGELOG.md b/plugins/firehydrant/CHANGELOG.md index 065d6e0bd5..c03b08e828 100644 --- a/plugins/firehydrant/CHANGELOG.md +++ b/plugins/firehydrant/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-firehydrant +## 0.1.24-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## 0.1.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## 0.1.24-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + ## 0.1.23 ### Patch Changes diff --git a/plugins/firehydrant/package.json b/plugins/firehydrant/package.json index a86a122fd0..2690fbcb1d 100644 --- a/plugins/firehydrant/package.json +++ b/plugins/firehydrant/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-firehydrant", "description": "A Backstage plugin that integrates towards FireHydrant", - "version": "0.1.23", + "version": "0.1.24-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -25,10 +25,10 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.9.5", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/plugin-catalog-react": "^1.1.1", - "@backstage/theme": "^0.2.15", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -39,17 +39,17 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/jest": "^26.0.7", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/fossa/CHANGELOG.md b/plugins/fossa/CHANGELOG.md index 07880deb60..99d6445627 100644 --- a/plugins/fossa/CHANGELOG.md +++ b/plugins/fossa/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-fossa +## 0.2.39-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## 0.2.39-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## 0.2.39-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + ## 0.2.38 ### Patch Changes diff --git a/plugins/fossa/README.md b/plugins/fossa/README.md index 898c9d0475..10ccba5ba7 100644 --- a/plugins/fossa/README.md +++ b/plugins/fossa/README.md @@ -43,9 +43,12 @@ proxy: headers: Authorization: token ${FOSSA_API_TOKEN} -# if you have a fossa organization, configure your id here fossa: + # if you have a fossa organization, configure your id here organizationId: + # if you have a self-managed fossa instance, + # configure the baseUrl to use for links to the fossa page here + externalLinkBaseUrl: ``` 4. Get an api-token and provide `FOSSA_AUTH_HEADER` as env variable (https://app.fossa.com/account/settings/integrations/api_tokens) diff --git a/plugins/fossa/config.d.ts b/plugins/fossa/config.d.ts index 72d844c4e9..26a2823097 100644 --- a/plugins/fossa/config.d.ts +++ b/plugins/fossa/config.d.ts @@ -20,6 +20,12 @@ export interface Config { * The organization id in fossa. * @visibility frontend */ - organizationId: string; + organizationId?: string; + + /** + * The base url to use for external links (from Backstage to Fossa). + * @visibility frontend + */ + externalLinkBaseUrl?: string; }; } diff --git a/plugins/fossa/package.json b/plugins/fossa/package.json index e97dc7c0f9..223a246151 100644 --- a/plugins/fossa/package.json +++ b/plugins/fossa/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-fossa", "description": "A Backstage plugin that integrates towards FOSSA", - "version": "0.2.38", + "version": "0.2.39-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,12 +35,12 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", - "@backstage/core-components": "^0.9.5", + "@backstage/catalog-model": "^1.1.0-next.2", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/errors": "^1.0.0", - "@backstage/plugin-catalog-react": "^1.1.1", - "@backstage/theme": "^0.2.15", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -53,16 +53,16 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/jest": "^26.0.7", "@types/node": "^16.11.26", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist", diff --git a/plugins/fossa/src/api/FossaClient.test.ts b/plugins/fossa/src/api/FossaClient.test.ts index 65b0fc1d53..0e2dc81e1f 100644 --- a/plugins/fossa/src/api/FossaClient.test.ts +++ b/plugins/fossa/src/api/FossaClient.test.ts @@ -175,6 +175,58 @@ describe('FossaClient', () => { expect(summary).toBeUndefined(); }); + it('should allow custom external link base url', async () => { + client = new FossaClient({ + discoveryApi, + identityApi, + organizationId: '8736', + externalLinkBaseUrl: 'https://custom.fossa.com', // overrides the default app.fossa.com + }); + server.use( + rest.get(`${mockBaseUrl}/fossa/projects`, (req, res, ctx) => { + const expectedQuery = + 'count=1000&page=0&sort=title%2B&organizationId=8736&title=our-service'; + if (req.url.searchParams.toString() !== expectedQuery) { + return res( + ctx.status(500), + ctx.body( + `${req.url.searchParams.toString()} !== ${expectedQuery}`, + ), + ); + } + + return res( + ctx.json([ + { + locator: 'custom+8736/our-service', + title: 'our-service', + default_branch: 'develop', + revisions: [ + { + updatedAt: '2020-01-01T00:00:00Z', + dependency_count: 160, + unresolved_licensing_issue_count: 5, + unresolved_issue_count: 100, + }, + ], + }, + ]), + ); + }), + ); + + const summary = await client.getFindingSummary('our-service'); + + expect(summary).toEqual({ + timestamp: '2020-01-01T00:00:00Z', + issueCount: 5, + dependencyCount: 160, + projectDefaultBranch: 'develop', + projectUrl: + 'https://custom.fossa.com/projects/custom%2B8736%2Four-service', + } as FindingSummary); + }); + it('should handle 404 status', async () => { server.use( rest.get(`${mockBaseUrl}/fossa/projects`, (_req, res, ctx) => { diff --git a/plugins/fossa/src/api/FossaClient.ts b/plugins/fossa/src/api/FossaClient.ts index 66b44de21e..8b4b4b02e5 100644 --- a/plugins/fossa/src/api/FossaClient.ts +++ b/plugins/fossa/src/api/FossaClient.ts @@ -36,20 +36,24 @@ export class FossaClient implements FossaApi { discoveryApi: DiscoveryApi; identityApi: IdentityApi; organizationId?: string; + externalLinkBaseUrl: string; private readonly limit = pLimit(5); constructor({ discoveryApi, identityApi, organizationId, + externalLinkBaseUrl = 'https://app.fossa.com', }: { discoveryApi: DiscoveryApi; identityApi: IdentityApi; organizationId?: string; + externalLinkBaseUrl?: string; }) { this.discoveryApi = discoveryApi; this.identityApi = identityApi; this.organizationId = organizationId; + this.externalLinkBaseUrl = externalLinkBaseUrl; } private async callApi( @@ -104,9 +108,9 @@ export class FossaClient implements FossaApi { revision.unresolved_issue_count, dependencyCount: revision.dependency_count, projectDefaultBranch: project.default_branch, - projectUrl: `https://app.fossa.com/projects/${encodeURIComponent( - project.locator, - )}`, + projectUrl: `${ + this.externalLinkBaseUrl + }/projects/${encodeURIComponent(project.locator)}`, }, }; } diff --git a/plugins/fossa/src/plugin.ts b/plugins/fossa/src/plugin.ts index a586d6d8a6..954ecedc81 100644 --- a/plugins/fossa/src/plugin.ts +++ b/plugins/fossa/src/plugin.ts @@ -39,6 +39,9 @@ export const fossaPlugin = createPlugin({ discoveryApi, identityApi, organizationId: configApi.getOptionalString('fossa.organizationId'), + externalLinkBaseUrl: configApi.getOptionalString( + 'fossa.externalLinkBaseUrl', + ), }), }), ], diff --git a/plugins/gcalendar/CHANGELOG.md b/plugins/gcalendar/CHANGELOG.md index c5d63a19db..12e37176a7 100644 --- a/plugins/gcalendar/CHANGELOG.md +++ b/plugins/gcalendar/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-gcalendar +## 0.3.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + +## 0.3.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + +## 0.3.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + ## 0.3.2 ### Patch Changes diff --git a/plugins/gcalendar/package.json b/plugins/gcalendar/package.json index b74129b8bc..3024c80e26 100644 --- a/plugins/gcalendar/package.json +++ b/plugins/gcalendar/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-gcalendar", - "version": "0.3.2", + "version": "0.3.3-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,10 +22,10 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/core-components": "^0.9.5", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/errors": "^1.0.0", - "@backstage/theme": "^0.2.15", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -43,10 +43,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", @@ -55,7 +55,7 @@ "@types/node": "^16.11.26", "@types/sanitize-html": "^2.6.2", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/gcp-projects/CHANGELOG.md b/plugins/gcp-projects/CHANGELOG.md index 6c95f8ea4d..f2bedb646f 100644 --- a/plugins/gcp-projects/CHANGELOG.md +++ b/plugins/gcp-projects/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-gcp-projects +## 0.3.26-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + +## 0.3.26-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/theme@0.2.16-next.0 + +## 0.3.26-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + ## 0.3.25 ### Patch Changes diff --git a/plugins/gcp-projects/package.json b/plugins/gcp-projects/package.json index 0434e6b25a..c3809ffaac 100644 --- a/plugins/gcp-projects/package.json +++ b/plugins/gcp-projects/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-gcp-projects", "description": "A Backstage plugin that helps you manage projects in GCP", - "version": "0.3.25", + "version": "0.3.26-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,9 +34,9 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.9.5", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/theme": "^0.2.15", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -47,17 +47,17 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/jest": "^26.0.7", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/git-release-manager/CHANGELOG.md b/plugins/git-release-manager/CHANGELOG.md index 7b3a0bc993..e617ca7342 100644 --- a/plugins/git-release-manager/CHANGELOG.md +++ b/plugins/git-release-manager/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-git-release-manager +## 0.3.20-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/integration@1.2.2-next.2 + +## 0.3.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/integration@1.2.2-next.1 + +## 0.3.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + - @backstage/integration@1.2.2-next.0 + ## 0.3.19 ### Patch Changes diff --git a/plugins/git-release-manager/package.json b/plugins/git-release-manager/package.json index 9ae263b882..28bfa001a0 100644 --- a/plugins/git-release-manager/package.json +++ b/plugins/git-release-manager/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-git-release-manager", "description": "A Backstage plugin that helps you manage releases in git", - "version": "0.3.19", + "version": "0.3.20-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -24,10 +24,10 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.9.5", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/integration": "^1.2.1", - "@backstage/theme": "^0.2.15", + "@backstage/integration": "^1.2.2-next.2", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -43,10 +43,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/react-hooks": "^8.0.0", @@ -55,7 +55,7 @@ "@types/node": "^16.11.26", "@types/recharts": "^1.8.15", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/github-actions/CHANGELOG.md b/plugins/github-actions/CHANGELOG.md index 23e66cc1f6..de2a693116 100644 --- a/plugins/github-actions/CHANGELOG.md +++ b/plugins/github-actions/CHANGELOG.md @@ -1,5 +1,38 @@ # @backstage/plugin-github-actions +## 0.5.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/integration@1.2.2-next.2 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## 0.5.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/integration@1.2.2-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## 0.5.7-next.0 + +### Patch Changes + +- 217f919f0a: Minor cleanup of the API surface. +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + ## 0.5.6 ### Patch Changes diff --git a/plugins/github-actions/package.json b/plugins/github-actions/package.json index f843755e9b..eefc7c1f4c 100644 --- a/plugins/github-actions/package.json +++ b/plugins/github-actions/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-github-actions", "description": "A Backstage plugin that integrates towards GitHub Actions", - "version": "0.5.6", + "version": "0.5.7-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -36,12 +36,12 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", - "@backstage/core-components": "^0.9.5", + "@backstage/catalog-model": "^1.1.0-next.2", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/integration": "^1.2.1", - "@backstage/plugin-catalog-react": "^1.1.1", - "@backstage/theme": "^0.2.15", + "@backstage/integration": "^1.2.2-next.2", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -55,17 +55,17 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/jest": "^26.0.7", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/github-deployments/CHANGELOG.md b/plugins/github-deployments/CHANGELOG.md index 45a93e3b34..cd0542d5cf 100644 --- a/plugins/github-deployments/CHANGELOG.md +++ b/plugins/github-deployments/CHANGELOG.md @@ -1,5 +1,41 @@ # @backstage/plugin-github-deployments +## 0.1.38-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/integration@1.2.2-next.2 + - @backstage/plugin-catalog-react@1.1.2-next.2 + - @backstage/integration-react@1.1.2-next.2 + +## 0.1.38-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + - @backstage/integration@1.2.2-next.1 + - @backstage/integration-react@1.1.2-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## 0.1.38-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + - @backstage/integration-react@1.1.2-next.0 + ## 0.1.37 ### Patch Changes diff --git a/plugins/github-deployments/package.json b/plugins/github-deployments/package.json index 1a27d21aa2..cbfc076a9b 100644 --- a/plugins/github-deployments/package.json +++ b/plugins/github-deployments/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-github-deployments", "description": "A Backstage plugin that integrates towards GitHub Deployments", - "version": "0.1.37", + "version": "0.1.38-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -24,14 +24,14 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", - "@backstage/core-components": "^0.9.5", + "@backstage/catalog-model": "^1.1.0-next.2", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/errors": "^1.0.0", - "@backstage/integration": "^1.2.1", - "@backstage/integration-react": "^1.1.1", - "@backstage/plugin-catalog-react": "^1.1.1", - "@backstage/theme": "^0.2.15", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/integration": "^1.2.2-next.2", + "@backstage/integration-react": "^1.1.2-next.2", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -43,17 +43,17 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/jest": "^26.0.7", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/github-pull-requests-board/CHANGELOG.md b/plugins/github-pull-requests-board/CHANGELOG.md index 629713540e..91faf82d07 100644 --- a/plugins/github-pull-requests-board/CHANGELOG.md +++ b/plugins/github-pull-requests-board/CHANGELOG.md @@ -1,5 +1,39 @@ # @backstage/plugin-github-pull-requests-board +## 0.1.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/integration@1.2.2-next.2 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## 0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/integration@1.2.2-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## 0.1.1-next.0 + +### Patch Changes + +- c6690d9d24: Fix bug on fetching teams repositories where were being filtered by type service unnecessarily +- 04e1504e85: Support namespaced teams and fetch all kinds +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + ## 0.1.0 ### Minor Changes diff --git a/plugins/github-pull-requests-board/package.json b/plugins/github-pull-requests-board/package.json index 24909c5b5d..c167cc8d88 100644 --- a/plugins/github-pull-requests-board/package.json +++ b/plugins/github-pull-requests-board/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-github-pull-requests-board", "description": "A Backstage plugin that allows you to see all open Pull Requests for all the repositories owned by your team", - "version": "0.1.0", + "version": "0.1.1-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,12 +35,12 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", - "@backstage/core-components": "^0.9.5", + "@backstage/catalog-model": "^1.1.0-next.2", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/integration": "^1.2.1", - "@backstage/plugin-catalog-react": "^1.1.1", - "@backstage/theme": "^0.2.15", + "@backstage/integration": "^1.2.2-next.2", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -49,16 +49,16 @@ "react-use": "^17.2.4" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/jest": "^26.0.7", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "peerDependencies": { "@types/react": "^16.13.1 || ^17.0.0", diff --git a/plugins/github-pull-requests-board/src/hooks/useUserRepositories.tsx b/plugins/github-pull-requests-board/src/hooks/useUserRepositories.tsx index 638a8cb487..b905811aea 100644 --- a/plugins/github-pull-requests-board/src/hooks/useUserRepositories.tsx +++ b/plugins/github-pull-requests-board/src/hooks/useUserRepositories.tsx @@ -14,7 +14,11 @@ * limitations under the License. */ import { useApi } from '@backstage/core-plugin-api'; -import { useEntity, catalogApiRef } from '@backstage/plugin-catalog-react'; +import { + catalogApiRef, + humanizeEntityRef, + useEntity, +} from '@backstage/plugin-catalog-react'; import { useCallback, useEffect, useState } from 'react'; import { getProjectNameFromEntity } from '../utils/functions'; @@ -26,8 +30,7 @@ export function useUserRepositories() { const getRepositoriesNames = useCallback(async () => { const entitiesList = await catalogApi.getEntities({ filter: { - kind: 'Component', - 'spec.owner': teamEntity?.metadata?.name, + 'spec.owner': humanizeEntityRef(teamEntity, { defaultKind: 'group' }), }, }); @@ -36,7 +39,7 @@ export function useUserRepositories() { ); setRepositories([...new Set(entitiesNames)]); - }, [catalogApi, teamEntity?.metadata?.name]); + }, [catalogApi, teamEntity]); useEffect(() => { getRepositoriesNames(); diff --git a/plugins/gitops-profiles/CHANGELOG.md b/plugins/gitops-profiles/CHANGELOG.md index eea6cc0554..0c47ffc99f 100644 --- a/plugins/gitops-profiles/CHANGELOG.md +++ b/plugins/gitops-profiles/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-gitops-profiles +## 0.3.25-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + +## 0.3.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/theme@0.2.16-next.0 + +## 0.3.25-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + ## 0.3.24 ### Patch Changes diff --git a/plugins/gitops-profiles/package.json b/plugins/gitops-profiles/package.json index ee7b3da11b..3b48f5a6a1 100644 --- a/plugins/gitops-profiles/package.json +++ b/plugins/gitops-profiles/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-gitops-profiles", "description": "A Backstage plugin that helps you manage GitOps profiles", - "version": "0.3.24", + "version": "0.3.25-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,9 +35,9 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.9.5", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/theme": "^0.2.15", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -48,17 +48,17 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/jest": "^26.0.7", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/gocd/CHANGELOG.md b/plugins/gocd/CHANGELOG.md index 1df24b97cd..692a789447 100644 --- a/plugins/gocd/CHANGELOG.md +++ b/plugins/gocd/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-gocd +## 0.1.13-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## 0.1.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## 0.1.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + ## 0.1.12 ### Patch Changes diff --git a/plugins/gocd/package.json b/plugins/gocd/package.json index 1bf938fb1d..a7d968d3c7 100644 --- a/plugins/gocd/package.json +++ b/plugins/gocd/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-gocd", "description": "A Backstage plugin that integrates towards GoCD", - "version": "0.1.12", + "version": "0.1.13-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,12 +31,12 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", - "@backstage/core-components": "^0.9.5", + "@backstage/catalog-model": "^1.1.0-next.2", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/errors": "^1.0.0", - "@backstage/plugin-catalog-react": "^1.1.1", - "@backstage/theme": "^0.2.15", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -49,10 +49,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", @@ -61,7 +61,7 @@ "@types/luxon": "^2.0.4", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist", diff --git a/plugins/graphiql/CHANGELOG.md b/plugins/graphiql/CHANGELOG.md index 56cc49f3a4..c034cef2b5 100644 --- a/plugins/graphiql/CHANGELOG.md +++ b/plugins/graphiql/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-graphiql +## 0.2.39-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + +## 0.2.39-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/theme@0.2.16-next.0 + +## 0.2.39-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + ## 0.2.38 ### Patch Changes diff --git a/plugins/graphiql/package.json b/plugins/graphiql/package.json index 4cbbc7f262..0b124ecbc9 100644 --- a/plugins/graphiql/package.json +++ b/plugins/graphiql/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-graphiql", "description": "Backstage plugin for browsing GraphQL APIs", - "version": "0.2.38", + "version": "0.2.39-next.2", "private": false, "publishConfig": { "access": "public", @@ -34,9 +34,9 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.9.5", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/theme": "^0.2.15", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -49,10 +49,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", @@ -60,7 +60,7 @@ "@types/jest": "^26.0.7", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.42.0", + "msw": "^0.43.0", "react-router-dom": "6.0.0-beta.0" }, "files": [ diff --git a/plugins/graphql-backend/CHANGELOG.md b/plugins/graphql-backend/CHANGELOG.md index d1426552e0..0f826cd492 100644 --- a/plugins/graphql-backend/CHANGELOG.md +++ b/plugins/graphql-backend/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-graphql-backend +## 0.1.24-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/plugin-catalog-graphql@0.3.11-next.0 + ## 0.1.23 ### Patch Changes diff --git a/plugins/graphql-backend/package.json b/plugins/graphql-backend/package.json index d7b03bddf5..0664f5a44d 100644 --- a/plugins/graphql-backend/package.json +++ b/plugins/graphql-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-graphql-backend", "description": "An experimental Backstage backend plugin for GraphQL", - "version": "0.1.23", + "version": "0.1.24-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,9 +34,9 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", + "@backstage/backend-common": "^0.14.1-next.1", "@backstage/config": "^1.0.1", - "@backstage/plugin-catalog-graphql": "^0.3.10", + "@backstage/plugin-catalog-graphql": "^0.3.11-next.0", "@graphql-tools/schema": "^8.3.1", "@types/express": "^4.17.6", "apollo-server": "^3.0.0", @@ -51,9 +51,9 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", + "@backstage/cli": "^0.18.0-next.1", "@types/supertest": "^2.0.8", - "msw": "^0.42.0", + "msw": "^0.43.0", "supertest": "^6.1.3" }, "files": [ diff --git a/plugins/home/CHANGELOG.md b/plugins/home/CHANGELOG.md index ef03c3797c..bb2e5d7405 100644 --- a/plugins/home/CHANGELOG.md +++ b/plugins/home/CHANGELOG.md @@ -1,5 +1,60 @@ # @backstage/plugin-home +## 0.4.23-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + - @backstage/plugin-stack-overflow@0.1.3-next.2 + +## 0.4.23-next.1 + +### Patch Changes + +- a46e317a75: Added support for customizing the time format used in the `HeaderWorldClock` component + + Here's an example of how this can be used in the `HomePage.tsx` found in `\packages\app\src\components\home` to change the clock to be in the 24hr time format: + + ```diff + +const timeFormat: Intl.DateTimeFormatOptions = { + + hour: '2-digit', + + minute: '2-digit', + + hour12: false, + +}; + + export const homePage = ( + +
} pageTitleOverride="Home"> + + +
+ + + + + + ``` + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/plugin-stack-overflow@0.1.3-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## 0.4.23-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-stack-overflow@0.1.3-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + ## 0.4.22 ### Patch Changes diff --git a/plugins/home/api-report.md b/plugins/home/api-report.md index a65f8cda5c..452b3e1685 100644 --- a/plugins/home/api-report.md +++ b/plugins/home/api-report.md @@ -59,9 +59,10 @@ export function createCardExtension(options: { name?: string; }): Extension<(props: CardExtensionProps) => JSX.Element>; -// @public (undocumented) +// @public export const HeaderWorldClock: (props: { clockConfigs: ClockConfig[]; + customTimeFormat?: Intl.DateTimeFormatOptions | undefined; }) => JSX.Element | null; // @public diff --git a/plugins/home/package.json b/plugins/home/package.json index d1529a37fd..4800ba1842 100644 --- a/plugins/home/package.json +++ b/plugins/home/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-home", "description": "A Backstage plugin that helps you build a home page", - "version": "0.4.22", + "version": "0.4.23-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,13 +34,13 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", + "@backstage/catalog-model": "^1.1.0-next.2", "@backstage/config": "^1.0.1", - "@backstage/core-components": "^0.9.5", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/plugin-catalog-react": "^1.1.1", - "@backstage/plugin-stack-overflow": "^0.1.2", - "@backstage/theme": "^0.2.15", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", + "@backstage/plugin-stack-overflow": "^0.1.3-next.2", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -53,17 +53,17 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/jest": "^26.0.7", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/home/src/components/index.ts b/plugins/home/src/components/index.ts index 1408853f5f..aae0cbe26d 100644 --- a/plugins/home/src/components/index.ts +++ b/plugins/home/src/components/index.ts @@ -16,5 +16,3 @@ export { HomepageCompositionRoot } from './HomepageCompositionRoot'; export { SettingsModal } from './SettingsModal'; -export { HeaderWorldClock } from './HeaderWorldClock'; -export type { ClockConfig } from './HeaderWorldClock'; diff --git a/plugins/home/src/homePageComponents/HeaderWorldClock/HeaderWorldClock.stories.tsx b/plugins/home/src/homePageComponents/HeaderWorldClock/HeaderWorldClock.stories.tsx new file mode 100644 index 0000000000..706dfa06ce --- /dev/null +++ b/plugins/home/src/homePageComponents/HeaderWorldClock/HeaderWorldClock.stories.tsx @@ -0,0 +1,97 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Header } from '@backstage/core-components'; +import { wrapInTestApp } from '@backstage/test-utils'; +import React, { ComponentType } from 'react'; +import { ClockConfig, HeaderWorldClock } from './HeaderWorldClock'; + +export default { + title: 'Plugins/Home/Components/HeaderWorldClock', + decorators: [(Story: ComponentType<{}>) => wrapInTestApp()], +}; + +export const Default = () => { + const clockConfigs: ClockConfig[] = [ + { + label: 'NYC', + timeZone: 'America/New_York', + }, + { + label: 'UTC', + timeZone: 'UTC', + }, + { + label: 'STO', + timeZone: 'Europe/Stockholm', + }, + { + label: 'TYO', + timeZone: 'Asia/Tokyo', + }, + ]; + + const timeFormat: Intl.DateTimeFormatOptions = { + hour: '2-digit', + minute: '2-digit', + hour12: true, + }; + + return ( +
+ +
+ ); +}; + +export const TwentyFourHourClocks = () => { + const clockConfigs: ClockConfig[] = [ + { + label: 'NYC', + timeZone: 'America/New_York', + }, + { + label: 'UTC', + timeZone: 'UTC', + }, + { + label: 'STO', + timeZone: 'Europe/Stockholm', + }, + { + label: 'TYO', + timeZone: 'Asia/Tokyo', + }, + ]; + + const timeFormat: Intl.DateTimeFormatOptions = { + hour: '2-digit', + minute: '2-digit', + hour12: false, + }; + + return ( +
+ +
+ ); +}; diff --git a/plugins/home/src/components/HeaderWorldClock/HeaderWorldClock.test.tsx b/plugins/home/src/homePageComponents/HeaderWorldClock/HeaderWorldClock.test.tsx similarity index 77% rename from plugins/home/src/components/HeaderWorldClock/HeaderWorldClock.test.tsx rename to plugins/home/src/homePageComponents/HeaderWorldClock/HeaderWorldClock.test.tsx index 9dbfceac81..db92fbb89f 100644 --- a/plugins/home/src/components/HeaderWorldClock/HeaderWorldClock.test.tsx +++ b/plugins/home/src/homePageComponents/HeaderWorldClock/HeaderWorldClock.test.tsx @@ -86,3 +86,33 @@ describe('HeaderWorldClock with invalid Time Zone', () => { expect(rendered.getByText('GMT')).toBeInTheDocument(); }); }); + +describe('HeaderWorldClock with custom Time Format', () => { + it('uses 24hr clock from custom Time Format', async () => { + jest.useFakeTimers().setSystemTime(new Date('2022-06-28T09:10:13.502Z')); + + const clockConfigs: ClockConfig[] = [ + { + label: 'UTC', + timeZone: 'UTC', + }, + ]; + + const timeFormat: Intl.DateTimeFormatOptions = { + hour: '2-digit', + minute: '2-digit', + hour12: false, + }; + + const rendered = await renderInTestApp( + + + , + ); + + expect(rendered.getByText('09:10')).toBeInTheDocument(); + }); +}); diff --git a/plugins/home/src/components/HeaderWorldClock/HeaderWorldClock.tsx b/plugins/home/src/homePageComponents/HeaderWorldClock/HeaderWorldClock.tsx similarity index 63% rename from plugins/home/src/components/HeaderWorldClock/HeaderWorldClock.tsx rename to plugins/home/src/homePageComponents/HeaderWorldClock/HeaderWorldClock.tsx index 7e3065cc7a..6672fe6a22 100644 --- a/plugins/home/src/components/HeaderWorldClock/HeaderWorldClock.tsx +++ b/plugins/home/src/homePageComponents/HeaderWorldClock/HeaderWorldClock.tsx @@ -32,7 +32,10 @@ export type ClockConfig = { timeZone: string; }; -function getTimes(clockConfigs: ClockConfig[]) { +function getTimes( + clockConfigs: ClockConfig[], + customTimeFormat?: Intl.DateTimeFormatOptions, +) { const d = new Date(); const lang = window.navigator.language; @@ -47,7 +50,7 @@ function getTimes(clockConfigs: ClockConfig[]) { const options: Intl.DateTimeFormatOptions = { timeZone: clockConfig.timeZone, - ...timeFormat, + ...(customTimeFormat ?? timeFormat), }; try { @@ -68,24 +71,57 @@ function getTimes(clockConfigs: ClockConfig[]) { return clocks; } -/** @public */ -export const HeaderWorldClock = (props: { clockConfigs: ClockConfig[] }) => { - const { clockConfigs } = props; +/** + * A component to display a configurable list of clocks for various time zones. + * + * @example + * Here's a simple example: + * ``` + * // This will give you a clock for the time zone that Stockholm is in + * // you can add more than one but keep in mind space may be limited + * const clockConfigs: ClockConfig[] = [ + * { + * label: 'STO', + * timeZone: 'Europe/Stockholm', + * }, + * ]; + * + * // Setting hour12 to false will make all the clocks show in the 24hr format + * const timeFormat: Intl.DateTimeFormatOptions = { + * hour: '2-digit', + * minute: '2-digit', + * hour12: false, + * }; + * + * // Here is the component in use: + * + * ``` + * + * @public + */ +export const HeaderWorldClock = (props: { + clockConfigs: ClockConfig[]; + customTimeFormat?: Intl.DateTimeFormatOptions; +}) => { + const { clockConfigs, customTimeFormat } = props; const defaultTimes: TimeObj[] = []; const [clocks, setTimes] = React.useState(defaultTimes); React.useEffect(() => { - setTimes(getTimes(clockConfigs)); + setTimes(getTimes(clockConfigs, customTimeFormat)); const intervalId = setInterval(() => { - setTimes(getTimes(clockConfigs)); + setTimes(getTimes(clockConfigs, customTimeFormat)); }, 1000); return () => { clearInterval(intervalId); }; - }, [clockConfigs]); + }, [clockConfigs, customTimeFormat]); if (clocks.length !== 0) { return ( diff --git a/plugins/home/src/components/HeaderWorldClock/index.ts b/plugins/home/src/homePageComponents/HeaderWorldClock/index.ts similarity index 100% rename from plugins/home/src/components/HeaderWorldClock/index.ts rename to plugins/home/src/homePageComponents/HeaderWorldClock/index.ts diff --git a/plugins/home/src/homePageComponents/index.ts b/plugins/home/src/homePageComponents/index.ts index 4d2802fb98..d318226dbd 100644 --- a/plugins/home/src/homePageComponents/index.ts +++ b/plugins/home/src/homePageComponents/index.ts @@ -16,3 +16,4 @@ export * from './CompanyLogo'; export * from './Toolkit'; +export type { ClockConfig } from './HeaderWorldClock'; diff --git a/plugins/home/src/index.ts b/plugins/home/src/index.ts index 8f137d589b..1776b5aa9c 100644 --- a/plugins/home/src/index.ts +++ b/plugins/home/src/index.ts @@ -31,9 +31,10 @@ export { ComponentTabs, ComponentTab, WelcomeTitle, + HeaderWorldClock, } from './plugin'; -export { SettingsModal, HeaderWorldClock } from './components'; +export { SettingsModal } from './components'; export * from './assets'; -export type { ClockConfig } from './components'; +export type { ClockConfig } from './homePageComponents'; export { createCardExtension } from './extensions'; export type { ComponentRenderer } from './extensions'; diff --git a/plugins/home/src/plugin.ts b/plugins/home/src/plugin.ts index 93110faffb..9b221ad8dc 100644 --- a/plugins/home/src/plugin.ts +++ b/plugins/home/src/plugin.ts @@ -136,3 +136,20 @@ export const HomePageStarredEntities = homePlugin.provide( components: () => import('./homePageComponents/StarredEntities'), }), ); + +/** + * A component to display a configurable list of clocks for various time zones. + * + * @public + */ +export const HeaderWorldClock = homePlugin.provide( + createComponentExtension({ + name: 'HeaderWorldClock', + component: { + lazy: () => + import('./homePageComponents/HeaderWorldClock').then( + m => m.HeaderWorldClock, + ), + }, + }), +); diff --git a/plugins/ilert/CHANGELOG.md b/plugins/ilert/CHANGELOG.md index cd74af4e74..f24f1ede11 100644 --- a/plugins/ilert/CHANGELOG.md +++ b/plugins/ilert/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-ilert +## 0.1.33-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## 0.1.33-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## 0.1.33-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + ## 0.1.32 ### Patch Changes diff --git a/plugins/ilert/package.json b/plugins/ilert/package.json index 341c934836..c844d5bd7e 100644 --- a/plugins/ilert/package.json +++ b/plugins/ilert/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-ilert", "description": "A Backstage plugin that integrates towards iLert", - "version": "0.1.32", + "version": "0.1.33-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -24,12 +24,12 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", - "@backstage/core-components": "^0.9.5", + "@backstage/catalog-model": "^1.1.0-next.2", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/errors": "^1.0.0", - "@backstage/plugin-catalog-react": "^1.1.1", - "@backstage/theme": "^0.2.15", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", + "@backstage/theme": "^0.2.16-next.1", "@date-io/luxon": "1.x", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -43,17 +43,17 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/jest": "^26.0.7", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist", diff --git a/plugins/jenkins-backend/CHANGELOG.md b/plugins/jenkins-backend/CHANGELOG.md index ef18b5708d..c96b147b18 100644 --- a/plugins/jenkins-backend/CHANGELOG.md +++ b/plugins/jenkins-backend/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/plugin-jenkins-backend +## 0.1.24-next.2 + +### Patch Changes + +- 8747824221: feature: added support for multiple branches to the `JenkinsApi` +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/backend-common@0.14.1-next.2 + +## 0.1.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/catalog-client@1.0.4-next.1 + - @backstage/plugin-auth-node@0.2.3-next.1 + - @backstage/plugin-jenkins-common@0.1.6-next.0 + - @backstage/plugin-permission-common@0.6.3-next.0 + +## 0.1.24-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/plugin-auth-node@0.2.3-next.0 + - @backstage/catalog-client@1.0.4-next.0 + ## 0.1.23 ### Patch Changes diff --git a/plugins/jenkins-backend/package.json b/plugins/jenkins-backend/package.json index 1ab98c3255..bc24160dcf 100644 --- a/plugins/jenkins-backend/package.json +++ b/plugins/jenkins-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-jenkins-backend", "description": "A Backstage backend plugin that integrates towards Jenkins", - "version": "0.1.23", + "version": "0.1.24-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -25,26 +25,27 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", - "@backstage/catalog-client": "^1.0.3", - "@backstage/catalog-model": "^1.0.3", + "@backstage/backend-common": "^0.14.1-next.2", + "@backstage/catalog-client": "^1.0.4-next.1", + "@backstage/catalog-model": "^1.1.0-next.2", "@backstage/config": "^1.0.1", - "@backstage/errors": "^1.0.0", - "@backstage/plugin-auth-node": "^0.2.2", - "@backstage/plugin-jenkins-common": "^0.1.5", - "@backstage/plugin-permission-common": "^0.6.2", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/plugin-auth-node": "^0.2.3-next.1", + "@backstage/plugin-jenkins-common": "^0.1.6-next.0", + "@backstage/plugin-permission-common": "^0.6.3-next.0", "@types/express": "^4.17.6", "express": "^4.17.1", "express-promise-router": "^4.1.0", "jenkins": "^0.28.1", + "promise-any-polyfill": "^1.0.1", "winston": "^3.2.1", "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", + "@backstage/cli": "^0.18.0-next.2", "@types/jenkins": "^0.23.1", "@types/supertest": "^2.0.8", - "msw": "^0.42.0", + "msw": "^0.43.0", "supertest": "^6.1.6" }, "files": [ diff --git a/plugins/jenkins-backend/src/service/jenkinsApi.test.ts b/plugins/jenkins-backend/src/service/jenkinsApi.test.ts index 29da414470..bada5e1c29 100644 --- a/plugins/jenkins-backend/src/service/jenkinsApi.test.ts +++ b/plugins/jenkins-backend/src/service/jenkinsApi.test.ts @@ -118,10 +118,9 @@ describe('JenkinsApi', () => { it('standard github layout', async () => { mockedJenkinsClient.job.get.mockResolvedValueOnce(project); - const result = await jenkinsApi.getProjects( - jenkinsInfo, + const result = await jenkinsApi.getProjects(jenkinsInfo, [ 'testBranchName', - ); + ]); expect(mockedJenkins).toHaveBeenCalledWith({ baseUrl: jenkinsInfo.baseUrl, @@ -134,6 +133,35 @@ describe('JenkinsApi', () => { }); expect(result).toHaveLength(1); }); + + it('supports multiple branches', async () => { + mockedJenkinsClient.job.get.mockResolvedValue(project); + + const result = await jenkinsApi.getProjects(jenkinsInfo, [ + 'foo', + 'bar', + 'catpants', + ]); + + expect(mockedJenkins).toHaveBeenCalledWith({ + baseUrl: jenkinsInfo.baseUrl, + headers: jenkinsInfo.headers, + promisify: true, + }); + expect(mockedJenkinsClient.job.get).toBeCalledWith({ + name: `${jenkinsInfo.jobFullName}/foo`, + tree: expect.anything(), + }); + expect(mockedJenkinsClient.job.get).toBeCalledWith({ + name: `${jenkinsInfo.jobFullName}/bar`, + tree: expect.anything(), + }); + expect(mockedJenkinsClient.job.get).toBeCalledWith({ + name: `${jenkinsInfo.jobFullName}/catpants`, + tree: expect.anything(), + }); + expect(result).toHaveLength(1); + }); }); describe('augmented', () => { const projectWithScmActions: JenkinsProject = { diff --git a/plugins/jenkins-backend/src/service/jenkinsApi.ts b/plugins/jenkins-backend/src/service/jenkinsApi.ts index 8069f57692..ae2fa0f7b5 100644 --- a/plugins/jenkins-backend/src/service/jenkinsApi.ts +++ b/plugins/jenkins-backend/src/service/jenkinsApi.ts @@ -30,6 +30,12 @@ import { import { jenkinsExecutePermission } from '@backstage/plugin-jenkins-common'; import { NotAllowedError } from '@backstage/errors'; +if (!Promise.any) { + (async () => { + await import('promise-any-polyfill'); + })(); +} + export class JenkinsApiImpl { private static readonly lastBuildTreeSpec = `lastBuild[ number, @@ -70,18 +76,21 @@ export class JenkinsApiImpl { * Get a list of projects for the given JenkinsInfo. * @see ../../../jenkins/src/api/JenkinsApi.ts#getProjects */ - async getProjects(jenkinsInfo: JenkinsInfo, branch?: string) { + async getProjects(jenkinsInfo: JenkinsInfo, branches?: string[]) { const client = await JenkinsApiImpl.getClient(jenkinsInfo); const projects: BackstageProject[] = []; - if (branch) { - // we have been asked to filter to a single branch. + if (branches) { // Assume jenkinsInfo.jobFullName is a folder which contains one job per branch. // TODO: extract a strategy interface for this - const job = await client.job.get({ - name: `${jenkinsInfo.jobFullName}/${branch}`, - tree: JenkinsApiImpl.jobTreeSpec.replace(/\s/g, ''), - }); + const job = await Promise.any( + branches.map(branch => + client.job.get({ + name: `${jenkinsInfo.jobFullName}/${branch}`, + tree: JenkinsApiImpl.jobTreeSpec.replace(/\s/g, ''), + }), + ), + ); projects.push(this.augmentProject(job)); } else { // We aren't filtering diff --git a/plugins/jenkins-backend/src/service/router.ts b/plugins/jenkins-backend/src/service/router.ts index 2c9e268165..b4c06314e1 100644 --- a/plugins/jenkins-backend/src/service/router.ts +++ b/plugins/jenkins-backend/src/service/router.ts @@ -64,12 +64,12 @@ export async function createRouter( request.header('authorization'), ); const branch = request.query.branch; - let branchStr: string | undefined; + let branches: string[] | undefined; if (branch === undefined) { - branchStr = undefined; + branches = undefined; } else if (typeof branch === 'string') { - branchStr = branch; + branches = branch.split(/,/g); } else { // this was passed in as something weird -> 400 // https://evanhahn.com/gotchas-with-express-query-parsing-and-how-to-avoid-them/ @@ -88,7 +88,7 @@ export async function createRouter( }, backstageToken: token, }); - const projects = await jenkinsApi.getProjects(jenkinsInfo, branchStr); + const projects = await jenkinsApi.getProjects(jenkinsInfo, branches); response.json({ projects: projects, diff --git a/plugins/jenkins-common/CHANGELOG.md b/plugins/jenkins-common/CHANGELOG.md index 53cf222e5a..ea0afcde79 100644 --- a/plugins/jenkins-common/CHANGELOG.md +++ b/plugins/jenkins-common/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-jenkins-common +## 0.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-common@1.0.4-next.0 + - @backstage/plugin-permission-common@0.6.3-next.0 + ## 0.1.5 ### Patch Changes diff --git a/plugins/jenkins-common/package.json b/plugins/jenkins-common/package.json index c47ac94a2b..d6520cd085 100644 --- a/plugins/jenkins-common/package.json +++ b/plugins/jenkins-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-jenkins-common", - "version": "0.1.5", + "version": "0.1.6-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,11 +22,11 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/plugin-catalog-common": "^1.0.3", - "@backstage/plugin-permission-common": "^0.6.2" + "@backstage/plugin-catalog-common": "^1.0.4-next.0", + "@backstage/plugin-permission-common": "^0.6.3-next.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2" + "@backstage/cli": "^0.18.0-next.1" }, "files": [ "dist" diff --git a/plugins/jenkins/CHANGELOG.md b/plugins/jenkins/CHANGELOG.md index fd4e4420e7..a55f8a3d4b 100644 --- a/plugins/jenkins/CHANGELOG.md +++ b/plugins/jenkins/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/plugin-jenkins +## 0.7.6-next.2 + +### Patch Changes + +- 8747824221: feature: added support for multiple branches to the `JenkinsApi` +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## 0.7.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + - @backstage/plugin-jenkins-common@0.1.6-next.0 + +## 0.7.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + ## 0.7.5 ### Patch Changes diff --git a/plugins/jenkins/README.md b/plugins/jenkins/README.md index 80e39d2095..2a0ec451c8 100644 --- a/plugins/jenkins/README.md +++ b/plugins/jenkins/README.md @@ -19,7 +19,7 @@ yarn add --cwd packages/app @backstage/plugin-jenkins 3. Add the `EntityJenkinsContent` extension to the `CI/CD` page and `EntityLatestJenkinsRunCard` to the `overview` page in the app (or wherever you'd prefer): -Note that if you configured a custom JenkinsInfoProvider in step 2, you may need a custom isJenkinsAvailable. +Note that if you configured a custom JenkinsInfoProvider in step 2, you may need a custom isJenkinsAvailable. Also if you're transitioning to a new default branch name, you can pass multiple branch names as a comma-separated list and it will check for each branch name. ```tsx // In packages/app/src/components/catalog/EntityPage.tsx @@ -38,7 +38,10 @@ const serviceEntityPage = ( - + {/* ... */} diff --git a/plugins/jenkins/package.json b/plugins/jenkins/package.json index ae86828505..e70aea32f4 100644 --- a/plugins/jenkins/package.json +++ b/plugins/jenkins/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-jenkins", "description": "A Backstage plugin that integrates towards Jenkins", - "version": "0.7.5", + "version": "0.7.6-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,13 +35,13 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", - "@backstage/core-components": "^0.9.5", + "@backstage/catalog-model": "^1.1.0-next.2", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/errors": "^1.0.0", - "@backstage/plugin-catalog-react": "^1.1.1", - "@backstage/plugin-jenkins-common": "^0.1.5", - "@backstage/theme": "^0.2.15", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", + "@backstage/plugin-jenkins-common": "^0.1.6-next.0", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -54,10 +54,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", @@ -65,7 +65,7 @@ "@types/node": "^16.11.26", "@types/testing-library__jest-dom": "^5.9.1", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/kafka-backend/CHANGELOG.md b/plugins/kafka-backend/CHANGELOG.md index 32b147ffdd..5a35d5a504 100644 --- a/plugins/kafka-backend/CHANGELOG.md +++ b/plugins/kafka-backend/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-kafka-backend +## 0.2.27-next.2 + +### Patch Changes + +- 8751667541: Updated dependency `kafkajs` to `^2.0.0`. +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/backend-common@0.14.1-next.2 + +## 0.2.27-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + +## 0.2.27-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + ## 0.2.26 ### Patch Changes diff --git a/plugins/kafka-backend/package.json b/plugins/kafka-backend/package.json index 965b15bd6b..5a666ee6df 100644 --- a/plugins/kafka-backend/package.json +++ b/plugins/kafka-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kafka-backend", "description": "A Backstage backend plugin that integrates towards Kafka", - "version": "0.2.26", + "version": "0.2.27-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,19 +35,19 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", - "@backstage/catalog-model": "^1.0.3", + "@backstage/backend-common": "^0.14.1-next.2", + "@backstage/catalog-model": "^1.1.0-next.2", "@backstage/config": "^1.0.1", - "@backstage/errors": "^1.0.0", + "@backstage/errors": "^1.1.0-next.0", "@types/express": "^4.17.6", "express": "^4.17.1", "express-promise-router": "^4.1.0", - "kafkajs": "^1.16.0-beta.6", + "kafkajs": "^2.0.0", "lodash": "^4.17.21", "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.17.2", + "@backstage/cli": "^0.18.0-next.2", "@types/jest-when": "^3.5.0", "@types/lodash": "^4.14.151", "jest-when": "^3.1.0", diff --git a/plugins/kafka/CHANGELOG.md b/plugins/kafka/CHANGELOG.md index c2743bf92b..7f5db4402c 100644 --- a/plugins/kafka/CHANGELOG.md +++ b/plugins/kafka/CHANGELOG.md @@ -1,5 +1,34 @@ # @backstage/plugin-kafka +## 0.3.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## 0.3.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## 0.3.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + ## 0.3.6 ### Patch Changes diff --git a/plugins/kafka/package.json b/plugins/kafka/package.json index 43f4b8d35c..522cefb94f 100644 --- a/plugins/kafka/package.json +++ b/plugins/kafka/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kafka", "description": "A Backstage plugin that integrates towards Kafka", - "version": "0.3.6", + "version": "0.3.7-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -24,11 +24,11 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", - "@backstage/core-components": "^0.9.5", + "@backstage/catalog-model": "^1.1.0-next.2", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/plugin-catalog-react": "^1.1.1", - "@backstage/theme": "^0.2.15", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -39,10 +39,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/react-hooks": "^8.0.0", @@ -51,7 +51,7 @@ "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", "jest-when": "^3.1.0", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/kubernetes-backend/CHANGELOG.md b/plugins/kubernetes-backend/CHANGELOG.md index d829136819..b11a5b045f 100644 --- a/plugins/kubernetes-backend/CHANGELOG.md +++ b/plugins/kubernetes-backend/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/plugin-kubernetes-backend +## 0.7.0-next.2 + +### Patch Changes + +- 60e5f9fe68: Fixed the lack of `limitranges` as part of the Default Objects to fetch from the kubernetes api +- Updated dependencies + - @backstage/plugin-kubernetes-common@0.4.0-next.1 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/backend-common@0.14.1-next.2 + +## 0.7.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + +## 0.7.0-next.0 + +### Minor Changes + +- 0791af993f: Refactor `KubernetesObjectsProvider` with new methods, `KubernetesServiceLocator` now takes an `Entity` instead of `serviceId` + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/plugin-kubernetes-common@0.4.0-next.0 + ## 0.6.0 ### Minor Changes diff --git a/plugins/kubernetes-backend/api-report.md b/plugins/kubernetes-backend/api-report.md index be81b4d5dd..363af1b02f 100644 --- a/plugins/kubernetes-backend/api-report.md +++ b/plugins/kubernetes-backend/api-report.md @@ -3,20 +3,21 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { CatalogApi } from '@backstage/catalog-client'; import { Config } from '@backstage/config'; import { Duration } from 'luxon'; +import { Entity } from '@backstage/catalog-model'; import express from 'express'; import type { FetchResponse } from '@backstage/plugin-kubernetes-common'; import type { JsonObject } from '@backstage/types'; import type { KubernetesFetchError } from '@backstage/plugin-kubernetes-common'; +import type { KubernetesRequestAuth } from '@backstage/plugin-kubernetes-common'; import type { KubernetesRequestBody } from '@backstage/plugin-kubernetes-common'; import { Logger } from 'winston'; import type { ObjectsByEntityResponse } from '@backstage/plugin-kubernetes-common'; import { PodStatus } from '@kubernetes/client-node/dist/top'; -// Warning: (ae-missing-release-tag) "AWSClusterDetails" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) +// @alpha (undocumented) export interface AWSClusterDetails extends ClusterDetails { // (undocumented) assumeRole?: string; @@ -24,14 +25,10 @@ export interface AWSClusterDetails extends ClusterDetails { externalId?: string; } -// Warning: (ae-missing-release-tag) "AzureClusterDetails" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) +// @alpha (undocumented) export interface AzureClusterDetails extends ClusterDetails {} -// Warning: (ae-missing-release-tag) "ClusterDetails" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) +// @alpha (undocumented) export interface ClusterDetails { // (undocumented) authProvider: string; @@ -51,27 +48,28 @@ export interface ClusterDetails { url: string; } -// Warning: (ae-missing-release-tag) "createRouter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public @deprecated +// @alpha @deprecated export function createRouter(options: RouterOptions): Promise; -// Warning: (ae-missing-release-tag) "CustomResource" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) +// @alpha (undocumented) export interface CustomResource extends ObjectToFetch { // (undocumented) objectType: 'customresources'; } -// Warning: (ae-missing-release-tag) "DEFAULT_OBJECTS" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) +// @alpha (undocumented) +export type CustomResourceMatcher = Omit; + +// @alpha (undocumented) +export interface CustomResourcesByEntity extends KubernetesObjectsByEntity { + // (undocumented) + customResources: CustomResourceMatcher[]; +} + +// @alpha (undocumented) export const DEFAULT_OBJECTS: ObjectToFetch[]; -// Warning: (ae-missing-release-tag) "FetchResponseWrapper" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) +// @alpha (undocumented) export interface FetchResponseWrapper { // (undocumented) errors: KubernetesFetchError[]; @@ -79,14 +77,10 @@ export interface FetchResponseWrapper { responses: FetchResponse[]; } -// Warning: (ae-missing-release-tag) "GKEClusterDetails" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) +// @alpha (undocumented) export interface GKEClusterDetails extends ClusterDetails {} -// Warning: (ae-missing-release-tag) "KubernetesBuilder" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) +// @alpha (undocumented) export class KubernetesBuilder { constructor(env: KubernetesEnvironment); // (undocumented) @@ -115,6 +109,7 @@ export class KubernetesBuilder { protected buildRouter( objectsProvider: KubernetesObjectsProvider, clusterSupplier: KubernetesClustersSupplier, + catalogApi: CatalogApi, ): express.Router; // (undocumented) protected buildServiceLocator( @@ -145,7 +140,7 @@ export class KubernetesBuilder { setServiceLocator(serviceLocator?: KubernetesServiceLocator): this; } -// @public +// @alpha export type KubernetesBuilderReturn = Promise<{ router: express.Router; clusterSupplier: KubernetesClustersSupplier; @@ -155,26 +150,22 @@ export type KubernetesBuilderReturn = Promise<{ serviceLocator: KubernetesServiceLocator; }>; -// Warning: (ae-missing-release-tag) "KubernetesClustersSupplier" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) +// @alpha export interface KubernetesClustersSupplier { getClusters(): Promise; } -// Warning: (ae-missing-release-tag) "KubernetesEnvironment" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) +// @alpha (undocumented) export interface KubernetesEnvironment { + // (undocumented) + catalogApi: CatalogApi; // (undocumented) config: Config; // (undocumented) logger: Logger; } -// Warning: (ae-missing-release-tag) "KubernetesFetcher" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) +// @alpha export interface KubernetesFetcher { // (undocumented) fetchObjectsForService( @@ -187,19 +178,27 @@ export interface KubernetesFetcher { ): Promise; } -// Warning: (ae-missing-release-tag) "KubernetesObjectsProvider" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) +// @alpha (undocumented) +export interface KubernetesObjectsByEntity { + // (undocumented) + auth: KubernetesRequestAuth; + // (undocumented) + entity: Entity; +} + +// @alpha (undocumented) export interface KubernetesObjectsProvider { + // (undocumented) + getCustomResourcesByEntity( + customResourcesByEntity: CustomResourcesByEntity, + ): Promise; // (undocumented) getKubernetesObjectsByEntity( - request: ObjectsByEntityRequest, + kubernetesObjectsByEntity: KubernetesObjectsByEntity, ): Promise; } -// Warning: (ae-missing-release-tag) "KubernetesObjectsProviderOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) +// @alpha (undocumented) export interface KubernetesObjectsProviderOptions { // (undocumented) customResources: CustomResource[]; @@ -213,14 +212,13 @@ export interface KubernetesObjectsProviderOptions { serviceLocator: KubernetesServiceLocator; } -// Warning: (ae-missing-release-tag) "KubernetesObjectTypes" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) +// @alpha (undocumented) export type KubernetesObjectTypes = | 'pods' | 'services' | 'configmaps' | 'deployments' + | 'limitranges' | 'replicasets' | 'horizontalpodautoscalers' | 'jobs' @@ -229,17 +227,15 @@ export type KubernetesObjectTypes = | 'customresources' | 'statefulsets'; -// Warning: (ae-missing-release-tag) "KubernetesServiceLocator" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) +// @alpha export interface KubernetesServiceLocator { // (undocumented) - getClustersByServiceId(serviceId: string): Promise; + getClustersByEntity(entity: Entity): Promise<{ + clusters: ClusterDetails[]; + }>; } -// Warning: (ae-missing-release-tag) "ObjectFetchParams" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) +// @alpha (undocumented) export interface ObjectFetchParams { // (undocumented) clusterDetails: @@ -259,14 +255,10 @@ export interface ObjectFetchParams { serviceId: string; } -// Warning: (ae-missing-release-tag) "ObjectsByEntityRequest" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) +// @alpha (undocumented) export type ObjectsByEntityRequest = KubernetesRequestBody; -// Warning: (ae-missing-release-tag) "ObjectToFetch" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) +// @alpha (undocumented) export interface ObjectToFetch { // (undocumented) apiVersion: string; @@ -278,10 +270,10 @@ export interface ObjectToFetch { plural: string; } -// Warning: (ae-missing-release-tag) "RouterOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) +// @alpha (undocumented) export interface RouterOptions { + // (undocumented) + catalogApi: CatalogApi; // (undocumented) clusterSupplier?: KubernetesClustersSupplier; // (undocumented) @@ -290,13 +282,9 @@ export interface RouterOptions { logger: Logger; } -// Warning: (ae-missing-release-tag) "ServiceAccountClusterDetails" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) +// @alpha (undocumented) export interface ServiceAccountClusterDetails extends ClusterDetails {} -// Warning: (ae-missing-release-tag) "ServiceLocatorMethod" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) +// @alpha (undocumented) export type ServiceLocatorMethod = 'multiTenant' | 'http'; ``` diff --git a/plugins/kubernetes-backend/package.json b/plugins/kubernetes-backend/package.json index 33dcc1dfff..10eb6828f5 100644 --- a/plugins/kubernetes-backend/package.json +++ b/plugins/kubernetes-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes-backend", "description": "A Backstage backend plugin that integrates towards Kubernetes", - "version": "0.6.0", + "version": "0.7.0-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -36,11 +36,13 @@ }, "dependencies": { "@azure/identity": "^2.0.4", - "@backstage/backend-common": "^0.14.0", - "@backstage/catalog-model": "^1.0.3", + "@backstage/backend-common": "^0.14.1-next.2", + "@backstage/catalog-client": "^1.0.4-next.1", + "@backstage/catalog-model": "^1.1.0-next.2", "@backstage/config": "^1.0.1", - "@backstage/errors": "^1.0.0", - "@backstage/plugin-kubernetes-common": "^0.3.0", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/plugin-auth-node": "^0.2.3-next.1", + "@backstage/plugin-kubernetes-common": "^0.4.0-next.0", "@google-cloud/container": "^4.0.0", "@kubernetes/client-node": "^0.16.0", "@types/express": "^4.17.6", @@ -61,7 +63,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", + "@backstage/cli": "^0.18.0-next.2", "@types/aws4": "^1.5.1", "aws-sdk-mock": "^5.2.1", "supertest": "^6.1.3" diff --git a/plugins/kubernetes-backend/src/kubernetes-auth-translator/GoogleKubernetesAuthTranslator.ts b/plugins/kubernetes-backend/src/kubernetes-auth-translator/GoogleKubernetesAuthTranslator.ts index 8c74945ec7..741e6b2533 100644 --- a/plugins/kubernetes-backend/src/kubernetes-auth-translator/GoogleKubernetesAuthTranslator.ts +++ b/plugins/kubernetes-backend/src/kubernetes-auth-translator/GoogleKubernetesAuthTranslator.ts @@ -16,20 +16,20 @@ import { KubernetesAuthTranslator } from './types'; import { GKEClusterDetails } from '../types/types'; -import { KubernetesRequestBody } from '@backstage/plugin-kubernetes-common'; +import { KubernetesRequestAuth } from '@backstage/plugin-kubernetes-common'; export class GoogleKubernetesAuthTranslator implements KubernetesAuthTranslator { async decorateClusterDetailsWithAuth( clusterDetails: GKEClusterDetails, - requestBody: KubernetesRequestBody, + authConfig: KubernetesRequestAuth, ): Promise { const clusterDetailsWithAuthToken: GKEClusterDetails = Object.assign( {}, clusterDetails, ); - const authToken: string | undefined = requestBody.auth?.google; + const authToken: string | undefined = authConfig.google; if (authToken) { clusterDetailsWithAuthToken.serviceAccountToken = authToken; diff --git a/plugins/kubernetes-backend/src/kubernetes-auth-translator/KubernetesAuthTranslatorGenerator.test.ts b/plugins/kubernetes-backend/src/kubernetes-auth-translator/KubernetesAuthTranslatorGenerator.test.ts index 123b05456c..f8abdde9cf 100644 --- a/plugins/kubernetes-backend/src/kubernetes-auth-translator/KubernetesAuthTranslatorGenerator.test.ts +++ b/plugins/kubernetes-backend/src/kubernetes-auth-translator/KubernetesAuthTranslatorGenerator.test.ts @@ -17,7 +17,7 @@ import { KubernetesAuthTranslator } from './types'; import { GoogleKubernetesAuthTranslator } from './GoogleKubernetesAuthTranslator'; import { KubernetesAuthTranslatorGenerator } from './KubernetesAuthTranslatorGenerator'; -import { ServiceAccountKubernetesAuthTranslator } from './ServiceAccountKubernetesAuthTranslator'; +import { NoopKubernetesAuthTranslator } from './NoopKubernetesAuthTranslator'; import { AwsIamKubernetesAuthTranslator } from './AwsIamKubernetesAuthTranslator'; import { OidcKubernetesAuthTranslator } from './OidcKubernetesAuthTranslator'; import { getVoidLogger } from '@backstage/backend-common'; @@ -42,9 +42,7 @@ describe('getKubernetesAuthTranslatorInstance', () => { it('can return an auth translator for serviceAccount auth', () => { const authTranslator: KubernetesAuthTranslator = sut.getKubernetesAuthTranslatorInstance('serviceAccount', { logger }); - expect( - authTranslator instanceof ServiceAccountKubernetesAuthTranslator, - ).toBe(true); + expect(authTranslator instanceof NoopKubernetesAuthTranslator).toBe(true); }); it('can return an auth translator for oidc auth', () => { diff --git a/plugins/kubernetes-backend/src/kubernetes-auth-translator/KubernetesAuthTranslatorGenerator.ts b/plugins/kubernetes-backend/src/kubernetes-auth-translator/KubernetesAuthTranslatorGenerator.ts index fa69ad42b5..c2df3e6c23 100644 --- a/plugins/kubernetes-backend/src/kubernetes-auth-translator/KubernetesAuthTranslatorGenerator.ts +++ b/plugins/kubernetes-backend/src/kubernetes-auth-translator/KubernetesAuthTranslatorGenerator.ts @@ -17,7 +17,7 @@ import { Logger } from 'winston'; import { KubernetesAuthTranslator } from './types'; import { GoogleKubernetesAuthTranslator } from './GoogleKubernetesAuthTranslator'; -import { ServiceAccountKubernetesAuthTranslator } from './ServiceAccountKubernetesAuthTranslator'; +import { NoopKubernetesAuthTranslator } from './NoopKubernetesAuthTranslator'; import { AwsIamKubernetesAuthTranslator } from './AwsIamKubernetesAuthTranslator'; import { GoogleServiceAccountAuthTranslator } from './GoogleServiceAccountAuthProvider'; import { AzureIdentityKubernetesAuthTranslator } from './AzureIdentityKubernetesAuthTranslator'; @@ -41,7 +41,7 @@ export class KubernetesAuthTranslatorGenerator { return new AzureIdentityKubernetesAuthTranslator(options.logger); } case 'serviceAccount': { - return new ServiceAccountKubernetesAuthTranslator(); + return new NoopKubernetesAuthTranslator(); } case 'googleServiceAccount': { return new GoogleServiceAccountAuthTranslator(); diff --git a/plugins/kubernetes-backend/src/kubernetes-auth-translator/ServiceAccountKubernetesAuthTranslator.ts b/plugins/kubernetes-backend/src/kubernetes-auth-translator/NoopKubernetesAuthTranslator.ts similarity index 80% rename from plugins/kubernetes-backend/src/kubernetes-auth-translator/ServiceAccountKubernetesAuthTranslator.ts rename to plugins/kubernetes-backend/src/kubernetes-auth-translator/NoopKubernetesAuthTranslator.ts index ec90f82c91..d68b1a4365 100644 --- a/plugins/kubernetes-backend/src/kubernetes-auth-translator/ServiceAccountKubernetesAuthTranslator.ts +++ b/plugins/kubernetes-backend/src/kubernetes-auth-translator/NoopKubernetesAuthTranslator.ts @@ -16,14 +16,10 @@ import { KubernetesAuthTranslator } from './types'; import { ServiceAccountClusterDetails } from '../types/types'; -import { KubernetesRequestBody } from '@backstage/plugin-kubernetes-common'; -export class ServiceAccountKubernetesAuthTranslator - implements KubernetesAuthTranslator -{ +export class NoopKubernetesAuthTranslator implements KubernetesAuthTranslator { async decorateClusterDetailsWithAuth( clusterDetails: ServiceAccountClusterDetails, - _requestBody: KubernetesRequestBody, ): Promise { return clusterDetails; } diff --git a/plugins/kubernetes-backend/src/kubernetes-auth-translator/OidcKubernetesAuthTranslator.test.ts b/plugins/kubernetes-backend/src/kubernetes-auth-translator/OidcKubernetesAuthTranslator.test.ts index 9f983aedc3..68f24bd020 100644 --- a/plugins/kubernetes-backend/src/kubernetes-auth-translator/OidcKubernetesAuthTranslator.test.ts +++ b/plugins/kubernetes-backend/src/kubernetes-auth-translator/OidcKubernetesAuthTranslator.test.ts @@ -16,15 +16,9 @@ import { OidcKubernetesAuthTranslator } from './OidcKubernetesAuthTranslator'; import { ClusterDetails } from '../types/types'; -import { Entity } from '@backstage/catalog-model'; describe('OidcKubernetesAuthTranslator tests', () => { const at = new OidcKubernetesAuthTranslator(); - const entity: Entity = { - apiVersion: 'v1', - kind: 'service', - metadata: { name: 'test' }, - }; const baseClusterDetails: ClusterDetails = { name: 'test', authProvider: 'oidc', @@ -38,10 +32,7 @@ describe('OidcKubernetesAuthTranslator tests', () => { ...baseClusterDetails, }, { - auth: { - oidc: { okta: 'fakeToken' }, - }, - entity, + oidc: { okta: 'fakeToken' }, }, ); @@ -50,7 +41,7 @@ describe('OidcKubernetesAuthTranslator tests', () => { it('returns error when oidcTokenProvider is not configured', async () => { await expect( - at.decorateClusterDetailsWithAuth(baseClusterDetails, { entity }), + at.decorateClusterDetailsWithAuth(baseClusterDetails, {}), ).rejects.toThrow( 'oidc authProvider requires a configured oidcTokenProvider', ); @@ -60,7 +51,7 @@ describe('OidcKubernetesAuthTranslator tests', () => { await expect( at.decorateClusterDetailsWithAuth( { oidcTokenProvider: 'okta', ...baseClusterDetails }, - { entity }, + {}, ), ).rejects.toThrow('Auth token not found under oidc.okta in request body'); }); diff --git a/plugins/kubernetes-backend/src/kubernetes-auth-translator/OidcKubernetesAuthTranslator.ts b/plugins/kubernetes-backend/src/kubernetes-auth-translator/OidcKubernetesAuthTranslator.ts index c53269abf3..8ca546a25b 100644 --- a/plugins/kubernetes-backend/src/kubernetes-auth-translator/OidcKubernetesAuthTranslator.ts +++ b/plugins/kubernetes-backend/src/kubernetes-auth-translator/OidcKubernetesAuthTranslator.ts @@ -16,12 +16,12 @@ import { KubernetesAuthTranslator } from './types'; import { ClusterDetails } from '../types/types'; -import { KubernetesRequestBody } from '@backstage/plugin-kubernetes-common'; +import { KubernetesRequestAuth } from '@backstage/plugin-kubernetes-common'; export class OidcKubernetesAuthTranslator implements KubernetesAuthTranslator { async decorateClusterDetailsWithAuth( clusterDetails: ClusterDetails, - requestBody: KubernetesRequestBody, + authConfig: KubernetesRequestAuth, ): Promise { const clusterDetailsWithAuthToken: ClusterDetails = Object.assign( {}, @@ -36,8 +36,7 @@ export class OidcKubernetesAuthTranslator implements KubernetesAuthTranslator { ); } - const authToken: string | undefined = - requestBody.auth?.oidc?.[oidcTokenProvider]; + const authToken: string | undefined = authConfig.oidc?.[oidcTokenProvider]; if (authToken) { clusterDetailsWithAuthToken.serviceAccountToken = authToken; diff --git a/plugins/kubernetes-backend/src/kubernetes-auth-translator/types.ts b/plugins/kubernetes-backend/src/kubernetes-auth-translator/types.ts index f14ba877b7..640a20303e 100644 --- a/plugins/kubernetes-backend/src/kubernetes-auth-translator/types.ts +++ b/plugins/kubernetes-backend/src/kubernetes-auth-translator/types.ts @@ -15,11 +15,11 @@ */ import { ClusterDetails } from '../types/types'; -import { KubernetesRequestBody } from '@backstage/plugin-kubernetes-common'; +import { KubernetesRequestAuth } from '@backstage/plugin-kubernetes-common'; export interface KubernetesAuthTranslator { decorateClusterDetailsWithAuth( clusterDetails: ClusterDetails, - requestBody: KubernetesRequestBody, + authConfig: KubernetesRequestAuth, ): Promise; } diff --git a/plugins/kubernetes-backend/src/routes/resourceRoutes.test.ts b/plugins/kubernetes-backend/src/routes/resourceRoutes.test.ts new file mode 100644 index 0000000000..57e6514a96 --- /dev/null +++ b/plugins/kubernetes-backend/src/routes/resourceRoutes.test.ts @@ -0,0 +1,545 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { errorHandler } from '@backstage/backend-common'; +import express from 'express'; +import request from 'supertest'; +import Router from 'express-promise-router'; +import { addResourceRoutesToRouter } from './resourcesRoutes'; +import { Entity } from '@backstage/catalog-model'; + +describe('resourcesRoutes', () => { + let app: express.Express; + + beforeAll(() => { + app = express(); + app.use(express.json()); + const router = Router(); + addResourceRoutesToRouter( + router, + { + getEntityByRef: jest.fn().mockImplementation(entityRef => { + if (entityRef.name === 'noentity') { + return Promise.resolve(undefined); + } + return Promise.resolve({ + kind: entityRef.kind, + metadata: { + name: entityRef.name, + namespace: entityRef.namespace, + }, + } as Entity); + }), + } as any, + { + getKubernetesObjectsByEntity: jest.fn().mockImplementation(args => { + if (args.entity.metadata.name === 'inject500') { + return Promise.reject(new Error('some internal error')); + } + + return Promise.resolve({ + items: [ + { + clusterOne: { + pods: [ + { + metadata: { + name: 'pod1', + }, + }, + ], + }, + }, + ], + }); + }), + getCustomResourcesByEntity: jest.fn().mockImplementation(args => { + if (args.entity.metadata.name === 'inject500') { + return Promise.reject(new Error('some internal error')); + } + + return Promise.resolve({ + items: [ + { + clusterOne: { + pods: [ + { + metadata: { + name: 'pod1', + }, + }, + ], + }, + }, + ], + }); + }), + } as any, + ); + app.use('/', router); + app.use(errorHandler()); + }); + + describe('POST /resources/workloads/query', () => { + // eslint-disable-next-line jest/expect-expect + it('200 happy path', async () => { + await request(app) + .post('/resources/workloads/query') + .send({ + entityRef: 'kind:namespacec/someComponent', + auth: { + google: 'something', + }, + }) + .set('Content-Type', 'application/json') + .set('Authorization', 'Bearer Zm9vYmFy') + .expect(200, { + items: [ + { + clusterOne: { + pods: [ + { + metadata: { + name: 'pod1', + }, + }, + ], + }, + }, + ], + }); + }); + // eslint-disable-next-line jest/expect-expect + it('400 when missing entity ref', async () => { + await request(app) + .post('/resources/workloads/query') + .send({ + auth: { + google: 'something', + }, + }) + .set('Content-Type', 'application/json') + .set('Authorization', 'Bearer Zm9vYmFy') + .expect(400, { + error: { name: 'InputError', message: 'entity is a required field' }, + request: { + method: 'POST', + url: '/resources/workloads/query', + }, + response: { statusCode: 400 }, + }); + }); + // eslint-disable-next-line jest/expect-expect + it('400 when bad entity ref', async () => { + await request(app) + .post('/resources/workloads/query') + .send({ + entityRef: 'ffff', + auth: { + google: 'something', + }, + }) + .set('Content-Type', 'application/json') + .set('Authorization', 'Bearer Zm9vYmFy') + .expect(400, { + error: { + name: 'InputError', + message: + 'Invalid entity ref, Error: Entity reference "ffff" had missing or empty kind (e.g. did not start with "component:" or similar)', + }, + request: { + method: 'POST', + url: '/resources/workloads/query', + }, + response: { statusCode: 400 }, + }); + }); + // eslint-disable-next-line jest/expect-expect + it('400 when no entity in catalog', async () => { + await request(app) + .post('/resources/workloads/query') + .send({ + entityRef: 'noentity:noentity', + auth: { + google: 'something', + }, + }) + .set('Content-Type', 'application/json') + .set('Authorization', 'Bearer Zm9vYmFy') + .expect(400, { + error: { + name: 'InputError', + message: 'Entity ref missing, noentity:default/noentity', + }, + request: { + method: 'POST', + url: '/resources/workloads/query', + }, + response: { statusCode: 400 }, + }); + }); + // eslint-disable-next-line jest/expect-expect + it('401 when no Auth header', async () => { + await request(app) + .post('/resources/workloads/query') + .send({ + entityRef: 'component:someComponent', + auth: { + google: 'something', + }, + }) + .set('Content-Type', 'application/json') + .expect(401, { + error: { name: 'AuthenticationError', message: 'No Backstage token' }, + request: { + method: 'POST', + url: '/resources/workloads/query', + }, + response: { statusCode: 401 }, + }); + }); + // eslint-disable-next-line jest/expect-expect + it('401 when invalid Auth header', async () => { + await request(app) + .post('/resources/workloads/query') + .send({ + entityRef: 'component:someComponent', + auth: { + google: 'something', + }, + }) + .set('Content-Type', 'application/json') + .set('Authorization', 'ffffff') + .expect(401, { + error: { name: 'AuthenticationError', message: 'No Backstage token' }, + request: { + method: 'POST', + url: '/resources/workloads/query', + }, + response: { statusCode: 401 }, + }); + }); + // eslint-disable-next-line jest/expect-expect + it('500 handle gracefully', async () => { + await request(app) + .post('/resources/workloads/query') + .send({ + entityRef: 'inject500:inject500/inject500', + auth: { + google: 'something', + }, + }) + .set('Content-Type', 'application/json') + .set('Authorization', 'Bearer Zm9vYmFy') + .expect(500, { + error: { + name: 'Error', + message: 'some internal error', + level: 'error', + service: 'backstage', + }, + request: { method: 'POST', url: '/resources/workloads/query' }, + response: { statusCode: 500 }, + }); + }); + }); + describe('POST /resources/custom/query', () => { + // eslint-disable-next-line jest/expect-expect + it('200 happy path', async () => { + await request(app) + .post('/resources/custom/query') + .send({ + entityRef: 'component:someComponent', + auth: { + google: 'something', + }, + customResources: [ + { + group: 'someGroup', + apiVersion: 'someApiVersion', + plural: 'somePlural', + }, + ], + }) + .set('Content-Type', 'application/json') + .set('Authorization', 'Bearer Zm9vYmFy') + .expect(200, { + items: [ + { + clusterOne: { + pods: [ + { + metadata: { + name: 'pod1', + }, + }, + ], + }, + }, + ], + }); + }); + // eslint-disable-next-line jest/expect-expect + it('400 when missing custom resources', async () => { + await request(app) + .post('/resources/custom/query') + .send({ + entityRef: 'component:someComponent', + auth: { + google: 'something', + }, + }) + .set('Content-Type', 'application/json') + .set('Authorization', 'Bearer Zm9vYmFy') + .expect(400, { + error: { + name: 'InputError', + message: 'customResources is a required field', + }, + request: { + method: 'POST', + url: '/resources/custom/query', + }, + response: { statusCode: 400 }, + }); + }); + // eslint-disable-next-line jest/expect-expect + it('400 when custom resources not array', async () => { + await request(app) + .post('/resources/custom/query') + .send({ + entityRef: 'component:someComponent', + auth: { + google: 'something', + }, + customResources: 'somestring', + }) + .set('Content-Type', 'application/json') + .set('Authorization', 'Bearer Zm9vYmFy') + .expect(400, { + error: { + name: 'InputError', + message: 'customResources must be an array', + }, + request: { + method: 'POST', + url: '/resources/custom/query', + }, + response: { statusCode: 400 }, + }); + }); + // eslint-disable-next-line jest/expect-expect + it('400 when custom resources empty', async () => { + await request(app) + .post('/resources/custom/query') + .send({ + entityRef: 'component:someComponent', + auth: { + google: 'something', + }, + customResources: [], + }) + .set('Content-Type', 'application/json') + .set('Authorization', 'Bearer Zm9vYmFy') + .expect(400, { + error: { + name: 'InputError', + message: 'at least 1 customResource is required', + }, + request: { + method: 'POST', + url: '/resources/custom/query', + }, + response: { statusCode: 400 }, + }); + }); + // eslint-disable-next-line jest/expect-expect + it('400 when missing entity ref', async () => { + await request(app) + .post('/resources/custom/query') + .send({ + auth: { + google: 'something', + }, + customResources: [ + { + group: 'someGroup', + apiVersion: 'someApiVersion', + plural: 'somePlural', + }, + ], + }) + .set('Content-Type', 'application/json') + .set('Authorization', 'Bearer Zm9vYmFy') + .expect(400, { + error: { name: 'InputError', message: 'entity is a required field' }, + request: { + method: 'POST', + url: '/resources/custom/query', + }, + response: { statusCode: 400 }, + }); + }); + // eslint-disable-next-line jest/expect-expect + it('400 when bad entity ref', async () => { + await request(app) + .post('/resources/custom/query') + .send({ + entityRef: 'ffff', + auth: { + google: 'something', + }, + customResources: [ + { + group: 'someGroup', + apiVersion: 'someApiVersion', + plural: 'somePlural', + }, + ], + }) + .set('Content-Type', 'application/json') + .set('Authorization', 'Bearer Zm9vYmFy') + .expect(400, { + error: { + name: 'InputError', + message: + 'Invalid entity ref, Error: Entity reference "ffff" had missing or empty kind (e.g. did not start with "component:" or similar)', + }, + request: { + method: 'POST', + url: '/resources/custom/query', + }, + response: { statusCode: 400 }, + }); + }); + // eslint-disable-next-line jest/expect-expect + it('400 when no entity in catalog', async () => { + await request(app) + .post('/resources/custom/query') + .send({ + entityRef: 'noentity:noentity', + auth: { + google: 'something', + }, + customResources: [ + { + group: 'someGroup', + apiVersion: 'someApiVersion', + plural: 'somePlural', + }, + ], + }) + .set('Content-Type', 'application/json') + .set('Authorization', 'Bearer Zm9vYmFy') + .expect(400, { + error: { + name: 'InputError', + message: 'Entity ref missing, noentity:default/noentity', + }, + request: { + method: 'POST', + url: '/resources/custom/query', + }, + response: { statusCode: 400 }, + }); + }); + // eslint-disable-next-line jest/expect-expect + it('401 when no Auth header', async () => { + await request(app) + .post('/resources/custom/query') + .send({ + entityRef: 'component:someComponent', + auth: { + google: 'something', + }, + customResources: [ + { + group: 'someGroup', + apiVersion: 'someApiVersion', + plural: 'somePlural', + }, + ], + }) + .set('Content-Type', 'application/json') + .expect(401, { + error: { name: 'AuthenticationError', message: 'No Backstage token' }, + request: { + method: 'POST', + url: '/resources/custom/query', + }, + response: { statusCode: 401 }, + }); + }); + // eslint-disable-next-line jest/expect-expect + it('401 when invalid Auth header', async () => { + await request(app) + .post('/resources/custom/query') + .send({ + entityRef: 'component:someComponent', + auth: { + google: 'something', + }, + customResources: [ + { + group: 'someGroup', + apiVersion: 'someApiVersion', + plural: 'somePlural', + }, + ], + }) + .set('Content-Type', 'application/json') + .set('Authorization', 'ffffff') + .expect(401, { + error: { name: 'AuthenticationError', message: 'No Backstage token' }, + request: { + method: 'POST', + url: '/resources/custom/query', + }, + response: { statusCode: 401 }, + }); + }); + // eslint-disable-next-line jest/expect-expect + it('500 handle gracefully', async () => { + await request(app) + .post('/resources/custom/query') + .send({ + entityRef: 'inject500:inject500/inject500', + auth: { + google: 'something', + }, + customResources: [ + { + group: 'someGroup', + apiVersion: 'someApiVersion', + plural: 'somePlural', + }, + ], + }) + .set('Content-Type', 'application/json') + .set('Authorization', 'Bearer Zm9vYmFy') + .expect(500, { + error: { + name: 'Error', + message: 'some internal error', + level: 'error', + service: 'backstage', + }, + request: { method: 'POST', url: '/resources/custom/query' }, + response: { statusCode: 500 }, + }); + }); + }); +}); diff --git a/plugins/kubernetes-backend/src/routes/resourcesRoutes.ts b/plugins/kubernetes-backend/src/routes/resourcesRoutes.ts new file mode 100644 index 0000000000..2b2a48f707 --- /dev/null +++ b/plugins/kubernetes-backend/src/routes/resourcesRoutes.ts @@ -0,0 +1,94 @@ +/* + * 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 { + CompoundEntityRef, + parseEntityRef, + stringifyEntityRef, +} from '@backstage/catalog-model'; +import { CatalogApi } from '@backstage/catalog-client'; +import { InputError, AuthenticationError } from '@backstage/errors'; +import express, { Request } from 'express'; +import { KubernetesObjectsProvider } from '../types/types'; +import { getBearerTokenFromAuthorizationHeader } from '@backstage/plugin-auth-node'; + +export const addResourceRoutesToRouter = ( + router: express.Router, + catalogApi: CatalogApi, + objectsProvider: KubernetesObjectsProvider, +) => { + const getEntityByReq = async (req: Request) => { + const rawEntityRef = req.body.entityRef; + if (rawEntityRef && typeof rawEntityRef !== 'string') { + throw new InputError(`entity query must be a string`); + } else if (!rawEntityRef) { + throw new InputError('entity is a required field'); + } + let entityRef: CompoundEntityRef | undefined = undefined; + + try { + entityRef = parseEntityRef(rawEntityRef); + } catch (error) { + throw new InputError(`Invalid entity ref, ${error}`); + } + + const token = getBearerTokenFromAuthorizationHeader( + req.headers.authorization, + ); + + if (!token) { + throw new AuthenticationError('No Backstage token'); + } + + const entity = await catalogApi.getEntityByRef(entityRef, { + token: token, + }); + + if (!entity) { + throw new InputError( + `Entity ref missing, ${stringifyEntityRef(entityRef)}`, + ); + } + return entity; + }; + + router.post('/resources/workloads/query', async (req, res) => { + const entity = await getEntityByReq(req); + const response = await objectsProvider.getKubernetesObjectsByEntity({ + entity, + auth: req.body.auth, + }); + res.json(response); + }); + + router.post('/resources/custom/query', async (req, res) => { + const entity = await getEntityByReq(req); + + if (!req.body.customResources) { + throw new InputError('customResources is a required field'); + } else if (!Array.isArray(req.body.customResources)) { + throw new InputError('customResources must be an array'); + } else if (req.body.customResources.length === 0) { + throw new InputError('at least 1 customResource is required'); + } + + const response = await objectsProvider.getCustomResourcesByEntity({ + entity, + customResources: req.body.customResources, + auth: req.body.auth, + }); + res.json(response); + }); +}; diff --git a/plugins/kubernetes-backend/src/service-locator/MultiTenantServiceLocator.test.ts b/plugins/kubernetes-backend/src/service-locator/MultiTenantServiceLocator.test.ts index 0dce2305bf..2ead460848 100644 --- a/plugins/kubernetes-backend/src/service-locator/MultiTenantServiceLocator.test.ts +++ b/plugins/kubernetes-backend/src/service-locator/MultiTenantServiceLocator.test.ts @@ -15,6 +15,7 @@ */ import '@backstage/backend-common'; +import { Entity } from '@backstage/catalog-model'; import { MultiTenantServiceLocator } from './MultiTenantServiceLocator'; describe('MultiTenantConfigClusterLocator', () => { @@ -23,9 +24,9 @@ describe('MultiTenantConfigClusterLocator', () => { getClusters: async () => [], }); - const result = await sut.getClustersByServiceId('ignored'); + const result = await sut.getClustersByEntity({} as Entity); - expect(result).toStrictEqual([]); + expect(result).toStrictEqual({ clusters: [] }); }); it('one clusters returns one cluster details', async () => { @@ -42,16 +43,18 @@ describe('MultiTenantConfigClusterLocator', () => { }, }); - const result = await sut.getClustersByServiceId('ignored'); + const result = await sut.getClustersByEntity({} as Entity); - expect(result).toStrictEqual([ - { - name: 'cluster1', - serviceAccountToken: '12345', - url: 'http://localhost:8080', - authProvider: 'serviceAccount', - }, - ]); + expect(result).toStrictEqual({ + clusters: [ + { + name: 'cluster1', + serviceAccountToken: '12345', + url: 'http://localhost:8080', + authProvider: 'serviceAccount', + }, + ], + }); }); it('two clusters returns two cluster details', async () => { @@ -73,20 +76,22 @@ describe('MultiTenantConfigClusterLocator', () => { }, }); - const result = await sut.getClustersByServiceId('ignored'); + const result = await sut.getClustersByEntity({} as Entity); - expect(result).toStrictEqual([ - { - name: 'cluster1', - serviceAccountToken: 'token', - url: 'http://localhost:8080', - authProvider: 'serviceAccount', - }, - { - name: 'cluster2', - url: 'http://localhost:8081', - authProvider: 'google', - }, - ]); + expect(result).toStrictEqual({ + clusters: [ + { + name: 'cluster1', + serviceAccountToken: 'token', + url: 'http://localhost:8080', + authProvider: 'serviceAccount', + }, + { + name: 'cluster2', + url: 'http://localhost:8081', + authProvider: 'google', + }, + ], + }); }); }); diff --git a/plugins/kubernetes-backend/src/service-locator/MultiTenantServiceLocator.ts b/plugins/kubernetes-backend/src/service-locator/MultiTenantServiceLocator.ts index 30c66a38d1..7bafbb10f3 100644 --- a/plugins/kubernetes-backend/src/service-locator/MultiTenantServiceLocator.ts +++ b/plugins/kubernetes-backend/src/service-locator/MultiTenantServiceLocator.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import { Entity } from '@backstage/catalog-model'; import { ClusterDetails, KubernetesClustersSupplier, @@ -30,8 +31,9 @@ export class MultiTenantServiceLocator implements KubernetesServiceLocator { } // As this implementation always returns all clusters serviceId is ignored here - // eslint-disable-next-line @typescript-eslint/no-unused-vars - async getClustersByServiceId(_serviceId: string): Promise { - return this.clusterSupplier.getClusters(); + getClustersByEntity( + _entity: Entity, + ): Promise<{ clusters: ClusterDetails[] }> { + return this.clusterSupplier.getClusters().then(clusters => ({ clusters })); } } diff --git a/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts b/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts index 37dad8c3e4..309141ec0e 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts @@ -15,6 +15,7 @@ */ import { getVoidLogger } from '@backstage/backend-common'; +import { Entity } from '@backstage/catalog-model'; import { Config, ConfigReader } from '@backstage/config'; import { ObjectsByEntityResponse } from '@backstage/plugin-kubernetes-common'; import express from 'express'; @@ -30,11 +31,13 @@ import { import { KubernetesBuilder } from './KubernetesBuilder'; import { KubernetesFanOutHandler } from './KubernetesFanOutHandler'; import { PodStatus } from '@kubernetes/client-node'; +import { CatalogApi } from '@backstage/catalog-client'; describe('KubernetesBuilder', () => { let app: express.Express; let kubernetesFanOutHandler: jest.Mocked; let config: Config; + let catalogApi: CatalogApi; beforeAll(async () => { const logger = getVoidLogger(); @@ -68,7 +71,13 @@ describe('KubernetesBuilder', () => { getKubernetesObjectsByEntity: jest.fn(), } as any; - const { router } = await KubernetesBuilder.createBuilder({ config, logger }) + catalogApi = {} as CatalogApi; + + const { router } = await KubernetesBuilder.createBuilder({ + config, + logger, + catalogApi, + }) .setObjectsProvider(kubernetesFanOutHandler) .setClusterSupplier(clusterSupplier) .build(); @@ -207,8 +216,10 @@ describe('KubernetesBuilder', () => { }; const serviceLocator: KubernetesServiceLocator = { - getClustersByServiceId(_serviceId: string): Promise { - return Promise.resolve([someCluster]); + getClustersByEntity( + _entity: Entity, + ): Promise<{ clusters: ClusterDetails[] }> { + return Promise.resolve({ clusters: [someCluster] }); }, }; @@ -237,6 +248,7 @@ describe('KubernetesBuilder', () => { const { router } = await KubernetesBuilder.createBuilder({ logger, config, + catalogApi, }) .setClusterSupplier(clusterSupplier) .setServiceLocator(serviceLocator) @@ -244,7 +256,15 @@ describe('KubernetesBuilder', () => { .build(); app = express().use(router); - const response = await request(app).post('/services/test-service'); + const response = await request(app) + .post('/services/test-service') + .send({ + entity: { + metadata: { + name: 'thing', + }, + }, + }); expect(response.body).toEqual(result); expect(response.status).toEqual(200); diff --git a/plugins/kubernetes-backend/src/service/KubernetesBuilder.ts b/plugins/kubernetes-backend/src/service/KubernetesBuilder.ts index 18c3fdc931..59bac4f30a 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesBuilder.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesBuilder.ts @@ -37,16 +37,23 @@ import { KubernetesFanOutHandler, } from './KubernetesFanOutHandler'; import { KubernetesClientBasedFetcher } from './KubernetesFetcher'; +import { addResourceRoutesToRouter } from '../routes/resourcesRoutes'; +import { CatalogApi } from '@backstage/catalog-client'; +/** + * + * @alpha + */ export interface KubernetesEnvironment { logger: Logger; config: Config; + catalogApi: CatalogApi; } /** * The return type of the `KubernetesBuilder.build` method * - * @public + * @alpha */ export type KubernetesBuilderReturn = Promise<{ router: express.Router; @@ -57,6 +64,10 @@ export type KubernetesBuilderReturn = Promise<{ serviceLocator: KubernetesServiceLocator; }>; +/** + * + * @alpha + */ export class KubernetesBuilder { private clusterSupplier?: KubernetesClustersSupplier; private defaultClusterRefreshInterval: Duration = Duration.fromObject({ @@ -111,7 +122,11 @@ export class KubernetesBuilder { objectTypesToFetch: this.getObjectTypesToFetch(), }); - const router = this.buildRouter(objectsProvider, clusterSupplier); + const router = this.buildRouter( + objectsProvider, + clusterSupplier, + this.env.catalogApi, + ); return { clusterSupplier, @@ -218,18 +233,21 @@ export class KubernetesBuilder { protected buildRouter( objectsProvider: KubernetesObjectsProvider, clusterSupplier: KubernetesClustersSupplier, + catalogApi: CatalogApi, ): express.Router { const logger = this.env.logger; const router = Router(); router.use(express.json()); + // @deprecated router.post('/services/:serviceId', async (req, res) => { const serviceId = req.params.serviceId; const requestBody: ObjectsByEntityRequest = req.body; try { - const response = await objectsProvider.getKubernetesObjectsByEntity( - requestBody, - ); + const response = await objectsProvider.getKubernetesObjectsByEntity({ + entity: requestBody.entity, + auth: requestBody.auth || {}, + }); res.json(response); } catch (e) { logger.error( @@ -250,6 +268,9 @@ export class KubernetesBuilder { })), }); }); + + addResourceRoutesToRouter(router, catalogApi, objectsProvider); + return router; } diff --git a/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.test.ts b/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.test.ts index da8f703ba0..176498839d 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.test.ts @@ -22,7 +22,7 @@ import { PodStatus } from '@kubernetes/client-node/dist/top'; const fetchObjectsForService = jest.fn(); const fetchPodMetricsByNamespace = jest.fn(); -const getClustersByServiceId = jest.fn(); +const getClustersByEntity = jest.fn(); const POD_METRICS_FIXTURE = { containers: [], @@ -166,13 +166,15 @@ describe('handleGetKubernetesObjectsForService', () => { }); it('retrieve objects for one cluster', async () => { - getClustersByServiceId.mockImplementation(() => - Promise.resolve([ - { - name: 'test-cluster', - authProvider: 'serviceAccount', - }, - ]), + getClustersByEntity.mockImplementation(() => + Promise.resolve({ + clusters: [ + { + name: 'test-cluster', + authProvider: 'serviceAccount', + }, + ], + }), ); mockFetch(fetchObjectsForService); @@ -185,7 +187,7 @@ describe('handleGetKubernetesObjectsForService', () => { fetchPodMetricsByNamespace, }, serviceLocator: { - getClustersByServiceId, + getClustersByEntity, }, customResources: [], }); @@ -207,9 +209,10 @@ describe('handleGetKubernetesObjectsForService', () => { owner: 'joe', }, }, + auth: {}, }); - expect(getClustersByServiceId.mock.calls.length).toBe(1); + expect(getClustersByEntity.mock.calls.length).toBe(1); expect(fetchObjectsForService.mock.calls.length).toBe(1); expect(fetchPodMetricsByNamespace.mock.calls.length).toBe(1); expect(fetchPodMetricsByNamespace.mock.calls[0][1]).toBe( @@ -265,13 +268,15 @@ describe('handleGetKubernetesObjectsForService', () => { }); it('dont call top for the same namespace twice', async () => { - getClustersByServiceId.mockImplementation(() => - Promise.resolve([ - { - name: 'test-cluster', - authProvider: 'serviceAccount', - }, - ]), + getClustersByEntity.mockImplementation(() => + Promise.resolve({ + clusters: [ + { + name: 'test-cluster', + authProvider: 'serviceAccount', + }, + ], + }), ); fetchObjectsForService.mockImplementation((_: ObjectFetchParams) => @@ -314,7 +319,7 @@ describe('handleGetKubernetesObjectsForService', () => { fetchPodMetricsByNamespace, }, serviceLocator: { - getClustersByServiceId, + getClustersByEntity, }, customResources: [], }); @@ -336,9 +341,10 @@ describe('handleGetKubernetesObjectsForService', () => { owner: 'joe', }, }, + auth: {}, }); - expect(getClustersByServiceId.mock.calls.length).toBe(1); + expect(getClustersByEntity.mock.calls.length).toBe(1); expect(fetchObjectsForService.mock.calls.length).toBe(1); expect(fetchPodMetricsByNamespace.mock.calls.length).toBe(2); expect(fetchPodMetricsByNamespace.mock.calls[0][1]).toBe('ns-a'); @@ -383,18 +389,20 @@ describe('handleGetKubernetesObjectsForService', () => { }); it('retrieve objects for two clusters', async () => { - getClustersByServiceId.mockImplementation(() => - Promise.resolve([ - { - name: 'test-cluster', - authProvider: 'serviceAccount', - dashboardUrl: 'https://k8s.foo.coom', - }, - { - name: 'other-cluster', - authProvider: 'google', - }, - ]), + getClustersByEntity.mockImplementation(() => + Promise.resolve({ + clusters: [ + { + name: 'test-cluster', + authProvider: 'serviceAccount', + dashboardUrl: 'https://k8s.foo.coom', + }, + { + name: 'other-cluster', + authProvider: 'google', + }, + ], + }), ); mockFetch(fetchObjectsForService); @@ -407,15 +415,12 @@ describe('handleGetKubernetesObjectsForService', () => { fetchPodMetricsByNamespace, }, serviceLocator: { - getClustersByServiceId, + getClustersByEntity, }, customResources: [], }); const result = await sut.getKubernetesObjectsByEntity({ - auth: { - google: 'google_token_123', - }, entity: { apiVersion: 'backstage.io/v1beta1', kind: 'Component', @@ -432,9 +437,12 @@ describe('handleGetKubernetesObjectsForService', () => { owner: 'joe', }, }, + auth: { + google: 'google_token_123', + }, }); - expect(getClustersByServiceId.mock.calls.length).toBe(1); + expect(getClustersByEntity.mock.calls.length).toBe(1); expect(fetchObjectsForService.mock.calls.length).toBe(2); expect(result).toStrictEqual({ items: [ @@ -527,21 +535,23 @@ describe('handleGetKubernetesObjectsForService', () => { }); }); it('retrieve objects for three clusters, only two have resources and show in ui', async () => { - getClustersByServiceId.mockImplementation(() => - Promise.resolve([ - { - name: 'test-cluster', - authProvider: 'serviceAccount', - }, - { - name: 'other-cluster', - authProvider: 'google', - }, - { - name: 'empty-cluster', - authProvider: 'google', - }, - ]), + getClustersByEntity.mockImplementation(() => + Promise.resolve({ + clusters: [ + { + name: 'test-cluster', + authProvider: 'serviceAccount', + }, + { + name: 'other-cluster', + authProvider: 'google', + }, + { + name: 'empty-cluster', + authProvider: 'google', + }, + ], + }), ); mockFetch(fetchObjectsForService); @@ -554,15 +564,12 @@ describe('handleGetKubernetesObjectsForService', () => { fetchPodMetricsByNamespace, }, serviceLocator: { - getClustersByServiceId, + getClustersByEntity, }, customResources: [], }); const result = await sut.getKubernetesObjectsByEntity({ - auth: { - google: 'google_token_123', - }, entity: { apiVersion: 'backstage.io/v1beta1', kind: 'Component', @@ -579,9 +586,12 @@ describe('handleGetKubernetesObjectsForService', () => { owner: 'joe', }, }, + auth: { + google: 'google_token_123', + }, }); - expect(getClustersByServiceId.mock.calls.length).toBe(1); + expect(getClustersByEntity.mock.calls.length).toBe(1); expect(fetchObjectsForService.mock.calls.length).toBe(3); expect(result).toStrictEqual({ items: [ @@ -673,25 +683,27 @@ describe('handleGetKubernetesObjectsForService', () => { }); }); it('retrieve objects for four clusters, two have resources and one error cluster', async () => { - getClustersByServiceId.mockImplementation(() => - Promise.resolve([ - { - name: 'test-cluster', - authProvider: 'serviceAccount', - }, - { - name: 'other-cluster', - authProvider: 'google', - }, - { - name: 'empty-cluster', - authProvider: 'google', - }, - { - name: 'error-cluster', - authProvider: 'google', - }, - ]), + getClustersByEntity.mockImplementation(() => + Promise.resolve({ + clusters: [ + { + name: 'test-cluster', + authProvider: 'serviceAccount', + }, + { + name: 'other-cluster', + authProvider: 'google', + }, + { + name: 'empty-cluster', + authProvider: 'google', + }, + { + name: 'error-cluster', + authProvider: 'google', + }, + ], + }), ); mockFetch(fetchObjectsForService); @@ -704,15 +716,12 @@ describe('handleGetKubernetesObjectsForService', () => { fetchPodMetricsByNamespace, }, serviceLocator: { - getClustersByServiceId, + getClustersByEntity, }, customResources: [], }); const result = await sut.getKubernetesObjectsByEntity({ - auth: { - google: 'google_token_123', - }, entity: { apiVersion: 'backstage.io/v1beta1', kind: 'Component', @@ -729,9 +738,12 @@ describe('handleGetKubernetesObjectsForService', () => { owner: 'joe', }, }, + auth: { + google: 'google_token_123', + }, }); - expect(getClustersByServiceId.mock.calls.length).toBe(1); + expect(getClustersByEntity.mock.calls.length).toBe(1); expect(fetchObjectsForService.mock.calls.length).toBe(4); expect(result).toStrictEqual({ items: [ diff --git a/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.ts b/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.ts index 427165e4f1..67748e1506 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.ts @@ -14,16 +14,20 @@ * limitations under the License. */ +import { Entity } from '@backstage/catalog-model'; import { Logger } from 'winston'; import { ClusterDetails, - CustomResource, KubernetesFetcher, KubernetesObjectsProviderOptions, KubernetesServiceLocator, ObjectsByEntityRequest, FetchResponseWrapper, ObjectToFetch, + CustomResource, + CustomResourceMatcher, + CustomResourcesByEntity, + KubernetesObjectsByEntity, } from '../types/types'; import { KubernetesAuthTranslator } from '../kubernetes-auth-translator/types'; import { KubernetesAuthTranslatorGenerator } from '../kubernetes-auth-translator/KubernetesAuthTranslatorGenerator'; @@ -35,6 +39,7 @@ import { FetchResponse, ObjectsByEntityResponse, PodFetchResponse, + KubernetesRequestAuth, } from '@backstage/plugin-kubernetes-common'; import { ContainerStatus, @@ -42,6 +47,10 @@ import { PodStatus, } from '@kubernetes/client-node'; +/** + * + * @alpha + */ export const DEFAULT_OBJECTS: ObjectToFetch[] = [ { group: '', @@ -61,6 +70,12 @@ export const DEFAULT_OBJECTS: ObjectToFetch[] = [ plural: 'configmaps', objectType: 'configmaps', }, + { + group: '', + apiVersion: 'v1', + plural: 'limitranges', + objectType: 'limitranges', + }, { group: 'apps', apiVersion: 'v1', @@ -178,26 +193,44 @@ export class KubernetesFanOutHandler { this.authTranslators = {}; } - async getKubernetesObjectsByEntity( - requestBody: KubernetesRequestBody, - ): Promise { - const entityName = - requestBody.entity?.metadata?.annotations?.[ - 'backstage.io/kubernetes-id' - ] || requestBody.entity?.metadata?.name; - - const clusterDetails: ClusterDetails[] = - await this.serviceLocator.getClustersByServiceId(entityName); - - // Execute all of these async actions simultaneously/without blocking sequentially as no common object is modified by them - const promises: Promise[] = clusterDetails.map(cd => { - return this.getAuthTranslator( - cd.authProvider, - ).decorateClusterDetailsWithAuth(cd, requestBody); - }); - const clusterDetailsDecoratedForAuth: ClusterDetails[] = await Promise.all( - promises, + async getCustomResourcesByEntity({ + entity, + auth, + customResources, + }: CustomResourcesByEntity): Promise { + // Don't fetch the default object types only the provided custom resources + return this.fanOutRequests( + entity, + auth, + new Set(), + customResources, ); + } + + async getKubernetesObjectsByEntity({ + entity, + auth, + }: KubernetesObjectsByEntity): Promise { + return this.fanOutRequests( + entity, + auth, + this.objectTypesToFetch, + this.customResources, + ); + } + + private async fanOutRequests( + entity: Entity, + auth: KubernetesRequestAuth, + objectTypesToFetch: Set, + customResources: CustomResourceMatcher[], + ) { + const entityName = + entity.metadata?.annotations?.['backstage.io/kubernetes-id'] || + entity.metadata?.name; + + const clusterDetailsDecoratedForAuth: ClusterDetails[] = + await this.decorateClusterDetailsWithAuth(entity, auth); this.logger.info( `entity.metadata.name=${entityName} clusterDetails=[${clusterDetailsDecoratedForAuth @@ -206,14 +239,12 @@ export class KubernetesFanOutHandler { ); const labelSelector: string = - requestBody.entity?.metadata?.annotations?.[ + entity.metadata?.annotations?.[ 'backstage.io/kubernetes-label-selector' ] || `backstage.io/kubernetes-id=${entityName}`; const namespace = - requestBody.entity?.metadata?.annotations?.[ - 'backstage.io/kubernetes-namespace' - ]; + entity.metadata?.annotations?.['backstage.io/kubernetes-namespace']; return Promise.all( clusterDetailsDecoratedForAuth.map(clusterDetailsItem => { @@ -221,9 +252,12 @@ export class KubernetesFanOutHandler { .fetchObjectsForService({ serviceId: entityName, clusterDetails: clusterDetailsItem, - objectTypesToFetch: this.objectTypesToFetch, + objectTypesToFetch: objectTypesToFetch, labelSelector, - customResources: this.customResources, + customResources: customResources.map(c => ({ + ...c, + objectType: 'customresources', + })), namespace, }) .then(result => this.getMetricsForPods(clusterDetailsItem, result)) @@ -232,6 +266,27 @@ export class KubernetesFanOutHandler { ).then(this.toObjectsByEntityResponse); } + private async decorateClusterDetailsWithAuth( + entity: Entity, + auth: KubernetesRequestAuth, + ) { + const clusterDetails: ClusterDetails[] = await ( + await this.serviceLocator.getClustersByEntity(entity) + ).clusters; + + // Execute all of these async actions simultaneously/without blocking sequentially as no common object is modified by them + return await Promise.all( + clusterDetails.map(cd => { + const kubernetesAuthTranslator: KubernetesAuthTranslator = + this.getAuthTranslator(cd.authProvider); + return kubernetesAuthTranslator.decorateClusterDetailsWithAuth( + cd, + auth, + ); + }), + ); + } + toObjectsByEntityResponse( clusterObjects: ClusterObjects[], ): ObjectsByEntityResponse { diff --git a/plugins/kubernetes-backend/src/service/router.ts b/plugins/kubernetes-backend/src/service/router.ts index 61082267be..6c26175058 100644 --- a/plugins/kubernetes-backend/src/service/router.ts +++ b/plugins/kubernetes-backend/src/service/router.ts @@ -19,10 +19,16 @@ import { Logger } from 'winston'; import { KubernetesClustersSupplier } from '../types/types'; import express from 'express'; import { KubernetesBuilder } from './KubernetesBuilder'; +import { CatalogApi } from '@backstage/catalog-client'; +/** + * + * @alpha + */ export interface RouterOptions { logger: Logger; config: Config; + catalogApi: CatalogApi; clusterSupplier?: KubernetesClustersSupplier; } @@ -38,6 +44,8 @@ export interface RouterOptions { * config, * }).build(); * ``` + * + * @alpha */ export async function createRouter( options: RouterOptions, diff --git a/plugins/kubernetes-backend/src/service/standaloneApplication.ts b/plugins/kubernetes-backend/src/service/standaloneApplication.ts index 29262744e5..c12d7be2bb 100644 --- a/plugins/kubernetes-backend/src/service/standaloneApplication.ts +++ b/plugins/kubernetes-backend/src/service/standaloneApplication.ts @@ -18,6 +18,7 @@ import { errorHandler, notFoundHandler, requestLoggingHandler, + SingleHostDiscovery, } from '@backstage/backend-common'; import compression from 'compression'; import cors from 'cors'; @@ -26,6 +27,7 @@ import helmet from 'helmet'; import { Logger } from 'winston'; import { createRouter } from './router'; import { ConfigReader } from '@backstage/config'; +import { CatalogClient } from '@backstage/catalog-client'; export interface ApplicationOptions { enableCors: boolean; @@ -39,6 +41,10 @@ export async function createStandaloneApplication( const config = new ConfigReader({}); const app = express(); + const catalogApi = new CatalogClient({ + discoveryApi: SingleHostDiscovery.fromConfig(config), + }); + app.use(helmet()); if (enableCors) { app.use(cors()); @@ -46,7 +52,7 @@ export async function createStandaloneApplication( app.use(compression()); app.use(express.json()); app.use(requestLoggingHandler()); - app.use('/', await createRouter({ logger, config })); + app.use('/', await createRouter({ logger, config, catalogApi })); app.use(notFoundHandler()); app.use(errorHandler()); diff --git a/plugins/kubernetes-backend/src/types/types.ts b/plugins/kubernetes-backend/src/types/types.ts index 67456d12c8..0826c4158c 100644 --- a/plugins/kubernetes-backend/src/types/types.ts +++ b/plugins/kubernetes-backend/src/types/types.ts @@ -14,16 +14,22 @@ * limitations under the License. */ +import { Entity } from '@backstage/catalog-model'; import { Logger } from 'winston'; import type { JsonObject } from '@backstage/types'; import type { FetchResponse, KubernetesFetchError, + KubernetesRequestAuth, KubernetesRequestBody, ObjectsByEntityResponse, } from '@backstage/plugin-kubernetes-common'; import { PodStatus } from '@kubernetes/client-node/dist/top'; +/** + * + * @alpha + */ export interface ObjectFetchParams { serviceId: string; clusterDetails: @@ -37,8 +43,11 @@ export interface ObjectFetchParams { namespace?: string; } -// Fetches information from a kubernetes cluster using the cluster details object -// to target a specific cluster +/** + * Fetches information from a kubernetes cluster using the cluster details object to target a specific cluster + * + * @alpha + */ export interface KubernetesFetcher { fetchObjectsForService( params: ObjectFetchParams, @@ -49,13 +58,19 @@ export interface KubernetesFetcher { ): Promise; } +/** + * + * @alpha + */ export interface FetchResponseWrapper { errors: KubernetesFetchError[]; responses: FetchResponse[]; } -// TODO fairly sure there's a easier way to do this - +/** + * + * @alpha + */ export interface ObjectToFetch { objectType: KubernetesObjectTypes; group: string; @@ -63,15 +78,30 @@ export interface ObjectToFetch { plural: string; } +/** + * + * @alpha + */ export interface CustomResource extends ObjectToFetch { objectType: 'customresources'; } +/** + * + * @alpha + */ +export type CustomResourceMatcher = Omit; + +/** + * + * @alpha + */ export type KubernetesObjectTypes = | 'pods' | 'services' | 'configmaps' | 'deployments' + | 'limitranges' | 'replicasets' | 'horizontalpodautoscalers' | 'jobs' @@ -80,7 +110,10 @@ export type KubernetesObjectTypes = | 'customresources' | 'statefulsets'; -// Used to load cluster details from different sources +/** + * Used to load cluster details from different sources + * @alpha + */ export interface KubernetesClustersSupplier { /** * Returns the cached list of clusters. @@ -91,13 +124,24 @@ export interface KubernetesClustersSupplier { getClusters(): Promise; } -// Used to locate which cluster(s) a service is running on +/** + * Used to locate which cluster(s) a service is running on + * @alpha + */ export interface KubernetesServiceLocator { - getClustersByServiceId(serviceId: string): Promise; + getClustersByEntity(entity: Entity): Promise<{ clusters: ClusterDetails[] }>; } +/** + * + * @alpha + */ export type ServiceLocatorMethod = 'multiTenant' | 'http'; // TODO implement http +/** + * + * @alpha + */ export interface ClusterDetails { /** * Specifies the name of the Kubernetes cluster. @@ -151,14 +195,37 @@ export interface ClusterDetails { dashboardParameters?: JsonObject; } +/** + * + * @alpha + */ export interface GKEClusterDetails extends ClusterDetails {} + +/** + * + * @alpha + */ export interface AzureClusterDetails extends ClusterDetails {} + +/** + * + * @alpha + */ export interface ServiceAccountClusterDetails extends ClusterDetails {} + +/** + * + * @alpha + */ export interface AWSClusterDetails extends ClusterDetails { assumeRole?: string; externalId?: string; } +/** + * + * @alpha + */ export interface KubernetesObjectsProviderOptions { logger: Logger; fetcher: KubernetesFetcher; @@ -167,10 +234,38 @@ export interface KubernetesObjectsProviderOptions { objectTypesToFetch?: ObjectToFetch[]; } +/** + * + * @alpha + */ export type ObjectsByEntityRequest = KubernetesRequestBody; +/** + * + * @alpha + */ +export interface KubernetesObjectsByEntity { + entity: Entity; + auth: KubernetesRequestAuth; +} + +/** + * + * @alpha + */ +export interface CustomResourcesByEntity extends KubernetesObjectsByEntity { + customResources: CustomResourceMatcher[]; +} + +/** + * + * @alpha + */ export interface KubernetesObjectsProvider { getKubernetesObjectsByEntity( - request: ObjectsByEntityRequest, + kubernetesObjectsByEntity: KubernetesObjectsByEntity, + ): Promise; + getCustomResourcesByEntity( + customResourcesByEntity: CustomResourcesByEntity, ): Promise; } diff --git a/plugins/kubernetes-common/CHANGELOG.md b/plugins/kubernetes-common/CHANGELOG.md index d9f7e60c13..dd1feff82e 100644 --- a/plugins/kubernetes-common/CHANGELOG.md +++ b/plugins/kubernetes-common/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/plugin-kubernetes-common +## 0.4.0-next.1 + +### Patch Changes + +- 60e5f9fe68: Fixed the lack of `limitranges` as part of the Default Objects to fetch from the kubernetes api +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.2 + +## 0.4.0-next.0 + +### Minor Changes + +- 0791af993f: Refactor `KubernetesObjectsProvider` with new methods, `KubernetesServiceLocator` now takes an `Entity` instead of `serviceId` + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + ## 0.3.0 ### Minor Changes diff --git a/plugins/kubernetes-common/api-report.md b/plugins/kubernetes-common/api-report.md index cca4a9760f..2ca33d1a97 100644 --- a/plugins/kubernetes-common/api-report.md +++ b/plugins/kubernetes-common/api-report.md @@ -11,6 +11,7 @@ import { V1Deployment } from '@kubernetes/client-node'; import { V1HorizontalPodAutoscaler } from '@kubernetes/client-node'; import { V1Ingress } from '@kubernetes/client-node'; import { V1Job } from '@kubernetes/client-node'; +import { V1LimitRange } from '@kubernetes/client-node'; import { V1Pod } from '@kubernetes/client-node'; import { V1ReplicaSet } from '@kubernetes/client-node'; import { V1Service } from '@kubernetes/client-node'; @@ -131,6 +132,7 @@ export type FetchResponse = | ServiceFetchResponse | ConfigMapFetchResponse | DeploymentFetchResponse + | LimitRangeFetchReponse | ReplicaSetsFetchResponse | HorizontalPodAutoscalersFetchResponse | JobsFetchResponse @@ -190,21 +192,38 @@ export interface KubernetesFetchError { statusCode?: number; } +// Warning: (ae-missing-release-tag) "KubernetesRequestAuth" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface KubernetesRequestAuth { + // (undocumented) + google?: string; + // (undocumented) + oidc?: { + [key: string]: string; + }; +} + // Warning: (ae-missing-release-tag) "KubernetesRequestBody" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) export interface KubernetesRequestBody { // (undocumented) - auth?: { - google?: string; - oidc?: { - [key: string]: string; - }; - }; + auth?: KubernetesRequestAuth; // (undocumented) entity: Entity; } +// Warning: (ae-missing-release-tag) "LimitRangeFetchReponse" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface LimitRangeFetchReponse { + // (undocumented) + resources: Array; + // (undocumented) + type: 'limitranges'; +} + // Warning: (ae-missing-release-tag) "ObjectsByEntityResponse" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) diff --git a/plugins/kubernetes-common/package.json b/plugins/kubernetes-common/package.json index 62c9eb9745..9e3ff7299e 100644 --- a/plugins/kubernetes-common/package.json +++ b/plugins/kubernetes-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes-common", "description": "Common functionalities for kubernetes, to be shared between kubernetes and kubernetes-backend plugin", - "version": "0.3.0", + "version": "0.4.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -38,11 +38,11 @@ "url": "https://github.com/backstage/backstage/issues" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", + "@backstage/catalog-model": "^1.1.0-next.2", "@kubernetes/client-node": "^0.16.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2" + "@backstage/cli": "^0.18.0-next.2" }, "jest": { "roots": [ diff --git a/plugins/kubernetes-common/src/types.ts b/plugins/kubernetes-common/src/types.ts index 3d4746ca44..9b8b790c79 100644 --- a/plugins/kubernetes-common/src/types.ts +++ b/plugins/kubernetes-common/src/types.ts @@ -22,6 +22,7 @@ import { V1HorizontalPodAutoscaler, V1Ingress, V1Job, + V1LimitRange, V1Pod, V1ReplicaSet, V1Service, @@ -29,13 +30,15 @@ import { } from '@kubernetes/client-node'; import { Entity } from '@backstage/catalog-model'; -export interface KubernetesRequestBody { - auth?: { - google?: string; - oidc?: { - [key: string]: string; - }; +export interface KubernetesRequestAuth { + google?: string; + oidc?: { + [key: string]: string; }; +} + +export interface KubernetesRequestBody { + auth?: KubernetesRequestAuth; entity: Entity; } @@ -95,6 +98,7 @@ export type FetchResponse = | ServiceFetchResponse | ConfigMapFetchResponse | DeploymentFetchResponse + | LimitRangeFetchReponse | ReplicaSetsFetchResponse | HorizontalPodAutoscalersFetchResponse | JobsFetchResponse @@ -128,6 +132,11 @@ export interface ReplicaSetsFetchResponse { resources: Array; } +export interface LimitRangeFetchReponse { + type: 'limitranges'; + resources: Array; +} + export interface HorizontalPodAutoscalersFetchResponse { type: 'horizontalpodautoscalers'; resources: Array; diff --git a/plugins/kubernetes/CHANGELOG.md b/plugins/kubernetes/CHANGELOG.md index 29f0ed0241..dc44dffad4 100644 --- a/plugins/kubernetes/CHANGELOG.md +++ b/plugins/kubernetes/CHANGELOG.md @@ -1,5 +1,36 @@ # @backstage/plugin-kubernetes +## 0.6.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/plugin-kubernetes-common@0.4.0-next.1 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## 0.6.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## 0.6.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-kubernetes-common@0.4.0-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + ## 0.6.6 ### Patch Changes diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index 1b63484224..0bb8ac0324 100644 --- a/plugins/kubernetes/package.json +++ b/plugins/kubernetes/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes", "description": "A Backstage plugin that integrates towards Kubernetes", - "version": "0.6.6", + "version": "0.6.7-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,13 +34,13 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", + "@backstage/catalog-model": "^1.1.0-next.2", "@backstage/config": "^1.0.1", - "@backstage/core-components": "^0.9.5", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/plugin-catalog-react": "^1.1.1", - "@backstage/plugin-kubernetes-common": "^0.3.0", - "@backstage/theme": "^0.2.15", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", + "@backstage/plugin-kubernetes-common": "^0.4.0-next.1", + "@backstage/theme": "^0.2.16-next.1", "@kubernetes/client-node": "^0.16.0", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -57,10 +57,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/react-hooks": "^8.0.0", @@ -68,7 +68,7 @@ "@types/jest": "^26.0.7", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/lighthouse/CHANGELOG.md b/plugins/lighthouse/CHANGELOG.md index 7dc3e30b1f..ded56ce2da 100644 --- a/plugins/lighthouse/CHANGELOG.md +++ b/plugins/lighthouse/CHANGELOG.md @@ -1,5 +1,34 @@ # @backstage/plugin-lighthouse +## 0.3.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## 0.3.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## 0.3.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + ## 0.3.6 ### Patch Changes diff --git a/plugins/lighthouse/package.json b/plugins/lighthouse/package.json index 5f7097c704..ea95636060 100644 --- a/plugins/lighthouse/package.json +++ b/plugins/lighthouse/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-lighthouse", "description": "A Backstage plugin that integrates towards Lighthouse", - "version": "0.3.6", + "version": "0.3.7-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,12 +35,12 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", + "@backstage/catalog-model": "^1.1.0-next.2", "@backstage/config": "^1.0.1", - "@backstage/core-components": "^0.9.5", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/plugin-catalog-react": "^1.1.1", - "@backstage/theme": "^0.2.15", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -51,10 +51,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/react-hooks": "^8.0.0", @@ -63,7 +63,7 @@ "@types/node": "^16.11.26", "@types/react": "^16.13.1 || ^17.0.0", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/newrelic-dashboard/CHANGELOG.md b/plugins/newrelic-dashboard/CHANGELOG.md index 54a058fcb9..ce7fb18e5c 100644 --- a/plugins/newrelic-dashboard/CHANGELOG.md +++ b/plugins/newrelic-dashboard/CHANGELOG.md @@ -1,5 +1,33 @@ # @backstage/plugin-newrelic-dashboard +## 0.1.15-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## 0.1.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## 0.1.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + ## 0.1.14 ### Patch Changes diff --git a/plugins/newrelic-dashboard/package.json b/plugins/newrelic-dashboard/package.json index 8166928a6a..a0a21fcf9c 100644 --- a/plugins/newrelic-dashboard/package.json +++ b/plugins/newrelic-dashboard/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-newrelic-dashboard", - "version": "0.1.14", + "version": "0.1.15-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,19 +23,19 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", - "@backstage/core-components": "^0.9.5", + "@backstage/catalog-model": "^1.1.0-next.2", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/errors": "^1.0.0", - "@backstage/plugin-catalog-react": "^1.1.1", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", "react-use": "^17.2.4" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/dev-utils": "^1.0.3", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/dev-utils": "^1.0.4-next.2", "@testing-library/jest-dom": "^5.10.1", "@types/react": "^16.13.1 || ^17.0.0", "cross-fetch": "^3.1.5" diff --git a/plugins/newrelic/CHANGELOG.md b/plugins/newrelic/CHANGELOG.md index 97da241a56..f3ff482fd8 100644 --- a/plugins/newrelic/CHANGELOG.md +++ b/plugins/newrelic/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-newrelic +## 0.3.25-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + +## 0.3.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/theme@0.2.16-next.0 + +## 0.3.25-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + ## 0.3.24 ### Patch Changes diff --git a/plugins/newrelic/package.json b/plugins/newrelic/package.json index 09f3d3196d..61b49060a4 100644 --- a/plugins/newrelic/package.json +++ b/plugins/newrelic/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-newrelic", "description": "A Backstage plugin that integrates towards New Relic", - "version": "0.3.24", + "version": "0.3.25-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,9 +35,9 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.9.5", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/theme": "^0.2.15", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -47,17 +47,17 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/jest": "^26.0.7", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/org/CHANGELOG.md b/plugins/org/CHANGELOG.md index 73129feed6..f21231dc81 100644 --- a/plugins/org/CHANGELOG.md +++ b/plugins/org/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-org +## 0.5.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## 0.5.7-next.1 + +### Patch Changes + +- 1e984b11fc: Render namespaces for teams with subtitles in `MyGroupsSidebarItem` +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## 0.5.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + ## 0.5.6 ### Patch Changes diff --git a/plugins/org/package.json b/plugins/org/package.json index 2b62e81683..9bc58b26bf 100644 --- a/plugins/org/package.json +++ b/plugins/org/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-org", "description": "A Backstage plugin that helps you create entity pages for your organization", - "version": "0.5.6", + "version": "0.5.7-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -29,11 +29,11 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", - "@backstage/core-components": "^0.9.5", + "@backstage/catalog-model": "^1.1.0-next.2", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/plugin-catalog-react": "^1.1.1", - "@backstage/theme": "^0.2.15", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -48,18 +48,18 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/catalog-client": "^1.0.3", - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/catalog-client": "^1.0.4-next.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/jest": "^26.0.7", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.stories.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.stories.tsx index c07815f39e..fc050feb2a 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.stories.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.stories.tsx @@ -110,14 +110,14 @@ const monochromeTheme = (outer: BackstageTheme) => ...outer, defaultPageTheme: 'home', pageTheme: { - home: genPageTheme(['#444'], shapes.wave2), - documentation: genPageTheme(['#474747'], shapes.wave2), - tool: genPageTheme(['#222'], shapes.wave2), - service: genPageTheme(['#aaa'], shapes.wave2), - website: genPageTheme(['#0e0e0e'], shapes.wave2), - library: genPageTheme(['#9d9d9d'], shapes.wave2), - other: genPageTheme(['#aaa'], shapes.wave2), - app: genPageTheme(['#666'], shapes.wave2), + home: genPageTheme({ colors: ['#444'], shape: shapes.wave2 }), + documentation: genPageTheme({ colors: ['#474747'], shape: shapes.wave2 }), + tool: genPageTheme({ colors: ['#222'], shape: shapes.wave2 }), + service: genPageTheme({ colors: ['#aaa'], shape: shapes.wave2 }), + website: genPageTheme({ colors: ['#0e0e0e'], shape: shapes.wave2 }), + library: genPageTheme({ colors: ['#9d9d9d'], shape: shapes.wave2 }), + other: genPageTheme({ colors: ['#aaa'], shape: shapes.wave2 }), + app: genPageTheme({ colors: ['#666'], shape: shapes.wave2 }), }, }); diff --git a/plugins/org/src/components/MyGroupsSidebarItem/MyGroupsSidebarItem.tsx b/plugins/org/src/components/MyGroupsSidebarItem/MyGroupsSidebarItem.tsx index fa8f8405ff..f3e3a6bd9a 100644 --- a/plugins/org/src/components/MyGroupsSidebarItem/MyGroupsSidebarItem.tsx +++ b/plugins/org/src/components/MyGroupsSidebarItem/MyGroupsSidebarItem.tsx @@ -15,7 +15,10 @@ */ import React from 'react'; -import { stringifyEntityRef } from '@backstage/catalog-model'; +import { + DEFAULT_NAMESPACE, + stringifyEntityRef, +} from '@backstage/catalog-model'; import { SidebarItem, SidebarSubmenu, @@ -32,7 +35,6 @@ import { catalogApiRef, CatalogApi, entityRouteRef, - humanizeEntityRef, } from '@backstage/plugin-catalog-react'; import { getCompoundEntityRef } from '@backstage/catalog-model'; @@ -94,9 +96,11 @@ export const MyGroupsSidebarItem = (props: { {groups?.map(function groupsMap(group) { return ( ; +// Warning: (ae-missing-release-tag) "PagerDutyAssignee" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type PagerDutyAssignee = { + id: string; + summary: string; + html_url: string; +}; + // Warning: (ae-missing-release-tag) "PagerDutyCard" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) export const PagerDutyCard: () => JSX.Element; +// Warning: (ae-missing-release-tag) "PagerDutyChangeEvent" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type PagerDutyChangeEvent = { + id: string; + integration: [ + { + service: PagerDutyService; + }, + ]; + source: string; + html_url: string; + links: [ + { + href: string; + text: string; + }, + ]; + summary: string; + timestamp: string; +}; + +// Warning: (ae-missing-release-tag) "PagerDutyChangeEventsResponse" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type PagerDutyChangeEventsResponse = { + change_events: PagerDutyChangeEvent[]; +}; + // Warning: (ae-missing-release-tag) "PagerDutyClient" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) export class PagerDutyClient implements PagerDutyApi { - // Warning: (ae-forgotten-export) The symbol "ClientApiConfig" needs to be exported by the entry point index.d.ts - constructor(config: ClientApiConfig); + constructor(config: PagerDutyClientApiConfig); // (undocumented) static fromConfig( configApi: ConfigApi, - discoveryApi: DiscoveryApi, - identityApi: IdentityApi, + { discoveryApi, fetchApi }: PagerDutyClientApiDependencies, ): PagerDutyClient; - // Warning: (ae-forgotten-export) The symbol "ChangeEvent" needs to be exported by the entry point index.d.ts - // // (undocumented) - getChangeEventsByServiceId(serviceId: string): Promise; - // Warning: (ae-forgotten-export) The symbol "Incident" needs to be exported by the entry point index.d.ts - // + getChangeEventsByServiceId( + serviceId: string, + ): Promise; // (undocumented) - getIncidentsByServiceId(serviceId: string): Promise; - // Warning: (ae-forgotten-export) The symbol "OnCall" needs to be exported by the entry point index.d.ts - // + getIncidentsByServiceId( + serviceId: string, + ): Promise; // (undocumented) - getOnCallByPolicyId(policyId: string): Promise; - // Warning: (ae-forgotten-export) The symbol "Service" needs to be exported by the entry point index.d.ts - // + getOnCallByPolicyId(policyId: string): Promise; // (undocumented) - getServiceByIntegrationKey(integrationKey: string): Promise; - // Warning: (ae-forgotten-export) The symbol "TriggerAlarmRequest" needs to be exported by the entry point index.d.ts - // + getServiceByEntity(entity: Entity): Promise; // (undocumented) - triggerAlarm(request: TriggerAlarmRequest): Promise; + triggerAlarm(request: PagerDutyTriggerAlarmRequest): Promise; } +// Warning: (ae-missing-release-tag) "PagerDutyClientApiConfig" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type PagerDutyClientApiConfig = PagerDutyClientApiDependencies & { + eventsBaseUrl?: string; +}; + +// Warning: (ae-missing-release-tag) "PagerDutyClientApiDependencies" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type PagerDutyClientApiDependencies = { + discoveryApi: DiscoveryApi; + fetchApi: FetchApi; +}; + +// Warning: (ae-missing-release-tag) "PagerDutyEntity" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type PagerDutyEntity = { + integrationKey?: string; + serviceId?: string; + name: string; +}; + +// Warning: (ae-missing-release-tag) "PagerDutyIncident" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type PagerDutyIncident = { + id: string; + title: string; + status: string; + html_url: string; + assignments: [ + { + assignee: PagerDutyAssignee; + }, + ]; + serviceId: string; + created_at: string; +}; + +// Warning: (ae-missing-release-tag) "PagerDutyIncidentsResponse" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type PagerDutyIncidentsResponse = { + incidents: PagerDutyIncident[]; +}; + +// Warning: (ae-missing-release-tag) "PagerDutyOnCall" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type PagerDutyOnCall = { + user: PagerDutyUser; + escalation_level: number; +}; + +// Warning: (ae-missing-release-tag) "PagerDutyOnCallsResponse" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type PagerDutyOnCallsResponse = { + oncalls: PagerDutyOnCall[]; +}; + // Warning: (ae-missing-release-tag) "pagerDutyPlugin" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -77,6 +170,49 @@ const pagerDutyPlugin: BackstagePlugin<{}, {}>; export { pagerDutyPlugin }; export { pagerDutyPlugin as plugin }; +// Warning: (ae-missing-release-tag) "PagerDutyService" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type PagerDutyService = { + id: string; + name: string; + html_url: string; + integrationKey: string; + escalation_policy: { + id: string; + user: PagerDutyUser; + html_url: string; + }; +}; + +// Warning: (ae-missing-release-tag) "PagerDutyServiceResponse" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type PagerDutyServiceResponse = { + service: PagerDutyService; +}; + +// Warning: (ae-missing-release-tag) "PagerDutyTriggerAlarmRequest" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type PagerDutyTriggerAlarmRequest = { + integrationKey: string; + source: string; + description: string; + userName: string; +}; + +// Warning: (ae-missing-release-tag) "PagerDutyUser" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type PagerDutyUser = { + id: string; + summary: string; + email: string; + html_url: string; + name: string; +}; + // Warning: (ae-forgotten-export) The symbol "TriggerButtonProps" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "TriggerButton" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // diff --git a/plugins/pagerduty/package.json b/plugins/pagerduty/package.json index 73a92ed5f7..b638bbd573 100644 --- a/plugins/pagerduty/package.json +++ b/plugins/pagerduty/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-pagerduty", "description": "A Backstage plugin that integrates towards PagerDuty", - "version": "0.4.0", + "version": "0.5.0-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,11 +34,12 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", - "@backstage/core-components": "^0.9.5", + "@backstage/catalog-model": "^1.1.0-next.2", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/plugin-catalog-react": "^1.1.1", - "@backstage/theme": "^0.2.15", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -52,17 +53,17 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/jest": "^26.0.7", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/pagerduty/src/api/client.test.ts b/plugins/pagerduty/src/api/client.test.ts new file mode 100644 index 0000000000..a32a533e68 --- /dev/null +++ b/plugins/pagerduty/src/api/client.test.ts @@ -0,0 +1,376 @@ +/* + * 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 { MockFetchApi } from '@backstage/test-utils'; +import { DiscoveryApi } from '@backstage/core-plugin-api'; +import { PagerDutyClient, UnauthorizedError } from './client'; +import { PagerDutyService, PagerDutyUser } from '../components/types'; +import { NotFoundError } from '@backstage/errors'; +import { Entity } from '@backstage/catalog-model'; + +const mockFetch = jest.fn().mockName('fetch'); +const mockDiscoveryApi: jest.Mocked = { + getBaseUrl: jest + .fn() + .mockName('discoveryApi') + .mockResolvedValue('http://localhost:7007/proxy'), +}; +const mockFetchApi: MockFetchApi = new MockFetchApi({ + baseImplementation: mockFetch, +}); + +let client: PagerDutyClient; +let entity: Entity; + +const user: PagerDutyUser = { + name: 'person1', + id: 'p1', + summary: 'person1', + email: 'person1@example.com', + html_url: 'http://a.com/id1', +}; + +const service: PagerDutyService = { + id: 'def456', + name: 'pagerduty-name', + html_url: 'www.example.com', + escalation_policy: { + id: 'def', + user: user, + html_url: 'http://a.com/id1', + }, + integrationKey: 'abc123', +}; + +const requestHeaders = { + headers: { + Accept: 'application/vnd.pagerduty+json;version=2', + 'Content-Type': 'application/json', + }, + method: 'GET', +}; + +describe('PagerDutyClient', () => { + beforeEach(() => { + mockFetch.mockReset(); + + client = new PagerDutyClient({ + eventsBaseUrl: 'https://events.pagerduty.com/v2', + discoveryApi: mockDiscoveryApi, + fetchApi: mockFetchApi, + }); + }); + + describe('getServiceByEntity', () => { + describe('when provided entity has an integrationKey value', () => { + beforeEach(() => { + entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'pagerduty-test', + annotations: { + 'pagerduty.com/integration-key': 'abc123', + }, + }, + }; + }); + + it('queries proxy path by integration id', async () => { + mockFetch.mockResolvedValueOnce({ + status: 200, + ok: true, + json: () => Promise.resolve({ services: [service] }), + }); + + expect(await client.getServiceByEntity(entity)).toEqual({ + service, + }); + expect(mockFetch).toHaveBeenCalledWith( + 'http://localhost:7007/proxy/pagerduty/services?time_zone=UTC&include[]=integrations&include[]=escalation_policies&query=abc123', + requestHeaders, + ); + }); + + describe('on 401 response code', () => { + beforeEach(() => { + mockFetch.mockResolvedValueOnce({ + status: 401, + ok: false, + json: () => Promise.resolve({}), + }); + }); + + it('throws UnauthorizedError', async () => { + await expect(client.getServiceByEntity(entity)).rejects.toThrowError( + UnauthorizedError, + ); + }); + }); + + describe('on 404 response code', () => { + beforeEach(() => { + mockFetch.mockResolvedValueOnce({ + status: 404, + ok: false, + json: () => Promise.resolve({}), + }); + }); + + it('throws NotFoundError', async () => { + await expect(client.getServiceByEntity(entity)).rejects.toThrowError( + NotFoundError, + ); + }); + }); + + describe('on other non-ok response', () => { + beforeEach(() => { + mockFetch.mockResolvedValueOnce({ + status: 500, + ok: false, + json: () => + Promise.resolve({ + errors: ['Not valid request', 'internal error occurred'], + }), + }); + }); + + it('throws NotFoundError', async () => { + await expect(client.getServiceByEntity(entity)).rejects.toThrowError( + 'Request failed with 500, Not valid request internal error occurred', + ); + }); + }); + + describe('when services response is empty', () => { + beforeEach(() => { + mockFetch.mockResolvedValueOnce({ + status: 200, + ok: true, + json: () => Promise.resolve({ services: [] }), + }); + }); + + it('throws NotFoundError', async () => { + await expect(client.getServiceByEntity(entity)).rejects.toThrowError( + NotFoundError, + ); + }); + }); + }); + + describe('when provided entity has a serviceId value', () => { + beforeEach(() => { + entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'pagerduty-test', + annotations: { + 'pagerduty.com/service-id': 'def456', + }, + }, + }; + }); + + it('queries proxy path by integration id', async () => { + mockFetch.mockResolvedValueOnce({ + status: 200, + ok: true, + json: () => Promise.resolve({ service }), + }); + + expect(await client.getServiceByEntity(entity)).toEqual({ + service, + }); + expect(mockFetch).toHaveBeenCalledWith( + 'http://localhost:7007/proxy/pagerduty/services/def456?time_zone=UTC&include[]=integrations&include[]=escalation_policies', + requestHeaders, + ); + }); + + describe('on 401 response code', () => { + beforeEach(() => { + mockFetch.mockResolvedValueOnce({ + status: 401, + ok: false, + json: () => Promise.resolve({}), + }); + }); + + it('throws UnauthorizedError', async () => { + await expect(client.getServiceByEntity(entity)).rejects.toThrowError( + UnauthorizedError, + ); + }); + }); + + describe('on 404 response code', () => { + beforeEach(() => { + mockFetch.mockResolvedValueOnce({ + status: 404, + ok: false, + json: () => Promise.resolve({}), + }); + }); + + it('throws NotFoundError', async () => { + await expect(client.getServiceByEntity(entity)).rejects.toThrowError( + NotFoundError, + ); + }); + }); + + describe('on other non-ok response', () => { + beforeEach(() => { + mockFetch.mockResolvedValueOnce({ + status: 500, + ok: false, + json: () => + Promise.resolve({ + errors: ['Not valid request', 'internal error occurred'], + }), + }); + }); + + it('throws NotFoundError', async () => { + await expect(client.getServiceByEntity(entity)).rejects.toThrowError( + 'Request failed with 500, Not valid request internal error occurred', + ); + }); + }); + }); + + describe('when provided entity has both integrationKey and serviceId', () => { + beforeEach(() => { + entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'pagerduty-test', + annotations: { + 'pagerduty.com/integration-key': 'abc123', + 'pagerduty.com/service-id': 'def456', + }, + }, + }; + }); + + it('queries proxy path by integration id', async () => { + mockFetch.mockResolvedValueOnce({ + status: 200, + ok: true, + json: () => Promise.resolve({ services: [service] }), + }); + + expect(await client.getServiceByEntity(entity)).toEqual({ + service, + }); + expect(mockFetch).toHaveBeenCalledWith( + 'http://localhost:7007/proxy/pagerduty/services?time_zone=UTC&include[]=integrations&include[]=escalation_policies&query=abc123', + requestHeaders, + ); + }); + + describe('on 401 response code', () => { + beforeEach(() => { + mockFetch.mockResolvedValueOnce({ + status: 401, + ok: false, + json: () => Promise.resolve({}), + }); + }); + + it('throws UnauthorizedError', async () => { + await expect(client.getServiceByEntity(entity)).rejects.toThrowError( + UnauthorizedError, + ); + }); + }); + + describe('on 404 response code', () => { + beforeEach(() => { + mockFetch.mockResolvedValueOnce({ + status: 404, + ok: false, + json: () => Promise.resolve({}), + }); + }); + + it('throws NotFoundError', async () => { + await expect(client.getServiceByEntity(entity)).rejects.toThrowError( + NotFoundError, + ); + }); + }); + + describe('on other non-ok response', () => { + beforeEach(() => { + mockFetch.mockResolvedValueOnce({ + status: 500, + ok: false, + json: () => + Promise.resolve({ + errors: ['Not valid request', 'internal error occurred'], + }), + }); + }); + + it('throws NotFoundError', async () => { + await expect(client.getServiceByEntity(entity)).rejects.toThrowError( + 'Request failed with 500, Not valid request internal error occurred', + ); + }); + }); + + describe('when services response is empty', () => { + beforeEach(() => { + mockFetch.mockResolvedValueOnce({ + status: 200, + ok: true, + json: () => Promise.resolve({ services: [] }), + }); + }); + + it('throws NotFoundError', async () => { + await expect(client.getServiceByEntity(entity)).rejects.toThrowError( + NotFoundError, + ); + }); + }); + }); + + describe('when provided entity has no integrationKey or serviceId values', () => { + beforeEach(() => { + entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'pagerduty-test', + annotations: {}, + }, + }; + }); + + it('throws NotFoundError', async () => { + await expect(client.getServiceByEntity(entity)).rejects.toThrowError( + NotFoundError, + ); + expect(mockFetch).not.toHaveBeenCalled(); + }); + }); + }); +}); diff --git a/plugins/pagerduty/src/api/client.ts b/plugins/pagerduty/src/api/client.ts index 43c6165c91..69a702f66d 100644 --- a/plugins/pagerduty/src/api/client.ts +++ b/plugins/pagerduty/src/api/client.ts @@ -14,23 +14,22 @@ * limitations under the License. */ -import { Service, Incident, ChangeEvent, OnCall } from '../components/types'; import { PagerDutyApi, - TriggerAlarmRequest, - ServicesResponse, - IncidentsResponse, - OnCallsResponse, - ClientApiConfig, + PagerDutyTriggerAlarmRequest, + PagerDutyServicesResponse, + PagerDutyServiceResponse, + PagerDutyIncidentsResponse, + PagerDutyOnCallsResponse, + PagerDutyClientApiDependencies, + PagerDutyClientApiConfig, RequestOptions, - ChangeEventsResponse, + PagerDutyChangeEventsResponse, } from './types'; -import { - createApiRef, - DiscoveryApi, - ConfigApi, - IdentityApi, -} from '@backstage/core-plugin-api'; +import { createApiRef, ConfigApi } from '@backstage/core-plugin-api'; +import { NotFoundError } from '@backstage/errors'; +import { Entity } from '@backstage/catalog-model'; +import { getPagerDutyEntity } from '../components/pagerDutyEntity'; export class UnauthorizedError extends Error {} @@ -38,65 +37,89 @@ export const pagerDutyApiRef = createApiRef({ id: 'plugin.pagerduty.api', }); +const commonGetServiceParams = + 'time_zone=UTC&include[]=integrations&include[]=escalation_policies'; + export class PagerDutyClient implements PagerDutyApi { static fromConfig( configApi: ConfigApi, - discoveryApi: DiscoveryApi, - identityApi: IdentityApi, + { discoveryApi, fetchApi }: PagerDutyClientApiDependencies, ) { const eventsBaseUrl: string = configApi.getOptionalString('pagerDuty.eventsBaseUrl') ?? 'https://events.pagerduty.com/v2'; + return new PagerDutyClient({ eventsBaseUrl, discoveryApi, - identityApi, + fetchApi, }); } - constructor(private readonly config: ClientApiConfig) {} + constructor(private readonly config: PagerDutyClientApiConfig) {} - async getServiceByIntegrationKey(integrationKey: string): Promise { - const params = `time_zone=UTC&include[]=integrations&include[]=escalation_policies&query=${integrationKey}`; - const url = `${await this.config.discoveryApi.getBaseUrl( - 'proxy', - )}/pagerduty/services?${params}`; - const { services } = await this.getByUrl(url); + async getServiceByEntity(entity: Entity): Promise { + const { integrationKey, serviceId } = getPagerDutyEntity(entity); - return services; + let response: PagerDutyServiceResponse; + let url: string; + + if (integrationKey) { + url = `${await this.config.discoveryApi.getBaseUrl( + 'proxy', + )}/pagerduty/services?${commonGetServiceParams}&query=${integrationKey}`; + const { services } = await this.getByUrl(url); + const service = services[0]; + + if (!service) throw new NotFoundError(); + + response = { service }; + } else if (serviceId) { + url = `${await this.config.discoveryApi.getBaseUrl( + 'proxy', + )}/pagerduty/services/${serviceId}?${commonGetServiceParams}`; + + response = await this.getByUrl(url); + } else { + throw new NotFoundError(); + } + + return response; } - async getIncidentsByServiceId(serviceId: string): Promise { + async getIncidentsByServiceId( + serviceId: string, + ): Promise { const params = `time_zone=UTC&sort_by=created_at&statuses[]=triggered&statuses[]=acknowledged&service_ids[]=${serviceId}`; const url = `${await this.config.discoveryApi.getBaseUrl( 'proxy', )}/pagerduty/incidents?${params}`; - const { incidents } = await this.getByUrl(url); - return incidents; + return await this.getByUrl(url); } - async getChangeEventsByServiceId(serviceId: string): Promise { + async getChangeEventsByServiceId( + serviceId: string, + ): Promise { const params = `limit=5&time_zone=UTC&sort_by=timestamp`; const url = `${await this.config.discoveryApi.getBaseUrl( 'proxy', )}/pagerduty/services/${serviceId}/change_events?${params}`; - const { change_events } = await this.getByUrl(url); - - return change_events; + return await this.getByUrl(url); } - async getOnCallByPolicyId(policyId: string): Promise { + async getOnCallByPolicyId( + policyId: string, + ): Promise { const params = `time_zone=UTC&include[]=users&escalation_policy_ids[]=${policyId}`; const url = `${await this.config.discoveryApi.getBaseUrl( 'proxy', )}/pagerduty/oncalls?${params}`; - const { oncalls } = await this.getByUrl(url); - return oncalls; + return await this.getByUrl(url); } - triggerAlarm(request: TriggerAlarmRequest): Promise { + triggerAlarm(request: PagerDutyTriggerAlarmRequest): Promise { const { integrationKey, source, description, userName } = request; const body = JSON.stringify({ @@ -130,13 +153,11 @@ export class PagerDutyClient implements PagerDutyApi { } private async getByUrl(url: string): Promise { - const { token: idToken } = await this.config.identityApi.getCredentials(); const options = { method: 'GET', headers: { Accept: 'application/vnd.pagerduty+json;version=2', 'Content-Type': 'application/json', - ...(idToken && { Authorization: `Bearer ${idToken}` }), }, }; const response = await this.request(url, options); @@ -147,10 +168,15 @@ export class PagerDutyClient implements PagerDutyApi { url: string, options: RequestOptions, ): Promise { - const response = await fetch(url, options); + const response = await this.config.fetchApi.fetch(url, options); if (response.status === 401) { throw new UnauthorizedError(); } + + if (response.status === 404) { + throw new NotFoundError(); + } + if (!response.ok) { const payload = await response.json(); const errors = payload.errors.map((error: string) => error).join(' '); diff --git a/plugins/pagerduty/src/api/index.ts b/plugins/pagerduty/src/api/index.ts index 015204b1e8..9a0c08973d 100644 --- a/plugins/pagerduty/src/api/index.ts +++ b/plugins/pagerduty/src/api/index.ts @@ -15,4 +15,12 @@ */ export { PagerDutyClient, pagerDutyApiRef, UnauthorizedError } from './client'; -export type { PagerDutyApi } from './types'; +export type { + PagerDutyServiceResponse, + PagerDutyIncidentsResponse, + PagerDutyChangeEventsResponse, + PagerDutyOnCallsResponse, + PagerDutyTriggerAlarmRequest, + PagerDutyClientApiDependencies, + PagerDutyClientApiConfig, +} from './types'; diff --git a/plugins/pagerduty/src/api/types.ts b/plugins/pagerduty/src/api/types.ts index 8acd24f033..786b0bdffd 100644 --- a/plugins/pagerduty/src/api/types.ts +++ b/plugins/pagerduty/src/api/types.ts @@ -14,10 +14,36 @@ * limitations under the License. */ -import { Incident, ChangeEvent, OnCall, Service } from '../components/types'; -import { DiscoveryApi, IdentityApi } from '@backstage/core-plugin-api'; +import { + PagerDutyIncident, + PagerDutyChangeEvent, + PagerDutyOnCall, + PagerDutyService, +} from '../components/types'; +import { DiscoveryApi, FetchApi } from '@backstage/core-plugin-api'; +import { Entity } from '@backstage/catalog-model'; -export type TriggerAlarmRequest = { +export type PagerDutyServicesResponse = { + services: PagerDutyService[]; +}; + +export type PagerDutyServiceResponse = { + service: PagerDutyService; +}; + +export type PagerDutyIncidentsResponse = { + incidents: PagerDutyIncident[]; +}; + +export type PagerDutyChangeEventsResponse = { + change_events: PagerDutyChangeEvent[]; +}; + +export type PagerDutyOnCallsResponse = { + oncalls: PagerDutyOnCall[]; +}; + +export type PagerDutyTriggerAlarmRequest = { integrationKey: string; source: string; description: string; @@ -26,55 +52,46 @@ export type TriggerAlarmRequest = { export interface PagerDutyApi { /** - * Fetches a list of services, filtered by the provided integration key. + * Fetches the service for the provided Entity. * */ - getServiceByIntegrationKey(integrationKey: string): Promise; + getServiceByEntity(entity: Entity): Promise; /** * Fetches a list of incidents a provided service has. * */ - getIncidentsByServiceId(serviceId: string): Promise; + getIncidentsByServiceId( + serviceId: string, + ): Promise; /** * Fetches a list of change events a provided service has. * */ - getChangeEventsByServiceId(serviceId: string): Promise; + getChangeEventsByServiceId( + serviceId: string, + ): Promise; /** * Fetches the list of users in an escalation policy. * */ - getOnCallByPolicyId(policyId: string): Promise; + getOnCallByPolicyId(policyId: string): Promise; /** * Triggers an incident to whoever is on-call. */ - triggerAlarm(request: TriggerAlarmRequest): Promise; + triggerAlarm(request: PagerDutyTriggerAlarmRequest): Promise; } -export type ServicesResponse = { - services: Service[]; -}; - -export type IncidentsResponse = { - incidents: Incident[]; -}; - -export type ChangeEventsResponse = { - change_events: ChangeEvent[]; -}; - -export type OnCallsResponse = { - oncalls: OnCall[]; -}; - -export type ClientApiConfig = { - eventsBaseUrl?: string; +export type PagerDutyClientApiDependencies = { discoveryApi: DiscoveryApi; - identityApi: IdentityApi; + fetchApi: FetchApi; +}; + +export type PagerDutyClientApiConfig = PagerDutyClientApiDependencies & { + eventsBaseUrl?: string; }; export type RequestOptions = { diff --git a/plugins/pagerduty/src/components/ChangeEvents/ChangeEventListItem.tsx b/plugins/pagerduty/src/components/ChangeEvents/ChangeEventListItem.tsx index 4912277cee..7b531bf1de 100644 --- a/plugins/pagerduty/src/components/ChangeEvents/ChangeEventListItem.tsx +++ b/plugins/pagerduty/src/components/ChangeEvents/ChangeEventListItem.tsx @@ -26,7 +26,7 @@ import { Typography, } from '@material-ui/core'; import { DateTime, Duration } from 'luxon'; -import { ChangeEvent } from '../types'; +import { PagerDutyChangeEvent } from '../types'; import OpenInBrowserIcon from '@material-ui/icons/OpenInBrowser'; import { BackstageTheme } from '@backstage/theme'; @@ -44,7 +44,7 @@ const useStyles = makeStyles({ }); type Props = { - changeEvent: ChangeEvent; + changeEvent: PagerDutyChangeEvent; }; export const ChangeEventListItem = ({ changeEvent }: Props) => { @@ -54,7 +54,7 @@ export const ChangeEventListItem = ({ changeEvent }: Props) => { const changedAt = DateTime.local() .minus(Duration.fromMillis(duration)) .toRelative({ locale: 'en' }); - let externalLinkElem = null; + let externalLinkElem: JSX.Element | undefined; if (changeEvent.links.length > 0) { const text: string = changeEvent.links[0].text; externalLinkElem = ( diff --git a/plugins/pagerduty/src/components/ChangeEvents/ChangeEvents.test.tsx b/plugins/pagerduty/src/components/ChangeEvents/ChangeEvents.test.tsx index fca2422198..a518e0caea 100644 --- a/plugins/pagerduty/src/components/ChangeEvents/ChangeEvents.test.tsx +++ b/plugins/pagerduty/src/components/ChangeEvents/ChangeEvents.test.tsx @@ -15,7 +15,7 @@ */ import React from 'react'; import { render, waitFor } from '@testing-library/react'; -import { ChangeEvent } from '../types'; +import { PagerDutyChangeEvent } from '../types'; import { TestApiRegistry, wrapInTestApp } from '@backstage/test-utils'; import { pagerDutyApiRef } from '../../api'; import { ApiProvider } from '@backstage/core-app-api'; @@ -30,7 +30,7 @@ describe('Incidents', () => { it('Renders an empty state when there are no change events', async () => { mockPagerDutyApi.getChangeEventsByServiceId = jest .fn() - .mockImplementationOnce(async () => []); + .mockImplementationOnce(async () => ({ change_events: [] })); const { getByText, queryByTestId } = render( wrapInTestApp( @@ -46,37 +46,36 @@ describe('Incidents', () => { it('Renders all change events', async () => { mockPagerDutyApi.getChangeEventsByServiceId = jest .fn() - .mockImplementationOnce( - async () => - [ - { - id: 'id1', - source: 'changeSource1', - html_url: 'www.pdlink.com', - links: [ - { - href: 'www.externalLink1.com', - text: 'link1', - }, - ], - summary: 'summary of event', - timestamp: '2020-07-17T08:42:58.315+0000', - }, - { - id: 'id2', - source: 'changeSource1', - html_url: 'www.pdlink.com/link', - links: [ - { - href: 'www.externalLink1.com', - text: 'link1', - }, - ], - summary: 'sum of EVENT', - timestamp: '2020-07-18T08:42:58.315+0000', - }, - ] as ChangeEvent[], - ); + .mockImplementationOnce(async () => ({ + change_events: [ + { + id: 'id1', + source: 'changeSource1', + html_url: 'www.pdlink.com', + links: [ + { + href: 'www.externalLink1.com', + text: 'link1', + }, + ], + summary: 'summary of event', + timestamp: '2020-07-17T08:42:58.315+0000', + }, + { + id: 'id2', + source: 'changeSource1', + html_url: 'www.pdlink.com/link', + links: [ + { + href: 'www.externalLink1.com', + text: 'link1', + }, + ], + summary: 'sum of EVENT', + timestamp: '2020-07-18T08:42:58.315+0000', + }, + ] as PagerDutyChangeEvent[], + })); const { getByText, getAllByTitle, queryByTestId } = render( wrapInTestApp( @@ -95,36 +94,35 @@ describe('Incidents', () => { it('Does not render a pagerduty link when html_url is not present in response', async () => { mockPagerDutyApi.getChangeEventsByServiceId = jest .fn() - .mockImplementationOnce( - async () => - [ - { - id: 'id1', - source: 'changeSource1', - links: [ - { - href: 'www.externalLink1.com', - text: 'link1', - }, - ], - summary: 'summary of event', - timestamp: '2020-07-17T08:42:58.315+0000', - }, - { - id: 'id2', - source: 'changeSource1', - html_url: 'www.pdlink.com/link', - links: [ - { - href: 'www.externalLink1.com', - text: 'link1', - }, - ], - summary: 'sum of EVENT', - timestamp: '2020-07-18T08:42:58.315+0000', - }, - ] as ChangeEvent[], - ); + .mockImplementationOnce(async () => ({ + change_events: [ + { + id: 'id1', + source: 'changeSource1', + links: [ + { + href: 'www.externalLink1.com', + text: 'link1', + }, + ], + summary: 'summary of event', + timestamp: '2020-07-17T08:42:58.315+0000', + }, + { + id: 'id2', + source: 'changeSource1', + html_url: 'www.pdlink.com/link', + links: [ + { + href: 'www.externalLink1.com', + text: 'link1', + }, + ], + summary: 'sum of EVENT', + timestamp: '2020-07-18T08:42:58.315+0000', + }, + ] as PagerDutyChangeEvent[], + })); const { getByText, getAllByTitle, queryByTestId } = render( wrapInTestApp( diff --git a/plugins/pagerduty/src/components/ChangeEvents/ChangeEvents.tsx b/plugins/pagerduty/src/components/ChangeEvents/ChangeEvents.tsx index 58b4dd6acf..4b19257cdc 100644 --- a/plugins/pagerduty/src/components/ChangeEvents/ChangeEvents.tsx +++ b/plugins/pagerduty/src/components/ChangeEvents/ChangeEvents.tsx @@ -33,7 +33,10 @@ export const ChangeEvents = ({ serviceId, refreshEvents }: Props) => { const api = useApi(pagerDutyApiRef); const [{ value: changeEvents, loading, error }, getChangeEvents] = useAsyncFn( - async () => await api.getChangeEventsByServiceId(serviceId), + async () => { + const { change_events } = await api.getChangeEventsByServiceId(serviceId); + return change_events; + }, ); useEffect(() => { diff --git a/plugins/pagerduty/src/components/Errors/ServiceNotFoundError.tsx b/plugins/pagerduty/src/components/Errors/ServiceNotFoundError.tsx new file mode 100644 index 0000000000..d8b61ef7cd --- /dev/null +++ b/plugins/pagerduty/src/components/Errors/ServiceNotFoundError.tsx @@ -0,0 +1,35 @@ +/* + * 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 { Button } from '@material-ui/core'; +import { EmptyState } from '@backstage/core-components'; + +export const ServiceNotFoundError = () => ( + + Read More + + } + /> +); diff --git a/plugins/pagerduty/src/components/Errors/index.ts b/plugins/pagerduty/src/components/Errors/index.ts index df255749e0..6c35e0bfd1 100644 --- a/plugins/pagerduty/src/components/Errors/index.ts +++ b/plugins/pagerduty/src/components/Errors/index.ts @@ -15,3 +15,4 @@ */ export { MissingTokenError } from './MissingTokenError'; +export { ServiceNotFoundError } from './ServiceNotFoundError'; diff --git a/plugins/pagerduty/src/components/Escalation/Escalation.test.tsx b/plugins/pagerduty/src/components/Escalation/Escalation.test.tsx index 47f18002fe..97c02a37f3 100644 --- a/plugins/pagerduty/src/components/Escalation/Escalation.test.tsx +++ b/plugins/pagerduty/src/components/Escalation/Escalation.test.tsx @@ -17,7 +17,7 @@ import React from 'react'; import { render, waitFor } from '@testing-library/react'; import { EscalationPolicy } from './EscalationPolicy'; import { TestApiRegistry, wrapInTestApp } from '@backstage/test-utils'; -import { User } from '../types'; +import { PagerDutyUser } from '../types'; import { pagerDutyApiRef } from '../../api'; import { ApiProvider } from '@backstage/core-app-api'; @@ -30,7 +30,7 @@ describe('Escalation', () => { it('Handles an empty response', async () => { mockPagerDutyApi.getOnCallByPolicyId = jest .fn() - .mockImplementationOnce(async () => []); + .mockImplementationOnce(async () => ({ oncalls: [] })); const { getByText, queryByTestId } = render( wrapInTestApp( @@ -48,17 +48,19 @@ describe('Escalation', () => { it('Render a list of users', async () => { mockPagerDutyApi.getOnCallByPolicyId = jest .fn() - .mockImplementationOnce(async () => [ - { - user: { - name: 'person1', - id: 'p1', - summary: 'person1', - email: 'person1@example.com', - html_url: 'http://a.com/id1', - } as User, - }, - ]); + .mockImplementationOnce(async () => ({ + oncalls: [ + { + user: { + name: 'person1', + id: 'p1', + summary: 'person1', + email: 'person1@example.com', + html_url: 'http://a.com/id1', + } as PagerDutyUser, + }, + ], + })); const { getByText, queryByTestId } = render( wrapInTestApp( diff --git a/plugins/pagerduty/src/components/Escalation/EscalationPolicy.tsx b/plugins/pagerduty/src/components/Escalation/EscalationPolicy.tsx index 704887be58..8602733ee3 100644 --- a/plugins/pagerduty/src/components/Escalation/EscalationPolicy.tsx +++ b/plugins/pagerduty/src/components/Escalation/EscalationPolicy.tsx @@ -37,7 +37,7 @@ export const EscalationPolicy = ({ policyId }: Props) => { loading, error, } = useAsync(async () => { - const oncalls = await api.getOnCallByPolicyId(policyId); + const { oncalls } = await api.getOnCallByPolicyId(policyId); const usersItem = oncalls .sort((a, b) => a.escalation_level - b.escalation_level) .map(oncall => oncall.user); diff --git a/plugins/pagerduty/src/components/Escalation/EscalationUser.tsx b/plugins/pagerduty/src/components/Escalation/EscalationUser.tsx index a460906d22..d418ad02c0 100644 --- a/plugins/pagerduty/src/components/Escalation/EscalationUser.tsx +++ b/plugins/pagerduty/src/components/Escalation/EscalationUser.tsx @@ -28,7 +28,7 @@ import { import Avatar from '@material-ui/core/Avatar'; import EmailIcon from '@material-ui/icons/Email'; import OpenInBrowserIcon from '@material-ui/icons/OpenInBrowser'; -import { User } from '../types'; +import { PagerDutyUser } from '../types'; const useStyles = makeStyles({ listItemPrimary: { @@ -37,7 +37,7 @@ const useStyles = makeStyles({ }); type Props = { - user: User; + user: PagerDutyUser; }; export const EscalationUser = ({ user }: Props) => { diff --git a/plugins/pagerduty/src/components/Incident/IncidentListItem.tsx b/plugins/pagerduty/src/components/Incident/IncidentListItem.tsx index 807685a83e..5945c45e83 100644 --- a/plugins/pagerduty/src/components/Incident/IncidentListItem.tsx +++ b/plugins/pagerduty/src/components/Incident/IncidentListItem.tsx @@ -29,7 +29,7 @@ import { import Done from '@material-ui/icons/Done'; import Warning from '@material-ui/icons/Warning'; import { DateTime, Duration } from 'luxon'; -import { Incident } from '../types'; +import { PagerDutyIncident } from '../types'; import OpenInBrowserIcon from '@material-ui/icons/OpenInBrowser'; import { BackstageTheme } from '@backstage/theme'; @@ -61,7 +61,7 @@ const useStyles = makeStyles(theme => ({ })); type Props = { - incident: Incident; + incident: PagerDutyIncident; }; export const IncidentListItem = ({ incident }: Props) => { diff --git a/plugins/pagerduty/src/components/Incident/Incidents.test.tsx b/plugins/pagerduty/src/components/Incident/Incidents.test.tsx index 74e7d82e8b..a83874a995 100644 --- a/plugins/pagerduty/src/components/Incident/Incidents.test.tsx +++ b/plugins/pagerduty/src/components/Incident/Incidents.test.tsx @@ -18,7 +18,7 @@ import { render, waitFor } from '@testing-library/react'; import { Incidents } from './Incidents'; import { TestApiRegistry, wrapInTestApp } from '@backstage/test-utils'; import { pagerDutyApiRef } from '../../api'; -import { Incident } from '../types'; +import { PagerDutyIncident } from '../types'; import { ApiProvider } from '@backstage/core-app-api'; const mockPagerDutyApi = { @@ -30,7 +30,7 @@ describe('Incidents', () => { it('Renders an empty state when there are no incidents', async () => { mockPagerDutyApi.getIncidentsByServiceId = jest .fn() - .mockImplementationOnce(async () => []); + .mockImplementationOnce(async () => ({ incidents: [] })); const { getByText, queryByTestId } = render( wrapInTestApp( @@ -44,9 +44,10 @@ describe('Incidents', () => { }); it('Renders all incidents', async () => { - mockPagerDutyApi.getIncidentsByServiceId = jest.fn().mockImplementationOnce( - async () => - [ + mockPagerDutyApi.getIncidentsByServiceId = jest + .fn() + .mockImplementationOnce(async () => ({ + incidents: [ { id: 'id1', status: 'triggered', @@ -82,8 +83,8 @@ describe('Incidents', () => { html_url: 'http://a.com/id2', serviceId: 'sId2', }, - ] as Incident[], - ); + ] as PagerDutyIncident[], + })); const { getByText, getAllByTitle, queryByTestId } = render( wrapInTestApp( diff --git a/plugins/pagerduty/src/components/Incident/Incidents.tsx b/plugins/pagerduty/src/components/Incident/Incidents.tsx index 06dd50bdaa..2e0e201c79 100644 --- a/plugins/pagerduty/src/components/Incident/Incidents.tsx +++ b/plugins/pagerduty/src/components/Incident/Incidents.tsx @@ -34,7 +34,12 @@ export const Incidents = ({ serviceId, refreshIncidents }: Props) => { const api = useApi(pagerDutyApiRef); const [{ value: incidents, loading, error }, getIncidents] = useAsyncFn( - async () => await api.getIncidentsByServiceId(serviceId), + async () => { + const { incidents: foundIncidents } = await api.getIncidentsByServiceId( + serviceId, + ); + return foundIncidents; + }, ); useEffect(() => { diff --git a/plugins/pagerduty/src/components/PagerDutyCard/index.test.tsx b/plugins/pagerduty/src/components/PagerDutyCard/index.test.tsx index e0a857ccc7..85202a9cfc 100644 --- a/plugins/pagerduty/src/components/PagerDutyCard/index.test.tsx +++ b/plugins/pagerduty/src/components/PagerDutyCard/index.test.tsx @@ -15,26 +15,17 @@ */ import React from 'react'; import { render, waitFor, fireEvent, act } from '@testing-library/react'; -import { PagerDutyCard } from '../PagerDutyCard'; +import { PagerDutyCard, isPluginApplicableToEntity } from '../PagerDutyCard'; import { Entity } from '@backstage/catalog-model'; import { EntityProvider } from '@backstage/plugin-catalog-react'; +import { NotFoundError } from '@backstage/errors'; import { TestApiRegistry, wrapInTestApp } from '@backstage/test-utils'; import { pagerDutyApiRef, UnauthorizedError, PagerDutyClient } from '../../api'; -import { Service, User } from '../types'; +import { PagerDutyService, PagerDutyUser } from '../types'; import { alertApiRef } from '@backstage/core-plugin-api'; import { ApiProvider } from '@backstage/core-app-api'; -const mockPagerDutyApi: Partial = { - getServiceByIntegrationKey: async () => [], - getOnCallByPolicyId: async () => [], - getIncidentsByServiceId: async () => [], -}; - -const apis = TestApiRegistry.from( - [pagerDutyApiRef, mockPagerDutyApi], - [alertApiRef, {}], -); const entity: Entity = { apiVersion: 'backstage.io/v1alpha1', kind: 'Component', @@ -46,7 +37,39 @@ const entity: Entity = { }, }; -const user: User = { +const entityWithoutAnnotations: Entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'pagerduty-test', + annotations: {}, + }, +}; + +const entityWithServiceId: Entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'pagerduty-test', + annotations: { + 'pagerduty.com/service-id': 'def456', + }, + }, +}; + +const entityWithAllAnnotations: Entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'pagerduty-test', + annotations: { + 'pagerduty.com/integration-key': 'abc123', + 'pagerduty.com/service-id': 'def456', + }, + }, +}; + +const user: PagerDutyUser = { name: 'person1', id: 'p1', summary: 'person1', @@ -54,8 +77,8 @@ const user: User = { html_url: 'http://a.com/id1', }; -const service: Service = { - id: 'abc', +const service: PagerDutyService = { + id: 'def456', name: 'pagerduty-name', html_url: 'www.example.com', escalation_policy: { @@ -63,14 +86,51 @@ const service: Service = { user: user, html_url: 'http://a.com/id1', }, - integrationKey: 'abcd', + integrationKey: 'abc123', }; +const mockPagerDutyApi: Partial = { + getServiceByEntity: async () => ({ service }), + getOnCallByPolicyId: async () => ({ oncalls: [] }), + getIncidentsByServiceId: async () => ({ incidents: [] }), +}; + +const apis = TestApiRegistry.from( + [pagerDutyApiRef, mockPagerDutyApi], + [alertApiRef, {}], +); + +describe('isPluginApplicableToEntity', () => { + describe('when entity has no annotations', () => { + it('returns false', () => { + expect(isPluginApplicableToEntity(entityWithoutAnnotations)).toBe(false); + }); + }); + + describe('when entity has the pagerduty.com/integration-key annotation', () => { + it('returns true', () => { + expect(isPluginApplicableToEntity(entity)).toBe(true); + }); + }); + + describe('when entity has the pagerduty.com/service-id annotation', () => { + it('returns true', () => { + expect(isPluginApplicableToEntity(entityWithServiceId)).toBe(true); + }); + }); + + describe('when entity has all annotations', () => { + it('returns true', () => { + expect(isPluginApplicableToEntity(entityWithAllAnnotations)).toBe(true); + }); + }); +}); + describe('PageDutyCard', () => { it('Render pagerduty', async () => { - mockPagerDutyApi.getServiceByIntegrationKey = jest + mockPagerDutyApi.getServiceByEntity = jest .fn() - .mockImplementationOnce(async () => [service]); + .mockImplementationOnce(async () => ({ service })); const { getByText, queryByTestId } = render( wrapInTestApp( @@ -89,7 +149,7 @@ describe('PageDutyCard', () => { }); it('Handles custom error for missing token', async () => { - mockPagerDutyApi.getServiceByIntegrationKey = jest + mockPagerDutyApi.getServiceByEntity = jest .fn() .mockRejectedValueOnce(new UnauthorizedError()); @@ -106,8 +166,26 @@ describe('PageDutyCard', () => { expect(getByText('Missing or invalid PagerDuty Token')).toBeInTheDocument(); }); + it('Handles custom NotFoundError', async () => { + mockPagerDutyApi.getServiceByEntity = jest + .fn() + .mockRejectedValueOnce(new NotFoundError()); + + const { getByText, queryByTestId } = render( + wrapInTestApp( + + + + + , + ), + ); + await waitFor(() => !queryByTestId('progress')); + expect(getByText('PagerDuty Service Not Found')).toBeInTheDocument(); + }); + it('handles general error', async () => { - mockPagerDutyApi.getServiceByIntegrationKey = jest + mockPagerDutyApi.getServiceByEntity = jest .fn() .mockRejectedValueOnce(new Error('An error occurred')); const { getByText, queryByTestId } = render( @@ -127,10 +205,11 @@ describe('PageDutyCard', () => { ), ).toBeInTheDocument(); }); + it('opens the dialog when trigger button is clicked', async () => { - mockPagerDutyApi.getServiceByIntegrationKey = jest + mockPagerDutyApi.getServiceByEntity = jest .fn() - .mockImplementationOnce(async () => [service]); + .mockImplementationOnce(async () => ({ service })); const { getByText, queryByTestId, getByRole } = render( wrapInTestApp( @@ -150,4 +229,131 @@ describe('PageDutyCard', () => { }); expect(getByRole('dialog')).toBeInTheDocument(); }); + + describe('when entity has the pagerduty.com/service-id annotation', () => { + it('Renders PagerDuty service information', async () => { + mockPagerDutyApi.getServiceByEntity = jest + .fn() + .mockImplementationOnce(async () => ({ service })); + + const { getByText, queryByTestId } = render( + wrapInTestApp( + + + + + , + ), + ); + await waitFor(() => !queryByTestId('progress')); + expect(getByText('Service Directory')).toBeInTheDocument(); + expect(getByText('Create Incident')).toBeInTheDocument(); + expect(getByText('Nice! No incidents found!')).toBeInTheDocument(); + expect(getByText('Empty escalation policy')).toBeInTheDocument(); + }); + + it('Handles custom error for missing token', async () => { + mockPagerDutyApi.getServiceByEntity = jest + .fn() + .mockRejectedValueOnce(new UnauthorizedError()); + + const { getByText, queryByTestId } = render( + wrapInTestApp( + + + + + , + ), + ); + await waitFor(() => !queryByTestId('progress')); + expect( + getByText('Missing or invalid PagerDuty Token'), + ).toBeInTheDocument(); + }); + + it('Handles custom NotFoundError', async () => { + mockPagerDutyApi.getServiceByEntity = jest + .fn() + .mockRejectedValueOnce(new NotFoundError()); + + const { getByText, queryByTestId } = render( + wrapInTestApp( + + + + + , + ), + ); + await waitFor(() => !queryByTestId('progress')); + expect(getByText('PagerDuty Service Not Found')).toBeInTheDocument(); + }); + + it('handles general error', async () => { + mockPagerDutyApi.getServiceByEntity = jest + .fn() + .mockRejectedValueOnce(new Error('An error occurred')); + const { getByText, queryByTestId } = render( + wrapInTestApp( + + + + + , + ), + ); + await waitFor(() => !queryByTestId('progress')); + + expect( + getByText( + 'Error encountered while fetching information. An error occurred', + ), + ).toBeInTheDocument(); + }); + + it('disables the Create Incident button', async () => { + mockPagerDutyApi.getServiceByEntity = jest + .fn() + .mockImplementationOnce(async () => ({ service })); + + const { queryByTestId, getByTitle } = render( + wrapInTestApp( + + + + + , + ), + ); + await waitFor(() => !queryByTestId('progress')); + expect( + getByTitle('Must provide an integration-key to create incidents') + .className, + ).toMatch('disabled'); + }); + }); + + describe('when entity has all annotations', () => { + it('queries by integration key', async () => { + mockPagerDutyApi.getServiceByEntity = jest + .fn() + .mockImplementationOnce(async () => ({ service })); + + const { getByText, queryByTestId } = render( + wrapInTestApp( + + + + + , + ), + ); + await waitFor(() => !queryByTestId('progress')); + expect(getByText('Service Directory')).toBeInTheDocument(); + expect(getByText('Create Incident')).toBeInTheDocument(); + expect(getByText('Nice! No incidents found!')).toBeInTheDocument(); + expect(getByText('Empty escalation policy')).toBeInTheDocument(); + }); + }); }); diff --git a/plugins/pagerduty/src/components/PagerDutyCard/index.tsx b/plugins/pagerduty/src/components/PagerDutyCard/index.tsx index bbade09e51..e8ba2c522c 100644 --- a/plugins/pagerduty/src/components/PagerDutyCard/index.tsx +++ b/plugins/pagerduty/src/components/PagerDutyCard/index.tsx @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React, { useState, useCallback } from 'react'; +import React, { ReactNode, useState, useCallback } from 'react'; import { Entity } from '@backstage/catalog-model'; import { Card, CardHeader, Divider, CardContent } from '@material-ui/core'; import { Incidents } from '../Incident'; @@ -22,28 +22,39 @@ import useAsync from 'react-use/lib/useAsync'; import { Alert } from '@material-ui/lab'; import { pagerDutyApiRef, UnauthorizedError } from '../../api'; import AlarmAddIcon from '@material-ui/icons/AlarmAdd'; -import { MissingTokenError } from '../Errors/MissingTokenError'; +import { MissingTokenError, ServiceNotFoundError } from '../Errors'; import WebIcon from '@material-ui/icons/Web'; import DateRangeIcon from '@material-ui/icons/DateRange'; -import { usePagerdutyEntity } from '../../hooks'; -import { PAGERDUTY_INTEGRATION_KEY } from '../constants'; +import { PAGERDUTY_INTEGRATION_KEY, PAGERDUTY_SERVICE_ID } from '../constants'; import { TriggerDialog } from '../TriggerDialog'; import { ChangeEvents } from '../ChangeEvents'; import { useApi } from '@backstage/core-plugin-api'; +import { NotFoundError } from '@backstage/errors'; import { Progress, HeaderIconLinkRow, IconLinkVerticalProps, TabbedCard, CardTab, + InfoCard, } from '@backstage/core-components'; +import { useEntity } from '@backstage/plugin-catalog-react'; +import { getPagerDutyEntity } from '../pagerDutyEntity'; + +const BasicCard = ({ children }: { children: ReactNode }) => ( + {children} +); export const isPluginApplicableToEntity = (entity: Entity) => - Boolean(entity.metadata.annotations?.[PAGERDUTY_INTEGRATION_KEY]); + Boolean( + entity.metadata.annotations?.[PAGERDUTY_INTEGRATION_KEY] || + entity.metadata.annotations?.[PAGERDUTY_SERVICE_ID], + ); export const PagerDutyCard = () => { - const { integrationKey } = usePagerdutyEntity(); + const { entity } = useEntity(); + const pagerDutyEntity = getPagerDutyEntity(entity); const api = useApi(pagerDutyApiRef); const [refreshIncidents, setRefreshIncidents] = useState(false); const [refreshChangeEvents, setRefreshChangeEvents] = @@ -67,33 +78,44 @@ export const PagerDutyCard = () => { loading, error, } = useAsync(async () => { - const services = await api.getServiceByIntegrationKey( - integrationKey as string, - ); + const { service: foundService } = await api.getServiceByEntity(entity); return { - id: services[0].id, - name: services[0].name, - url: services[0].html_url, - policyId: services[0].escalation_policy.id, - policyLink: services[0].escalation_policy.html_url, + id: foundService.id, + name: foundService.name, + url: foundService.html_url, + policyId: foundService.escalation_policy.id, + policyLink: foundService.escalation_policy.html_url, }; }); - if (error instanceof UnauthorizedError) { - return ; - } - if (error) { - return ( - - Error encountered while fetching information. {error.message} - - ); + let errorNode: ReactNode; + + switch (error.constructor) { + case UnauthorizedError: + errorNode = ; + break; + case NotFoundError: + errorNode = ; + break; + default: + errorNode = ( + + Error encountered while fetching information. {error.message} + + ); + } + + return {errorNode}; } if (loading) { - return ; + return ( + + + + ); } const serviceLink: IconLinkVerticalProps = { @@ -102,11 +124,21 @@ export const PagerDutyCard = () => { icon: , }; + /** + * In order to create incidents using the REST API, a valid user email address must be present. + * There is no guarantee the current user entity has a valid email association, so instead just + * only allow triggering incidents when an integration key is present. + */ + const createIncidentDisabled = !pagerDutyEntity.integrationKey; const triggerLink: IconLinkVerticalProps = { label: 'Create Incident', onClick: showDialog, icon: , color: 'secondary', + disabled: createIncidentDisabled, + title: createIncidentDisabled + ? 'Must provide an integration-key to create incidents' + : '', }; const escalationPolicyLink: IconLinkVerticalProps = { @@ -145,12 +177,14 @@ export const PagerDutyCard = () => { - + {!createIncidentDisabled && ( + + )} ); }; diff --git a/plugins/pagerduty/src/components/constants.ts b/plugins/pagerduty/src/components/constants.ts index bfe1aea298..01308590f1 100644 --- a/plugins/pagerduty/src/components/constants.ts +++ b/plugins/pagerduty/src/components/constants.ts @@ -14,3 +14,4 @@ * limitations under the License. */ export const PAGERDUTY_INTEGRATION_KEY = 'pagerduty.com/integration-key'; +export const PAGERDUTY_SERVICE_ID = 'pagerduty.com/service-id'; diff --git a/plugins/pagerduty/src/components/index.ts b/plugins/pagerduty/src/components/index.ts new file mode 100644 index 0000000000..17bb2c03dc --- /dev/null +++ b/plugins/pagerduty/src/components/index.ts @@ -0,0 +1,32 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export type { + PagerDutyChangeEvent, + PagerDutyIncident, + PagerDutyService, + PagerDutyOnCall, + PagerDutyAssignee, + PagerDutyUser, +} from './types'; + +export { + isPluginApplicableToEntity, + isPluginApplicableToEntity as isPagerDutyAvailable, + PagerDutyCard, +} from './PagerDutyCard'; + +export { TriggerButton } from './TriggerButton'; diff --git a/plugins/pagerduty/src/components/pagerDutyEntity.test.ts b/plugins/pagerduty/src/components/pagerDutyEntity.test.ts new file mode 100644 index 0000000000..cf551d3d6e --- /dev/null +++ b/plugins/pagerduty/src/components/pagerDutyEntity.test.ts @@ -0,0 +1,98 @@ +/* + * 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 } from '@backstage/catalog-model'; +import { getPagerDutyEntity } from './pagerDutyEntity'; + +const entity: Entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'pagerduty-test', + annotations: { + 'pagerduty.com/integration-key': 'abc123', + }, + }, +}; + +const entityWithoutAnnotations: Entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'pagerduty-test', + annotations: {}, + }, +}; + +const entityWithServiceId: Entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'pagerduty-test', + annotations: { + 'pagerduty.com/service-id': 'def456', + }, + }, +}; + +const entityWithAllAnnotations: Entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'pagerduty-test', + annotations: { + 'pagerduty.com/integration-key': 'abc123', + 'pagerduty.com/service-id': 'def456', + }, + }, +}; + +describe('getPagerDutyEntity', () => { + describe('when entity has no annotations', () => { + it('returns a PagerDutyEntity', () => { + expect(getPagerDutyEntity(entityWithoutAnnotations)).toEqual({ + name: 'pagerduty-test', + }); + }); + }); + + describe('when entity has integration key annotation', () => { + it('returns a PagerDutyEntity', () => { + expect(getPagerDutyEntity(entity)).toEqual({ + name: 'pagerduty-test', + integrationKey: 'abc123', + }); + }); + }); + + describe('when entity has service id annotation', () => { + it('returns a PagerDutyEntity', () => { + expect(getPagerDutyEntity(entityWithServiceId)).toEqual({ + name: 'pagerduty-test', + serviceId: 'def456', + }); + }); + }); + + describe('when entity has all annotations', () => { + it('returns a PagerDutyEntity', () => { + expect(getPagerDutyEntity(entityWithAllAnnotations)).toEqual({ + name: 'pagerduty-test', + integrationKey: 'abc123', + serviceId: 'def456', + }); + }); + }); +}); diff --git a/plugins/pagerduty/src/components/pagerDutyEntity.ts b/plugins/pagerduty/src/components/pagerDutyEntity.ts new file mode 100644 index 0000000000..950525881e --- /dev/null +++ b/plugins/pagerduty/src/components/pagerDutyEntity.ts @@ -0,0 +1,29 @@ +/* + * 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 } from '@backstage/catalog-model'; +import { PagerDutyEntity } from '../types'; +import { PAGERDUTY_INTEGRATION_KEY, PAGERDUTY_SERVICE_ID } from './constants'; + +export function getPagerDutyEntity(entity: Entity): PagerDutyEntity { + const { + [PAGERDUTY_INTEGRATION_KEY]: integrationKey, + [PAGERDUTY_SERVICE_ID]: serviceId, + } = entity.metadata.annotations || ({} as Record); + const name = entity.metadata.name; + + return { integrationKey, serviceId, name }; +} diff --git a/plugins/pagerduty/src/components/types.ts b/plugins/pagerduty/src/components/types.ts index d0d05d82d1..89cdffea16 100644 --- a/plugins/pagerduty/src/components/types.ts +++ b/plugins/pagerduty/src/components/types.ts @@ -14,11 +14,11 @@ * limitations under the License. */ -export type ChangeEvent = { +export type PagerDutyChangeEvent = { id: string; integration: [ { - service: Service; + service: PagerDutyService; }, ]; source: string; @@ -33,44 +33,44 @@ export type ChangeEvent = { timestamp: string; }; -export type Incident = { +export type PagerDutyIncident = { id: string; title: string; status: string; html_url: string; assignments: [ { - assignee: Assignee; + assignee: PagerDutyAssignee; }, ]; serviceId: string; created_at: string; }; -export type Service = { +export type PagerDutyService = { id: string; name: string; html_url: string; integrationKey: string; escalation_policy: { id: string; - user: User; + user: PagerDutyUser; html_url: string; }; }; -export type OnCall = { - user: User; +export type PagerDutyOnCall = { + user: PagerDutyUser; escalation_level: number; }; -export type Assignee = { +export type PagerDutyAssignee = { id: string; summary: string; html_url: string; }; -export type User = { +export type PagerDutyUser = { id: string; summary: string; email: string; diff --git a/plugins/pagerduty/src/hooks/index.ts b/plugins/pagerduty/src/hooks/index.ts index 40a34788f0..8950e443e2 100644 --- a/plugins/pagerduty/src/hooks/index.ts +++ b/plugins/pagerduty/src/hooks/index.ts @@ -15,14 +15,11 @@ */ import { useEntity } from '@backstage/plugin-catalog-react'; +import { PagerDutyEntity } from '../types'; +import { getPagerDutyEntity } from '../components/pagerDutyEntity'; -import { PAGERDUTY_INTEGRATION_KEY } from '../components/constants'; - -export function usePagerdutyEntity() { +export function usePagerdutyEntity(): PagerDutyEntity { const { entity } = useEntity(); - const integrationKey = - entity.metadata.annotations?.[PAGERDUTY_INTEGRATION_KEY]; - const name = entity.metadata.name; - return { integrationKey, name }; + return getPagerDutyEntity(entity); } diff --git a/plugins/pagerduty/src/index.ts b/plugins/pagerduty/src/index.ts index 8c970c01bb..2e0eddc9a8 100644 --- a/plugins/pagerduty/src/index.ts +++ b/plugins/pagerduty/src/index.ts @@ -25,14 +25,8 @@ export { pagerDutyPlugin as plugin, EntityPagerDutyCard, } from './plugin'; -export { - isPluginApplicableToEntity, - isPluginApplicableToEntity as isPagerDutyAvailable, - PagerDutyCard, -} from './components/PagerDutyCard'; -export { TriggerButton } from './components/TriggerButton'; -export { - PagerDutyClient, - pagerDutyApiRef, - UnauthorizedError, -} from './api/client'; + +export * from './components'; +export * from './api'; + +export type { PagerDutyEntity } from './types'; diff --git a/plugins/pagerduty/src/plugin.ts b/plugins/pagerduty/src/plugin.ts index 32093015ff..d49de29416 100644 --- a/plugins/pagerduty/src/plugin.ts +++ b/plugins/pagerduty/src/plugin.ts @@ -19,9 +19,9 @@ import { createPlugin, createRouteRef, discoveryApiRef, + fetchApiRef, configApiRef, createComponentExtension, - identityApiRef, } from '@backstage/core-plugin-api'; export const rootRouteRef = createRouteRef({ @@ -36,10 +36,10 @@ export const pagerDutyPlugin = createPlugin({ deps: { discoveryApi: discoveryApiRef, configApi: configApiRef, - identityApi: identityApiRef, + fetchApi: fetchApiRef, }, - factory: ({ configApi, discoveryApi, identityApi }) => - PagerDutyClient.fromConfig(configApi, discoveryApi, identityApi), + factory: ({ configApi, discoveryApi, fetchApi }) => + PagerDutyClient.fromConfig(configApi, { discoveryApi, fetchApi }), }), ], }); diff --git a/packages/cli/src/commands/plugin/build.ts b/plugins/pagerduty/src/types.ts similarity index 66% rename from packages/cli/src/commands/plugin/build.ts rename to plugins/pagerduty/src/types.ts index 671aece818..07f7f2bbe3 100644 --- a/packages/cli/src/commands/plugin/build.ts +++ b/plugins/pagerduty/src/types.ts @@ -14,13 +14,8 @@ * limitations under the License. */ -import { OptionValues } from 'commander'; -import { buildPackage, Output } from '../../lib/builder'; - -export default async (opts: OptionValues) => { - await buildPackage({ - outputs: new Set([Output.esm, Output.types]), - minify: opts.minify, - useApiExtractor: opts.experimentalTypeBuild, - }); +export type PagerDutyEntity = { + integrationKey?: string; + serviceId?: string; + name: string; }; diff --git a/plugins/periskop-backend/CHANGELOG.md b/plugins/periskop-backend/CHANGELOG.md index 3a4de21e28..0a270b9f0a 100644 --- a/plugins/periskop-backend/CHANGELOG.md +++ b/plugins/periskop-backend/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-periskop-backend +## 0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + ## 0.1.4 ### Patch Changes diff --git a/plugins/periskop-backend/package.json b/plugins/periskop-backend/package.json index a555124743..03be1e44ec 100644 --- a/plugins/periskop-backend/package.json +++ b/plugins/periskop-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-periskop-backend", - "version": "0.1.4", + "version": "0.1.5-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -24,7 +24,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", + "@backstage/backend-common": "^0.14.1-next.1", "@backstage/config": "^1.0.1", "@types/express": "*", "cross-fetch": "^3.0.6", @@ -35,9 +35,9 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", + "@backstage/cli": "^0.18.0-next.1", "@types/supertest": "^2.0.8", - "msw": "^0.42.0", + "msw": "^0.43.0", "supertest": "^6.1.6" }, "files": [ diff --git a/plugins/periskop/CHANGELOG.md b/plugins/periskop/CHANGELOG.md index 9c5887509b..db6854741f 100644 --- a/plugins/periskop/CHANGELOG.md +++ b/plugins/periskop/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-periskop +## 0.1.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## 0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## 0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + ## 0.1.4 ### Patch Changes diff --git a/plugins/periskop/package.json b/plugins/periskop/package.json index c7c6af850b..a9c538d957 100644 --- a/plugins/periskop/package.json +++ b/plugins/periskop/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-periskop", - "version": "0.1.4", + "version": "0.1.5-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -25,12 +25,12 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", - "@backstage/core-components": "^0.9.5", + "@backstage/catalog-model": "^1.1.0-next.2", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/errors": "^1.0.0", - "@backstage/plugin-catalog-react": "^1.1.1", - "@backstage/theme": "^0.2.15", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -42,10 +42,10 @@ "react-dom": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", @@ -53,7 +53,7 @@ "@types/luxon": "^2.0.4", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist", diff --git a/plugins/permission-backend/CHANGELOG.md b/plugins/permission-backend/CHANGELOG.md index f0e391d8d8..e2b2cedb19 100644 --- a/plugins/permission-backend/CHANGELOG.md +++ b/plugins/permission-backend/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-permission-backend +## 0.5.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/plugin-auth-node@0.2.3-next.1 + - @backstage/plugin-permission-common@0.6.3-next.0 + - @backstage/plugin-permission-node@0.6.3-next.1 + +## 0.5.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/plugin-auth-node@0.2.3-next.0 + - @backstage/plugin-permission-node@0.6.3-next.0 + ## 0.5.8 ### Patch Changes diff --git a/plugins/permission-backend/package.json b/plugins/permission-backend/package.json index fd3ce984cc..4df852d255 100644 --- a/plugins/permission-backend/package.json +++ b/plugins/permission-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-backend", - "version": "0.5.8", + "version": "0.5.9-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,12 +22,12 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", + "@backstage/backend-common": "^0.14.1-next.1", "@backstage/config": "^1.0.1", - "@backstage/errors": "^1.0.0", - "@backstage/plugin-auth-node": "^0.2.2", - "@backstage/plugin-permission-common": "^0.6.2", - "@backstage/plugin-permission-node": "^0.6.2", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/plugin-auth-node": "^0.2.3-next.1", + "@backstage/plugin-permission-common": "^0.6.3-next.0", + "@backstage/plugin-permission-node": "^0.6.3-next.1", "@types/express": "*", "dataloader": "^2.0.0", "express": "^4.17.1", @@ -39,11 +39,11 @@ "zod": "^3.11.6" }, "devDependencies": { - "@backstage/cli": "^0.17.2", + "@backstage/cli": "^0.18.0-next.1", "@types/lodash": "^4.14.151", "@types/supertest": "^2.0.8", "supertest": "^6.1.6", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/permission-common/CHANGELOG.md b/plugins/permission-common/CHANGELOG.md index b578c1e8fb..769887f86e 100644 --- a/plugins/permission-common/CHANGELOG.md +++ b/plugins/permission-common/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-permission-common +## 0.6.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.1.0-next.0 + ## 0.6.2 ### Patch Changes diff --git a/plugins/permission-common/package.json b/plugins/permission-common/package.json index 82ab09c853..b811b63438 100644 --- a/plugins/permission-common/package.json +++ b/plugins/permission-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-permission-common", "description": "Isomorphic types and client for Backstage permissions and authorization", - "version": "0.6.2", + "version": "0.6.3-next.0", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { @@ -42,14 +42,14 @@ }, "dependencies": { "@backstage/config": "^1.0.1", - "@backstage/errors": "^1.0.0", + "@backstage/errors": "^1.1.0-next.0", "cross-fetch": "^3.1.5", "uuid": "^8.0.0", "zod": "^3.11.6" }, "devDependencies": { - "@backstage/cli": "^0.17.2", + "@backstage/cli": "^0.18.0-next.1", "@types/jest": "^26.0.7", - "msw": "^0.42.0" + "msw": "^0.43.0" } } diff --git a/plugins/permission-node/CHANGELOG.md b/plugins/permission-node/CHANGELOG.md index 889b3ba374..d412a981eb 100644 --- a/plugins/permission-node/CHANGELOG.md +++ b/plugins/permission-node/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-permission-node +## 0.6.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/plugin-auth-node@0.2.3-next.1 + - @backstage/plugin-permission-common@0.6.3-next.0 + +## 0.6.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/plugin-auth-node@0.2.3-next.0 + ## 0.6.2 ### Patch Changes diff --git a/plugins/permission-node/package.json b/plugins/permission-node/package.json index 1281b4ecba..a0bc4585b0 100644 --- a/plugins/permission-node/package.json +++ b/plugins/permission-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-permission-node", "description": "Common permission and authorization utilities for backend plugins", - "version": "0.6.2", + "version": "0.6.3-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,20 +33,20 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", + "@backstage/backend-common": "^0.14.1-next.1", "@backstage/config": "^1.0.1", - "@backstage/errors": "^1.0.0", - "@backstage/plugin-auth-node": "^0.2.2", - "@backstage/plugin-permission-common": "^0.6.2", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/plugin-auth-node": "^0.2.3-next.1", + "@backstage/plugin-permission-common": "^0.6.3-next.0", "@types/express": "^4.17.6", "express": "^4.17.1", "express-promise-router": "^4.1.0", "zod": "^3.11.6" }, "devDependencies": { - "@backstage/cli": "^0.17.2", + "@backstage/cli": "^0.18.0-next.1", "@types/supertest": "^2.0.8", - "msw": "^0.42.0", + "msw": "^0.43.0", "supertest": "^6.1.3" }, "files": [ diff --git a/plugins/permission-react/CHANGELOG.md b/plugins/permission-react/CHANGELOG.md index cd991549bd..aa6f06a45c 100644 --- a/plugins/permission-react/CHANGELOG.md +++ b/plugins/permission-react/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-permission-react +## 0.4.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.6.3-next.0 + ## 0.4.2 ### Patch Changes diff --git a/plugins/permission-react/package.json b/plugins/permission-react/package.json index ffdb72d385..f0dcc88de0 100644 --- a/plugins/permission-react/package.json +++ b/plugins/permission-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-react", - "version": "0.4.2", + "version": "0.4.3-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,7 +33,7 @@ "dependencies": { "@backstage/config": "^1.0.1", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/plugin-permission-common": "^0.6.2", + "@backstage/plugin-permission-common": "^0.6.3-next.0", "cross-fetch": "^3.1.5", "react-router": "6.0.0-beta.0", "react-use": "^17.2.4", @@ -44,8 +44,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.1", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@types/jest": "^26.0.7" diff --git a/plugins/proxy-backend/CHANGELOG.md b/plugins/proxy-backend/CHANGELOG.md index b23cce864d..fe6aaf541d 100644 --- a/plugins/proxy-backend/CHANGELOG.md +++ b/plugins/proxy-backend/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-proxy-backend +## 0.2.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + ## 0.2.27 ### Patch Changes diff --git a/plugins/proxy-backend/package.json b/plugins/proxy-backend/package.json index a0f7668e3e..7eba901c54 100644 --- a/plugins/proxy-backend/package.json +++ b/plugins/proxy-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-proxy-backend", "description": "A Backstage backend plugin that helps you set up proxy endpoints in the backend", - "version": "0.2.27", + "version": "0.2.28-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,7 +32,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", + "@backstage/backend-common": "^0.14.1-next.1", "@backstage/config": "^1.0.1", "@types/express": "^4.17.6", "express": "^4.17.1", @@ -46,7 +46,7 @@ "yup": "^0.32.9" }, "devDependencies": { - "@backstage/cli": "^0.17.2", + "@backstage/cli": "^0.18.0-next.1", "@types/http-proxy-middleware": "^0.19.3", "@types/supertest": "^2.0.8", "@types/uuid": "^8.0.0", diff --git a/plugins/rollbar-backend/CHANGELOG.md b/plugins/rollbar-backend/CHANGELOG.md index 75e665c02d..1947f00622 100644 --- a/plugins/rollbar-backend/CHANGELOG.md +++ b/plugins/rollbar-backend/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-rollbar-backend +## 0.1.31-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + ## 0.1.30 ### Patch Changes diff --git a/plugins/rollbar-backend/package.json b/plugins/rollbar-backend/package.json index 53fba7bfe3..8f8be07621 100644 --- a/plugins/rollbar-backend/package.json +++ b/plugins/rollbar-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-rollbar-backend", "description": "A Backstage backend plugin that integrates towards Rollbar", - "version": "0.1.30", + "version": "0.1.31-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,7 +34,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", + "@backstage/backend-common": "^0.14.1-next.1", "@backstage/config": "^1.0.1", "@types/express": "^4.17.6", "camelcase-keys": "^7.0.1", @@ -50,10 +50,10 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/backend-test-utils": "^0.1.25", - "@backstage/cli": "^0.17.2", + "@backstage/backend-test-utils": "^0.1.26-next.1", + "@backstage/cli": "^0.18.0-next.1", "@types/supertest": "^2.0.8", - "msw": "^0.42.0", + "msw": "^0.43.0", "supertest": "^6.1.3" }, "files": [ diff --git a/plugins/rollbar/CHANGELOG.md b/plugins/rollbar/CHANGELOG.md index bb55d819a3..367b7a07f3 100644 --- a/plugins/rollbar/CHANGELOG.md +++ b/plugins/rollbar/CHANGELOG.md @@ -1,5 +1,34 @@ # @backstage/plugin-rollbar +## 0.4.7-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## 0.4.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## 0.4.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + ## 0.4.6 ### Patch Changes diff --git a/plugins/rollbar/package.json b/plugins/rollbar/package.json index 5633c9b09a..1ba43e05bc 100644 --- a/plugins/rollbar/package.json +++ b/plugins/rollbar/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-rollbar", "description": "A Backstage plugin that integrates towards Rollbar", - "version": "0.4.6", + "version": "0.4.7-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,11 +35,11 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", - "@backstage/core-components": "^0.9.5", + "@backstage/catalog-model": "^1.1.0-next.2", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/plugin-catalog-react": "^1.1.1", - "@backstage/theme": "^0.2.15", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -53,10 +53,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/react-hooks": "^8.0.0", @@ -65,7 +65,7 @@ "@types/node": "^16.11.26", "@types/react": "^16.13.1 || ^17.0.0", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist", diff --git a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md index 698a746a2a..2bf18ee3a8 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/plugin-scaffolder-backend-module-cookiecutter +## 0.2.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.4.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/integration@1.2.2-next.1 + +## 0.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/plugin-scaffolder-backend@1.4.0-next.0 + - @backstage/integration@1.2.2-next.0 + ## 0.2.8 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-cookiecutter/package.json b/plugins/scaffolder-backend-module-cookiecutter/package.json index 630f672231..f953bac5cd 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/package.json +++ b/plugins/scaffolder-backend-module-cookiecutter/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-backend-module-cookiecutter", "description": "A module for the scaffolder backend that lets you template projects using cookiecutter", - "version": "0.2.8", + "version": "0.2.9-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,10 +23,10 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", - "@backstage/errors": "^1.0.0", - "@backstage/integration": "^1.2.1", - "@backstage/plugin-scaffolder-backend": "^1.3.0", + "@backstage/backend-common": "^0.14.1-next.1", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/integration": "^1.2.2-next.1", + "@backstage/plugin-scaffolder-backend": "^1.4.0-next.1", "@backstage/config": "^1.0.1", "@backstage/types": "^1.0.0", "command-exists": "^1.2.9", @@ -35,13 +35,13 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", + "@backstage/cli": "^0.18.0-next.1", "@types/fs-extra": "^9.0.1", "@types/mock-fs": "^4.13.0", "@types/jest": "^26.0.7", "@types/command-exists": "^1.2.0", "mock-fs": "^5.1.0", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/scaffolder-backend-module-rails/CHANGELOG.md b/plugins/scaffolder-backend-module-rails/CHANGELOG.md index 6a1f59ef7e..1a1d249fd3 100644 --- a/plugins/scaffolder-backend-module-rails/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-rails/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/plugin-scaffolder-backend-module-rails +## 0.4.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.4.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/integration@1.2.2-next.1 + +## 0.4.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/plugin-scaffolder-backend@1.4.0-next.0 + - @backstage/integration@1.2.2-next.0 + ## 0.4.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-rails/package.json b/plugins/scaffolder-backend-module-rails/package.json index 1f755a8f81..e42f34b762 100644 --- a/plugins/scaffolder-backend-module-rails/package.json +++ b/plugins/scaffolder-backend-module-rails/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-backend-module-rails", "description": "A module for the scaffolder backend that lets you template projects using Rails", - "version": "0.4.1", + "version": "0.4.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -24,17 +24,17 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", - "@backstage/plugin-scaffolder-backend": "^1.3.0", + "@backstage/backend-common": "^0.14.1-next.1", + "@backstage/plugin-scaffolder-backend": "^1.4.0-next.1", "@backstage/config": "^1.0.1", - "@backstage/errors": "^1.0.0", - "@backstage/integration": "^1.2.1", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/integration": "^1.2.2-next.1", "@backstage/types": "^1.0.0", "command-exists": "^1.2.9", "fs-extra": "^10.0.1" }, "devDependencies": { - "@backstage/cli": "^0.17.2", + "@backstage/cli": "^0.18.0-next.1", "@types/jest": "^26.0.7", "@types/node": "^16.11.26", "@types/command-exists": "^1.2.0", diff --git a/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md b/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md index a6da817ba6..367adc7034 100644 --- a/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-scaffolder-backend-module-yeoman +## 0.2.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.4.0-next.0 + ## 0.2.6 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-yeoman/package.json b/plugins/scaffolder-backend-module-yeoman/package.json index b876b5e87c..123d563fad 100644 --- a/plugins/scaffolder-backend-module-yeoman/package.json +++ b/plugins/scaffolder-backend-module-yeoman/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-yeoman", - "version": "0.2.6", + "version": "0.2.7-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -24,13 +24,13 @@ }, "dependencies": { "@backstage/config": "^1.0.1", - "@backstage/plugin-scaffolder-backend": "^1.3.0", + "@backstage/plugin-scaffolder-backend": "^1.4.0-next.0", "@backstage/types": "^1.0.0", "winston": "^3.2.1", "yeoman-environment": "^3.9.1" }, "devDependencies": { - "@backstage/backend-common": "^0.14.0", + "@backstage/backend-common": "^0.14.1-next.0", "@types/jest": "^26.0.7" }, "files": [ diff --git a/plugins/scaffolder-backend/CHANGELOG.md b/plugins/scaffolder-backend/CHANGELOG.md index 598de4122f..ed97db5617 100644 --- a/plugins/scaffolder-backend/CHANGELOG.md +++ b/plugins/scaffolder-backend/CHANGELOG.md @@ -1,5 +1,59 @@ # @backstage/plugin-scaffolder-backend +## 1.4.0-next.2 + +### Minor Changes + +- 4baf8a4ece: Update GitLab Merge Request Action to allow source branch to be deleted +- 2db07887cb: Added two new scaffolder actions: `github:repo:create` and `github:repo:push` + +### Patch Changes + +- 679b32172e: Updated dependency `knex` to `^2.0.0`. +- e2d7b76f43: Upgrade git-url-parse to 12.0.0. + + Motivation for upgrade is transitively upgrading parse-url which is vulnerable + to several CVEs detected by Snyk. + + - SNYK-JS-PARSEURL-2935944 + - SNYK-JS-PARSEURL-2935947 + - SNYK-JS-PARSEURL-2936249 + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/backend-common@0.14.1-next.2 + - @backstage/plugin-catalog-backend@1.2.1-next.2 + - @backstage/integration@1.2.2-next.2 + +## 1.4.0-next.1 + +### Patch Changes + +- 801d606909: Improve error messaging when passing in malformed auth +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.1 + - @backstage/catalog-client@1.0.4-next.1 + - @backstage/integration@1.2.2-next.1 + +## 1.4.0-next.0 + +### Minor Changes + +- 3500c13a33: Added a new `/v2/dry-run` endpoint that allows for a synchronous dry run of a provided template. A `supportsDryRun` option has been added to `createTemplateAction`, which signals whether the action should be executed during dry runs. When enabled, the action context will have the new `isDryRun` property set to signal if the action is being executed during a dry run. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/plugin-catalog-backend@1.2.1-next.0 + - @backstage/catalog-client@1.0.4-next.0 + - @backstage/plugin-scaffolder-common@1.1.2-next.0 + ## 1.3.0 ### Minor Changes diff --git a/plugins/scaffolder-backend/api-report.md b/plugins/scaffolder-backend/api-report.md index b5950cd868..30f77aac01 100644 --- a/plugins/scaffolder-backend/api-report.md +++ b/plugins/scaffolder-backend/api-report.md @@ -168,6 +168,62 @@ export type CreateGithubPullRequestClientFactoryInput = { token?: string; }; +// @public +export function createGithubRepoCreateAction(options: { + integrations: ScmIntegrationRegistry; + githubCredentialsProvider?: GithubCredentialsProvider; +}): TemplateAction<{ + repoUrl: string; + description?: string | undefined; + access?: string | undefined; + deleteBranchOnMerge?: boolean | undefined; + gitAuthorName?: string | undefined; + gitAuthorEmail?: string | undefined; + allowRebaseMerge?: boolean | undefined; + allowSquashMerge?: boolean | undefined; + allowMergeCommit?: boolean | undefined; + requireCodeOwnerReviews?: boolean | undefined; + requiredStatusCheckContexts?: string[] | undefined; + repoVisibility?: 'internal' | 'private' | 'public' | undefined; + collaborators?: + | ( + | { + user: string; + access: 'pull' | 'push' | 'admin' | 'maintain' | 'triage'; + } + | { + team: string; + access: 'pull' | 'push' | 'admin' | 'maintain' | 'triage'; + } + | { + username: string; + access: 'pull' | 'push' | 'admin' | 'maintain' | 'triage'; + } + )[] + | undefined; + token?: string | undefined; + topics?: string[] | undefined; +}>; + +// @public +export function createGithubRepoPushAction(options: { + integrations: ScmIntegrationRegistry; + config: Config; + githubCredentialsProvider?: GithubCredentialsProvider; +}): TemplateAction<{ + repoUrl: string; + description?: string | undefined; + defaultBranch?: string | undefined; + protectDefaultBranch?: boolean | undefined; + gitCommitMessage?: string | undefined; + gitAuthorName?: string | undefined; + gitAuthorEmail?: string | undefined; + requireCodeOwnerReviews?: boolean | undefined; + requiredStatusCheckContexts?: string[] | undefined; + sourcePath?: string | undefined; + token?: string | undefined; +}>; + // @public export function createGithubWebhookAction(options: { integrations: ScmIntegrationRegistry; @@ -332,6 +388,7 @@ export function createPublishGitlabAction(options: { gitCommitMessage?: string | undefined; gitAuthorName?: string | undefined; gitAuthorEmail?: string | undefined; + setUserAsOwner?: boolean | undefined; }>; // @public @@ -346,6 +403,7 @@ export const createPublishGitlabMergeRequestAction: (options: { token?: string | undefined; commitAction?: 'update' | 'delete' | 'create' | undefined; projectid?: string | undefined; + removeSourceBranch?: boolean | undefined; }>; // @public diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index 9dfe00672e..a70e60f714 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-backend", "description": "The Backstage backend plugin that helps you create new things", - "version": "1.3.0", + "version": "1.4.0-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,14 +34,14 @@ "build:assets": "node scripts/build-nunjucks.js" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", - "@backstage/catalog-client": "^1.0.3", - "@backstage/catalog-model": "^1.0.3", + "@backstage/backend-common": "^0.14.1-next.2", + "@backstage/catalog-client": "^1.0.4-next.1", + "@backstage/catalog-model": "^1.1.0-next.2", "@backstage/config": "^1.0.1", - "@backstage/errors": "^1.0.0", - "@backstage/integration": "^1.2.1", - "@backstage/plugin-catalog-backend": "^1.2.0", - "@backstage/plugin-scaffolder-common": "^1.1.1", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/integration": "^1.2.2-next.2", + "@backstage/plugin-catalog-backend": "^1.2.1-next.2", + "@backstage/plugin-scaffolder-common": "^1.1.2-next.0", "@backstage/types": "^1.0.0", "@gitbeaker/core": "^35.6.0", "@gitbeaker/node": "^35.1.0", @@ -54,12 +54,12 @@ "express": "^4.17.1", "express-promise-router": "^4.1.0", "fs-extra": "10.1.0", - "git-url-parse": "^11.6.0", + "git-url-parse": "^12.0.0", "globby": "^11.0.0", "isbinaryfile": "^5.0.0", "isomorphic-git": "^1.8.0", "jsonschema": "^1.2.6", - "knex": "^1.0.2", + "knex": "^2.0.0", "lodash": "^4.17.21", "luxon": "^2.0.2", "morgan": "^1.10.0", @@ -76,8 +76,8 @@ "zod": "^3.11.6" }, "devDependencies": { - "@backstage/backend-test-utils": "^0.1.25", - "@backstage/cli": "^0.17.2", + "@backstage/backend-test-utils": "^0.1.26-next.2", + "@backstage/cli": "^0.18.0-next.2", "@types/command-exists": "^1.2.0", "@types/fs-extra": "^9.0.1", "@types/git-url-parse": "^9.0.0", @@ -88,7 +88,7 @@ "esbuild": "^0.14.1", "jest-when": "^3.1.0", "mock-fs": "^5.1.0", - "msw": "^0.42.0", + "msw": "^0.43.0", "supertest": "^6.1.3", "yaml": "^1.10.0" }, diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts index 2ffbc09ce5..91f1e180d0 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts @@ -15,25 +15,34 @@ */ import { UrlReader } from '@backstage/backend-common'; -import { JsonObject } from '@backstage/types'; import { CatalogApi } from '@backstage/catalog-client'; -import { - GithubCredentialsProvider, - ScmIntegrations, - DefaultGithubCredentialsProvider, -} from '@backstage/integration'; import { Config } from '@backstage/config'; import { - createCatalogWriteAction, + DefaultGithubCredentialsProvider, + GithubCredentialsProvider, + ScmIntegrations, +} from '@backstage/integration'; +import { JsonObject } from '@backstage/types'; +import { createCatalogRegisterAction, + createCatalogWriteAction, } from './catalog'; +import { TemplateFilter } from '../../../lib'; +import { TemplateAction } from '../types'; import { createDebugLogAction } from './debug'; import { createFetchPlainAction, createFetchTemplateAction } from './fetch'; import { createFilesystemDeleteAction, createFilesystemRenameAction, } from './filesystem'; +import { + createGithubActionsDispatchAction, + createGithubIssuesLabelAction, + createGithubRepoCreateAction, + createGithubRepoPushAction, + createGithubWebhookAction, +} from './github'; import { createPublishAzureAction, createPublishBitbucketAction, @@ -45,13 +54,6 @@ import { createPublishGitlabAction, createPublishGitlabMergeRequestAction, } from './publish'; -import { - createGithubActionsDispatchAction, - createGithubWebhookAction, - createGithubIssuesLabelAction, -} from './github'; -import { TemplateFilter } from '../../../lib'; -import { TemplateAction } from '../types'; /** * The options passed to {@link createBuiltinActions} @@ -165,6 +167,15 @@ export const createBuiltinActions = ( integrations, githubCredentialsProvider, }), + createGithubRepoCreateAction({ + integrations, + githubCredentialsProvider, + }), + createGithubRepoPushAction({ + integrations, + config, + githubCredentialsProvider, + }), ]; return actions as TemplateAction[]; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.test.ts new file mode 100644 index 0000000000..0e7e907917 --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.test.ts @@ -0,0 +1,416 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { TemplateAction } from '../../types'; + +jest.mock('../helpers'); + +import { getVoidLogger } from '@backstage/backend-common'; +import { ConfigReader } from '@backstage/config'; +import { + DefaultGithubCredentialsProvider, + GithubCredentialsProvider, + ScmIntegrations, +} from '@backstage/integration'; +import { when } from 'jest-when'; +import { PassThrough } from 'stream'; +import { createGithubRepoCreateAction } from './githubRepoCreate'; + +const mockOctokit = { + rest: { + users: { + getByUsername: jest.fn(), + }, + repos: { + addCollaborator: jest.fn(), + createInOrg: jest.fn(), + createForAuthenticatedUser: jest.fn(), + replaceAllTopics: jest.fn(), + }, + teams: { + addOrUpdateRepoPermissionsInOrg: jest.fn(), + }, + }, +}; +jest.mock('octokit', () => ({ + Octokit: class { + constructor() { + return mockOctokit; + } + }, +})); + +describe('github:repo:create', () => { + const config = new ConfigReader({ + integrations: { + github: [ + { host: 'github.com', token: 'tokenlols' }, + { host: 'ghe.github.com' }, + ], + }, + }); + + const integrations = ScmIntegrations.fromConfig(config); + let githubCredentialsProvider: GithubCredentialsProvider; + let action: TemplateAction; + + const mockContext = { + input: { + repoUrl: 'github.com?repo=repo&owner=owner', + description: 'description', + repoVisibility: 'private' as const, + access: 'owner/blam', + }, + workspacePath: 'lol', + logger: getVoidLogger(), + logStream: new PassThrough(), + output: jest.fn(), + createTemporaryDirectory: jest.fn(), + }; + + beforeEach(() => { + jest.resetAllMocks(); + githubCredentialsProvider = + DefaultGithubCredentialsProvider.fromIntegrations(integrations); + action = createGithubRepoCreateAction({ + integrations, + githubCredentialsProvider, + }); + }); + + it('should call the githubApis with the correct values for createInOrg', async () => { + mockOctokit.rest.users.getByUsername.mockResolvedValue({ + data: { type: 'Organization' }, + }); + + mockOctokit.rest.repos.createInOrg.mockResolvedValue({ data: {} }); + + await action.handler(mockContext); + expect(mockOctokit.rest.repos.createInOrg).toHaveBeenCalledWith({ + description: 'description', + name: 'repo', + org: 'owner', + private: true, + delete_branch_on_merge: false, + allow_squash_merge: true, + allow_merge_commit: true, + allow_rebase_merge: true, + visibility: 'private', + }); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + repoVisibility: 'public', + }, + }); + expect(mockOctokit.rest.repos.createInOrg).toHaveBeenCalledWith({ + description: 'description', + name: 'repo', + org: 'owner', + private: false, + delete_branch_on_merge: false, + allow_squash_merge: true, + allow_merge_commit: true, + allow_rebase_merge: true, + visibility: 'public', + }); + }); + + it('should call the githubApis with the correct values for createForAuthenticatedUser', async () => { + mockOctokit.rest.users.getByUsername.mockResolvedValue({ + data: { type: 'User' }, + }); + + mockOctokit.rest.repos.createForAuthenticatedUser.mockResolvedValue({ + data: {}, + }); + + await action.handler(mockContext); + expect( + mockOctokit.rest.repos.createForAuthenticatedUser, + ).toHaveBeenCalledWith({ + description: 'description', + name: 'repo', + private: true, + delete_branch_on_merge: false, + allow_squash_merge: true, + allow_merge_commit: true, + allow_rebase_merge: true, + }); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + repoVisibility: 'public', + }, + }); + expect( + mockOctokit.rest.repos.createForAuthenticatedUser, + ).toHaveBeenCalledWith({ + description: 'description', + name: 'repo', + private: false, + delete_branch_on_merge: false, + allow_squash_merge: true, + allow_merge_commit: true, + allow_rebase_merge: true, + }); + }); + + it('should add access for the team when it starts with the owner', async () => { + mockOctokit.rest.users.getByUsername.mockResolvedValue({ + data: { type: 'User' }, + }); + + mockOctokit.rest.repos.createForAuthenticatedUser.mockResolvedValue({ + data: { + clone_url: 'https://github.com/clone/url.git', + html_url: 'https://github.com/html/url', + }, + }); + + await action.handler(mockContext); + + expect( + mockOctokit.rest.teams.addOrUpdateRepoPermissionsInOrg, + ).toHaveBeenCalledWith({ + org: 'owner', + team_slug: 'blam', + owner: 'owner', + repo: 'repo', + permission: 'admin', + }); + }); + + it('should add outside collaborators when provided', async () => { + mockOctokit.rest.users.getByUsername.mockResolvedValue({ + data: { type: 'User' }, + }); + + mockOctokit.rest.repos.createForAuthenticatedUser.mockResolvedValue({ + data: { + clone_url: 'https://github.com/clone/url.git', + html_url: 'https://github.com/html/url', + }, + }); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + access: 'outsidecollaborator', + }, + }); + + expect(mockOctokit.rest.repos.addCollaborator).toHaveBeenCalledWith({ + username: 'outsidecollaborator', + owner: 'owner', + repo: 'repo', + permission: 'admin', + }); + }); + + it('should add multiple collaborators when provided', async () => { + mockOctokit.rest.users.getByUsername.mockResolvedValue({ + data: { type: 'User' }, + }); + + mockOctokit.rest.repos.createForAuthenticatedUser.mockResolvedValue({ + data: { + clone_url: 'https://github.com/clone/url.git', + html_url: 'https://github.com/html/url', + }, + }); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + collaborators: [ + { + access: 'pull', + user: 'robot-1', + }, + { + access: 'push', + team: 'robot-2', + }, + ], + }, + }); + + const commonProperties = { + owner: 'owner', + repo: 'repo', + }; + + expect(mockOctokit.rest.repos.addCollaborator).toHaveBeenCalledWith({ + ...commonProperties, + username: 'robot-1', + permission: 'pull', + }); + + expect( + mockOctokit.rest.teams.addOrUpdateRepoPermissionsInOrg, + ).toHaveBeenCalledWith({ + ...commonProperties, + org: 'owner', + team_slug: 'robot-2', + permission: 'push', + }); + }); + + it('should ignore failures when adding multiple collaborators', async () => { + mockOctokit.rest.users.getByUsername.mockResolvedValue({ + data: { type: 'User' }, + }); + + mockOctokit.rest.repos.createForAuthenticatedUser.mockResolvedValue({ + data: { + clone_url: 'https://github.com/clone/url.git', + html_url: 'https://github.com/html/url', + }, + }); + + when(mockOctokit.rest.teams.addOrUpdateRepoPermissionsInOrg) + .calledWith({ + org: 'owner', + owner: 'owner', + repo: 'repo', + team_slug: 'robot-1', + permission: 'pull', + }) + .mockRejectedValueOnce(new Error('Something bad happened') as never); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + collaborators: [ + { + access: 'pull', + team: 'robot-1', + }, + { + access: 'push', + team: 'robot-2', + }, + ], + }, + }); + + expect( + mockOctokit.rest.teams.addOrUpdateRepoPermissionsInOrg.mock.calls[2], + ).toEqual([ + { + org: 'owner', + owner: 'owner', + repo: 'repo', + team_slug: 'robot-2', + permission: 'push', + }, + ]); + }); + + it('should add topics when provided', async () => { + mockOctokit.rest.users.getByUsername.mockResolvedValue({ + data: { type: 'User' }, + }); + + mockOctokit.rest.repos.createForAuthenticatedUser.mockResolvedValue({ + data: { + clone_url: 'https://github.com/clone/url.git', + html_url: 'https://github.com/html/url', + }, + }); + + mockOctokit.rest.repos.replaceAllTopics.mockResolvedValue({ + data: { + names: ['node.js'], + }, + }); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + topics: ['node.js'], + }, + }); + + expect(mockOctokit.rest.repos.replaceAllTopics).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repo', + names: ['node.js'], + }); + }); + + it('should lowercase topics when provided', async () => { + mockOctokit.rest.users.getByUsername.mockResolvedValue({ + data: { type: 'User' }, + }); + + mockOctokit.rest.repos.createForAuthenticatedUser.mockResolvedValue({ + data: { + clone_url: 'https://github.com/clone/url.git', + html_url: 'https://github.com/html/url', + }, + }); + + mockOctokit.rest.repos.replaceAllTopics.mockResolvedValue({ + data: { + names: ['backstage'], + }, + }); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + topics: ['BACKSTAGE'], + }, + }); + + expect(mockOctokit.rest.repos.replaceAllTopics).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repo', + names: ['backstage'], + }); + }); + + it('should call output with the remoteUrl', async () => { + mockOctokit.rest.users.getByUsername.mockResolvedValue({ + data: { type: 'User' }, + }); + + mockOctokit.rest.repos.createForAuthenticatedUser.mockResolvedValue({ + data: { + clone_url: 'https://github.com/clone/url.git', + html_url: 'https://github.com/html/url', + }, + }); + + await action.handler(mockContext); + + expect(mockContext.output).toHaveBeenCalledWith( + 'remoteUrl', + 'https://github.com/clone/url.git', + ); + }); +}); diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.ts new file mode 100644 index 0000000000..1e92d91a64 --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.ts @@ -0,0 +1,151 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { InputError } from '@backstage/errors'; +import { + GithubCredentialsProvider, + ScmIntegrationRegistry, +} from '@backstage/integration'; +import { Octokit } from 'octokit'; +import { createTemplateAction } from '../../createTemplateAction'; +import { parseRepoUrl } from '../publish/util'; +import { + createGithubRepoWithCollaboratorsAndTopics, + getOctokitOptions, +} from './helpers'; +import * as inputProps from './inputProperties'; +import * as outputProps from './outputProperties'; + +/** + * Creates a new action that initializes a git repository + * + * @public + */ +export function createGithubRepoCreateAction(options: { + integrations: ScmIntegrationRegistry; + githubCredentialsProvider?: GithubCredentialsProvider; +}) { + const { integrations, githubCredentialsProvider } = options; + + return createTemplateAction<{ + repoUrl: string; + description?: string; + access?: string; + deleteBranchOnMerge?: boolean; + gitAuthorName?: string; + gitAuthorEmail?: string; + allowRebaseMerge?: boolean; + allowSquashMerge?: boolean; + allowMergeCommit?: boolean; + requireCodeOwnerReviews?: boolean; + requiredStatusCheckContexts?: string[]; + repoVisibility?: 'private' | 'internal' | 'public'; + collaborators?: Array< + | { + user: string; + access: 'pull' | 'push' | 'admin' | 'maintain' | 'triage'; + } + | { + team: string; + access: 'pull' | 'push' | 'admin' | 'maintain' | 'triage'; + } + | { + /** @deprecated This field is deprecated in favor of team */ + username: string; + access: 'pull' | 'push' | 'admin' | 'maintain' | 'triage'; + } + >; + token?: string; + topics?: string[]; + }>({ + id: 'github:repo:create', + description: 'Creates a GitHub repository.', + schema: { + input: { + type: 'object', + required: ['repoUrl'], + properties: { + repoUrl: inputProps.repoUrl, + description: inputProps.description, + access: inputProps.access, + requireCodeOwnerReviews: inputProps.requireCodeOwnerReviews, + requiredStatusCheckContexts: inputProps.requiredStatusCheckContexts, + repoVisibility: inputProps.repoVisibility, + deleteBranchOnMerge: inputProps.deleteBranchOnMerge, + allowMergeCommit: inputProps.allowMergeCommit, + allowSquashMerge: inputProps.allowSquashMerge, + allowRebaseMerge: inputProps.allowRebaseMerge, + collaborators: inputProps.collaborators, + token: inputProps.token, + topics: inputProps.topics, + }, + }, + output: { + type: 'object', + properties: { + remoteUrl: outputProps.remoteUrl, + repoContentsUrl: outputProps.repoContentsUrl, + }, + }, + }, + async handler(ctx) { + const { + repoUrl, + description, + access, + repoVisibility = 'private', + deleteBranchOnMerge = false, + allowMergeCommit = true, + allowSquashMerge = true, + allowRebaseMerge = true, + collaborators, + topics, + token: providedToken, + } = ctx.input; + + const octokitOptions = await getOctokitOptions({ + integrations, + credentialsProvider: githubCredentialsProvider, + token: providedToken, + repoUrl: repoUrl, + }); + const client = new Octokit(octokitOptions); + + const { owner, repo } = parseRepoUrl(repoUrl, integrations); + + if (!owner) { + throw new InputError('Invalid repository owner provided in repoUrl'); + } + + const newRepo = await createGithubRepoWithCollaboratorsAndTopics( + client, + repo, + owner, + repoVisibility, + description, + deleteBranchOnMerge, + allowMergeCommit, + allowSquashMerge, + allowRebaseMerge, + access, + collaborators, + topics, + ctx.logger, + ); + + ctx.output('remoteUrl', newRepo.clone_url); + }, + }); +} diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoPush.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoPush.test.ts new file mode 100644 index 0000000000..f23e3dde9f --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoPush.test.ts @@ -0,0 +1,400 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { TemplateAction } from '../../types'; + +jest.mock('../helpers'); + +import { getVoidLogger } from '@backstage/backend-common'; +import { ConfigReader } from '@backstage/config'; +import { + DefaultGithubCredentialsProvider, + GithubCredentialsProvider, + ScmIntegrations, +} from '@backstage/integration'; +import { PassThrough } from 'stream'; +import { + enableBranchProtectionOnDefaultRepoBranch, + initRepoAndPush, +} from '../helpers'; +import { createGithubRepoPushAction } from './githubRepoPush'; + +const mockOctokit = { + rest: { + repos: { + get: jest.fn(), + }, + }, +}; +jest.mock('octokit', () => ({ + Octokit: class { + constructor() { + return mockOctokit; + } + }, +})); + +describe('github:repo:push', () => { + const config = new ConfigReader({ + integrations: { + github: [ + { host: 'github.com', token: 'tokenlols' }, + { host: 'ghe.github.com' }, + ], + }, + }); + + const integrations = ScmIntegrations.fromConfig(config); + let githubCredentialsProvider: GithubCredentialsProvider; + let action: TemplateAction; + + const mockContext = { + input: { + repoUrl: 'github.com?repo=repository&owner=owner', + description: 'description', + repoVisibility: 'private' as const, + access: 'owner/blam', + }, + workspacePath: 'lol', + logger: getVoidLogger(), + logStream: new PassThrough(), + output: jest.fn(), + createTemporaryDirectory: jest.fn(), + }; + + beforeEach(() => { + jest.resetAllMocks(); + githubCredentialsProvider = + DefaultGithubCredentialsProvider.fromIntegrations(integrations); + action = createGithubRepoPushAction({ + integrations, + config, + githubCredentialsProvider, + }); + }); + + it('should call initRepoAndPush with the correct values', async () => { + mockOctokit.rest.repos.get.mockResolvedValue({ + data: { + clone_url: 'https://github.com/clone/url.git', + html_url: 'https://github.com/html/url', + }, + }); + + await action.handler(mockContext); + + expect(initRepoAndPush).toHaveBeenCalledWith({ + dir: mockContext.workspacePath, + remoteUrl: 'https://github.com/clone/url.git', + defaultBranch: 'master', + auth: { username: 'x-access-token', password: 'tokenlols' }, + logger: mockContext.logger, + commitMessage: 'initial commit', + gitAuthorInfo: {}, + }); + }); + + it('should call initRepoAndPush with the correct defaultBranch main', async () => { + mockOctokit.rest.repos.get.mockResolvedValue({ + data: { + clone_url: 'https://github.com/clone/url.git', + html_url: 'https://github.com/html/url', + }, + }); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + defaultBranch: 'main', + }, + }); + + expect(initRepoAndPush).toHaveBeenCalledWith({ + dir: mockContext.workspacePath, + remoteUrl: 'https://github.com/clone/url.git', + defaultBranch: 'main', + auth: { username: 'x-access-token', password: 'tokenlols' }, + logger: mockContext.logger, + commitMessage: 'initial commit', + gitAuthorInfo: {}, + }); + }); + + it('should call initRepoAndPush with the configured defaultAuthor', async () => { + const customAuthorConfig = new ConfigReader({ + integrations: { + github: [ + { host: 'github.com', token: 'tokenlols' }, + { host: 'ghe.github.com' }, + ], + }, + scaffolder: { + defaultAuthor: { + name: 'Test', + email: 'example@example.com', + }, + }, + }); + + const customAuthorIntegrations = + ScmIntegrations.fromConfig(customAuthorConfig); + const customAuthorAction = createGithubRepoPushAction({ + integrations: customAuthorIntegrations, + config: customAuthorConfig, + githubCredentialsProvider, + }); + + mockOctokit.rest.repos.get.mockResolvedValue({ + data: { + clone_url: 'https://github.com/clone/url.git', + html_url: 'https://github.com/html/url', + }, + }); + + await customAuthorAction.handler(mockContext); + + expect(initRepoAndPush).toHaveBeenCalledWith({ + dir: mockContext.workspacePath, + remoteUrl: 'https://github.com/clone/url.git', + defaultBranch: 'master', + auth: { username: 'x-access-token', password: 'tokenlols' }, + logger: mockContext.logger, + commitMessage: 'initial commit', + gitAuthorInfo: { name: 'Test', email: 'example@example.com' }, + }); + }); + + it('should call initRepoAndPush with the configured defaultCommitMessage', async () => { + const customAuthorConfig = new ConfigReader({ + integrations: { + github: [ + { host: 'github.com', token: 'tokenlols' }, + { host: 'ghe.github.com' }, + ], + }, + scaffolder: { + defaultCommitMessage: 'Test commit message', + }, + }); + + const customAuthorIntegrations = + ScmIntegrations.fromConfig(customAuthorConfig); + const customAuthorAction = createGithubRepoPushAction({ + integrations: customAuthorIntegrations, + config: customAuthorConfig, + githubCredentialsProvider, + }); + + mockOctokit.rest.repos.get.mockResolvedValue({ + data: { + clone_url: 'https://github.com/clone/url.git', + html_url: 'https://github.com/html/url', + }, + }); + + await customAuthorAction.handler(mockContext); + + expect(initRepoAndPush).toHaveBeenCalledWith({ + dir: mockContext.workspacePath, + remoteUrl: 'https://github.com/clone/url.git', + defaultBranch: 'master', + auth: { username: 'x-access-token', password: 'tokenlols' }, + logger: mockContext.logger, + commitMessage: 'initial commit', + gitAuthorInfo: { email: undefined, name: undefined }, + }); + }); + + it('should call output with the remoteUrl and the repoContentsUrl', async () => { + mockOctokit.rest.repos.get.mockResolvedValue({ + data: { + clone_url: 'https://github.com/clone/url.git', + html_url: 'https://github.com/html/url', + }, + }); + + await action.handler(mockContext); + + expect(mockContext.output).toHaveBeenCalledWith( + 'remoteUrl', + 'https://github.com/clone/url.git', + ); + expect(mockContext.output).toHaveBeenCalledWith( + 'repoContentsUrl', + 'https://github.com/html/url/blob/master', + ); + }); + + it('should use main as default branch', async () => { + mockOctokit.rest.repos.get.mockResolvedValue({ + data: { + clone_url: 'https://github.com/clone/url.git', + html_url: 'https://github.com/html/url', + }, + }); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + defaultBranch: 'main', + }, + }); + + expect(mockContext.output).toHaveBeenCalledWith( + 'remoteUrl', + 'https://github.com/clone/url.git', + ); + expect(mockContext.output).toHaveBeenCalledWith( + 'repoContentsUrl', + 'https://github.com/html/url/blob/main', + ); + }); + + it('should call enableBranchProtectionOnDefaultRepoBranch with the correct values of requireCodeOwnerReviews', async () => { + mockOctokit.rest.repos.get.mockResolvedValue({ + data: { + clone_url: 'https://github.com/clone/url.git', + html_url: 'https://github.com/html/url', + }, + }); + + await action.handler(mockContext); + + expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ + owner: 'owner', + client: mockOctokit, + repoName: 'repository', + logger: mockContext.logger, + defaultBranch: 'master', + requireCodeOwnerReviews: false, + requiredStatusCheckContexts: [], + }); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + requireCodeOwnerReviews: true, + }, + }); + + expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ + owner: 'owner', + client: mockOctokit, + repoName: 'repository', + logger: mockContext.logger, + defaultBranch: 'master', + requireCodeOwnerReviews: true, + requiredStatusCheckContexts: [], + }); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + requireCodeOwnerReviews: false, + }, + }); + + expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ + owner: 'owner', + client: mockOctokit, + repoName: 'repository', + logger: mockContext.logger, + defaultBranch: 'master', + requireCodeOwnerReviews: false, + requiredStatusCheckContexts: [], + }); + }); + + it('should call enableBranchProtectionOnDefaultRepoBranch with the correct values of requiredStatusCheckContexts', async () => { + mockOctokit.rest.repos.get.mockResolvedValue({ + data: { + clone_url: 'https://github.com/clone/url.git', + html_url: 'https://github.com/html/url', + }, + }); + + await action.handler(mockContext); + + expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ + owner: 'owner', + client: mockOctokit, + repoName: 'repository', + logger: mockContext.logger, + defaultBranch: 'master', + requireCodeOwnerReviews: false, + requiredStatusCheckContexts: [], + }); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + requiredStatusCheckContexts: ['statusCheck'], + }, + }); + + expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ + owner: 'owner', + client: mockOctokit, + repoName: 'repository', + logger: mockContext.logger, + defaultBranch: 'master', + requireCodeOwnerReviews: false, + requiredStatusCheckContexts: ['statusCheck'], + }); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + requiredStatusCheckContexts: [], + }, + }); + + expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ + owner: 'owner', + client: mockOctokit, + repoName: 'repository', + logger: mockContext.logger, + defaultBranch: 'master', + requireCodeOwnerReviews: false, + requiredStatusCheckContexts: [], + }); + }); + + it('should not call enableBranchProtectionOnDefaultRepoBranch with protectDefaultBranch disabled', async () => { + mockOctokit.rest.repos.get.mockResolvedValue({ + data: { + clone_url: 'https://github.com/clone/url.git', + html_url: 'https://github.com/html/url', + }, + }); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + protectDefaultBranch: false, + }, + }); + + expect(enableBranchProtectionOnDefaultRepoBranch).not.toHaveBeenCalled(); + }); +}); diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoPush.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoPush.ts new file mode 100644 index 0000000000..942ebe578d --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoPush.ts @@ -0,0 +1,139 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { Config } from '@backstage/config'; +import { InputError } from '@backstage/errors'; +import { + GithubCredentialsProvider, + ScmIntegrationRegistry, +} from '@backstage/integration'; +import { Octokit } from 'octokit'; +import { createTemplateAction } from '../../createTemplateAction'; +import { parseRepoUrl } from '../publish/util'; +import { getOctokitOptions, initRepoPushAndProtect } from './helpers'; +import * as inputProps from './inputProperties'; +import * as outputProps from './outputProperties'; + +/** + * Creates a new action that initializes a git repository of the content in the workspace + * and publishes it to GitHub. + * + * @public + */ +export function createGithubRepoPushAction(options: { + integrations: ScmIntegrationRegistry; + config: Config; + githubCredentialsProvider?: GithubCredentialsProvider; +}) { + const { integrations, config, githubCredentialsProvider } = options; + + return createTemplateAction<{ + repoUrl: string; + description?: string; + defaultBranch?: string; + protectDefaultBranch?: boolean; + gitCommitMessage?: string; + gitAuthorName?: string; + gitAuthorEmail?: string; + requireCodeOwnerReviews?: boolean; + requiredStatusCheckContexts?: string[]; + sourcePath?: string; + token?: string; + }>({ + id: 'github:repo:push', + description: + 'Initializes a git repository of contents in workspace and publishes it to GitHub.', + schema: { + input: { + type: 'object', + required: ['repoUrl'], + properties: { + repoUrl: inputProps.repoUrl, + requireCodeOwnerReviews: inputProps.requireCodeOwnerReviews, + requiredStatusCheckContexts: inputProps.requiredStatusCheckContexts, + defaultBranch: inputProps.defaultBranch, + protectDefaultBranch: inputProps.protectDefaultBranch, + gitCommitMessage: inputProps.gitCommitMessage, + gitAuthorName: inputProps.gitAuthorName, + gitAuthorEmail: inputProps.gitAuthorEmail, + sourcePath: inputProps.sourcePath, + token: inputProps.token, + }, + }, + output: { + type: 'object', + properties: { + remoteUrl: outputProps.remoteUrl, + repoContentsUrl: outputProps.repoContentsUrl, + }, + }, + }, + async handler(ctx) { + const { + repoUrl, + defaultBranch = 'master', + protectDefaultBranch = true, + gitCommitMessage = 'initial commit', + gitAuthorName, + gitAuthorEmail, + requireCodeOwnerReviews = false, + requiredStatusCheckContexts = [], + token: providedToken, + } = ctx.input; + + const { owner, repo } = parseRepoUrl(repoUrl, integrations); + + if (!owner) { + throw new InputError('Invalid repository owner provided in repoUrl'); + } + + const octokitOptions = await getOctokitOptions({ + integrations, + credentialsProvider: githubCredentialsProvider, + token: providedToken, + repoUrl, + }); + + const client = new Octokit(octokitOptions); + + const targetRepo = await client.rest.repos.get({ owner, repo }); + + const remoteUrl = targetRepo.data.clone_url; + const repoContentsUrl = `${targetRepo.data.html_url}/blob/${defaultBranch}`; + + await initRepoPushAndProtect( + remoteUrl, + octokitOptions.auth, + ctx.workspacePath, + ctx.input.sourcePath, + defaultBranch, + protectDefaultBranch, + owner, + client, + repo, + requireCodeOwnerReviews, + requiredStatusCheckContexts, + config, + ctx.logger, + gitCommitMessage, + gitAuthorName, + gitAuthorEmail, + ); + + ctx.output('remoteUrl', remoteUrl); + ctx.output('repoContentsUrl', repoContentsUrl); + }, + }); +} diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/helpers.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/helpers.ts index 29997e5843..c8f508e4c0 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/helpers.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/helpers.ts @@ -13,14 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { InputError } from '@backstage/errors'; +import { Config } from '@backstage/config'; +import { assertError, InputError } from '@backstage/errors'; import { DefaultGithubCredentialsProvider, GithubCredentialsProvider, ScmIntegrationRegistry, } from '@backstage/integration'; import { OctokitOptions } from '@octokit/core/dist-types/types'; -import { parseRepoUrl } from '../publish/util'; +import { Octokit } from 'octokit'; +import { Logger } from 'winston'; +import { + enableBranchProtectionOnDefaultRepoBranch, + initRepoAndPush, +} from '../helpers'; +import { getRepoSourceDirectory, parseRepoUrl } from '../publish/util'; const DEFAULT_TIMEOUT_MS = 60_000; @@ -83,3 +90,213 @@ export async function getOctokitOptions(options: { previews: ['nebula-preview'], }; } + +export async function createGithubRepoWithCollaboratorsAndTopics( + client: Octokit, + repo: string, + owner: string, + repoVisibility: 'private' | 'internal' | 'public', + description: string | undefined, + deleteBranchOnMerge: boolean, + allowMergeCommit: boolean, + allowSquashMerge: boolean, + allowRebaseMerge: boolean, + access: string | undefined, + collaborators: + | ( + | { + user: string; + access: 'pull' | 'push' | 'admin' | 'maintain' | 'triage'; + } + | { + team: string; + access: 'pull' | 'push' | 'admin' | 'maintain' | 'triage'; + } + | { + /** @deprecated This field is deprecated in favor of team */ + username: string; + access: 'pull' | 'push' | 'admin' | 'maintain' | 'triage'; + } + )[] + | undefined, + topics: string[] | undefined, + logger: Logger, +) { + const user = await client.rest.users.getByUsername({ + username: owner, + }); + + const repoCreationPromise = + user.data.type === 'Organization' + ? client.rest.repos.createInOrg({ + name: repo, + org: owner, + private: repoVisibility === 'private', + visibility: repoVisibility, + description: description, + delete_branch_on_merge: deleteBranchOnMerge, + allow_merge_commit: allowMergeCommit, + allow_squash_merge: allowSquashMerge, + allow_rebase_merge: allowRebaseMerge, + }) + : client.rest.repos.createForAuthenticatedUser({ + name: repo, + private: repoVisibility === 'private', + description: description, + delete_branch_on_merge: deleteBranchOnMerge, + allow_merge_commit: allowMergeCommit, + allow_squash_merge: allowSquashMerge, + allow_rebase_merge: allowRebaseMerge, + }); + + let newRepo; + + try { + newRepo = (await repoCreationPromise).data; + } catch (e) { + assertError(e); + if (e.message === 'Resource not accessible by integration') { + logger.warn( + `The GitHub app or token provided may not have the required permissions to create the ${user.data.type} repository ${owner}/${repo}.`, + ); + } + throw new Error( + `Failed to create the ${user.data.type} repository ${owner}/${repo}, ${e.message}`, + ); + } + + if (access?.startsWith(`${owner}/`)) { + const [, team] = access.split('/'); + await client.rest.teams.addOrUpdateRepoPermissionsInOrg({ + org: owner, + team_slug: team, + owner, + repo, + permission: 'admin', + }); + // No need to add access if it's the person who owns the personal account + } else if (access && access !== owner) { + await client.rest.repos.addCollaborator({ + owner, + repo, + username: access, + permission: 'admin', + }); + } + + if (collaborators) { + for (const collaborator of collaborators) { + try { + if ('user' in collaborator) { + await client.rest.repos.addCollaborator({ + owner, + repo, + username: collaborator.user, + permission: collaborator.access, + }); + } else if ('team' in collaborator) { + await client.rest.teams.addOrUpdateRepoPermissionsInOrg({ + org: owner, + team_slug: collaborator.team, + owner, + repo, + permission: collaborator.access, + }); + } + } catch (e) { + assertError(e); + const name = extractCollaboratorName(collaborator); + logger.warn( + `Skipping ${collaborator.access} access for ${name}, ${e.message}`, + ); + } + } + } + + if (topics) { + try { + await client.rest.repos.replaceAllTopics({ + owner, + repo, + names: topics.map(t => t.toLowerCase()), + }); + } catch (e) { + assertError(e); + logger.warn(`Skipping topics ${topics.join(' ')}, ${e.message}`); + } + } + + return newRepo; +} + +export async function initRepoPushAndProtect( + remoteUrl: string, + password: string, + workspacePath: string, + sourcePath: string | undefined, + defaultBranch: string, + protectDefaultBranch: boolean, + owner: string, + client: Octokit, + repo: string, + requireCodeOwnerReviews: boolean, + requiredStatusCheckContexts: string[], + config: Config, + logger: any, + gitCommitMessage?: string, + gitAuthorName?: string, + gitAuthorEmail?: string, +) { + const gitAuthorInfo = { + name: gitAuthorName + ? gitAuthorName + : config.getOptionalString('scaffolder.defaultAuthor.name'), + email: gitAuthorEmail + ? gitAuthorEmail + : config.getOptionalString('scaffolder.defaultAuthor.email'), + }; + + const commitMessage = gitCommitMessage + ? gitCommitMessage + : config.getOptionalString('scaffolder.defaultCommitMessage'); + + await initRepoAndPush({ + dir: getRepoSourceDirectory(workspacePath, sourcePath), + remoteUrl, + defaultBranch, + auth: { + username: 'x-access-token', + password, + }, + logger, + commitMessage, + gitAuthorInfo, + }); + + if (protectDefaultBranch) { + try { + await enableBranchProtectionOnDefaultRepoBranch({ + owner, + client, + repoName: repo, + logger, + defaultBranch, + requireCodeOwnerReviews, + requiredStatusCheckContexts, + }); + } catch (e) { + assertError(e); + logger.warn( + `Skipping: default branch protection on '${repo}', ${e.message}`, + ); + } + } +} + +function extractCollaboratorName( + collaborator: { user: string } | { team: string } | { username: string }, +) { + if ('username' in collaborator) return collaborator.username; + if ('user' in collaborator) return collaborator.user; + return collaborator.team; +} diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/index.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/index.ts index c5788afc3a..6746aef37e 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/index.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/index.ts @@ -15,5 +15,7 @@ */ export { createGithubActionsDispatchAction } from './githubActionsDispatch'; -export { createGithubWebhookAction } from './githubWebhook'; export { createGithubIssuesLabelAction } from './githubIssuesLabel'; +export { createGithubRepoCreateAction } from './githubRepoCreate'; +export { createGithubRepoPushAction } from './githubRepoPush'; +export { createGithubWebhookAction } from './githubWebhook'; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/inputProperties.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/inputProperties.ts new file mode 100644 index 0000000000..0aad402f1f --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/inputProperties.ts @@ -0,0 +1,161 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const repoUrl = { + title: 'Repository Location', + description: `Accepts the format 'github.com?repo=reponame&owner=owner' where 'reponame' is the new repository name and 'owner' is an organization or username`, + type: 'string', +}; +const description = { + title: 'Repository Description', + type: 'string', +}; +const access = { + title: 'Repository Access', + description: `Sets an admin collaborator on the repository. Can either be a user reference different from 'owner' in 'repoUrl' or team reference, eg. 'org/team-name'`, + type: 'string', +}; +const requireCodeOwnerReviews = { + title: 'Require CODEOWNER Reviews?', + description: + 'Require an approved review in PR including files with a designated Code Owner', + type: 'boolean', +}; +const requiredStatusCheckContexts = { + title: 'Required Status Check Contexts', + description: + 'The list of status checks to require in order to merge into this branch', + type: 'array', + items: { + type: 'string', + }, +}; +const repoVisibility = { + title: 'Repository Visibility', + type: 'string', + enum: ['private', 'public', 'internal'], +}; +const deleteBranchOnMerge = { + title: 'Delete Branch On Merge', + type: 'boolean', + description: `Delete the branch after merging the PR. The default value is 'false'`, +}; +const gitAuthorName = { + title: 'Default Author Name', + type: 'string', + description: `Sets the default author name for the commit. The default value is 'Scaffolder'`, +}; +const gitAuthorEmail = { + title: 'Default Author Email', + type: 'string', + description: `Sets the default author email for the commit.`, +}; +const allowMergeCommit = { + title: 'Allow Merge Commits', + type: 'boolean', + description: `Allow merge commits. The default value is 'true'`, +}; +const allowSquashMerge = { + title: 'Allow Squash Merges', + type: 'boolean', + description: `Allow squash merges. The default value is 'true'`, +}; +const allowRebaseMerge = { + title: 'Allow Rebase Merges', + type: 'boolean', + description: `Allow rebase merges. The default value is 'true'`, +}; +const collaborators = { + title: 'Collaborators', + description: 'Provide additional users or teams with permissions', + type: 'array', + items: { + type: 'object', + additionalProperties: false, + required: ['access'], + properties: { + access: { + type: 'string', + description: 'The type of access for the user', + enum: ['push', 'pull', 'admin', 'maintain', 'triage'], + }, + user: { + type: 'string', + description: + 'The name of the user that will be added as a collaborator', + }, + team: { + type: 'string', + description: + 'The name of the team that will be added as a collaborator', + }, + }, + oneOf: [{ required: ['user'] }, { required: ['team'] }], + }, +}; +const token = { + title: 'Authentication Token', + type: 'string', + description: 'The token to use for authorization to GitHub', +}; +const topics = { + title: 'Topics', + type: 'array', + items: { + type: 'string', + }, +}; +const defaultBranch = { + title: 'Default Branch', + type: 'string', + description: `Sets the default branch on the repository. The default value is 'master'`, +}; +const protectDefaultBranch = { + title: 'Protect Default Branch', + type: 'boolean', + description: `Protect the default branch after creating the repository. The default value is 'true'`, +}; +const gitCommitMessage = { + title: 'Git Commit Message', + type: 'string', + description: `Sets the commit message on the repository. The default value is 'initial commit'`, +}; +const sourcePath = { + title: 'Source Path', + description: + 'Path within the workspace that will be used as the repository root. If omitted, the entire workspace will be published as the repository.', + type: 'string', +}; + +export { access }; +export { allowMergeCommit }; +export { allowRebaseMerge }; +export { allowSquashMerge }; +export { collaborators }; +export { defaultBranch }; +export { deleteBranchOnMerge }; +export { description }; +export { gitAuthorEmail }; +export { gitAuthorName }; +export { gitCommitMessage }; +export { protectDefaultBranch }; +export { repoUrl }; +export { repoVisibility }; +export { requireCodeOwnerReviews }; +export { requiredStatusCheckContexts }; +export { sourcePath }; +export { token }; +export { topics }; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/outputProperties.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/outputProperties.ts new file mode 100644 index 0000000000..d5d6eb108f --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/outputProperties.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const remoteUrl = { + title: 'A URL to the repository with the provider', + type: 'string', +}; +const repoContentsUrl = { + title: 'A URL to the root of the repository', + type: 'string', +}; + +export { remoteUrl }; +export { repoContentsUrl }; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/helpers.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/helpers.ts index 529a504cba..8753d44041 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/helpers.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/helpers.ts @@ -14,12 +14,13 @@ * limitations under the License. */ -import { SpawnOptionsWithoutStdio, spawn } from 'child_process'; +import { Git } from '@backstage/backend-common'; +import { Config } from '@backstage/config'; +import { assertError } from '@backstage/errors'; +import { spawn, SpawnOptionsWithoutStdio } from 'child_process'; +import { Octokit } from 'octokit'; import { PassThrough, Writable } from 'stream'; import { Logger } from 'winston'; -import { Git } from '@backstage/backend-common'; -import { Octokit } from 'octokit'; -import { assertError } from '@backstage/errors'; /** @public */ export type RunCommandOptions = { @@ -200,3 +201,12 @@ export const enableBranchProtectionOnDefaultRepoBranch = async ({ await tryOnce(); } }; + +export function getGitCommitMessage( + gitCommitMessage: string | undefined, + config: Config, +): string | undefined { + return gitCommitMessage + ? gitCommitMessage + : config.getOptionalString('scaffolder.defaultCommitMessage'); +} diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.test.ts index ff20d1014b..036c5d66ee 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 @@ -18,20 +18,20 @@ import { TemplateAction } from '../../types'; jest.mock('../helpers'); -import { createPublishGithubAction } from './github'; +import { getVoidLogger } from '@backstage/backend-common'; +import { ConfigReader } from '@backstage/config'; import { - ScmIntegrations, DefaultGithubCredentialsProvider, GithubCredentialsProvider, + ScmIntegrations, } from '@backstage/integration'; -import { ConfigReader } from '@backstage/config'; -import { getVoidLogger } from '@backstage/backend-common'; +import { when } from 'jest-when'; import { PassThrough } from 'stream'; import { enableBranchProtectionOnDefaultRepoBranch, initRepoAndPush, } from '../helpers'; -import { when } from 'jest-when'; +import { createPublishGithubAction } from './github'; const mockOctokit = { rest: { @@ -609,7 +609,7 @@ describe('publish:github', () => { mockOctokit.rest.repos.createForAuthenticatedUser.mockResolvedValue({ data: { - name: 'repository', + name: 'repo', }, }); @@ -618,7 +618,7 @@ describe('publish:github', () => { expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ owner: 'owner', client: mockOctokit, - repoName: 'repository', + repoName: 'repo', logger: mockContext.logger, defaultBranch: 'master', requireCodeOwnerReviews: false, @@ -636,7 +636,7 @@ describe('publish:github', () => { expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ owner: 'owner', client: mockOctokit, - repoName: 'repository', + repoName: 'repo', logger: mockContext.logger, defaultBranch: 'master', requireCodeOwnerReviews: true, @@ -654,7 +654,7 @@ describe('publish:github', () => { expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ owner: 'owner', client: mockOctokit, - repoName: 'repository', + repoName: 'repo', logger: mockContext.logger, defaultBranch: 'master', requireCodeOwnerReviews: false, @@ -669,7 +669,7 @@ describe('publish:github', () => { mockOctokit.rest.repos.createForAuthenticatedUser.mockResolvedValue({ data: { - name: 'repository', + name: 'repo', }, }); @@ -678,7 +678,7 @@ describe('publish:github', () => { expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ owner: 'owner', client: mockOctokit, - repoName: 'repository', + repoName: 'repo', logger: mockContext.logger, defaultBranch: 'master', requireCodeOwnerReviews: false, @@ -696,7 +696,7 @@ describe('publish:github', () => { expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ owner: 'owner', client: mockOctokit, - repoName: 'repository', + repoName: 'repo', logger: mockContext.logger, defaultBranch: 'master', requireCodeOwnerReviews: false, @@ -714,7 +714,7 @@ describe('publish:github', () => { expect(enableBranchProtectionOnDefaultRepoBranch).toHaveBeenCalledWith({ owner: 'owner', client: mockOctokit, - repoName: 'repository', + repoName: 'repo', logger: mockContext.logger, defaultBranch: 'master', requireCodeOwnerReviews: false, @@ -729,7 +729,7 @@ describe('publish:github', () => { mockOctokit.rest.repos.createForAuthenticatedUser.mockResolvedValue({ data: { - name: 'repository', + name: 'repo', }, }); 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 d9a7112fc9..0815a2cd00 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts @@ -13,21 +13,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { Config } from '@backstage/config'; +import { InputError } from '@backstage/errors'; import { GithubCredentialsProvider, ScmIntegrationRegistry, } from '@backstage/integration'; -import { - enableBranchProtectionOnDefaultRepoBranch, - initRepoAndPush, -} from '../helpers'; -import { getRepoSourceDirectory, parseRepoUrl } from './util'; -import { createTemplateAction } from '../../createTemplateAction'; -import { Config } from '@backstage/config'; -import { assertError, InputError } from '@backstage/errors'; -import { getOctokitOptions } from '../github/helpers'; import { Octokit } from 'octokit'; - +import { createTemplateAction } from '../../createTemplateAction'; +import { + createGithubRepoWithCollaboratorsAndTopics, + getOctokitOptions, + initRepoPushAndProtect, +} from '../github/helpers'; +import * as inputProps from '../github/inputProperties'; +import * as outputProps from '../github/outputProperties'; +import { parseRepoUrl } from './util'; /** * Creates a new action that initializes a git repository of the content in the workspace * and publishes it to GitHub. @@ -84,153 +85,32 @@ export function createPublishGithubAction(options: { type: 'object', required: ['repoUrl'], properties: { - repoUrl: { - title: 'Repository Location', - description: `Accepts the format 'github.com?repo=reponame&owner=owner' where 'reponame' is the new repository name and 'owner' is an organization or username`, - type: 'string', - }, - description: { - title: 'Repository Description', - type: 'string', - }, - access: { - title: 'Repository Access', - description: `Sets an admin collaborator on the repository. Can either be a user reference different from 'owner' in 'repoUrl' or team reference, eg. 'org/team-name'`, - type: 'string', - }, - requireCodeOwnerReviews: { - title: 'Require CODEOWNER Reviews?', - description: - 'Require an approved review in PR including files with a designated Code Owner', - type: 'boolean', - }, - requiredStatusCheckContexts: { - title: 'Required Status Check Contexts', - description: - 'The list of status checks to require in order to merge into this branch', - type: 'array', - items: { - type: 'string', - }, - }, - repoVisibility: { - title: 'Repository Visibility', - type: 'string', - enum: ['private', 'public', 'internal'], - }, - defaultBranch: { - title: 'Default Branch', - type: 'string', - description: `Sets the default branch on the repository. The default value is 'master'`, - }, - protectDefaultBranch: { - title: 'Protect Default Branch', - type: 'boolean', - description: `Protect the default branch after creating the repository. The default value is 'true'`, - }, - deleteBranchOnMerge: { - title: 'Delete Branch On Merge', - type: 'boolean', - description: `Delete the branch after merging the PR. The default value is 'false'`, - }, - gitCommitMessage: { - title: 'Git Commit Message', - type: 'string', - description: `Sets the commit message on the repository. The default value is 'initial commit'`, - }, - gitAuthorName: { - title: 'Default Author Name', - type: 'string', - description: `Sets the default author name for the commit. The default value is 'Scaffolder'`, - }, - gitAuthorEmail: { - title: 'Default Author Email', - type: 'string', - description: `Sets the default author email for the commit.`, - }, - allowMergeCommit: { - title: 'Allow Merge Commits', - type: 'boolean', - description: `Allow merge commits. The default value is 'true'`, - }, - allowSquashMerge: { - title: 'Allow Squash Merges', - type: 'boolean', - description: `Allow squash merges. The default value is 'true'`, - }, - allowRebaseMerge: { - title: 'Allow Rebase Merges', - type: 'boolean', - description: `Allow rebase merges. The default value is 'true'`, - }, - sourcePath: { - title: 'Source Path', - description: - 'Path within the workspace that will be used as the repository root. If omitted, the entire workspace will be published as the repository.', - type: 'string', - }, - collaborators: { - title: 'Collaborators', - description: 'Provide additional users or teams with permissions', - type: 'array', - items: { - type: 'object', - additionalProperties: false, - required: ['access'], - properties: { - access: { - type: 'string', - description: 'The type of access for the user', - enum: ['push', 'pull', 'admin', 'maintain', 'triage'], - }, - user: { - type: 'string', - description: - 'The name of the user that will be added as a collaborator', - }, - username: { - type: 'string', - description: - 'Deprecated. Use the `team` or `user` field instead.', - }, - team: { - type: 'string', - description: - 'The name of the team that will be added as a collaborator', - }, - }, - oneOf: [ - { required: ['user'] }, - { required: ['username'] }, - { required: ['team'] }, - ], - }, - }, - token: { - title: 'Authentication Token', - type: 'string', - description: 'The token to use for authorization to GitHub', - }, - topics: { - title: 'Topics', - type: 'array', - items: { - type: 'string', - }, - }, + repoUrl: inputProps.repoUrl, + description: inputProps.description, + access: inputProps.access, + requireCodeOwnerReviews: inputProps.requireCodeOwnerReviews, + requiredStatusCheckContexts: inputProps.requiredStatusCheckContexts, + repoVisibility: inputProps.repoVisibility, + defaultBranch: inputProps.defaultBranch, + protectDefaultBranch: inputProps.protectDefaultBranch, + deleteBranchOnMerge: inputProps.deleteBranchOnMerge, + gitCommitMessage: inputProps.gitCommitMessage, + gitAuthorName: inputProps.gitAuthorName, + gitAuthorEmail: inputProps.gitAuthorEmail, + allowMergeCommit: inputProps.allowMergeCommit, + allowSquashMerge: inputProps.allowSquashMerge, + allowRebaseMerge: inputProps.allowRebaseMerge, + sourcePath: inputProps.sourcePath, + collaborators: inputProps.collaborators, + token: inputProps.token, + topics: inputProps.topics, }, }, output: { type: 'object', properties: { - remoteUrl: { - title: 'A URL to the repository with the provider', - type: 'string', - }, - repoContentsUrl: { - title: 'A URL to the root of the repository', - type: 'string', - }, + remoteUrl: outputProps.remoteUrl, + repoContentsUrl: outputProps.repoContentsUrl, }, }, }, @@ -256,192 +136,60 @@ export function createPublishGithubAction(options: { token: providedToken, } = ctx.input; + const octokitOptions = await getOctokitOptions({ + integrations, + credentialsProvider: githubCredentialsProvider, + token: providedToken, + repoUrl: repoUrl, + }); + const client = new Octokit(octokitOptions); + const { owner, repo } = parseRepoUrl(repoUrl, integrations); if (!owner) { throw new InputError('Invalid repository owner provided in repoUrl'); } - const octokitOptions = await getOctokitOptions({ - integrations, - credentialsProvider: githubCredentialsProvider, - token: providedToken, - repoUrl, - }); - - const client = new Octokit(octokitOptions); - - const user = await client.rest.users.getByUsername({ - username: owner, - }); - - const repoCreationPromise = - user.data.type === 'Organization' - ? client.rest.repos.createInOrg({ - name: repo, - org: owner, - private: repoVisibility === 'private', - visibility: repoVisibility, - description: description, - delete_branch_on_merge: deleteBranchOnMerge, - allow_merge_commit: allowMergeCommit, - allow_squash_merge: allowSquashMerge, - allow_rebase_merge: allowRebaseMerge, - }) - : client.rest.repos.createForAuthenticatedUser({ - name: repo, - private: repoVisibility === 'private', - description: description, - delete_branch_on_merge: deleteBranchOnMerge, - allow_merge_commit: allowMergeCommit, - allow_squash_merge: allowSquashMerge, - allow_rebase_merge: allowRebaseMerge, - }); - - let newRepo; - - try { - newRepo = (await repoCreationPromise).data; - } catch (e) { - assertError(e); - if (e.message === 'Resource not accessible by integration') { - ctx.logger.warn( - `The GitHub app or token provided may not have the required permissions to create the ${user.data.type} repository ${owner}/${repo}.`, - ); - } - throw new Error( - `Failed to create the ${user.data.type} repository ${owner}/${repo}, ${e.message}`, - ); - } - - if (access?.startsWith(`${owner}/`)) { - const [, team] = access.split('/'); - await client.rest.teams.addOrUpdateRepoPermissionsInOrg({ - org: owner, - team_slug: team, - owner, - repo, - permission: 'admin', - }); - // No need to add access if it's the person who owns the personal account - } else if (access && access !== owner) { - await client.rest.repos.addCollaborator({ - owner, - repo, - username: access, - permission: 'admin', - }); - } - - if (collaborators) { - for (const collaborator of collaborators) { - try { - if ('user' in collaborator) { - await client.rest.repos.addCollaborator({ - owner, - repo, - username: collaborator.user, - permission: collaborator.access, - }); - } else if ('username' in collaborator) { - ctx.logger.warn( - 'The field `username` is deprecated in favor of `team` and will be removed in the future.', - ); - await client.rest.teams.addOrUpdateRepoPermissionsInOrg({ - org: owner, - team_slug: collaborator.username, - owner, - repo, - permission: collaborator.access, - }); - } else if ('team' in collaborator) { - await client.rest.teams.addOrUpdateRepoPermissionsInOrg({ - org: owner, - team_slug: collaborator.team, - owner, - repo, - permission: collaborator.access, - }); - } - } catch (e) { - assertError(e); - const name = extractCollaboratorName(collaborator); - ctx.logger.warn( - `Skipping ${collaborator.access} access for ${name}, ${e.message}`, - ); - } - } - } - - if (topics) { - try { - await client.rest.repos.replaceAllTopics({ - owner, - repo, - names: topics.map(t => t.toLowerCase()), - }); - } catch (e) { - assertError(e); - ctx.logger.warn(`Skipping topics ${topics.join(' ')}, ${e.message}`); - } - } + const newRepo = await createGithubRepoWithCollaboratorsAndTopics( + client, + repo, + owner, + repoVisibility, + description, + deleteBranchOnMerge, + allowMergeCommit, + allowSquashMerge, + allowRebaseMerge, + access, + collaborators, + topics, + ctx.logger, + ); const remoteUrl = newRepo.clone_url; const repoContentsUrl = `${newRepo.html_url}/blob/${defaultBranch}`; - const gitAuthorInfo = { - name: gitAuthorName - ? gitAuthorName - : config.getOptionalString('scaffolder.defaultAuthor.name'), - email: gitAuthorEmail - ? gitAuthorEmail - : config.getOptionalString('scaffolder.defaultAuthor.email'), - }; - - await initRepoAndPush({ - dir: getRepoSourceDirectory(ctx.workspacePath, ctx.input.sourcePath), + await initRepoPushAndProtect( remoteUrl, + octokitOptions.auth, + ctx.workspacePath, + ctx.input.sourcePath, defaultBranch, - auth: { - username: 'x-access-token', - password: octokitOptions.auth, - }, - logger: ctx.logger, - commitMessage: gitCommitMessage - ? gitCommitMessage - : config.getOptionalString('scaffolder.defaultCommitMessage'), - gitAuthorInfo, - }); - - if (protectDefaultBranch) { - try { - await enableBranchProtectionOnDefaultRepoBranch({ - owner, - client, - repoName: newRepo.name, - logger: ctx.logger, - defaultBranch, - requireCodeOwnerReviews, - requiredStatusCheckContexts, - }); - } catch (e) { - assertError(e); - ctx.logger.warn( - `Skipping: default branch protection on '${newRepo.name}', ${e.message}`, - ); - } - } + protectDefaultBranch, + owner, + client, + repo, + requireCodeOwnerReviews, + requiredStatusCheckContexts, + config, + ctx.logger, + gitCommitMessage, + gitAuthorName, + gitAuthorEmail, + ); ctx.output('remoteUrl', remoteUrl); ctx.output('repoContentsUrl', repoContentsUrl); }, }); } - -function extractCollaboratorName( - collaborator: { user: string } | { team: string } | { username: string }, -) { - if ('username' in collaborator) return collaborator.username; - if ('user' in collaborator) return collaborator.user; - return collaborator.team; -} 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 f427023c69..27261ecd49 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 @@ -32,6 +32,9 @@ const mockGitlabClient = { Users: { current: jest.fn(), }, + ProjectMembers: { + add: jest.fn(), + }, }; jest.mock('@gitbeaker/node', () => ({ Gitlab: class { @@ -113,6 +116,7 @@ describe('publish:gitlab', () => { }); it('should work when there is a token provided through ctx.input', async () => { + mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 }); mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 }); mockGitlabClient.Projects.create.mockResolvedValue({ http_url_to_repo: 'http://mockurl.git', @@ -135,6 +139,7 @@ describe('publish:gitlab', () => { }); it('should call the correct Gitlab APIs when the owner is an organization', async () => { + mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 }); mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 }); mockGitlabClient.Projects.create.mockResolvedValue({ http_url_to_repo: 'http://mockurl.git', @@ -168,6 +173,7 @@ describe('publish:gitlab', () => { }); it('should call initRepoAndPush with the correct values', async () => { + mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 }); mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 }); mockGitlabClient.Projects.create.mockResolvedValue({ http_url_to_repo: 'http://mockurl.git', @@ -187,6 +193,7 @@ describe('publish:gitlab', () => { }); it('should call initRepoAndPush with the correct default branch', async () => { + mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 }); mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 }); mockGitlabClient.Projects.create.mockResolvedValue({ http_url_to_repo: 'http://mockurl.git', @@ -241,6 +248,7 @@ describe('publish:gitlab', () => { config: customAuthorConfig, }); + mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 }); mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 }); mockGitlabClient.Projects.create.mockResolvedValue({ http_url_to_repo: 'http://mockurl.git', @@ -286,6 +294,7 @@ describe('publish:gitlab', () => { config: customAuthorConfig, }); + mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 }); mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 }); mockGitlabClient.Projects.create.mockResolvedValue({ http_url_to_repo: 'http://mockurl.git', @@ -305,6 +314,7 @@ describe('publish:gitlab', () => { }); it('should call output with the remoteUrl and repoContentsUrl', async () => { + mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 }); mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 }); mockGitlabClient.Projects.create.mockResolvedValue({ http_url_to_repo: 'http://mockurl.git', @@ -321,4 +331,54 @@ describe('publish:gitlab', () => { 'http://mockurl/-/blob/master', ); }); + + it('should call the correct Gitlab APIs when setUserAsOwner option is true and integration config has a token', async () => { + const customAuthorConfig = new ConfigReader({ + integrations: { + gitlab: [ + { + host: 'gitlab.com', + token: 'tokenlols', + apiBaseUrl: 'https://api.gitlab.com', + }, + ], + }, + }); + + const customAuthorIntegrations = + ScmIntegrations.fromConfig(customAuthorConfig); + const customAuthorAction = createPublishGitlabAction({ + integrations: customAuthorIntegrations, + config: customAuthorConfig, + }); + + mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 }); + mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 }); + mockGitlabClient.Projects.create.mockResolvedValue({ + id: 123456, + http_url_to_repo: 'http://mockurl.git', + }); + + await customAuthorAction.handler({ + ...mockContext, + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + token: 'token', + setUserAsOwner: true, + }, + }); + + expect(mockGitlabClient.Namespaces.show).toHaveBeenCalledWith('owner'); + expect(mockGitlabClient.Users.current).toHaveBeenCalled(); + expect(mockGitlabClient.ProjectMembers.add).toHaveBeenCalledWith( + 123456, + 12345, + 50, + ); + expect(mockGitlabClient.Projects.create).toHaveBeenCalledWith({ + namespace_id: 1234, + name: 'repo', + visibility: 'private', + }); + }); }); 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 a7c247f4d9..4fe55b77a2 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.ts @@ -43,6 +43,7 @@ export function createPublishGitlabAction(options: { gitCommitMessage?: string; gitAuthorName?: string; gitAuthorEmail?: string; + setUserAsOwner?: boolean; }>({ id: 'publish:gitlab', description: @@ -92,6 +93,12 @@ export function createPublishGitlabAction(options: { type: 'string', description: 'The token to use for authorization to GitLab', }, + setUserAsOwner: { + title: 'Set User As Owner', + type: 'boolean', + description: + 'Set the token user as owner of the newly created repository. Requires a token authorized to do the edit in the integration configuration for the matching host', + }, }, }, output: { @@ -116,6 +123,7 @@ export function createPublishGitlabAction(options: { gitCommitMessage = 'initial commit', gitAuthorName, gitAuthorEmail, + setUserAsOwner = false, } = ctx.input; const { owner, repo, host } = parseRepoUrl(repoUrl, integrations); @@ -149,19 +157,35 @@ export function createPublishGitlabAction(options: { id: number; }; + const { id: userId } = (await client.Users.current()) as { + id: number; + }; + if (!targetNamespace) { - const { id } = (await client.Users.current()) as { - id: number; - }; - targetNamespace = id; + targetNamespace = userId; } - const { http_url_to_repo } = await client.Projects.create({ + const { id: projectId, http_url_to_repo } = await client.Projects.create({ namespace_id: targetNamespace, name: repo, visibility: repoVisibility, }); + // When setUserAsOwner is true the input token is expected to come from an unprivileged user GitLab + // OAuth flow. In this case GitLab works in a way that allows the unprivileged user to + // create the repository, but not to push the default protected branch (e.g. master). + // In order to set the user as owner of the newly created repository we need to check that the + // GitLab integration configuration for the matching host contains a token and use + // such token to bootstrap a new privileged client. + if (setUserAsOwner && integrationConfig.config.token) { + const adminClient = new Gitlab({ + host: integrationConfig.config.baseUrl, + token: integrationConfig.config.token, + }); + + await adminClient.ProjectMembers.add(projectId, userId, 50); + } + const remoteUrl = (http_url_to_repo as string).replace(/\.git$/, ''); const repoContentsUrl = `${remoteUrl}/-/blob/${defaultBranch}`; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.test.ts new file mode 100644 index 0000000000..987e360617 --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.test.ts @@ -0,0 +1,207 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { getRootLogger } from '@backstage/backend-common'; +import { ConfigReader } from '@backstage/config'; +import { ScmIntegrations } from '@backstage/integration'; +import mockFs from 'mock-fs'; +import os from 'os'; +import { resolve as resolvePath } from 'path'; +import { Writable } from 'stream'; +import { TemplateAction } from '../../types'; +import { createPublishGitlabMergeRequestAction } from './gitlabMergeRequest'; + +const root = os.platform() === 'win32' ? 'C:\\root' : '/root'; +const workspacePath = resolvePath(root, 'my-workspace'); + +const mockGitlabClient = { + Namespaces: { + show: jest.fn(), + }, + Branches: { + create: jest.fn(), + }, + Commits: { + create: jest.fn(), + }, + MergeRequests: { + create: jest.fn(async (_: any) => { + return { + default_branch: 'main', + }; + }), + }, + Projects: { + create: jest.fn(), + show: jest.fn(async (_: any) => { + return { + default_branch: 'main', + }; + }), + }, + Users: { + current: jest.fn(), + }, +}; + +jest.mock('@gitbeaker/node', () => ({ + Gitlab: class { + constructor() { + return mockGitlabClient; + } + }, +})); + +describe('createGitLabMergeRequest', () => { + let instance: TemplateAction; + + beforeEach(() => { + const config = new ConfigReader({ + integrations: { + gitlab: [ + { + host: 'gitlab.com', + token: 'token', + apiBaseUrl: 'https://api.gitlab.com', + }, + { + host: 'hosted.gitlab.com', + apiBaseUrl: 'https://api.hosted.gitlab.com', + }, + ], + }, + }); + + const integrations = ScmIntegrations.fromConfig(config); + instance = createPublishGitlabMergeRequestAction({ integrations }); + }); + + afterEach(() => { + mockFs.restore(); + }); + + describe('createGitLabMergeRequestWithoutRemoveBranch', () => { + it('removeSourceBranch is false by default when not passed in options', async () => { + const input = { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + title: 'Create my new MR', + branchName: 'new-mr', + description: 'This MR is really good', + draft: true, + targetPath: 'Subdirectory', + }; + mockFs({ + [workspacePath]: { + source: { 'foo.txt': 'Hello there!' }, + irrelevant: { 'bar.txt': 'Nothing to see here' }, + }, + }); + const ctx = { + createTemporaryDirectory: jest.fn(), + output: jest.fn(), + logger: getRootLogger(), + logStream: new Writable(), + input, + workspacePath, + }; + await instance.handler(ctx); + + expect(mockGitlabClient.MergeRequests.create).toHaveBeenCalledWith( + 'owner/repo', + 'new-mr', + 'main', + 'Create my new MR', + { description: 'This MR is really good', removeSourceBranch: false }, + ); + }); + }); + + describe('createGitLabMergeRequestWithRemoveBranch', () => { + it('removeSourceBranch is true when true is passed in options', async () => { + const input = { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + title: 'Create my new MR', + branchName: 'new-mr', + description: 'MR description', + removeSourceBranch: true, + draft: true, + targetPath: 'Subdirectory', + }; + mockFs({ + [workspacePath]: { + source: { 'foo.txt': 'Hello there!' }, + irrelevant: { 'bar.txt': 'Nothing to see here' }, + }, + }); + + const ctx = { + createTemporaryDirectory: jest.fn(), + output: jest.fn(), + logger: getRootLogger(), + logStream: new Writable(), + input, + workspacePath, + }; + await instance.handler(ctx); + + expect(mockGitlabClient.MergeRequests.create).toHaveBeenCalledWith( + 'owner/repo', + 'new-mr', + 'main', + 'Create my new MR', + { description: 'MR description', removeSourceBranch: true }, + ); + }); + + it('removeSourceBranch is false when false is passed in options', async () => { + const input = { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + title: 'Create my new MR', + branchName: 'new-mr', + description: 'other MR description', + removeSourceBranch: false, + draft: true, + targetPath: 'Subdirectory', + }; + mockFs({ + [workspacePath]: { + source: { 'foo.txt': 'Hello there!' }, + irrelevant: { 'bar.txt': 'Nothing to see here' }, + }, + }); + + const ctx = { + createTemporaryDirectory: jest.fn(), + output: jest.fn(), + logger: getRootLogger(), + logStream: new Writable(), + input, + workspacePath, + }; + await instance.handler(ctx); + + expect(mockGitlabClient.MergeRequests.create).toHaveBeenCalledWith( + 'owner/repo', + 'new-mr', + 'main', + 'Create my new MR', + { + description: 'other MR description', + removeSourceBranch: false, + }, + ); + }); + }); +}); 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 17026cc895..d68f68a719 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts @@ -43,6 +43,7 @@ export const createPublishGitlabMergeRequestAction = (options: { commitAction?: 'create' | 'delete' | 'update'; /** @deprecated Use projectPath instead */ projectid?: string; + removeSourceBranch?: boolean; }>({ id: 'publish:gitlab:merge-request', schema: { @@ -93,6 +94,12 @@ export const createPublishGitlabMergeRequestAction = (options: { description: 'The action to be used for git commit. Defaults to create.', }, + removeSourceBranch: { + title: 'Delete source branch', + type: 'boolean', + description: + 'Option to delete source branch once the MR has been merged. Default: false', + }, }, }, output: { @@ -195,7 +202,12 @@ export const createPublishGitlabMergeRequestAction = (options: { destinationBranch, String(defaultBranch), ctx.input.title, - { description: ctx.input.description }, + { + description: ctx.input.description, + removeSourceBranch: ctx.input.removeSourceBranch + ? ctx.input.removeSourceBranch + : false, + }, ).then((mergeRequest: { web_url: string }) => { return mergeRequest.web_url; }); diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index 4919d2e5f9..2abb730250 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -23,13 +23,14 @@ import { } from '@backstage/catalog-model'; import { Entity } from '@backstage/catalog-model'; import { Config, JsonObject } from '@backstage/config'; -import { InputError, NotFoundError } from '@backstage/errors'; +import { InputError, NotFoundError, stringifyError } from '@backstage/errors'; import { ScmIntegrations } from '@backstage/integration'; import { TemplateEntityV1beta3, TaskSpec, templateEntityV1beta3Validator, } from '@backstage/plugin-scaffolder-common'; +import { JsonValue } from '@backstage/types'; import express from 'express'; import Router from 'express-promise-router'; import { validate } from 'jsonschema'; @@ -431,17 +432,36 @@ function parseBearerToken(header?: string): { token?: string; entityRef?: string; } { - const token = header?.match(/Bearer\s+(\S+)/i)?.[1]; + if (!header) { + return {}; + } - if (!token) return {}; + try { + const token = header.match(/^Bearer\s(\S+\.\S+\.\S+)$/i)?.[1]; + if (!token) { + throw new TypeError('Expected Bearer with JWT'); + } - const [_header, rawPayload, _signature] = token.split('.'); - const payload: { sub: string } = JSON.parse( - Buffer.from(rawPayload, 'base64').toString(), - ); + const [_header, rawPayload, _signature] = token.split('.'); + const payload: JsonValue = JSON.parse( + Buffer.from(rawPayload, 'base64').toString(), + ); - return { - entityRef: payload.sub, - token, - }; + if ( + typeof payload !== 'object' || + payload === null || + Array.isArray(payload) + ) { + throw new TypeError('Malformed JWT payload'); + } + + const sub = payload.sub; + if (typeof sub !== 'string') { + throw new TypeError('Expected string sub claim'); + } + + return { entityRef: sub, token }; + } catch (e) { + throw new InputError(`Invalid authorization header: ${stringifyError(e)}`); + } } diff --git a/plugins/scaffolder-common/CHANGELOG.md b/plugins/scaffolder-common/CHANGELOG.md index 27a1abc7d2..1370f192f6 100644 --- a/plugins/scaffolder-common/CHANGELOG.md +++ b/plugins/scaffolder-common/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-scaffolder-common +## 1.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + ## 1.1.1 ### Patch Changes diff --git a/plugins/scaffolder-common/package.json b/plugins/scaffolder-common/package.json index beeec6430d..09503d0be6 100644 --- a/plugins/scaffolder-common/package.json +++ b/plugins/scaffolder-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-common", "description": "Common functionalities for the scaffolder, to be shared between scaffolder and scaffolder-backend plugin", - "version": "1.1.1", + "version": "1.1.2-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -39,10 +39,10 @@ "url": "https://github.com/backstage/backstage/issues" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", + "@backstage/catalog-model": "^1.1.0-next.1", "@backstage/types": "^1.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2" + "@backstage/cli": "^0.18.0-next.1" } } diff --git a/plugins/scaffolder/CHANGELOG.md b/plugins/scaffolder/CHANGELOG.md index 617fe95457..a8a606c73d 100644 --- a/plugins/scaffolder/CHANGELOG.md +++ b/plugins/scaffolder/CHANGELOG.md @@ -1,5 +1,70 @@ # @backstage/plugin-scaffolder +## 1.4.0-next.2 + +### Minor Changes + +- d8eb82f447: Add `allowedRepos` `ui:option` to `RepoUrlPicker` component, and move `repoName` field to own component + +### Patch Changes + +- e2d7b76f43: Upgrade git-url-parse to 12.0.0. + + Motivation for upgrade is transitively upgrading parse-url which is vulnerable + to several CVEs detected by Snyk. + + - SNYK-JS-PARSEURL-2935944 + - SNYK-JS-PARSEURL-2935947 + - SNYK-JS-PARSEURL-2936249 + +- 14146703e5: Add `allowArbitraryValues` to `ui:options` in `OwnedEntityPicker`, similar to `allowArbitraryValues` in `EntityPicker` +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/integration@1.2.2-next.2 + - @backstage/plugin-catalog-react@1.1.2-next.2 + - @backstage/integration-react@1.1.2-next.2 + +## 1.4.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + - @backstage/catalog-client@1.0.4-next.1 + - @backstage/integration@1.2.2-next.1 + - @backstage/integration-react@1.1.2-next.1 + - @backstage/plugin-catalog-common@1.0.4-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + - @backstage/plugin-permission-react@0.4.3-next.0 + +## 1.4.0-next.0 + +### Minor Changes + +- 3500c13a33: A new template editor has been added which is accessible via the context menu on the top right hand corner of the Create page. It allows you to load a template from a local directory, edit it with a preview, execute it in dry-run mode, and view the results. Note that the [File System Access API](https://developer.mozilla.org/en-US/docs/Web/API/File_System_Access_API) must be supported by your browser for this to be available. + + To support the new template editor the `ScaffolderApi` now has an optional `dryRun` method, which is implemented by the default `ScaffolderClient`. + +### Patch Changes + +- 37539e29d8: The template editor now shows the cause of request errors that happen during a dry-run. +- 842282ecf9: Bumped `codemirror` dependencies to `v6.0.0`. +- 464bb0e6c8: The max content size for dry-run files has been reduced from 256k to 64k. +- a7c0b34d70: Swap usage of `MaterialTable` with `Table` from `core-components` +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/catalog-client@1.0.4-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + - @backstage/plugin-scaffolder-common@1.1.2-next.0 + - @backstage/integration-react@1.1.2-next.0 + ## 1.3.0 ### Minor Changes diff --git a/plugins/scaffolder/api-report.md b/plugins/scaffolder/api-report.md index 9ffca426ac..3fa623b5b9 100644 --- a/plugins/scaffolder/api-report.md +++ b/plugins/scaffolder/api-report.md @@ -153,6 +153,8 @@ export const OwnedEntityPickerFieldExtension: FieldExtensionComponent< // @public export interface OwnedEntityPickerUiOptions { + // (undocumented) + allowArbitraryValues?: boolean; // (undocumented) allowedKinds?: string[]; // (undocumented) @@ -193,6 +195,8 @@ export interface RepoUrlPickerUiOptions { // (undocumented) allowedOwners?: string[]; // (undocumented) + allowedRepos?: string[]; + // (undocumented) requestUserCredentials?: { secretsKey: string; additionalScopes?: { diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index 54824c7699..c371c47907 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder", "description": "The Backstage plugin that helps you create new things", - "version": "1.3.0", + "version": "1.4.0-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,34 +35,33 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-client": "^1.0.3", - "@backstage/catalog-model": "^1.0.3", + "@backstage/catalog-client": "^1.0.4-next.1", + "@backstage/catalog-model": "^1.1.0-next.2", "@backstage/config": "^1.0.1", - "@backstage/core-components": "^0.9.5", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/errors": "^1.0.0", - "@backstage/integration": "^1.2.1", - "@backstage/integration-react": "^1.1.1", - "@backstage/plugin-catalog-common": "^1.0.3", - "@backstage/plugin-catalog-react": "^1.1.1", - "@backstage/plugin-permission-react": "^0.4.2", - "@backstage/plugin-scaffolder-common": "^1.1.1", - "@backstage/theme": "^0.2.15", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/integration": "^1.2.2-next.2", + "@backstage/integration-react": "^1.1.2-next.2", + "@backstage/plugin-catalog-common": "^1.0.4-next.0", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", + "@backstage/plugin-permission-react": "^0.4.3-next.0", + "@backstage/plugin-scaffolder-common": "^1.1.2-next.0", + "@backstage/theme": "^0.2.16-next.1", "@backstage/types": "^1.0.0", - "@codemirror/legacy-modes": "^0.20.0", - "@codemirror/language": "^0.20.0", - "@codemirror/view": "^0.20.2", + "@codemirror/language": "^6.0.0", + "@codemirror/legacy-modes": "^6.1.0", + "@codemirror/view": "^6.0.0", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", "@react-hookz/web": "^13.0.0", "@rjsf/core": "^3.2.1", - "@material-table/core": "^3.1.0", "@rjsf/material-ui": "^3.2.1", "@types/json-schema": "^7.0.9", - "@uiw/react-codemirror": "^4.7.0", + "@uiw/react-codemirror": "^4.9.3", "classnames": "^2.2.6", - "git-url-parse": "^11.6.0", + "git-url-parse": "^12.0.0", "humanize-duration": "^3.25.1", "immer": "^9.0.1", "json-schema": "^0.4.0", @@ -81,11 +80,11 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/plugin-catalog": "^1.3.0", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/plugin-catalog": "^1.4.0-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/react-hooks": "^8.0.0", @@ -95,7 +94,7 @@ "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", "event-source-polyfill": "1.0.25", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist", diff --git a/plugins/scaffolder/src/components/ListTasksPage/ListTasksPage.tsx b/plugins/scaffolder/src/components/ListTasksPage/ListTasksPage.tsx index d45d6f1ae7..0b00879d43 100644 --- a/plugins/scaffolder/src/components/ListTasksPage/ListTasksPage.tsx +++ b/plugins/scaffolder/src/components/ListTasksPage/ListTasksPage.tsx @@ -22,14 +22,15 @@ import { Link, Page, Progress, + Table, } from '@backstage/core-components'; import { useApi, useRouteRef } from '@backstage/core-plugin-api'; import { CatalogFilterLayout } from '@backstage/plugin-catalog-react'; import useAsync from 'react-use/lib/useAsync'; -import MaterialTable from '@material-table/core'; import React, { useState } from 'react'; import { scaffolderApiRef } from '../../api'; import { rootRouteRef } from '../../routes'; +import { ScaffolderTask } from '../../types'; import { OwnerListPicker } from './OwnerListPicker'; import { CreatedAtColumn, @@ -88,7 +89,7 @@ const ListTaskPageContent = (props: MyTaskPageProps) => { /> - data={value?.tasks ?? []} title="Tasks" columns={[ diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunContext.tsx b/plugins/scaffolder/src/components/TemplateEditorPage/DryRunContext.tsx index 0a5bfeefd5..b592e3cecd 100644 --- a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunContext.tsx +++ b/plugins/scaffolder/src/components/TemplateEditorPage/DryRunContext.tsx @@ -29,8 +29,8 @@ import React, { import { scaffolderApiRef } from '../../api'; import { ScaffolderDryRunResponse } from '../../types'; -const MAX_CONTENT_SIZE = 256 * 1024; -const CHUNK_SIZE = 0x8000; +const MAX_CONTENT_SIZE = 64 * 1024; +const CHUNK_SIZE = 32 * 1024; interface DryRunOptions { templateContent: string; diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorForm.tsx b/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorForm.tsx index 11b4da246d..d802ab07dc 100644 --- a/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorForm.tsx +++ b/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorForm.tsx @@ -212,11 +212,17 @@ export function TemplateEditorFormDirectoryEditorDryRun( return; } - await dryRun.execute({ - templateContent: selectedFile.content, - values: data, - files: directoryEditor.files, - }); + try { + await dryRun.execute({ + templateContent: selectedFile.content, + values: data, + files: directoryEditor.files, + }); + setErrorText(); + } catch (e) { + setErrorText(String(e.cause || e)); + throw e; + } }; const content = diff --git a/plugins/scaffolder/src/components/TemplatePage/createValidator.test.ts b/plugins/scaffolder/src/components/TemplatePage/createValidator.test.ts index 047f22e44e..a5b04df71e 100644 --- a/plugins/scaffolder/src/components/TemplatePage/createValidator.test.ts +++ b/plugins/scaffolder/src/components/TemplatePage/createValidator.test.ts @@ -23,8 +23,7 @@ describe('createValidator', () => { const validators: Record> = { CustomPicker: (value, validation, _context) => { - // @ts-ignore - if (!value || !value.value) { + if (!value || !(value as { value?: unknown }).value) { validation.addError('Error !'); } }, diff --git a/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx index 8e3590e8bf..a280ebad6a 100644 --- a/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx +++ b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx @@ -37,6 +37,7 @@ import { FieldExtensionComponentProps } from '../../../extensions'; export interface OwnedEntityPickerUiOptions { allowedKinds?: string[]; defaultKind?: string; + allowArbitraryValues?: boolean; } /** @@ -60,6 +61,8 @@ export const OwnedEntityPicker = ( const allowedKinds = uiSchema['ui:options']?.allowedKinds; const defaultKind = uiSchema['ui:options']?.defaultKind; + const allowArbitraryValues = + uiSchema['ui:options']?.allowArbitraryValues ?? true; const { ownedEntities, loading } = useOwnedEntities(allowedKinds); const entityRefs = ownedEntities?.items @@ -83,7 +86,7 @@ export const OwnedEntityPicker = ( onChange={onSelect} options={entityRefs || []} autoSelect - freeSolo + freeSolo={allowArbitraryValues} renderInput={params => ( { - it('renders the three input fields', async () => { + it('renders the two input fields', async () => { const { getAllByRole } = render( , ); const allInputs = getAllByRole('textbox'); - expect(allInputs).toHaveLength(3); + expect(allInputs).toHaveLength(2); }); describe('org field', () => { @@ -58,19 +58,4 @@ describe('AzureRepoPicker', () => { expect(onChange).toHaveBeenCalledWith({ owner: 'owner' }); }); }); - - describe('repoName field', () => { - it('calls onChange when the repoName changes', () => { - const onChange = jest.fn(); - const { getAllByRole } = render( - , - ); - - const repoNameInput = getAllByRole('textbox')[2]; - - fireEvent.change(repoNameInput, { target: { value: 'repoName' } }); - - expect(onChange).toHaveBeenCalledWith({ repoName: 'repoName' }); - }); - }); }); diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/AzureRepoPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/AzureRepoPicker.tsx index 0efadf4017..0246c67801 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/AzureRepoPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/AzureRepoPicker.tsx @@ -27,7 +27,7 @@ export const AzureRepoPicker = (props: { rawErrors: string[]; }) => { const { rawErrors, state, onChange } = props; - const { organization, repoName, owner } = state; + const { organization, owner } = state; return ( <> The Owner that this repo will belong to - 0 && !repoName} - > - Repository - onChange({ repoName: e.target.value })} - value={repoName} - /> - The name of the repository - ); }; diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx index 17fe656006..0ced19a596 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx @@ -26,7 +26,7 @@ describe('BitbucketRepoPicker', () => { , ); - expect(getAllByRole('textbox')).toHaveLength(3); + expect(getAllByRole('textbox')).toHaveLength(2); expect(getAllByRole('textbox')[0]).toHaveValue('lolsWorkspace'); }); @@ -39,7 +39,7 @@ describe('BitbucketRepoPicker', () => { , ); - expect(getAllByRole('textbox')).toHaveLength(2); + expect(getAllByRole('textbox')).toHaveLength(1); }); describe('workspace field', () => { it('calls onChange when the workspace changes', () => { @@ -78,23 +78,4 @@ describe('BitbucketRepoPicker', () => { expect(onChange).toHaveBeenCalledWith({ project: 'test-project' }); }); }); - - describe('repoName field', () => { - it('calls onChange when the repoName changes', () => { - const onChange = jest.fn(); - const { getAllByRole } = render( - , - ); - - const repoNameInput = getAllByRole('textbox')[2]; - - fireEvent.change(repoNameInput, { target: { value: 'test-repo' } }); - - expect(onChange).toHaveBeenCalledWith({ repoName: 'test-repo' }); - }); - }); }); diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx index 64eb4b8dac..fc59398d94 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx @@ -26,7 +26,7 @@ export const BitbucketRepoPicker = (props: { rawErrors: string[]; }) => { const { onChange, rawErrors, state } = props; - const { host, workspace, project, repoName } = state; + const { host, workspace, project } = state; return ( <> {host === 'bitbucket.org' && ( @@ -61,19 +61,6 @@ export const BitbucketRepoPicker = (props: { The Project that this repo will belong to - 0 && !repoName} - > - Repository - onChange({ repoName: e.target.value })} - value={repoName} - /> - The name of the repository - ); }; diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/GerritRepoPicker.test.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/GerritRepoPicker.test.tsx index edc6732588..66f0a234be 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/GerritRepoPicker.test.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/GerritRepoPicker.test.tsx @@ -56,23 +56,4 @@ describe('BitbucketRepoPicker', () => { expect(onChange).toHaveBeenCalledWith({ workspace: 'test-parent' }); }); }); - - describe('repoName field', () => { - it('calls onChange when the repoName changes', () => { - const onChange = jest.fn(); - const { getAllByRole } = render( - , - ); - - const repoNameInput = getAllByRole('textbox')[2]; - - fireEvent.change(repoNameInput, { target: { value: 'test-repo' } }); - - expect(onChange).toHaveBeenCalledWith({ repoName: 'test-repo' }); - }); - }); }); diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/GerritRepoPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/GerritRepoPicker.tsx index 4cbc0859e8..f021948532 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/GerritRepoPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/GerritRepoPicker.tsx @@ -26,7 +26,7 @@ export const GerritRepoPicker = (props: { rawErrors: string[]; }) => { const { onChange, rawErrors, state } = props; - const { workspace, repoName, owner } = state; + const { workspace, owner } = state; return ( <> - 0 && !repoName} - > - Repository - onChange({ repoName: e.target.value })} - value={repoName} - /> - The name of the repository - ); }; diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/GithubRepoPicker.test.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/GithubRepoPicker.test.tsx index 2c80c40c22..63bc5b8013 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/GithubRepoPicker.test.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/GithubRepoPicker.test.tsx @@ -84,24 +84,4 @@ describe('GithubRepoPicker', () => { expect(onChange).toHaveBeenCalledWith({ owner: 'my-mock-owner' }); }); }); - - describe('repo name', () => { - it('should render free text field for input of repo name', () => { - const onChange = jest.fn(); - const { getAllByRole } = render( - , - ); - - const repoNameField = getAllByRole('textbox')[1]; - fireEvent.change(repoNameField, { - target: { value: 'my-mock-repo-name' }, - }); - - expect(onChange).toHaveBeenCalledWith({ repoName: 'my-mock-repo-name' }); - }); - }); }); diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/GithubRepoPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/GithubRepoPicker.tsx index 13b57cb449..ec59d89ef8 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/GithubRepoPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/GithubRepoPicker.tsx @@ -32,7 +32,7 @@ export const GithubRepoPicker = (props: { ? allowedOwners.map(i => ({ label: i, value: i })) : [{ label: 'Loading...', value: 'loading' }]; - const { owner, repoName } = state; + const { owner } = state; return ( <> @@ -66,19 +66,6 @@ export const GithubRepoPicker = (props: { The organization, user or project that this repo will belong to - 0 && !repoName} - > - Repository - onChange({ repoName: e.target.value })} - value={repoName} - /> - The name of the repository - ); }; diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/GitlabRepoPicker.test.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/GitlabRepoPicker.test.tsx index 49a91c116e..ad5c7f765e 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/GitlabRepoPicker.test.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/GitlabRepoPicker.test.tsx @@ -84,24 +84,4 @@ describe('GitlabRepoPicker', () => { expect(onChange).toHaveBeenCalledWith({ owner: 'my-mock-owner' }); }); }); - - describe('repo name', () => { - it('should render free text field for input of repo name', () => { - const onChange = jest.fn(); - const { getAllByRole } = render( - , - ); - - const repoNameField = getAllByRole('textbox')[1]; - fireEvent.change(repoNameField, { - target: { value: 'my-mock-repo-name' }, - }); - - expect(onChange).toHaveBeenCalledWith({ repoName: 'my-mock-repo-name' }); - }); - }); }); diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/GitlabRepoPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/GitlabRepoPicker.tsx index e2052b792f..c628b364b9 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/GitlabRepoPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/GitlabRepoPicker.tsx @@ -23,16 +23,17 @@ import { RepoUrlPickerState } from './types'; export const GitlabRepoPicker = (props: { allowedOwners?: string[]; + allowedRepos?: string[]; state: RepoUrlPickerState; onChange: (state: RepoUrlPickerState) => void; rawErrors: string[]; }) => { - const { allowedOwners = [], rawErrors, state, onChange } = props; + const { allowedOwners = [], state, onChange, rawErrors } = props; const ownerItems: SelectItem[] = allowedOwners ? allowedOwners.map(i => ({ label: i, value: i })) : [{ label: 'Loading...', value: 'loading' }]; - const { owner, repoName } = state; + const { owner } = state; return ( <> @@ -69,19 +70,6 @@ export const GitlabRepoPicker = (props: { namespaces in gitlab), that this repo will belong to - 0 && !repoName} - > - Repository - onChange({ repoName: e.target.value })} - value={repoName} - /> - The name of the repository - ); }; diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx index 6f762933b6..b36b332d9e 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx @@ -26,6 +26,7 @@ import { BitbucketRepoPicker } from './BitbucketRepoPicker'; import { GerritRepoPicker } from './GerritRepoPicker'; import { FieldExtensionComponentProps } from '../../../extensions'; import { RepoUrlPickerHost } from './RepoUrlPickerHost'; +import { RepoUrlPickerRepoName } from './RepoUrlPickerRepoName'; import { parseRepoPickerUrl, serializeRepoPickerUrl } from './utils'; import { RepoUrlPickerState } from './types'; import useDebounce from 'react-use/lib/useDebounce'; @@ -40,6 +41,7 @@ import { useTemplateSecrets } from '../../secrets'; export interface RepoUrlPickerUiOptions { allowedHosts?: string[]; allowedOwners?: string[]; + allowedRepos?: string[]; requestUserCredentials?: { secretsKey: string; additionalScopes?: { @@ -76,6 +78,10 @@ export const RepoUrlPicker = ( () => uiSchema?.['ui:options']?.allowedOwners ?? [], [uiSchema], ); + const allowedRepos = useMemo( + () => uiSchema?.['ui:options']?.allowedRepos ?? [], + [uiSchema], + ); useEffect(() => { onChange(serializeRepoPickerUrl(state)); @@ -87,6 +93,11 @@ export const RepoUrlPicker = ( setState(prevState => ({ ...prevState, owner: allowedOwners[0] })); } }, [setState, allowedOwners]); + useEffect(() => { + if (allowedRepos.length === 1) { + setState(prevState => ({ ...prevState, repoName: allowedRepos[0] })); + } + }, [setState, allowedRepos]); const updateLocalState = useCallback( (newState: RepoUrlPickerState) => { @@ -179,6 +190,14 @@ export const RepoUrlPicker = ( onChange={updateLocalState} /> )} + + setState(prevState => ({ ...prevState, repoName })) + } + rawErrors={rawErrors} + /> ); }; diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.test.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.test.tsx new file mode 100644 index 0000000000..4c392d646c --- /dev/null +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.test.tsx @@ -0,0 +1,76 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; +import { RepoUrlPickerRepoName } from './RepoUrlPickerRepoName'; +import { render, fireEvent } from '@testing-library/react'; + +describe('RepoUrlPickerRepoName', () => { + it('should call onChange with the first allowed repo if there is none set already', async () => { + const onChange = jest.fn(); + + render( + , + ); + + expect(onChange).toHaveBeenCalledWith('foo'); + }); + + it('should render a dropdown of all the options', async () => { + const allowedRepos = ['foo', 'bar']; + + const onChange = jest.fn(); + + const { getByRole } = render( + , + ); + + const select = getByRole('combobox'); + await fireEvent.click(select); + + for (const option of allowedRepos) { + const element = getByRole('option', { name: option }); + expect(element).toBeVisible(); + } + }); + + it('should render a normal text area when no options are passed', async () => { + const onChange = jest.fn(); + + const { getByRole } = render( + , + ); + + const textArea = getByRole('textbox'); + + expect(textArea).toBeVisible(); + + fireEvent.change(textArea, { target: { value: 'foo' } }); + + expect(onChange).toHaveBeenCalledWith('foo'); + }); +}); diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.tsx new file mode 100644 index 0000000000..1393b1902e --- /dev/null +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.tsx @@ -0,0 +1,77 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React, { useEffect } from 'react'; +import { Select, SelectItem } from '@backstage/core-components'; +import FormControl from '@material-ui/core/FormControl'; +import FormHelperText from '@material-ui/core/FormHelperText'; +import Input from '@material-ui/core/Input'; +import InputLabel from '@material-ui/core/InputLabel'; + +export const RepoUrlPickerRepoName = (props: { + repoName?: string; + allowedRepos?: string[]; + onChange: (host: string) => void; + rawErrors: string[]; +}) => { + const { repoName, allowedRepos, onChange, rawErrors } = props; + + useEffect(() => { + // If there is no repoName chosen currently + if (!repoName) { + // Set the first of the allowedRepos option if that available + if (allowedRepos?.length) { + onChange(allowedRepos[0]); + } + } + }, [allowedRepos, repoName, onChange]); + + const repoItems: SelectItem[] = allowedRepos + ? allowedRepos.map(i => ({ label: i, value: i })) + : [{ label: 'Loading...', value: 'loading' }]; + + return ( + <> + 0 && !repoName} + > + {allowedRepos?.length ? ( + onChange(String(e.target.value))} + value={repoName} + /> + + )} + The name of the repository + + + ); +}; diff --git a/plugins/search-backend-module-elasticsearch/CHANGELOG.md b/plugins/search-backend-module-elasticsearch/CHANGELOG.md index a4247a2210..eadb4e5c8b 100644 --- a/plugins/search-backend-module-elasticsearch/CHANGELOG.md +++ b/plugins/search-backend-module-elasticsearch/CHANGELOG.md @@ -1,5 +1,43 @@ # @backstage/plugin-search-backend-module-elasticsearch +## 0.2.0-next.1 + +### Minor Changes + +- c5af773757: **BREAKING**: In order to remain interoperable with all currently supported + deployments of Elasticsearch, this package will now conditionally use either + the `@elastic/elasticsearch` or `@opensearch-project/opensearch` client when + communicating with your deployed cluster. + + If you do not rely on types exported from this package, or if you do not make + use of the `createElasticSearchClientOptions` or `newClient` methods on the + `ElasticSearchSearchEngine` class, then upgrading to this version should not + require any further action on your part. Everything will continue to work as it + always has. + + If you _do_ rely on either of the above methods or any underlying types, some + changes may be needed to your custom code. A type guard is now exported by this + package (`isOpenSearchCompatible(options)`), which you may use to help clarify + which client options are compatible with which client constructors. + + If you are using this package with the `search.elasticsearch.provider` set to + `aws`, and you are making use of the `newClient` method in particular, you may + wish to start using the `@opensearch-project/opensearch` client in your custom + code. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-node@0.6.3-next.1 + - @backstage/plugin-search-common@0.3.6-next.0 + +## 0.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-node@0.6.3-next.0 + ## 0.1.5 ### Patch Changes diff --git a/plugins/search-backend-module-elasticsearch/api-report.md b/plugins/search-backend-module-elasticsearch/api-report.md index 04b7f96f93..eed2b1b10a 100644 --- a/plugins/search-backend-module-elasticsearch/api-report.md +++ b/plugins/search-backend-module-elasticsearch/api-report.md @@ -5,60 +5,27 @@ ```ts /// +import { ApiResponse } from '@opensearch-project/opensearch'; import { BatchSearchEngineIndexer } from '@backstage/plugin-search-backend-node'; -import { Client } from '@elastic/elasticsearch'; +import { BulkHelper } from '@opensearch-project/opensearch/lib/Helpers'; +import { BulkStats } from '@opensearch-project/opensearch/lib/Helpers'; import { Config } from '@backstage/config'; import type { ConnectionOptions } from 'tls'; import { IndexableDocument } from '@backstage/plugin-search-common'; import { IndexableResultSet } from '@backstage/plugin-search-common'; import { Logger } from 'winston'; +import { Readable } from 'stream'; import { SearchEngine } from '@backstage/plugin-search-common'; import { SearchQuery } from '@backstage/plugin-search-common'; - -// @public (undocumented) -export interface ElasticSearchAgentOptions { - // (undocumented) - keepAlive?: boolean; - // (undocumented) - keepAliveMsecs?: number; - // (undocumented) - maxFreeSockets?: number; - // (undocumented) - maxSockets?: number; -} - -// @public (undocumented) -export type ElasticSearchAuth = - | { - username: string; - password: string; - } - | { - apiKey: - | string - | { - id: string; - api_key: string; - }; - }; +import { TransportRequestPromise } from '@opensearch-project/opensearch/lib/Transport'; // @public -export interface ElasticSearchClientOptions { +export interface BaseElasticSearchClientOptions { // (undocumented) agent?: ElasticSearchAgentOptions | ((opts?: any) => unknown) | false; // (undocumented) - auth?: ElasticSearchAuth; - // (undocumented) - cloud?: { - id: string; - username?: string; - password?: string; - }; - // (undocumented) compression?: 'gzip'; // (undocumented) - Connection?: ElasticSearchConnectionConstructor; - // (undocumented) disablePrototypePoisoningProtection?: boolean | 'proto' | 'constructor'; // (undocumented) enableMetaHeader?: boolean; @@ -69,28 +36,14 @@ export interface ElasticSearchClientOptions { // (undocumented) name?: string | symbol; // (undocumented) - node?: - | string - | string[] - | ElasticSearchNodeOptions - | ElasticSearchNodeOptions[]; - // (undocumented) nodeFilter?: (connection: any) => boolean; // (undocumented) - nodes?: - | string - | string[] - | ElasticSearchNodeOptions - | ElasticSearchNodeOptions[]; - // (undocumented) nodeSelector?: ((connections: any[]) => any) | string; // (undocumented) opaqueIdPrefix?: string; // (undocumented) pingTimeout?: number; // (undocumented) - provider?: 'aws' | 'elastic'; - // (undocumented) proxy?: string | URL; // (undocumented) requestTimeout?: number; @@ -112,6 +65,118 @@ export interface ElasticSearchClientOptions { Transport?: ElasticSearchTransportConstructor; } +// @public (undocumented) +export interface ElasticSearchAgentOptions { + // (undocumented) + keepAlive?: boolean; + // (undocumented) + keepAliveMsecs?: number; + // (undocumented) + maxFreeSockets?: number; + // (undocumented) + maxSockets?: number; +} + +// @public (undocumented) +export type ElasticSearchAliasAction = + | { + remove: { + index: any; + alias: any; + }; + add?: undefined; + } + | { + add: { + indices: any; + alias: any; + index?: undefined; + }; + remove?: undefined; + } + | { + add: { + index: any; + alias: any; + indices?: undefined; + }; + remove?: undefined; + } + | undefined; + +// @public (undocumented) +export type ElasticSearchAuth = + | OpenSearchAuth + | { + apiKey: + | string + | { + id: string; + api_key: string; + }; + }; + +// @public +export type ElasticSearchClientOptions = + | ElasticSearchElasticSearchClientOptions + | OpenSearchElasticSearchClientOptions; + +// @public +export class ElasticSearchClientWrapper { + // (undocumented) + bulk(bulkOptions: { + datasource: Readable; + onDocument: () => ElasticSearchIndexAction; + refreshOnCompletion?: string | boolean; + }): BulkHelper; + // (undocumented) + createIndex({ + index, + }: { + index: string; + }): TransportRequestPromise, unknown>>; + // (undocumented) + deleteIndex({ + index, + }: { + index: string | string[]; + }): TransportRequestPromise, unknown>>; + // (undocumented) + static fromClientOptions( + options: ElasticSearchClientOptions, + ): ElasticSearchClientWrapper; + // (undocumented) + getAliases({ + aliases, + }: { + aliases: string[]; + }): TransportRequestPromise, unknown>>; + // (undocumented) + indexExists({ + index, + }: { + index: string | string[]; + }): TransportRequestPromise>; + // (undocumented) + putIndexTemplate( + template: ElasticSearchCustomIndexTemplate, + ): TransportRequestPromise, unknown>>; + // (undocumented) + search({ + index, + body, + }: { + index: string | string[]; + body: Object; + }): TransportRequestPromise, unknown>>; + // (undocumented) + updateAliases({ + actions, + }: { + actions: ElasticSearchAliasAction[]; + }): TransportRequestPromise, unknown>>; +} + // @public export type ElasticSearchConcreteQuery = { documentTypes?: string[]; @@ -150,6 +215,35 @@ export type ElasticSearchCustomIndexTemplateBody = { template?: Record; }; +// @public +export interface ElasticSearchElasticSearchClientOptions + extends BaseElasticSearchClientOptions { + // (undocumented) + auth?: ElasticSearchAuth; + // (undocumented) + cloud?: { + id: string; + username?: string; + password?: string; + }; + // (undocumented) + Connection?: ElasticSearchConnectionConstructor; + // (undocumented) + node?: + | string + | string[] + | ElasticSearchNodeOptions + | ElasticSearchNodeOptions[]; + // (undocumented) + nodes?: + | string + | string[] + | ElasticSearchNodeOptions + | ElasticSearchNodeOptions[]; + // (undocumented) + provider?: 'elastic'; +} + // @public (undocumented) export type ElasticSearchHighlightConfig = { fragmentDelimiter: string; @@ -166,6 +260,14 @@ export type ElasticSearchHighlightOptions = { numFragments?: number; }; +// @public (undocumented) +export type ElasticSearchIndexAction = { + index: { + _index: string; + [key: string]: any; + }; +}; + // @public (undocumented) export interface ElasticSearchNodeOptions { // (undocumented) @@ -258,7 +360,7 @@ export type ElasticSearchSearchEngineIndexerOptions = { indexSeparator: string; alias: string; logger: Logger; - elasticSearchClient: Client; + elasticSearchClientWrapper: ElasticSearchClientWrapper; }; // @public (undocumented) @@ -273,4 +375,67 @@ export interface ElasticSearchTransportConstructor { DEFAULT: string; }; } + +// @public +export const isOpenSearchCompatible: ( + opts: ElasticSearchClientOptions, +) => opts is OpenSearchElasticSearchClientOptions; + +// @public (undocumented) +export type OpenSearchAuth = { + username: string; + password: string; +}; + +// @public (undocumented) +export interface OpenSearchConnectionConstructor { + // (undocumented) + new (opts?: any): any; + // (undocumented) + roles: { + MASTER: string; + DATA: string; + INGEST: string; + }; + // (undocumented) + statuses: { + ALIVE: string; + DEAD: string; + }; +} + +// @public +export interface OpenSearchElasticSearchClientOptions + extends BaseElasticSearchClientOptions { + // (undocumented) + auth?: OpenSearchAuth; + // (undocumented) + connection?: OpenSearchConnectionConstructor; + // (undocumented) + node?: string | string[] | OpenSearchNodeOptions | OpenSearchNodeOptions[]; + // (undocumented) + nodes?: string | string[] | OpenSearchNodeOptions | OpenSearchNodeOptions[]; + // (undocumented) + provider?: 'aws'; +} + +// @public (undocumented) +export interface OpenSearchNodeOptions { + // (undocumented) + agent?: ElasticSearchAgentOptions; + // (undocumented) + headers?: Record; + // (undocumented) + id?: string; + // (undocumented) + roles?: { + master: boolean; + data: boolean; + ingest: boolean; + }; + // (undocumented) + ssl?: ConnectionOptions; + // (undocumented) + url: URL; +} ``` diff --git a/plugins/search-backend-module-elasticsearch/package.json b/plugins/search-backend-module-elasticsearch/package.json index 719e923c5b..b12a87c37d 100644 --- a/plugins/search-backend-module-elasticsearch/package.json +++ b/plugins/search-backend-module-elasticsearch/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search-backend-module-elasticsearch", "description": "A module for the search backend that implements search using ElasticSearch", - "version": "0.1.5", + "version": "0.2.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,11 +23,12 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@acuris/aws-es-connection": "^2.2.0", "@backstage/config": "^1.0.1", - "@backstage/plugin-search-backend-node": "^0.6.2", - "@backstage/plugin-search-common": "^0.3.5", - "@elastic/elasticsearch": "7.13.0", + "@backstage/plugin-search-backend-node": "^0.6.3-next.1", + "@backstage/plugin-search-common": "^0.3.6-next.0", + "@elastic/elasticsearch": "^7.13.0", + "@opensearch-project/opensearch": "^1.1.0", + "aws-os-connection": "^0.1.0", "aws-sdk": "^2.948.0", "elastic-builder": "^2.16.0", "lodash": "^4.17.21", @@ -35,9 +36,10 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/backend-common": "^0.14.0", - "@backstage/cli": "^0.17.2", - "@elastic/elasticsearch-mock": "^1.0.0" + "@backstage/backend-common": "^0.14.1-next.1", + "@backstage/cli": "^0.18.0-next.1", + "@elastic/elasticsearch-mock": "^1.0.0", + "@short.io/opensearch-mock": "^0.3.1" }, "files": [ "dist", diff --git a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchClientOptions.ts b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchClientOptions.ts index c5d1f11b0c..74523020db 100644 --- a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchClientOptions.ts +++ b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchClientOptions.ts @@ -16,17 +16,60 @@ import type { ConnectionOptions as TLSConnectionOptions } from 'tls'; /** - * Options used to configure the `@elastic/elasticsearch` client and - * are what will be passed as an argument to the - * {@link ElasticSearchSearchEngine.newClient} method - * - * They are drawn from the `ClientOptions` class of `@elastic/elasticsearch`, - * but are maintained separately so that this interface is not coupled to + * Typeguard to differentiate ElasticSearch client options which are compatible + * with OpenSearch vs. ElasticSearch clients. Useful when calling the + * {@link ElasticSearchSearchEngine.newClient} method. * * @public */ -export interface ElasticSearchClientOptions { - provider?: 'aws' | 'elastic'; +export const isOpenSearchCompatible = ( + opts: ElasticSearchClientOptions, +): opts is OpenSearchElasticSearchClientOptions => { + return opts?.provider === 'aws'; +}; + +/** + * Options used to configure the `@elastic/elasticsearch` client or the + * `@opensearch-project/opensearch` client, depending on the given config. It + * will be passed as an argument to the + * {@link ElasticSearchSearchEngine.newClient} method. + * + * @public + */ +export type ElasticSearchClientOptions = + | ElasticSearchElasticSearchClientOptions + | OpenSearchElasticSearchClientOptions; + +/** + * Options used to configure the `@opensearch-project/opensearch` client. + * + * They are drawn from the `ClientOptions` class of `@opensearch-project/opensearch`, + * but are maintained separately so that this interface is not coupled to it. + * + * @public + */ +export interface OpenSearchElasticSearchClientOptions + extends BaseElasticSearchClientOptions { + provider?: 'aws'; + auth?: OpenSearchAuth; + connection?: OpenSearchConnectionConstructor; + node?: string | string[] | OpenSearchNodeOptions | OpenSearchNodeOptions[]; + nodes?: string | string[] | OpenSearchNodeOptions | OpenSearchNodeOptions[]; +} + +/** + * Options used to configure the `@elastic/elasticsearch` client. + * + * They are drawn from the `ClientOptions` class of `@elastic/elasticsearch`, + * but are maintained separately so that this interface is not coupled to it. + * + * @public + */ +export interface ElasticSearchElasticSearchClientOptions + extends BaseElasticSearchClientOptions { + provider?: 'elastic'; + auth?: ElasticSearchAuth; + Connection?: ElasticSearchConnectionConstructor; node?: | string | string[] @@ -37,8 +80,21 @@ export interface ElasticSearchClientOptions { | string[] | ElasticSearchNodeOptions | ElasticSearchNodeOptions[]; + cloud?: { + id: string; + username?: string; + password?: string; + }; +} + +/** + * Base client options that are shared across `@opensearch-project/opensearch` + * and `@elastic/elasticsearch` clients. + * + * @public + */ +export interface BaseElasticSearchClientOptions { Transport?: ElasticSearchTransportConstructor; - Connection?: ElasticSearchConnectionConstructor; maxRetries?: number; requestTimeout?: number; pingTimeout?: number; @@ -56,25 +112,24 @@ export interface ElasticSearchClientOptions { headers?: Record; opaqueIdPrefix?: string; name?: string | symbol; - auth?: ElasticSearchAuth; proxy?: string | URL; enableMetaHeader?: boolean; - cloud?: { - id: string; - username?: string; - password?: string; - }; disablePrototypePoisoningProtection?: boolean | 'proto' | 'constructor'; } +/** + * @public + */ +export type OpenSearchAuth = { + username: string; + password: string; +}; + /** * @public */ export type ElasticSearchAuth = - | { - username: string; - password: string; - } + | OpenSearchAuth | { apiKey: | string @@ -101,6 +156,22 @@ export interface ElasticSearchNodeOptions { }; } +/** + * @public + */ +export interface OpenSearchNodeOptions { + url: URL; + id?: string; + agent?: ElasticSearchAgentOptions; + ssl?: TLSConnectionOptions; + headers?: Record; + roles?: { + master: boolean; + data: boolean; + ingest: boolean; + }; +} + /** * @public */ @@ -127,6 +198,23 @@ export interface ElasticSearchConnectionConstructor { ML: string; }; } + +/** + * @public + */ +export interface OpenSearchConnectionConstructor { + new (opts?: any): any; + statuses: { + ALIVE: string; + DEAD: string; + }; + roles: { + MASTER: string; + DATA: string; + INGEST: string; + }; +} + /** * @public */ @@ -139,3 +227,5 @@ export interface ElasticSearchTransportConstructor { DEFAULT: string; }; } + +// todo(iamEAP) implement canary types to ensure we remain compatible through upgrades. diff --git a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchClientWrapper.test.ts b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchClientWrapper.test.ts new file mode 100644 index 0000000000..5bd8bb30b0 --- /dev/null +++ b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchClientWrapper.test.ts @@ -0,0 +1,337 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ConfigReader } from '@backstage/config'; +import { Client as ElasticSearchClient } from '@elastic/elasticsearch'; +import { Client as OpenSearchClient } from '@opensearch-project/opensearch'; +import Mock from '@short.io/opensearch-mock'; +import { Readable } from 'stream'; + +import { ElasticSearchClientWrapper } from './ElasticSearchClientWrapper'; +import { + createElasticSearchClientOptions, + ElasticSearchClientOptions, +} from './ElasticSearchSearchEngine'; + +jest.mock('@elastic/elasticsearch', () => ({ + ...jest.requireActual('@elastic/elasticsearch'), + Client: jest.fn().mockReturnValue({ + search: jest + .fn() + .mockImplementation(async args => ({ client: 'es', args })), + cat: { + aliases: jest + .fn() + .mockImplementation(async args => ({ client: 'es', args })), + }, + helpers: { + bulk: jest + .fn() + .mockImplementation(async args => ({ client: 'es', args })), + }, + indices: { + create: jest + .fn() + .mockImplementation(async args => ({ client: 'es', args })), + delete: jest + .fn() + .mockImplementation(async args => ({ client: 'es', args })), + exists: jest + .fn() + .mockImplementation(async args => ({ client: 'es', args })), + putIndexTemplate: jest + .fn() + .mockImplementation(async args => ({ client: 'es', args })), + updateAliases: jest + .fn() + .mockImplementation(async args => ({ client: 'es', args })), + }, + }), +})); + +jest.mock('@opensearch-project/opensearch', () => ({ + ...jest.requireActual('@opensearch-project/opensearch'), + Client: jest.fn().mockReturnValue({ + search: jest + .fn() + .mockImplementation(async args => ({ client: 'os', args })), + cat: { + aliases: jest + .fn() + .mockImplementation(async args => ({ client: 'os', args })), + }, + helpers: { + bulk: jest + .fn() + .mockImplementation(async args => ({ client: 'os', args })), + }, + indices: { + create: jest + .fn() + .mockImplementation(async args => ({ client: 'os', args })), + delete: jest + .fn() + .mockImplementation(async args => ({ client: 'os', args })), + exists: jest + .fn() + .mockImplementation(async args => ({ client: 'os', args })), + putIndexTemplate: jest + .fn() + .mockImplementation(async args => ({ client: 'os', args })), + updateAliases: jest + .fn() + .mockImplementation(async args => ({ client: 'os', args })), + }, + }), +})); + +describe('ElasticSearchClientWrapper', () => { + describe('elasticSearchClient', () => { + let esOptions: ElasticSearchClientOptions; + + beforeEach(async () => { + esOptions = await createElasticSearchClientOptions( + new ConfigReader({ + node: 'http://localhost:9200', + }), + ); + jest.clearAllMocks(); + }); + + it('instantiation', () => { + ElasticSearchClientWrapper.fromClientOptions(esOptions); + expect(ElasticSearchClient).toHaveBeenCalledWith(esOptions); + }); + + it('search', async () => { + const wrapper = ElasticSearchClientWrapper.fromClientOptions(esOptions); + + const searchInput = { index: 'xyz', body: { eg: 'etc' } }; + const result = (await wrapper.search(searchInput)) as any; + + // Should call the ElasticSearch client's search with expected input. + expect(result.client).toBe('es'); + expect(result.args).toStrictEqual(searchInput); + }); + + it('bulk', async () => { + const wrapper = ElasticSearchClientWrapper.fromClientOptions(esOptions); + + const bulkInput = { + datasource: Readable.from([{}]), + onDocument() { + return { index: { _index: 'xyz' } }; + }, + refreshCompletion: 'xyz', + }; + const result = (await wrapper.bulk(bulkInput)) as any; + + // Should call the ElasticSearch client's bulk helper with expected input + expect(result.client).toBe('es'); + expect(result.args).toStrictEqual(bulkInput); + }); + + it('putIndexTemplate', async () => { + const wrapper = ElasticSearchClientWrapper.fromClientOptions(esOptions); + + const indexTemplate = { name: 'xyz', body: { index_patterns: ['*'] } }; + const result = (await wrapper.putIndexTemplate(indexTemplate)) as any; + + // Should call the ElasticSearch client with expected input. + expect(result.client).toBe('es'); + expect(result.args).toStrictEqual(indexTemplate); + }); + + it('indexExists', async () => { + const wrapper = ElasticSearchClientWrapper.fromClientOptions(esOptions); + + const input = { index: 'xyz' }; + const result = (await wrapper.indexExists(input)) as any; + + // Should call the ElasticSearch client with expected input. + expect(result.client).toBe('es'); + expect(result.args).toStrictEqual(input); + }); + + it('deleteIndex', async () => { + const wrapper = ElasticSearchClientWrapper.fromClientOptions(esOptions); + + const input = { index: 'xyz' }; + const result = (await wrapper.deleteIndex(input)) as any; + + // Should call the OpenSearch client with expected input. + expect(result.client).toBe('es'); + expect(result.args).toStrictEqual(input); + }); + + it('createIndex', async () => { + const wrapper = ElasticSearchClientWrapper.fromClientOptions(esOptions); + + const input = { index: 'xyz' }; + const result = (await wrapper.createIndex(input)) as any; + + // Should call the OpenSearch client with expected input. + expect(result.client).toBe('es'); + expect(result.args).toStrictEqual(input); + }); + + it('getAliases', async () => { + const wrapper = ElasticSearchClientWrapper.fromClientOptions(esOptions); + + const input = { aliases: ['xyz'] }; + const result = (await wrapper.getAliases(input)) as any; + + // Should call the OpenSearch client with expected input. + expect(result.client).toBe('es'); + expect(result.args).toStrictEqual({ + format: 'json', + name: input.aliases, + }); + }); + + it('updateAliases', async () => { + const wrapper = ElasticSearchClientWrapper.fromClientOptions(esOptions); + + const input = { actions: [{ remove: { index: 'xyz', alias: 'abc' } }] }; + const result = (await wrapper.updateAliases(input)) as any; + + // Should call the OpenSearch client with expected input. + expect(result.client).toBe('es'); + expect(result.args).toStrictEqual({ + body: { actions: input.actions }, + }); + }); + }); + + describe('openSearchClient', () => { + const mock = new Mock(); + let osOptions: ElasticSearchClientOptions; + + beforeEach(() => { + osOptions = { + provider: 'aws', + node: 'https://my-es-cluster.eu-west-1.es.amazonaws.com', + connection: mock.getConnection(), + }; + + jest.clearAllMocks(); + }); + + it('instantiation', () => { + ElasticSearchClientWrapper.fromClientOptions(osOptions); + expect(OpenSearchClient).toHaveBeenCalledWith(osOptions); + }); + + it('search', async () => { + const wrapper = ElasticSearchClientWrapper.fromClientOptions(osOptions); + + const searchInput = { index: 'xyz', body: { eg: 'etc' } }; + const result = (await wrapper.search(searchInput)) as any; + + // Should call the OpenSearch client's search with expected input. + expect(result.client).toBe('os'); + expect(result.args).toStrictEqual(searchInput); + }); + + it('bulk', async () => { + const wrapper = ElasticSearchClientWrapper.fromClientOptions(osOptions); + + const bulkInput = { + datasource: Readable.from([{}]), + onDocument() { + return { index: { _index: 'xyz' } }; + }, + refreshCompletion: 'xyz', + }; + const result = (await wrapper.bulk(bulkInput)) as any; + + // Should call the OpenSearch client's bulk helper with expected input. + expect(result.client).toBe('os'); + expect(result.args).toStrictEqual(bulkInput); + }); + + it('putIndexTemplate', async () => { + const wrapper = ElasticSearchClientWrapper.fromClientOptions(osOptions); + + const indexTemplate = { name: 'xyz', body: { index_patterns: ['*'] } }; + const result = (await wrapper.putIndexTemplate(indexTemplate)) as any; + + // Should call the OpenSearch client with expected input. + expect(result.client).toBe('os'); + expect(result.args).toStrictEqual(indexTemplate); + }); + + it('indexExists', async () => { + const wrapper = ElasticSearchClientWrapper.fromClientOptions(osOptions); + + const input = { index: 'xyz' }; + const result = (await wrapper.indexExists(input)) as any; + + // Should call the OpenSearch client with expected input. + expect(result.client).toBe('os'); + expect(result.args).toStrictEqual(input); + }); + + it('deleteIndex', async () => { + const wrapper = ElasticSearchClientWrapper.fromClientOptions(osOptions); + + const input = { index: 'xyz' }; + const result = (await wrapper.deleteIndex(input)) as any; + + // Should call the OpenSearch client with expected input. + expect(result.client).toBe('os'); + expect(result.args).toStrictEqual(input); + }); + + it('createIndex', async () => { + const wrapper = ElasticSearchClientWrapper.fromClientOptions(osOptions); + + const input = { index: 'xyz' }; + const result = (await wrapper.createIndex(input)) as any; + + // Should call the OpenSearch client with expected input. + expect(result.client).toBe('os'); + expect(result.args).toStrictEqual(input); + }); + + it('getAliases', async () => { + const wrapper = ElasticSearchClientWrapper.fromClientOptions(osOptions); + + const input = { aliases: ['xyz'] }; + const result = (await wrapper.getAliases(input)) as any; + + // Should call the OpenSearch client with expected input. + expect(result.client).toBe('os'); + expect(result.args).toStrictEqual({ + format: 'json', + name: input.aliases, + }); + }); + + it('updateAliases', async () => { + const wrapper = ElasticSearchClientWrapper.fromClientOptions(osOptions); + + const input = { actions: [{ remove: { index: 'xyz', alias: 'abc' } }] }; + const result = (await wrapper.updateAliases(input)) as any; + + // Should call the OpenSearch client with expected input. + expect(result.client).toBe('os'); + expect(result.args).toStrictEqual({ + body: { actions: input.actions }, + }); + }); + }); +}); diff --git a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchClientWrapper.ts b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchClientWrapper.ts new file mode 100644 index 0000000000..bcf67e091c --- /dev/null +++ b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchClientWrapper.ts @@ -0,0 +1,209 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { Client as ElasticSearchClient } from '@elastic/elasticsearch'; +import { Client as OpenSearchClient } from '@opensearch-project/opensearch'; +import { Readable } from 'stream'; +import { + ElasticSearchClientOptions, + isOpenSearchCompatible, +} from './ElasticSearchClientOptions'; +import { ElasticSearchCustomIndexTemplate } from './types'; + +/** + * @public + */ +export type ElasticSearchAliasAction = + | { + remove: { index: any; alias: any }; + add?: undefined; + } + | { + add: { indices: any; alias: any; index?: undefined }; + remove?: undefined; + } + | { + add: { index: any; alias: any; indices?: undefined }; + remove?: undefined; + } + | undefined; + +/** + * @public + */ +export type ElasticSearchIndexAction = { + index: { + _index: string; + [key: string]: any; + }; +}; + +/** + * A wrapper class that exposes logical methods that are conditionally fired + * against either a configured Elasticsearch client or a configured Opensearch + * client. + * + * This is necessary because, despite its intention to be API-compatible, the + * opensearch client does not support API key-based authentication. This is + * also the sanest way to accomplish this while making typescript happy. + * + * In the future, if the differences between implementations become + * unmaintainably divergent, we should split out the Opensearch and + * Elasticsearch search engine implementations. + * + * @public + */ +export class ElasticSearchClientWrapper { + private readonly elasticSearchClient: ElasticSearchClient | undefined; + private readonly openSearchClient: OpenSearchClient | undefined; + + private constructor({ + openSearchClient, + elasticSearchClient, + }: { + openSearchClient?: OpenSearchClient; + elasticSearchClient?: ElasticSearchClient; + }) { + this.openSearchClient = openSearchClient; + this.elasticSearchClient = elasticSearchClient; + } + + static fromClientOptions(options: ElasticSearchClientOptions) { + if (isOpenSearchCompatible(options)) { + return new ElasticSearchClientWrapper({ + openSearchClient: new OpenSearchClient(options), + }); + } + + return new ElasticSearchClientWrapper({ + elasticSearchClient: new ElasticSearchClient(options), + }); + } + + search({ index, body }: { index: string | string[]; body: Object }) { + if (this.openSearchClient) { + return this.openSearchClient.search({ index, body }); + } + + if (this.elasticSearchClient) { + return this.elasticSearchClient.search({ index, body }); + } + + throw new Error('No client defined'); + } + + bulk(bulkOptions: { + datasource: Readable; + onDocument: () => ElasticSearchIndexAction; + refreshOnCompletion?: string | boolean; + }) { + if (this.openSearchClient) { + return this.openSearchClient.helpers.bulk(bulkOptions); + } + + if (this.elasticSearchClient) { + return this.elasticSearchClient.helpers.bulk(bulkOptions); + } + + throw new Error('No client defined'); + } + + putIndexTemplate(template: ElasticSearchCustomIndexTemplate) { + if (this.openSearchClient) { + return this.openSearchClient.indices.putIndexTemplate(template); + } + + if (this.elasticSearchClient) { + return this.elasticSearchClient.indices.putIndexTemplate(template); + } + + throw new Error('No client defined'); + } + + indexExists({ index }: { index: string | string[] }) { + if (this.openSearchClient) { + return this.openSearchClient.indices.exists({ index }); + } + + if (this.elasticSearchClient) { + return this.elasticSearchClient.indices.exists({ index }); + } + + throw new Error('No client defined'); + } + + deleteIndex({ index }: { index: string | string[] }) { + if (this.openSearchClient) { + return this.openSearchClient.indices.delete({ index }); + } + + if (this.elasticSearchClient) { + return this.elasticSearchClient.indices.delete({ index }); + } + + throw new Error('No client defined'); + } + + createIndex({ index }: { index: string }) { + if (this.openSearchClient) { + return this.openSearchClient.indices.create({ index }); + } + + if (this.elasticSearchClient) { + return this.elasticSearchClient.indices.create({ index }); + } + + throw new Error('No client defined'); + } + + getAliases({ aliases }: { aliases: string[] }) { + if (this.openSearchClient) { + return this.openSearchClient.cat.aliases({ + format: 'json', + name: aliases, + }); + } + + if (this.elasticSearchClient) { + return this.elasticSearchClient.cat.aliases({ + format: 'json', + name: aliases, + }); + } + + throw new Error('No client defined'); + } + + updateAliases({ actions }: { actions: ElasticSearchAliasAction[] }) { + const filteredActions = actions.filter(Boolean); + if (this.openSearchClient) { + return this.openSearchClient.indices.updateAliases({ + body: { + actions: filteredActions, + }, + }); + } + + if (this.elasticSearchClient) { + return this.elasticSearchClient.indices.updateAliases({ + body: { + actions: filteredActions, + }, + }); + } + + throw new Error('No client defined'); + } +} diff --git a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.test.ts b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.test.ts index 7892b731ed..b59c67c69c 100644 --- a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.test.ts +++ b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.test.ts @@ -16,8 +16,9 @@ import { getVoidLogger } from '@backstage/backend-common'; import { ConfigReader } from '@backstage/config'; -import { Client, errors } from '@elastic/elasticsearch'; +import { errors } from '@elastic/elasticsearch'; import Mock from '@elastic/elasticsearch-mock'; +import { ElasticSearchClientWrapper } from './ElasticSearchClientWrapper'; import { ElasticSearchConcreteQuery, decodePageCursor, @@ -70,7 +71,7 @@ const customIndexTemplate = { describe('ElasticSearchSearchEngine', () => { let testSearchEngine: ElasticSearchSearchEngine; let inspectableSearchEngine: ElasticSearchSearchEngineForTranslatorTests; - let client: Client; + let clientWrapper: ElasticSearchClientWrapper; beforeEach(() => { testSearchEngine = new ElasticSearchSearchEngine( @@ -86,7 +87,7 @@ describe('ElasticSearchSearchEngine', () => { getVoidLogger(), ); // eslint-disable-next-line dot-notation - client = testSearchEngine['elasticSearchClient']; + clientWrapper = testSearchEngine['elasticSearchClientWrapper']; }); describe('custom index template', () => { @@ -686,7 +687,7 @@ describe('ElasticSearchSearchEngine', () => { }); it('should handle index/search type filtering correctly', async () => { - const elasticSearchQuerySpy = jest.spyOn(client, 'search'); + const elasticSearchQuerySpy = jest.spyOn(clientWrapper, 'search'); await testSearchEngine.query({ term: 'testTerm', filters: {}, @@ -725,7 +726,7 @@ describe('ElasticSearchSearchEngine', () => { }); it('should create matchAll query if no term defined', async () => { - const elasticSearchQuerySpy = jest.spyOn(client, 'search'); + const elasticSearchQuerySpy = jest.spyOn(clientWrapper, 'search'); await testSearchEngine.query({ term: '', filters: {}, @@ -759,7 +760,7 @@ describe('ElasticSearchSearchEngine', () => { }); it('should query only specified indices if defined', async () => { - const elasticSearchQuerySpy = jest.spyOn(client, 'search'); + const elasticSearchQuerySpy = jest.spyOn(clientWrapper, 'search'); await testSearchEngine.query({ term: '', filters: {}, @@ -792,6 +793,29 @@ describe('ElasticSearchSearchEngine', () => { elasticSearchQuerySpy.mockClear(); }); + + it('should throws missing index error', async () => { + jest.spyOn(clientWrapper, 'search').mockRejectedValue({ + meta: { + body: { + error: { + type: 'index_not_found_exception', + }, + }, + }, + }); + + await expect( + async () => + await testSearchEngine.query({ + term: 'testTerm', + types: ['unknown'], + filters: {}, + }), + ).rejects.toThrow( + 'Missing index for unknown__search. This means there are no documents to search through.', + ); + }); }); describe('indexer', () => { @@ -809,7 +833,7 @@ describe('ElasticSearchSearchEngine', () => { type: 'test-index', indexPrefix: '', indexSeparator: '-index__', - elasticSearchClient: client, + elasticSearchClientWrapper: clientWrapper, }), ); expect(indexerMock.on).toHaveBeenCalledWith( diff --git a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts index 31112e3446..42c99dfe61 100644 --- a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts +++ b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts @@ -14,10 +14,7 @@ * limitations under the License. */ -import { - awsGetCredentials, - createAWSConnection, -} from '@acuris/aws-es-connection'; +import { awsGetCredentials, createAWSConnection } from 'aws-os-connection'; import { Config } from '@backstage/config'; import { IndexableDocument, @@ -26,47 +23,18 @@ import { SearchEngine, SearchQuery, } from '@backstage/plugin-search-common'; -import { Client } from '@elastic/elasticsearch'; +import { MissingIndexError } from '@backstage/plugin-search-backend-node'; import esb from 'elastic-builder'; import { isEmpty, isNaN as nan, isNumber } from 'lodash'; import { v4 as uuid } from 'uuid'; import { Logger } from 'winston'; -import type { ElasticSearchClientOptions } from './ElasticSearchClientOptions'; +import { ElasticSearchClientOptions } from './ElasticSearchClientOptions'; import { ElasticSearchSearchEngineIndexer } from './ElasticSearchSearchEngineIndexer'; +import { ElasticSearchCustomIndexTemplate } from './types'; +import { ElasticSearchClientWrapper } from './ElasticSearchClientWrapper'; export type { ElasticSearchClientOptions }; -/** - * Elasticsearch specific index template - * @public - */ -export type ElasticSearchCustomIndexTemplate = { - name: string; - body: ElasticSearchCustomIndexTemplateBody; -}; - -/** - * Elasticsearch specific index template body - * @public - */ -export type ElasticSearchCustomIndexTemplateBody = { - /** - * Array of wildcard (*) expressions used to match the names of data streams and indices during creation. - */ - index_patterns: string[]; - /** - * An ordered list of component template names. - * Component templates are merged in the order specified, - * meaning that the last component template specified has the highest precedence. - */ - composed_of?: string[]; - /** - * See available properties of template - * https://www.elastic.co/guide/en/elasticsearch/reference/7.15/indices-put-template.html#put-index-template-api-request-body - */ - template?: Record; -}; - /** * Search query that the elasticsearch engine understands. * @public @@ -143,7 +111,7 @@ function isBlank(str: string) { * @public */ export class ElasticSearchSearchEngine implements SearchEngine { - private readonly elasticSearchClient: Client; + private readonly elasticSearchClientWrapper: ElasticSearchClientWrapper; private readonly highlightOptions: ElasticSearchHighlightConfig; constructor( @@ -153,7 +121,8 @@ export class ElasticSearchSearchEngine implements SearchEngine { private readonly logger: Logger, highlightOptions?: ElasticSearchHighlightOptions, ) { - this.elasticSearchClient = this.newClient(options => new Client(options)); + this.elasticSearchClientWrapper = + ElasticSearchClientWrapper.fromClientOptions(elasticSearchClientOptions); const uuidTag = uuid(); this.highlightOptions = { preTag: `<${uuidTag}>`, @@ -177,7 +146,7 @@ export class ElasticSearchSearchEngine implements SearchEngine { if (options.provider === 'elastic') { logger.info('Initializing Elastic.co ElasticSearch search engine.'); } else if (options.provider === 'aws') { - logger.info('Initializing AWS ElasticSearch search engine.'); + logger.info('Initializing AWS OpenSearch search engine.'); } else { logger.info('Initializing ElasticSearch search engine.'); } @@ -269,7 +238,7 @@ export class ElasticSearchSearchEngine implements SearchEngine { async setIndexTemplate(template: ElasticSearchCustomIndexTemplate) { try { - await this.elasticSearchClient.indices.putIndexTemplate(template); + await this.elasticSearchClientWrapper.putIndexTemplate(template); this.logger.info('Custom index template set'); } catch (error) { this.logger.error(`Unable to set custom index template: ${error}`); @@ -284,7 +253,7 @@ export class ElasticSearchSearchEngine implements SearchEngine { indexPrefix: this.indexPrefix, indexSeparator: this.indexSeparator, alias, - elasticSearchClient: this.elasticSearchClient, + elasticSearchClientWrapper: this.elasticSearchClientWrapper, logger: this.logger, }); @@ -292,13 +261,13 @@ export class ElasticSearchSearchEngine implements SearchEngine { indexer.on('error', async e => { this.logger.error(`Failed to index documents for type ${type}`, e); try { - const response = await this.elasticSearchClient.indices.exists({ + const response = await this.elasticSearchClientWrapper.indexExists({ index: indexer.indexName, }); const indexCreated = response.body; if (indexCreated) { this.logger.info(`Removing created index ${indexer.indexName}`); - await this.elasticSearchClient.indices.delete({ + await this.elasticSearchClientWrapper.deleteIndex({ index: indexer.indexName, }); } @@ -319,7 +288,7 @@ export class ElasticSearchSearchEngine implements SearchEngine { ? documentTypes.map(it => this.constructSearchAlias(it)) : this.constructSearchAlias('*'); try { - const result = await this.elasticSearchClient.search({ + const result = await this.elasticSearchClientWrapper.search({ index: queryIndices, body: elasticSearchQuery, }); @@ -361,10 +330,16 @@ export class ElasticSearchSearchEngine implements SearchEngine { nextPageCursor, previousPageCursor, }; - } catch (e) { + } catch (error) { + if (error.meta?.body?.error?.type === 'index_not_found_exception') { + throw new MissingIndexError( + `Missing index for ${queryIndices}. This means there are no documents to search through.`, + error, + ); + } this.logger.error( `Failed to query documents for indices ${queryIndices}`, - e, + error, ); return Promise.reject({ results: [] }); } @@ -398,7 +373,7 @@ export function encodePageCursor({ page }: { page: number }): string { return Buffer.from(`${page}`, 'utf-8').toString('base64'); } -async function createElasticSearchClientOptions( +export async function createElasticSearchClientOptions( config?: Config, ): Promise { if (!config) { diff --git a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngineIndexer.test.ts b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngineIndexer.test.ts index 4e0e8e229f..eff056c3f4 100644 --- a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngineIndexer.test.ts +++ b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngineIndexer.test.ts @@ -16,13 +16,13 @@ import { getVoidLogger } from '@backstage/backend-common'; import { TestPipeline } from '@backstage/plugin-search-backend-node'; -import { Client } from '@elastic/elasticsearch'; import Mock from '@elastic/elasticsearch-mock'; import { range } from 'lodash'; +import { ElasticSearchClientWrapper } from './ElasticSearchClientWrapper'; import { ElasticSearchSearchEngineIndexer } from './ElasticSearchSearchEngineIndexer'; const mock = new Mock(); -const client = new Client({ +const clientWrapper = ElasticSearchClientWrapper.fromClientOptions({ node: 'http://localhost:9200', Connection: mock.getConnection(), }); @@ -43,7 +43,7 @@ describe('ElasticSearchSearchEngineIndexer', () => { indexSeparator: '-index__', alias: 'some-type-index__search', logger: getVoidLogger(), - elasticSearchClient: client, + elasticSearchClientWrapper: clientWrapper, }); // Set up all requisite Elastic mocks. diff --git a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngineIndexer.ts b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngineIndexer.ts index fd16d0c963..87a4472a15 100644 --- a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngineIndexer.ts +++ b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngineIndexer.ts @@ -16,9 +16,9 @@ import { BatchSearchEngineIndexer } from '@backstage/plugin-search-backend-node'; import { IndexableDocument } from '@backstage/plugin-search-common'; -import { Client } from '@elastic/elasticsearch'; import { Readable } from 'stream'; import { Logger } from 'winston'; +import { ElasticSearchClientWrapper } from './ElasticSearchClientWrapper'; /** * Options for instansiate ElasticSearchSearchEngineIndexer @@ -30,7 +30,7 @@ export type ElasticSearchSearchEngineIndexerOptions = { indexSeparator: string; alias: string; logger: Logger; - elasticSearchClient: Client; + elasticSearchClientWrapper: ElasticSearchClientWrapper; }; function duration(startTimestamp: [number, number]): string { @@ -57,7 +57,7 @@ export class ElasticSearchSearchEngineIndexer extends BatchSearchEngineIndexer { private readonly removableAlias: string; private readonly logger: Logger; private readonly sourceStream: Readable; - private readonly elasticSearchClient: Client; + private readonly elasticSearchClientWrapper: ElasticSearchClientWrapper; private bulkResult: Promise; constructor(options: ElasticSearchSearchEngineIndexerOptions) { @@ -70,7 +70,7 @@ export class ElasticSearchSearchEngineIndexer extends BatchSearchEngineIndexer { this.indexName = this.constructIndexName(`${Date.now()}`); this.alias = options.alias; this.removableAlias = `${this.alias}_removable`; - this.elasticSearchClient = options.elasticSearchClient; + this.elasticSearchClientWrapper = options.elasticSearchClientWrapper; // The ES client bulk helper supports stream-based indexing, but we have to // supply the stream directly to it at instantiation-time. We can't supply @@ -83,7 +83,7 @@ export class ElasticSearchSearchEngineIndexer extends BatchSearchEngineIndexer { // Keep a reference to the ES Bulk helper so that we can know when all // documents have been successfully written to ES. - this.bulkResult = this.elasticSearchClient.helpers.bulk({ + this.bulkResult = this.elasticSearchClientWrapper.bulk({ datasource: this.sourceStream, onDocument() { that.processed++; @@ -98,16 +98,15 @@ export class ElasticSearchSearchEngineIndexer extends BatchSearchEngineIndexer { async initialize(): Promise { this.logger.info(`Started indexing documents for index ${this.type}`); - const aliases = await this.elasticSearchClient.cat.aliases({ - format: 'json', - name: [this.alias, this.removableAlias], + const aliases = await this.elasticSearchClientWrapper.getAliases({ + aliases: [this.alias, this.removableAlias], }); this.removableIndices = [ ...new Set(aliases.body.map((r: Record) => r.index)), ] as string[]; - await this.elasticSearchClient.indices.create({ + await this.elasticSearchClientWrapper.createIndex({ index: this.indexName, }); } @@ -140,25 +139,23 @@ export class ElasticSearchSearchEngineIndexer extends BatchSearchEngineIndexer { )}`, result, ); - await this.elasticSearchClient.indices.updateAliases({ - body: { - actions: [ - { - remove: { index: this.constructIndexName('*'), alias: this.alias }, - }, - this.removableIndices.length - ? { - add: { - indices: this.removableIndices, - alias: this.removableAlias, - }, - } - : undefined, - { - add: { index: this.indexName, alias: this.alias }, - }, - ].filter(Boolean), - }, + await this.elasticSearchClientWrapper.updateAliases({ + actions: [ + { + remove: { index: this.constructIndexName('*'), alias: this.alias }, + }, + this.removableIndices.length + ? { + add: { + indices: this.removableIndices, + alias: this.removableAlias, + }, + } + : undefined, + { + add: { index: this.indexName, alias: this.alias }, + }, + ].filter(Boolean), }); // If any indices are removable, remove them. Do not bubble up this error, @@ -166,7 +163,7 @@ export class ElasticSearchSearchEngineIndexer extends BatchSearchEngineIndexer { if (this.removableIndices.length) { this.logger.info('Removing stale search indices', this.removableIndices); try { - await this.elasticSearchClient.indices.delete({ + await this.elasticSearchClientWrapper.deleteIndex({ index: this.removableIndices, }); } catch (e) { diff --git a/plugins/search-backend-module-elasticsearch/src/engines/index.ts b/plugins/search-backend-module-elasticsearch/src/engines/index.ts index 8ac86970a1..8c3b9e3c6d 100644 --- a/plugins/search-backend-module-elasticsearch/src/engines/index.ts +++ b/plugins/search-backend-module-elasticsearch/src/engines/index.ts @@ -15,13 +15,25 @@ */ export { ElasticSearchSearchEngine } from './ElasticSearchSearchEngine'; +export { isOpenSearchCompatible } from './ElasticSearchClientOptions'; export type { + BaseElasticSearchClientOptions, ElasticSearchAgentOptions, ElasticSearchConnectionConstructor, + ElasticSearchElasticSearchClientOptions, ElasticSearchTransportConstructor, ElasticSearchNodeOptions, ElasticSearchAuth, + OpenSearchAuth, + OpenSearchConnectionConstructor, + OpenSearchElasticSearchClientOptions, + OpenSearchNodeOptions, } from './ElasticSearchClientOptions'; +export type { + ElasticSearchAliasAction, + ElasticSearchClientWrapper, + ElasticSearchIndexAction, +} from './ElasticSearchClientWrapper'; export type { ElasticSearchConcreteQuery, ElasticSearchClientOptions, @@ -30,10 +42,12 @@ export type { ElasticSearchQueryTranslator, ElasticSearchQueryTranslatorOptions, ElasticSearchOptions, - ElasticSearchCustomIndexTemplate, - ElasticSearchCustomIndexTemplateBody, } from './ElasticSearchSearchEngine'; export type { ElasticSearchSearchEngineIndexer, ElasticSearchSearchEngineIndexerOptions, } from './ElasticSearchSearchEngineIndexer'; +export type { + ElasticSearchCustomIndexTemplate, + ElasticSearchCustomIndexTemplateBody, +} from './types'; diff --git a/plugins/search-backend-module-elasticsearch/src/engines/types.ts b/plugins/search-backend-module-elasticsearch/src/engines/types.ts new file mode 100644 index 0000000000..a83e8b09b6 --- /dev/null +++ b/plugins/search-backend-module-elasticsearch/src/engines/types.ts @@ -0,0 +1,46 @@ +/* + * 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. + */ + +/** + * Elasticsearch specific index template + * @public + */ +export type ElasticSearchCustomIndexTemplate = { + name: string; + body: ElasticSearchCustomIndexTemplateBody; +}; + +/** + * Elasticsearch specific index template body + * @public + */ +export type ElasticSearchCustomIndexTemplateBody = { + /** + * Array of wildcard (*) expressions used to match the names of data streams and indices during creation. + */ + index_patterns: string[]; + /** + * An ordered list of component template names. + * Component templates are merged in the order specified, + * meaning that the last component template specified has the highest precedence. + */ + composed_of?: string[]; + /** + * See available properties of template + * https://www.elastic.co/guide/en/elasticsearch/reference/7.15/indices-put-template.html#put-index-template-api-request-body + */ + template?: Record; +}; diff --git a/plugins/search-backend-module-elasticsearch/src/index.ts b/plugins/search-backend-module-elasticsearch/src/index.ts index adf7fa43f2..cb4f62098a 100644 --- a/plugins/search-backend-module-elasticsearch/src/index.ts +++ b/plugins/search-backend-module-elasticsearch/src/index.ts @@ -20,13 +20,18 @@ * @packageDocumentation */ -export { ElasticSearchSearchEngine } from './engines'; +export { ElasticSearchSearchEngine, isOpenSearchCompatible } from './engines'; export type { + BaseElasticSearchClientOptions, ElasticSearchAgentOptions, + ElasticSearchAliasAction, + ElasticSearchClientWrapper, ElasticSearchConcreteQuery, ElasticSearchClientOptions, + ElasticSearchElasticSearchClientOptions, ElasticSearchHighlightConfig, ElasticSearchHighlightOptions, + ElasticSearchIndexAction, ElasticSearchQueryTranslator, ElasticSearchQueryTranslatorOptions, ElasticSearchConnectionConstructor, @@ -38,4 +43,8 @@ export type { ElasticSearchSearchEngineIndexerOptions, ElasticSearchCustomIndexTemplate, ElasticSearchCustomIndexTemplateBody, + OpenSearchAuth, + OpenSearchConnectionConstructor, + OpenSearchElasticSearchClientOptions, + OpenSearchNodeOptions, } from './engines'; diff --git a/plugins/search-backend-module-pg/CHANGELOG.md b/plugins/search-backend-module-pg/CHANGELOG.md index fe18f8254b..fdbf4d01e4 100644 --- a/plugins/search-backend-module-pg/CHANGELOG.md +++ b/plugins/search-backend-module-pg/CHANGELOG.md @@ -1,5 +1,34 @@ # @backstage/plugin-search-backend-module-pg +## 0.3.5-next.2 + +### Patch Changes + +- 423e3d8e95: **DEPRECATED**: `PgSearchEngine` static `from` has been deprecated and will be removed in a future release. Use static `fromConfig` method to instantiate. + + Added support for highlighting matched terms in search result data + +- 679b32172e: Updated dependency `knex` to `^2.0.0`. +- Updated dependencies + - @backstage/backend-common@0.14.1-next.2 + +## 0.3.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.1 + - @backstage/plugin-search-backend-node@0.6.3-next.1 + - @backstage/plugin-search-common@0.3.6-next.0 + +## 0.3.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/plugin-search-backend-node@0.6.3-next.0 + ## 0.3.4 ### Patch Changes diff --git a/plugins/search-backend-module-pg/README.md b/plugins/search-backend-module-pg/README.md index d3f98132aa..49804a927c 100644 --- a/plugins/search-backend-module-pg/README.md +++ b/plugins/search-backend-module-pg/README.md @@ -14,3 +14,31 @@ other plugins. See [Backstage documentation](https://backstage.io/docs/features/search/search-engines#postgres) for details on how to setup Postgres based search for your Backstage instance. + +## Optional Configuration + +The following is an example of the optional configuration that can be applied when using Postgres as the search backend. Currently this is mostly for just the highlight feature: + +```yaml +search: + pg: + highlightOptions: + useHighlight: true # Used to enable to disable the highlight feature. The default value is true + maxWord: 35 # Used to set the longest headlines to output. The default value is 35. + minWord: 15 # Used to set the shortest headlines to output. The default value is 15. + shortWord: 3 # Words of this length or less will be dropped at the start and end of a headline, unless they are query terms. The default value of three (3) eliminates common English articles. + highlightAll: false # If true the whole document will be used as the headline, ignoring the preceding three parameters. The default is false. + maxFragments: 0 # Maximum number of text fragments to display. The default value of zero selects a non-fragment-based headline generation method. A value greater than zero selects fragment-based headline generation (see the linked documentation above for more details). + fragmentDelimiter: ' ... ' # Delimiter string used to concatenate fragments. Defaults to " ... ". +``` + +**Note:** the highlight search term feature uses `ts_headline` which has been known to potentially impact performance. You only need this minimal config to disable it should you have issues: + +```yaml +search: + pg: + highlightOptions: + useHighlight: false +``` + +The Postgres documentation on [Highlighting Results](https://www.postgresql.org/docs/current/textsearch-controls.html#TEXTSEARCH-HEADLINE) has more details. diff --git a/plugins/search-backend-module-pg/api-report.md b/plugins/search-backend-module-pg/api-report.md index 71ceac996e..f7a188a14e 100644 --- a/plugins/search-backend-module-pg/api-report.md +++ b/plugins/search-backend-module-pg/api-report.md @@ -4,6 +4,7 @@ ```ts import { BatchSearchEngineIndexer } from '@backstage/plugin-search-backend-node'; +import { Config } from '@backstage/config'; import { IndexableDocument } from '@backstage/plugin-search-common'; import { IndexableResultSet } from '@backstage/plugin-search-common'; import { Knex } from 'knex'; @@ -11,9 +12,7 @@ import { PluginDatabaseManager } from '@backstage/backend-common'; import { SearchEngine } from '@backstage/plugin-search-backend-node'; import { SearchQuery } from '@backstage/plugin-search-common'; -// Warning: (ae-missing-release-tag) "ConcretePgSearchQuery" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) +// @public export type ConcretePgSearchQuery = { pgQuery: PgSearchQuery; pageSize: number; @@ -43,7 +42,7 @@ export class DatabaseDocumentStore implements DatabaseStore { // (undocumented) query( tx: Knex.Transaction, - { types, pgTerm, fields, offset, limit }: PgSearchQuery, + searchQuery: PgSearchQuery, ): Promise; // (undocumented) static supported(knex: Knex): Promise; @@ -80,23 +79,31 @@ export interface DatabaseStore { // // @public (undocumented) export class PgSearchEngine implements SearchEngine { - constructor(databaseStore: DatabaseStore); - // (undocumented) + // @deprecated + constructor(databaseStore: DatabaseStore, config: Config); + // @deprecated (undocumented) static from(options: { database: PluginDatabaseManager; + config: Config; }): Promise; // (undocumented) + static fromConfig( + config: Config, + options: PgSearchOptions, + ): Promise; + // (undocumented) getIndexer(type: string): Promise; // (undocumented) query(query: SearchQuery): Promise; // (undocumented) - setTranslator( - translator: (query: SearchQuery) => ConcretePgSearchQuery, - ): void; + setTranslator(translator: PgSearchQueryTranslator): void; // (undocumented) static supported(database: PluginDatabaseManager): Promise; // (undocumented) - translator(query: SearchQuery): ConcretePgSearchQuery; + translator( + query: SearchQuery, + options: PgSearchQueryTranslatorOptions, + ): ConcretePgSearchQuery; } // Warning: (ae-missing-release-tag) "PgSearchEngineIndexer" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -121,6 +128,24 @@ export type PgSearchEngineIndexerOptions = { databaseStore: DatabaseStore; }; +// @public +export type PgSearchHighlightOptions = { + useHighlight?: boolean; + maxWords?: number; + minWords?: number; + shortWord?: number; + highlightAll?: boolean; + maxFragments?: number; + fragmentDelimiter?: string; + preTag: string; + postTag: string; +}; + +// @public +export type PgSearchOptions = { + database: PluginDatabaseManager; +}; + // Warning: (ae-missing-release-tag) "PgSearchQuery" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -132,11 +157,24 @@ export interface PgSearchQuery { // (undocumented) offset: number; // (undocumented) + options: PgSearchHighlightOptions; + // (undocumented) pgTerm?: string; // (undocumented) types?: string[]; } +// @public +export type PgSearchQueryTranslator = ( + query: SearchQuery, + options: PgSearchQueryTranslatorOptions, +) => ConcretePgSearchQuery; + +// @public +export type PgSearchQueryTranslatorOptions = { + highlightOptions: PgSearchHighlightOptions; +}; + // Warning: (ae-missing-release-tag) "RawDocumentRow" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) diff --git a/plugins/search-backend-module-pg/config.d.ts b/plugins/search-backend-module-pg/config.d.ts new file mode 100644 index 0000000000..7367b770bc --- /dev/null +++ b/plugins/search-backend-module-pg/config.d.ts @@ -0,0 +1,62 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface Config { + /** Configuration options for the search plugin */ + search?: { + /** + * Options for PG + */ + pg?: { + /** + * Options for configuring highlight settings + * See https://www.postgresql.org/docs/current/textsearch-controls.html#TEXTSEARCH-HEADLINE + */ + highlightOptions?: { + /** + * Used to enable to disable the highlight feature. The default value is true + */ + useHighlight?: boolean; + /** + * Used to set the longest headlines to output. The default value is 35. + */ + maxWords?: number; + /** + * Used to set the shortest headlines to output. The default value is 15. + */ + minWords?: number; + /** + * Words of this length or less will be dropped at the start and end of a headline, unless they are query terms. + * The default value of three (3) eliminates common English articles. + */ + shortWord?: number; + /** + * If true the whole document will be used as the headline, ignoring the preceding three parameters. The default is false. + */ + highlightAll?: boolean; + /** + * Maximum number of text fragments to display. The default value of zero selects a non-fragment-based headline generation method. + * A value greater than zero selects fragment-based headline generation (see the linked documentation above for more details). + */ + maxFragments?: number; + /** + * Delimiter string used to concatenate fragments. Defaults to " ... ". + */ + fragmentDelimiter?: string; + }; + }; + }; +} diff --git a/plugins/search-backend-module-pg/package.json b/plugins/search-backend-module-pg/package.json index b34d2c65b8..9e58859449 100644 --- a/plugins/search-backend-module-pg/package.json +++ b/plugins/search-backend-module-pg/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search-backend-module-pg", "description": "A module for the search backend that implements search using PostgreSQL", - "version": "0.3.4", + "version": "0.3.5-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,18 +23,22 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", - "@backstage/plugin-search-backend-node": "^0.6.2", - "@backstage/plugin-search-common": "^0.3.5", + "@backstage/backend-common": "^0.14.1-next.2", + "@backstage/config": "^1.0.1", + "@backstage/plugin-search-backend-node": "^0.6.3-next.1", + "@backstage/plugin-search-common": "^0.3.6-next.0", "lodash": "^4.17.21", - "knex": "^1.0.2" + "knex": "^2.0.0", + "uuid": "^8.3.2" }, "devDependencies": { - "@backstage/backend-test-utils": "^0.1.25", - "@backstage/cli": "^0.17.2" + "@backstage/backend-test-utils": "^0.1.26-next.2", + "@backstage/cli": "^0.18.0-next.2" }, "files": [ "dist", - "migrations" - ] + "migrations", + "config.d.ts" + ], + "configSchema": "config.d.ts" } diff --git a/plugins/search-backend-module-pg/src/PgSearchEngine/PgSearchEngine.test.ts b/plugins/search-backend-module-pg/src/PgSearchEngine/PgSearchEngine.test.ts index 3ed002567e..23f8983074 100644 --- a/plugins/search-backend-module-pg/src/PgSearchEngine/PgSearchEngine.test.ts +++ b/plugins/search-backend-module-pg/src/PgSearchEngine/PgSearchEngine.test.ts @@ -13,15 +13,31 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { ConfigReader } from '@backstage/config'; import { DatabaseStore } from '../database'; import { ConcretePgSearchQuery, decodePageCursor, encodePageCursor, PgSearchEngine, + PgSearchHighlightOptions, } from './PgSearchEngine'; import { PgSearchEngineIndexer } from './PgSearchEngineIndexer'; +const highlightOptions: PgSearchHighlightOptions = { + preTag: '', + postTag: '', + useHighlight: true, + maxWords: 35, + minWords: 15, + shortWord: 3, + highlightAll: false, + maxFragments: 0, + fragmentDelimiter: ' ... ', +}; + +jest.mock('uuid', () => ({ v4: () => 'tag' })); + jest.mock('./PgSearchEngineIndexer', () => ({ PgSearchEngineIndexer: jest .fn() @@ -32,6 +48,13 @@ describe('PgSearchEngine', () => { const tx: any = {} as any; let searchEngine: PgSearchEngine; let database: jest.Mocked; + const config = { + search: { + pg: { + highlightOptions, + }, + }, + }; beforeEach(() => { database = { @@ -42,7 +65,7 @@ describe('PgSearchEngine', () => { completeInsert: jest.fn(), prepareInsert: jest.fn(), }; - searchEngine = new PgSearchEngine(database); + searchEngine = new PgSearchEngine(database, new ConfigReader(config)); }); describe('translator', () => { @@ -58,17 +81,23 @@ describe('PgSearchEngine', () => { filters: {}, }); - expect(translatorSpy).toHaveBeenCalledWith({ - term: 'testTerm', - filters: {}, - }); + expect(translatorSpy).toHaveBeenCalledWith( + { + term: 'testTerm', + filters: {}, + }, + { highlightOptions }, + ); }); it('should pass page cursor', async () => { - const actualTranslatedQuery = searchEngine.translator({ - term: 'Hello', - pageCursor: 'MQ==', - }); + const actualTranslatedQuery = searchEngine.translator( + { + term: 'Hello', + pageCursor: 'MQ==', + }, + { highlightOptions }, + ); expect(actualTranslatedQuery).toMatchObject({ pgQuery: { @@ -81,9 +110,12 @@ describe('PgSearchEngine', () => { }); it('should return translated query term', async () => { - const actualTranslatedQuery = searchEngine.translator({ - term: 'Hello World', - }); + const actualTranslatedQuery = searchEngine.translator( + { + term: 'Hello World', + }, + { highlightOptions }, + ); expect(actualTranslatedQuery).toMatchObject({ pgQuery: { @@ -96,10 +128,13 @@ describe('PgSearchEngine', () => { }); it('should sanitize query term', async () => { - const actualTranslatedQuery = searchEngine.translator({ - term: 'H&e|l!l*o W\0o(r)l:d', - pageCursor: '', - }) as ConcretePgSearchQuery; + const actualTranslatedQuery = searchEngine.translator( + { + term: 'H&e|l!l*o W\0o(r)l:d', + pageCursor: '', + }, + { highlightOptions }, + ) as ConcretePgSearchQuery; expect(actualTranslatedQuery).toMatchObject({ pgQuery: { @@ -110,11 +145,14 @@ describe('PgSearchEngine', () => { }); it('should return translated query with filters', async () => { - const actualTranslatedQuery = searchEngine.translator({ - term: 'testTerm', - filters: { kind: 'testKind' }, - types: ['my-filter'], - }); + const actualTranslatedQuery = searchEngine.translator( + { + term: 'testTerm', + filters: { kind: 'testKind' }, + types: ['my-filter'], + }, + { highlightOptions }, + ); expect(actualTranslatedQuery).toMatchObject({ pgQuery: { @@ -158,6 +196,11 @@ describe('PgSearchEngine', () => { location: 'location-1', }, type: 'my-type', + highlight: { + title: 'Hello World', + text: 'Lorem Ipsum', + location: 'location-1', + }, }, ]); @@ -175,6 +218,16 @@ describe('PgSearchEngine', () => { }, type: 'my-type', rank: 1, + highlight: { + preTag: '', + postTag: '', + fields: { + title: 'Hello World', + text: 'Lorem Ipsum', + location: 'location-1', + path: '', + }, + }, }, ], nextPageCursor: undefined, @@ -184,6 +237,7 @@ describe('PgSearchEngine', () => { pgTerm: '("Hello" | "Hello":*)&("World" | "World":*)', offset: 0, limit: 26, + options: highlightOptions, }); }); @@ -199,6 +253,11 @@ describe('PgSearchEngine', () => { location: `location-${i}`, }, type: 'my-type', + highlight: { + title: 'Hello World', + text: 'Lorem Ipsum', + location: 'location-1', + }, })), ); @@ -217,6 +276,16 @@ describe('PgSearchEngine', () => { }, type: 'my-type', rank: i + 1, + highlight: { + preTag: '', + postTag: '', + fields: { + title: 'Hello World', + text: 'Lorem Ipsum', + location: 'location-1', + path: '', + }, + }, })), nextPageCursor: 'MQ==', }); @@ -225,6 +294,7 @@ describe('PgSearchEngine', () => { pgTerm: '("Hello" | "Hello":*)&("World" | "World":*)', offset: 0, limit: 26, + options: highlightOptions, }); }); @@ -240,6 +310,11 @@ describe('PgSearchEngine', () => { location: `location-${i}`, }, type: 'my-type', + highlight: { + title: 'Hello World', + text: 'Lorem Ipsum', + location: 'location-1', + }, })) .slice(25), ); @@ -260,6 +335,16 @@ describe('PgSearchEngine', () => { }, type: 'my-type', rank: i + 1, + highlight: { + preTag: '', + postTag: '', + fields: { + title: 'Hello World', + text: 'Lorem Ipsum', + location: 'location-1', + path: '', + }, + }, })) .slice(25), previousPageCursor: 'MA==', @@ -269,6 +354,7 @@ describe('PgSearchEngine', () => { pgTerm: '("Hello" | "Hello":*)&("World" | "World":*)', offset: 25, limit: 26, + options: highlightOptions, }); }); }); diff --git a/plugins/search-backend-module-pg/src/PgSearchEngine/PgSearchEngine.ts b/plugins/search-backend-module-pg/src/PgSearchEngine/PgSearchEngine.ts index bf98c58de9..abf7cdbf5c 100644 --- a/plugins/search-backend-module-pg/src/PgSearchEngine/PgSearchEngine.ts +++ b/plugins/search-backend-module-pg/src/PgSearchEngine/PgSearchEngine.ts @@ -26,20 +26,104 @@ import { DatabaseStore, PgSearchQuery, } from '../database'; +import { v4 as uuid } from 'uuid'; +import { Config } from '@backstage/config'; +/** + * Search query that the Postgres search engine understands. + * @public + */ export type ConcretePgSearchQuery = { pgQuery: PgSearchQuery; pageSize: number; }; -export class PgSearchEngine implements SearchEngine { - constructor(private readonly databaseStore: DatabaseStore) {} +/** + * Options available for the Postgres specific query translator. + * @public + */ +export type PgSearchQueryTranslatorOptions = { + highlightOptions: PgSearchHighlightOptions; +}; +/** + * Postgres specific query translator. + * @public + */ +export type PgSearchQueryTranslator = ( + query: SearchQuery, + options: PgSearchQueryTranslatorOptions, +) => ConcretePgSearchQuery; + +/** + * Options to instantiate PgSearchEngine + * @public + */ +export type PgSearchOptions = { + database: PluginDatabaseManager; +}; + +/** + * Options for highlighting search terms + * @public + */ +export type PgSearchHighlightOptions = { + useHighlight?: boolean; + maxWords?: number; + minWords?: number; + shortWord?: number; + highlightAll?: boolean; + maxFragments?: number; + fragmentDelimiter?: string; + preTag: string; + postTag: string; +}; + +export class PgSearchEngine implements SearchEngine { + private readonly highlightOptions: PgSearchHighlightOptions; + + /** + * @deprecated This will be marked as private in a future release, please us fromConfig instead + */ + constructor(private readonly databaseStore: DatabaseStore, config: Config) { + const uuidTag = uuid(); + const highlightConfig = config.getOptionalConfig( + 'search.pg.highlightOptions', + ); + + const highlightOptions: PgSearchHighlightOptions = { + preTag: `<${uuidTag}>`, + postTag: ``, + useHighlight: highlightConfig?.getOptionalBoolean('useHighlight') ?? true, + maxWords: highlightConfig?.getOptionalNumber('maxWords') ?? 35, + minWords: highlightConfig?.getOptionalNumber('minWords') ?? 15, + shortWord: highlightConfig?.getOptionalNumber('shortWord') ?? 3, + highlightAll: + highlightConfig?.getOptionalBoolean('highlightAll') ?? false, + maxFragments: highlightConfig?.getOptionalNumber('maxFragments') ?? 0, + fragmentDelimiter: + highlightConfig?.getOptionalString('fragmentDelimiter') ?? ' ... ', + }; + this.highlightOptions = highlightOptions; + } + + /** + * @deprecated This will be removed in a future release, please us fromConfig instead + */ static async from(options: { database: PluginDatabaseManager; + config: Config; }): Promise { return new PgSearchEngine( await DatabaseDocumentStore.create(await options.database.getClient()), + options.config, + ); + } + + static async fromConfig(config: Config, options: PgSearchOptions) { + return new PgSearchEngine( + await DatabaseDocumentStore.create(await options.database.getClient()), + config, ); } @@ -47,7 +131,10 @@ export class PgSearchEngine implements SearchEngine { return await DatabaseDocumentStore.supported(await database.getClient()); } - translator(query: SearchQuery): ConcretePgSearchQuery { + translator( + query: SearchQuery, + options: PgSearchQueryTranslatorOptions, + ): ConcretePgSearchQuery { const pageSize = 25; const { page } = decodePageCursor(query.pageCursor); const offset = page * pageSize; @@ -66,14 +153,13 @@ export class PgSearchEngine implements SearchEngine { types: query.types, offset, limit, + options: options.highlightOptions, }, pageSize, }; } - setTranslator( - translator: (query: SearchQuery) => ConcretePgSearchQuery, - ): void { + setTranslator(translator: PgSearchQueryTranslator) { this.translator = translator; } @@ -86,7 +172,9 @@ export class PgSearchEngine implements SearchEngine { } async query(query: SearchQuery): Promise { - const { pgQuery, pageSize } = this.translator(query); + const { pgQuery, pageSize } = this.translator(query, { + highlightOptions: this.highlightOptions, + }); const rows = await this.databaseStore.transaction(async tx => this.databaseStore.query(tx, pgQuery), @@ -106,10 +194,22 @@ export class PgSearchEngine implements SearchEngine { : undefined; const results = pageRows.map( - ({ type, document }, index): IndexableResult => ({ + ({ type, document, highlight }, index): IndexableResult => ({ type, document, rank: page * pageSize + index + 1, + highlight: { + preTag: pgQuery.options.preTag, + postTag: pgQuery.options.postTag, + fields: highlight + ? { + text: highlight.text, + title: highlight.title, + location: highlight.location, + path: '', + } + : {}, + }, }), ); diff --git a/plugins/search-backend-module-pg/src/PgSearchEngine/index.ts b/plugins/search-backend-module-pg/src/PgSearchEngine/index.ts index 7f8e297648..e9ea04e5c4 100644 --- a/plugins/search-backend-module-pg/src/PgSearchEngine/index.ts +++ b/plugins/search-backend-module-pg/src/PgSearchEngine/index.ts @@ -14,7 +14,13 @@ * limitations under the License. */ export { PgSearchEngine } from './PgSearchEngine'; -export type { ConcretePgSearchQuery } from './PgSearchEngine'; +export type { + ConcretePgSearchQuery, + PgSearchQueryTranslatorOptions, + PgSearchQueryTranslator, + PgSearchOptions, + PgSearchHighlightOptions, +} from './PgSearchEngine'; export type { PgSearchEngineIndexer, PgSearchEngineIndexerOptions, diff --git a/plugins/search-backend-module-pg/src/database/DatabaseDocumentStore.test.ts b/plugins/search-backend-module-pg/src/database/DatabaseDocumentStore.test.ts index b973c2e14f..355e41352d 100644 --- a/plugins/search-backend-module-pg/src/database/DatabaseDocumentStore.test.ts +++ b/plugins/search-backend-module-pg/src/database/DatabaseDocumentStore.test.ts @@ -15,8 +15,21 @@ */ import { TestDatabaseId, TestDatabases } from '@backstage/backend-test-utils'; import { IndexableDocument } from '@backstage/plugin-search-common'; +import { PgSearchHighlightOptions } from '../PgSearchEngine'; import { DatabaseDocumentStore } from './DatabaseDocumentStore'; +const highlightOptions: PgSearchHighlightOptions = { + preTag: '', + postTag: '', + useHighlight: false, + maxWords: 35, + minWords: 15, + shortWord: 3, + highlightAll: false, + maxFragments: 0, + fragmentDelimiter: ' ... ', +}; + describe('DatabaseDocumentStore', () => { describe('unsupported', () => { const databases = TestDatabases.create({ @@ -220,7 +233,12 @@ describe('DatabaseDocumentStore', () => { }); const rows = await store.transaction(tx => - store.query(tx, { pgTerm: 'Hello & World', offset: 1, limit: 1 }), + store.query(tx, { + pgTerm: 'Hello & World', + offset: 1, + limit: 1, + options: highlightOptions, + }), ); expect(rows).toEqual([ @@ -261,7 +279,12 @@ describe('DatabaseDocumentStore', () => { }); const rows = await store.transaction(tx => - store.query(tx, { pgTerm: 'Hello & World', offset: 0, limit: 25 }), + store.query(tx, { + pgTerm: 'Hello & World', + offset: 0, + limit: 25, + options: highlightOptions, + }), ); expect(rows).toEqual([ @@ -322,6 +345,7 @@ describe('DatabaseDocumentStore', () => { types: ['my-type'], offset: 0, limit: 25, + options: highlightOptions, }), ); @@ -375,6 +399,7 @@ describe('DatabaseDocumentStore', () => { fields: { myField: 'this' }, offset: 0, limit: 25, + options: highlightOptions, }), ); @@ -429,6 +454,7 @@ describe('DatabaseDocumentStore', () => { fields: { myField: ['this', 'that'] }, offset: 0, limit: 25, + options: highlightOptions, }), ); @@ -490,6 +516,7 @@ describe('DatabaseDocumentStore', () => { fields: { myField: 'this', otherField: 'another' }, offset: 0, limit: 25, + options: highlightOptions, }), ); @@ -539,6 +566,7 @@ describe('DatabaseDocumentStore', () => { fields: { myField: 'this' }, offset: 0, limit: 25, + options: highlightOptions, }), ); diff --git a/plugins/search-backend-module-pg/src/database/DatabaseDocumentStore.ts b/plugins/search-backend-module-pg/src/database/DatabaseDocumentStore.ts index 33b2d0c0d6..8e73c0f16f 100644 --- a/plugins/search-backend-module-pg/src/database/DatabaseDocumentStore.ts +++ b/plugins/search-backend-module-pg/src/database/DatabaseDocumentStore.ts @@ -132,10 +132,13 @@ export class DatabaseDocumentStore implements DatabaseStore { async query( tx: Knex.Transaction, - { types, pgTerm, fields, offset, limit }: PgSearchQuery, + searchQuery: PgSearchQuery, ): Promise { + const { types, pgTerm, fields, offset, limit, options } = searchQuery; + // TODO(awanlin): We should make the language a parameter so that we can support more then just english // Builds a query like: - // SELECT ts_rank_cd(body, query) AS rank, type, document + // SELECT ts_rank_cd(body, query) AS rank, type, document, + // ts_headline('english', document, query) AS highlight // FROM documents, to_tsquery('english', 'consent') query // WHERE query @@ body AND (document @> '{"kind": "API"}') // ORDER BY rank DESC @@ -170,7 +173,17 @@ export class DatabaseDocumentStore implements DatabaseStore { query.select('type', 'document'); - if (pgTerm) { + if (pgTerm && options.useHighlight) { + const headlineOptions = `MaxWords=${options.maxWords}, MinWords=${options.minWords}, ShortWord=${options.shortWord}, HighlightAll=${options.highlightAll}, MaxFragments=${options.maxFragments}, FragmentDelimiter=${options.fragmentDelimiter}, StartSel=${options.preTag}, StopSel=${options.postTag}`; + query + .select(tx.raw('ts_rank_cd(body, query) AS "rank"')) + .select( + tx.raw( + `ts_headline(\'english\', document, query, '${headlineOptions}') as "highlight"`, + ), + ) + .orderBy('rank', 'desc'); + } else if (pgTerm && !options.useHighlight) { query .select(tx.raw('ts_rank_cd(body, query) AS "rank"')) .orderBy('rank', 'desc'); diff --git a/plugins/search-backend-module-pg/src/database/types.ts b/plugins/search-backend-module-pg/src/database/types.ts index 7e87658745..151be7d13f 100644 --- a/plugins/search-backend-module-pg/src/database/types.ts +++ b/plugins/search-backend-module-pg/src/database/types.ts @@ -15,6 +15,7 @@ */ import { IndexableDocument } from '@backstage/plugin-search-common'; import { Knex } from 'knex'; +import { PgSearchHighlightOptions } from '../PgSearchEngine'; export interface PgSearchQuery { fields?: Record; @@ -22,6 +23,7 @@ export interface PgSearchQuery { pgTerm?: string; offset: number; limit: number; + options: PgSearchHighlightOptions; } export interface DatabaseStore { @@ -49,4 +51,5 @@ export interface RawDocumentRow { export interface DocumentResultRow { document: IndexableDocument; type: string; + highlight: IndexableDocument; } diff --git a/plugins/search-backend-node/CHANGELOG.md b/plugins/search-backend-node/CHANGELOG.md index 82f83436cd..d1b631fd53 100644 --- a/plugins/search-backend-node/CHANGELOG.md +++ b/plugins/search-backend-node/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/plugin-search-backend-node +## 0.6.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/backend-tasks@0.3.3-next.1 + - @backstage/plugin-permission-common@0.6.3-next.0 + - @backstage/plugin-search-common@0.3.6-next.0 + +## 0.6.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/backend-tasks@0.3.3-next.0 + ## 0.6.2 ### Patch Changes diff --git a/plugins/search-backend-node/api-report.md b/plugins/search-backend-node/api-report.md index 7649bc5d0f..ff9480c19d 100644 --- a/plugins/search-backend-node/api-report.md +++ b/plugins/search-backend-node/api-report.md @@ -113,6 +113,12 @@ export class LunrSearchEngineIndexer extends BatchSearchEngineIndexer { initialize(): Promise; } +// @public +export class MissingIndexError extends Error { + constructor(message?: string, cause?: Error | unknown); + readonly cause?: Error | undefined; +} + // @public export class NewlineDelimitedJsonCollatorFactory implements DocumentCollatorFactory diff --git a/plugins/search-backend-node/package.json b/plugins/search-backend-node/package.json index 3ebfb8782f..47d613c160 100644 --- a/plugins/search-backend-node/package.json +++ b/plugins/search-backend-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search-backend-node", "description": "A library for Backstage backend plugins that want to interact with the search backend plugin", - "version": "0.6.2", + "version": "0.6.3-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,12 +23,12 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", - "@backstage/backend-tasks": "^0.3.2", + "@backstage/backend-common": "^0.14.1-next.1", + "@backstage/backend-tasks": "^0.3.3-next.1", "@backstage/config": "^1.0.1", - "@backstage/errors": "^1.0.0", - "@backstage/plugin-permission-common": "^0.6.2", - "@backstage/plugin-search-common": "^0.3.5", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/plugin-permission-common": "^0.6.3-next.0", + "@backstage/plugin-search-common": "^0.3.6-next.0", "@types/lunr": "^2.3.3", "lodash": "^4.17.21", "lunr": "^2.3.9", @@ -38,8 +38,8 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/backend-common": "^0.14.0", - "@backstage/cli": "^0.17.2", + "@backstage/backend-common": "^0.14.1-next.1", + "@backstage/cli": "^0.18.0-next.1", "@types/ndjson": "^2.0.1" }, "files": [ diff --git a/plugins/search-backend-node/src/engines/LunrSearchEngine.test.ts b/plugins/search-backend-node/src/engines/LunrSearchEngine.test.ts index 098d1e8b16..1f69460448 100644 --- a/plugins/search-backend-node/src/engines/LunrSearchEngine.test.ts +++ b/plugins/search-backend-node/src/engines/LunrSearchEngine.test.ts @@ -949,6 +949,19 @@ describe('LunrSearchEngine', () => { previousPageCursor: undefined, }); }); + + it('should throws missing index error', async () => { + await expect( + async () => + await testLunrSearchEngine.query({ + term: 'testTerm', + types: ['unknown'], + filters: {}, + }), + ).rejects.toThrow( + "Missing index for unknown. This could be because the index hasn't been created yet or there was a problem during index creation.", + ); + }); }); it('should return previous page cursor if on another page', async () => { diff --git a/plugins/search-backend-node/src/engines/LunrSearchEngine.ts b/plugins/search-backend-node/src/engines/LunrSearchEngine.ts index 03cb421653..ec8550d721 100644 --- a/plugins/search-backend-node/src/engines/LunrSearchEngine.ts +++ b/plugins/search-backend-node/src/engines/LunrSearchEngine.ts @@ -21,6 +21,7 @@ import { QueryTranslator, SearchEngine, } from '@backstage/plugin-search-common'; +import { MissingIndexError } from '../errors'; import lunr from 'lunr'; import { v4 as uuid } from 'uuid'; import { Logger } from 'winston'; @@ -163,30 +164,38 @@ export class LunrSearchEngine implements SearchEngine { const results: LunrResultEnvelope[] = []; + const indexKeys = Object.keys(this.lunrIndices).filter( + type => !documentTypes || documentTypes.includes(type), + ); + + if (documentTypes?.length && !indexKeys.length) { + throw new MissingIndexError( + `Missing index for ${documentTypes?.toString()}. This could be because the index hasn't been created yet or there was a problem during index creation.`, + ); + } + // Iterate over the filtered list of this.lunrIndex keys. - Object.keys(this.lunrIndices) - .filter(type => !documentTypes || documentTypes.includes(type)) - .forEach(type => { - try { - results.push( - ...this.lunrIndices[type].query(lunrQueryBuilder).map(result => { - return { - result: result, - type: type, - }; - }), - ); - } catch (err) { - // if a field does not exist on a index, we can see that as a no-match - if ( - err instanceof Error && - err.message.startsWith('unrecognised field') - ) { - return; - } - throw err; + indexKeys.forEach(type => { + try { + results.push( + ...this.lunrIndices[type].query(lunrQueryBuilder).map(result => { + return { + result: result, + type: type, + }; + }), + ); + } catch (err) { + // if a field does not exist on a index, we can see that as a no-match + if ( + err instanceof Error && + err.message.startsWith('unrecognised field') + ) { + return; } - }); + throw err; + } + }); // Sort results. results.sort((doc1, doc2) => { diff --git a/plugins/auth-backend/src/lib/catalog/helpers.ts b/plugins/search-backend-node/src/errors.ts similarity index 51% rename from plugins/auth-backend/src/lib/catalog/helpers.ts rename to plugins/search-backend-node/src/errors.ts index 3ff1b5da05..00b168d460 100644 --- a/plugins/auth-backend/src/lib/catalog/helpers.ts +++ b/plugins/search-backend-node/src/errors.ts @@ -14,28 +14,24 @@ * limitations under the License. */ -import { - RELATION_MEMBER_OF, - stringifyEntityRef, - UserEntity, -} from '@backstage/catalog-model'; -import { TokenParams } from '../../identity'; +import { isError } from '@backstage/errors'; /** - * @deprecated use {@link getDefaultOwnershipEntityRefs} instead + * Failed to query documents for index that does not exist. + * @public */ -export function getEntityClaims(entity: UserEntity): TokenParams['claims'] { - const userRef = stringifyEntityRef(entity); +export class MissingIndexError extends Error { + /** + * An inner error that caused this error to be thrown, if any. + */ + readonly cause?: Error | undefined; - const membershipRefs = - entity.relations - ?.filter( - r => r.type === RELATION_MEMBER_OF && r.targetRef.startsWith('group:'), - ) - .map(r => r.targetRef) ?? []; + constructor(message?: string, cause?: Error | unknown) { + super(message); - return { - sub: userRef, - ent: [userRef, ...membershipRefs], - }; + Error.captureStackTrace?.(this, this.constructor); + + this.name = this.constructor.name; + this.cause = isError(cause) ? cause : undefined; + } } diff --git a/plugins/search-backend-node/src/index.ts b/plugins/search-backend-node/src/index.ts index d342bb9259..854881829c 100644 --- a/plugins/search-backend-node/src/index.ts +++ b/plugins/search-backend-node/src/index.ts @@ -34,6 +34,7 @@ export type { RegisterCollatorParameters, RegisterDecoratorParameters, } from './types'; +export * from './errors'; export * from './indexing'; export * from './test-utils'; diff --git a/plugins/search-backend/CHANGELOG.md b/plugins/search-backend/CHANGELOG.md index e214d6bb16..c779dbef3a 100644 --- a/plugins/search-backend/CHANGELOG.md +++ b/plugins/search-backend/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-search-backend +## 0.5.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/plugin-auth-node@0.2.3-next.1 + - @backstage/plugin-permission-common@0.6.3-next.0 + - @backstage/plugin-permission-node@0.6.3-next.1 + - @backstage/plugin-search-backend-node@0.6.3-next.1 + - @backstage/plugin-search-common@0.3.6-next.0 + +## 0.5.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/plugin-auth-node@0.2.3-next.0 + - @backstage/plugin-permission-node@0.6.3-next.0 + - @backstage/plugin-search-backend-node@0.6.3-next.0 + ## 0.5.3 ### Patch Changes diff --git a/plugins/search-backend/package.json b/plugins/search-backend/package.json index 6daa65bcb4..3e2e429b5a 100644 --- a/plugins/search-backend/package.json +++ b/plugins/search-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search-backend", "description": "The Backstage backend plugin that provides your backstage app with search", - "version": "0.5.3", + "version": "0.5.4-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,14 +23,14 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", + "@backstage/backend-common": "^0.14.1-next.1", "@backstage/config": "^1.0.1", - "@backstage/errors": "^1.0.0", - "@backstage/plugin-auth-node": "^0.2.2", - "@backstage/plugin-permission-common": "^0.6.2", - "@backstage/plugin-permission-node": "^0.6.2", - "@backstage/plugin-search-backend-node": "^0.6.2", - "@backstage/plugin-search-common": "^0.3.5", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/plugin-auth-node": "^0.2.3-next.1", + "@backstage/plugin-permission-common": "^0.6.3-next.0", + "@backstage/plugin-permission-node": "^0.6.3-next.1", + "@backstage/plugin-search-backend-node": "^0.6.3-next.1", + "@backstage/plugin-search-common": "^0.3.6-next.0", "@backstage/types": "^1.0.0", "@types/express": "^4.17.6", "dataloader": "^2.0.0", @@ -43,7 +43,7 @@ "zod": "^3.11.6" }, "devDependencies": { - "@backstage/cli": "^0.17.2", + "@backstage/cli": "^0.18.0-next.1", "@types/supertest": "^2.0.8", "supertest": "^6.1.3" }, diff --git a/plugins/search-backend/src/service/router.ts b/plugins/search-backend/src/service/router.ts index f54c2d388f..e4ac233406 100644 --- a/plugins/search-backend/src/service/router.ts +++ b/plugins/search-backend/src/service/router.ts @@ -19,7 +19,7 @@ import Router from 'express-promise-router'; import { Logger } from 'winston'; import { z } from 'zod'; import { errorHandler } from '@backstage/backend-common'; -import { InputError } from '@backstage/errors'; +import { ErrorResponseBody, InputError } from '@backstage/errors'; import { Config } from '@backstage/config'; import { JsonObject, JsonValue } from '@backstage/types'; import { getBearerTokenFromAuthorizationHeader } from '@backstage/plugin-auth-node'; @@ -129,7 +129,10 @@ export async function createRouter( const router = Router(); router.get( '/query', - async (req: express.Request, res: express.Response) => { + async ( + req: express.Request, + res: express.Response, + ) => { const parseResult = requestSchema.safeParse(req.query); if (!parseResult.success) { @@ -154,9 +157,14 @@ export async function createRouter( const resultSet = await engine?.query(query, { token }); res.send(filterResultSet(toSearchResults(resultSet))); - } catch (err) { + } catch (error) { + if (error.name === 'MissingIndexError') { + // re-throw and let the default error handler middleware captures it and serializes it with the right response code on the standard form + throw error; + } + throw new Error( - `There was a problem performing the search query. ${err}`, + `There was a problem performing the search query. ${error}`, ); } }, diff --git a/plugins/search-common/CHANGELOG.md b/plugins/search-common/CHANGELOG.md index 53a8afb0bf..3623d21e93 100644 --- a/plugins/search-common/CHANGELOG.md +++ b/plugins/search-common/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-search-common +## 0.3.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.6.3-next.0 + ## 0.3.5 ### Patch Changes diff --git a/plugins/search-common/package.json b/plugins/search-common/package.json index ae4c65d11e..65152206e2 100644 --- a/plugins/search-common/package.json +++ b/plugins/search-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search-common", "description": "Common functionalities for Search, to be shared between various search-enabled plugins", - "version": "0.3.5", + "version": "0.3.6-next.0", "main": "src/index.ts", "types": "src/index.ts", "private": false, @@ -40,10 +40,10 @@ }, "dependencies": { "@backstage/types": "^1.0.0", - "@backstage/plugin-permission-common": "^0.6.2" + "@backstage/plugin-permission-common": "^0.6.3-next.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2" + "@backstage/cli": "^0.18.0-next.1" }, "jest": { "roots": [ diff --git a/plugins/search-react/CHANGELOG.md b/plugins/search-react/CHANGELOG.md index 5f38994eeb..685aa56a86 100644 --- a/plugins/search-react/CHANGELOG.md +++ b/plugins/search-react/CHANGELOG.md @@ -1,5 +1,30 @@ # @backstage/plugin-search-react +## 0.2.2-next.2 + +### Patch Changes + +- 60408ca9d4: Fix search pagination to reset page cursor also when a term is cleared. +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + +## 0.2.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-search-common@0.3.6-next.0 + +## 0.2.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + ## 0.2.1 ### Patch Changes diff --git a/plugins/search-react/package.json b/plugins/search-react/package.json index c0914e6409..3e3b362919 100644 --- a/plugins/search-react/package.json +++ b/plugins/search-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-react", - "version": "0.2.1", + "version": "0.2.2-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,11 +31,11 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/plugin-search-common": "^0.3.5", - "@backstage/core-components": "^0.9.5", + "@backstage/plugin-search-common": "^0.3.6-next.0", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", "@backstage/version-bridge": "^1.0.1", - "@backstage/theme": "^0.2.15", + "@backstage/theme": "^0.2.16-next.1", "@backstage/types": "^1.0.0", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -48,8 +48,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/core-app-api": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/react": "^12.1.3", "@testing-library/react-hooks": "^8.0.0", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/search-react/src/components/SearchBar/SearchBar.test.tsx b/plugins/search-react/src/components/SearchBar/SearchBar.test.tsx index d65278f7ec..fba50f74d8 100644 --- a/plugins/search-react/src/components/SearchBar/SearchBar.test.tsx +++ b/plugins/search-react/src/components/SearchBar/SearchBar.test.tsx @@ -17,59 +17,59 @@ import React from 'react'; import { screen, render, waitFor, act } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; - import { configApiRef, analyticsApiRef } from '@backstage/core-plugin-api'; -import { ApiProvider, ConfigReader } from '@backstage/core-app-api'; -import { MockAnalyticsApi, TestApiRegistry } from '@backstage/test-utils'; - +import { ConfigReader } from '@backstage/core-app-api'; +import { + MockAnalyticsApi, + TestApiProvider, + renderWithEffects, +} from '@backstage/test-utils'; import { searchApiRef } from '../../api'; import { SearchContextProvider } from '../../context'; import { SearchBar } from './SearchBar'; -jest.mock('@backstage/core-plugin-api', () => ({ - ...jest.requireActual('@backstage/core-plugin-api'), -})); +const createInitialState = ({ + term = '', + filters = {}, + types = ['*'], + pageCursor = '', +} = {}) => ({ + term, + filters, + types, + pageCursor, +}); describe('SearchBar', () => { - const initialState = { - term: '', - filters: {}, - types: ['*'], - pageCursor: '', - }; + const query = jest.fn().mockResolvedValue({ results: [] }); - const query = jest.fn().mockResolvedValue({}); - const analyticsApiSpy = new MockAnalyticsApi(); - let apiRegistry: TestApiRegistry; + const analyticsApiMock = new MockAnalyticsApi(); - apiRegistry = TestApiRegistry.from( - [ - configApiRef, - new ConfigReader({ - app: { title: 'Mock title' }, - }), - ], - [searchApiRef, { query }], - ); + const configApiMock = new ConfigReader({ + app: { title: 'Mock title' }, + }); - const name = 'Search'; - const term = 'term'; + const searchApiMock = { query }; - afterAll(() => { - jest.resetAllMocks(); + beforeEach(() => { + jest.clearAllMocks(); }); it('Renders without exploding', async () => { - render( - - + await renderWithEffects( + + - , + , ); await waitFor(() => { - expect(screen.getByRole('textbox', { name })).toBeInTheDocument(); expect( screen.getByPlaceholderText('Search in Mock title'), ).toBeInTheDocument(); @@ -77,59 +77,72 @@ describe('SearchBar', () => { }); it('Renders with custom placeholder', async () => { - render( - - - + const placeholder = 'placeholder'; + + await renderWithEffects( + + + - , - , + , ); await waitFor(() => { - expect( - screen.getByPlaceholderText('This is a custom placeholder'), - ).toBeInTheDocument(); + expect(screen.getByPlaceholderText(placeholder)).toBeInTheDocument(); }); }); it('Renders based on initial search', async () => { + const term = 'term'; + render( - - + + - , - , + , ); await waitFor(() => { - expect(screen.getByRole('textbox', { name })).toHaveValue(term); + expect(screen.getByRole('textbox', { name: 'Search' })).toHaveValue(term); }); }); it('Updates term state when text is entered', async () => { - const user = userEvent.setup({ delay: null }); jest.useFakeTimers(); - const defaultDebounceTime = 200; + const user = userEvent.setup({ delay: null }); - render( - - + await renderWithEffects( + + - , - , + , ); - const textbox = screen.getByRole('textbox', { name }); + const textbox = screen.getByRole('textbox', { name: 'Search' }); const value = 'value'; await user.type(textbox, value); act(() => { - jest.advanceTimersByTime(defaultDebounceTime); + jest.advanceTimersByTime(200); }); await waitFor(() => { @@ -139,26 +152,36 @@ describe('SearchBar', () => { expect(query).toHaveBeenLastCalledWith( expect.objectContaining({ term: value }), ); + jest.useRealTimers(); }); it('Clear button clears term state', async () => { - render( - - + const term = 'term'; + + await renderWithEffects( + + - , + , ); + const textbox = screen.getByRole('textbox', { name: 'Search' }); + await waitFor(() => { - expect(screen.getByRole('textbox', { name })).toHaveValue(term); + expect(textbox).toHaveValue(term); }); await userEvent.click(screen.getByRole('button', { name: 'Clear' })); await waitFor(() => { - expect(screen.getByRole('textbox', { name })).toHaveValue(''); + expect(textbox).toHaveValue(''); }); expect(query).toHaveBeenLastCalledWith( @@ -167,12 +190,19 @@ describe('SearchBar', () => { }); it('Should not show clear button', async () => { - render( - - + const term = 'term'; + + await renderWithEffects( + + - , + , ); await waitFor(() => { @@ -183,170 +213,168 @@ describe('SearchBar', () => { }); it('Adheres to provided debounceTime', async () => { - const user = userEvent.setup({ delay: null }); jest.useFakeTimers(); - + const user = userEvent.setup({ delay: null }); const debounceTime = 600; - render( - - + await renderWithEffects( + + - , - , + , ); - await waitFor(() => { - expect(screen.getByRole('textbox', { name })).toBeInTheDocument(); - }); - - const textbox = screen.getByRole('textbox', { name }); + const textbox = await screen.findByRole('textbox', { name: 'Search' }); const value = 'value'; await user.type(textbox, value); - expect(query).not.toHaveBeenLastCalledWith( - expect.objectContaining({ term: value }), - ); + await waitFor(() => { + expect(query).not.toHaveBeenLastCalledWith( + expect.objectContaining({ term: value }), + ); + }); act(() => { jest.advanceTimersByTime(debounceTime); }); - expect(textbox).toHaveValue(value); + + await waitFor(() => { + expect(textbox).toHaveValue(value); + }); expect(query).toHaveBeenLastCalledWith( expect.objectContaining({ term: value }), ); + jest.useRealTimers(); }); it('does not capture analytics event if not enabled in app', async () => { - const user = userEvent.setup({ delay: null }); jest.useFakeTimers(); + const user = userEvent.setup({ delay: null }); - const debounceTime = 600; - - render( - - - + await renderWithEffects( + + + - , - , + , ); - await waitFor(() => { - expect(screen.getByRole('textbox', { name })).toBeInTheDocument(); - }); - - const textbox = screen.getByRole('textbox', { name }); + const textbox = await screen.findByRole('textbox', { name: 'Search' }); const value = 'value'; await user.type(textbox, value); act(() => { - jest.advanceTimersByTime(debounceTime); + jest.advanceTimersByTime(200); }); - await waitFor(() => expect(textbox).toHaveValue(value)); + await waitFor(() => { + expect(textbox).toHaveValue(value); + }); + + expect(analyticsApiMock.getEvents()).toHaveLength(0); - expect(analyticsApiSpy.getEvents()).toHaveLength(0); jest.useRealTimers(); }); it('captures analytics events if enabled in app', async () => { - const user = userEvent.setup({ delay: null }); jest.useFakeTimers(); + const user = userEvent.setup({ delay: null }); + const types = ['techdocs', 'software-catalog']; - const debounceTime = 600; - - apiRegistry = TestApiRegistry.from( - [analyticsApiRef, analyticsApiSpy], - [ - configApiRef, - new ConfigReader({ - app: { - title: 'Mock title', - analytics: { - ga: { - trackingId: 'xyz123', + await renderWithEffects( + - - + }), + ], + ]} + > + + - , + , ); - await waitFor(() => { - expect(screen.getByRole('textbox', { name })).toBeInTheDocument(); - }); + const textbox = await screen.findByRole('textbox', { name: 'Search' }); - const textbox = screen.getByRole('textbox', { name }); - - const value = 'value'; + let value = 'value'; await user.type(textbox, value); - expect(analyticsApiSpy.getEvents()).toHaveLength(0); + expect(analyticsApiMock.getEvents()).toHaveLength(0); act(() => { - jest.advanceTimersByTime(debounceTime); + jest.advanceTimersByTime(200); }); await waitFor(() => expect(textbox).toHaveValue(value)); - expect(analyticsApiSpy.getEvents()).toHaveLength(1); - expect(analyticsApiSpy.getEvents()[0]).toEqual({ + expect(analyticsApiMock.getEvents()).toHaveLength(1); + expect(analyticsApiMock.getEvents()[0]).toEqual({ action: 'search', context: { extension: 'SearchBar', pluginId: 'search', routeRef: 'unknown', - searchTypes: 'software-catalog,techdocs', + searchTypes: types.toString(), }, - subject: 'value', + subject: value, }); await user.clear(textbox); + value = 'new value'; + // make sure new term is captured - await user.type(textbox, 'new value'); + await user.type(textbox, value); act(() => { - jest.advanceTimersByTime(debounceTime); + jest.advanceTimersByTime(200); }); - await waitFor(() => expect(textbox).toHaveValue('new value')); + await waitFor(() => expect(textbox).toHaveValue(value)); - expect(analyticsApiSpy.getEvents()).toHaveLength(2); - expect(analyticsApiSpy.getEvents()[1]).toEqual({ + expect(analyticsApiMock.getEvents()).toHaveLength(2); + expect(analyticsApiMock.getEvents()[1]).toEqual({ action: 'search', context: { extension: 'SearchBar', pluginId: 'search', routeRef: 'unknown', - searchTypes: 'software-catalog,techdocs', + searchTypes: types.toString(), }, - subject: 'new value', + subject: value, }); + jest.useRealTimers(); }); }); diff --git a/plugins/search-react/src/context/SearchContext.test.tsx b/plugins/search-react/src/context/SearchContext.test.tsx index 0272176150..68c79d3a5e 100644 --- a/plugins/search-react/src/context/SearchContext.test.tsx +++ b/plugins/search-react/src/context/SearchContext.test.tsx @@ -108,40 +108,58 @@ describe('SearchContext', () => { expect(result.current).toEqual(expect.objectContaining(initialState)); }); - it('Resets cursor when term is set (and different from previous)', async () => { - const { result, waitForNextUpdate } = renderHook(() => useSearch(), { - wrapper, - initialProps: { - initialState: { - ...initialState, - pageCursor: 'SOMEPAGE', + describe('Resets cursor', () => { + it('When term is cleared', async () => { + const { result, waitForNextUpdate } = renderHook(() => useSearch(), { + wrapper, + initialProps: { + initialState: { + ...initialState, + term: 'first term', + pageCursor: 'SOMEPAGE', + }, }, - }, + }); + + await waitForNextUpdate(); + + expect(result.current.term).toEqual('first term'); + expect(result.current.pageCursor).toEqual('SOMEPAGE'); + + act(() => { + result.current.setTerm(''); + }); + + await waitForNextUpdate(); + + expect(result.current.pageCursor).toBeUndefined(); }); - await waitForNextUpdate(); + it('When term is set (and different from previous)', async () => { + const { result, waitForNextUpdate } = renderHook(() => useSearch(), { + wrapper, + initialProps: { + initialState: { + ...initialState, + term: 'first term', + pageCursor: 'SOMEPAGE', + }, + }, + }); - expect(result.current.pageCursor).toEqual('SOMEPAGE'); + await waitForNextUpdate(); - act(() => { - result.current.setTerm('first term'); + expect(result.current.term).toEqual('first term'); + expect(result.current.pageCursor).toEqual('SOMEPAGE'); + + act(() => { + result.current.setTerm('second term'); + }); + + await waitForNextUpdate(); + + expect(result.current.pageCursor).toBeUndefined(); }); - - act(() => { - result.current.setPageCursor('OTHERPAGE'); - }); - - await waitForNextUpdate(); - - expect(result.current.pageCursor).toEqual('OTHERPAGE'); - - act(() => { - result.current.setTerm('second term'); - }); - - await waitForNextUpdate(); - - expect(result.current.pageCursor).toEqual(undefined); }); describe('Performs search (and sets results)', () => { diff --git a/plugins/search-react/src/context/SearchContext.tsx b/plugins/search-react/src/context/SearchContext.tsx index 8a0f962121..faad50f37a 100644 --- a/plugins/search-react/src/context/SearchContext.tsx +++ b/plugins/search-react/src/context/SearchContext.tsx @@ -150,10 +150,11 @@ export const SearchContextProvider = (props: SearchContextProviderProps) => { useEffect(() => { // Any time a term is reset, we want to start from page 0. - if (term && prevTerm && term !== prevTerm) { + // Only reset the term if it has been modified by the user at least once, the initial state must not reset the term. + if (prevTerm !== undefined && term !== prevTerm) { setPageCursor(undefined); } - }, [term, prevTerm, initialState.pageCursor]); + }, [term, prevTerm, setPageCursor]); const value: SearchContextValue = { result, diff --git a/plugins/search/CHANGELOG.md b/plugins/search/CHANGELOG.md index 6283cee29b..707ba1cab7 100644 --- a/plugins/search/CHANGELOG.md +++ b/plugins/search/CHANGELOG.md @@ -1,5 +1,49 @@ # @backstage/plugin-search +## 0.9.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/plugin-search-react@0.2.2-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## 0.9.1-next.1 + +### Patch Changes + +- 509c4092f0: To allow people to use a global search context in the search modal, the code for the search modal has been changed to only create a local search context if there is no parent context already defined. + + If you want to continue using a local context even if you define a global one, you will have to wrap the modal in a new local context manually: + + ```tsx + + + + ``` + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + - @backstage/plugin-search-common@0.3.6-next.0 + - @backstage/plugin-search-react@0.2.2-next.1 + +## 0.9.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + - @backstage/plugin-search-react@0.2.2-next.0 + ## 0.9.0 ### Minor Changes diff --git a/plugins/search/package.json b/plugins/search/package.json index b658490b00..ed700e643f 100644 --- a/plugins/search/package.json +++ b/plugins/search/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search", "description": "The Backstage plugin that provides your backstage app with search", - "version": "0.9.0", + "version": "0.9.1-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,15 +33,15 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", + "@backstage/catalog-model": "^1.1.0-next.2", "@backstage/config": "^1.0.1", - "@backstage/core-components": "^0.9.5", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/errors": "^1.0.0", - "@backstage/plugin-catalog-react": "^1.1.1", - "@backstage/plugin-search-common": "^0.3.5", - "@backstage/plugin-search-react": "^0.2.1", - "@backstage/theme": "^0.2.15", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", + "@backstage/plugin-search-common": "^0.3.6-next.0", + "@backstage/plugin-search-react": "^0.2.2-next.2", + "@backstage/theme": "^0.2.16-next.1", "@backstage/types": "^1.0.0", "@backstage/version-bridge": "^1.0.1", "@material-ui/core": "^4.12.2", @@ -57,10 +57,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/react-hooks": "^8.0.0", @@ -68,7 +68,7 @@ "@types/jest": "^26.0.7", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/search/src/components/SearchBar/SearchBar.test.tsx b/plugins/search/src/components/SearchBar/SearchBar.test.tsx deleted file mode 100644 index c48c3d3ed2..0000000000 --- a/plugins/search/src/components/SearchBar/SearchBar.test.tsx +++ /dev/null @@ -1,353 +0,0 @@ -/* - * Copyright 2021 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import React from 'react'; -import { screen, render, waitFor, act } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import { configApiRef, analyticsApiRef } from '@backstage/core-plugin-api'; -import { ApiProvider, ConfigReader } from '@backstage/core-app-api'; -import { MockAnalyticsApi, TestApiRegistry } from '@backstage/test-utils'; -import { - SearchContextProvider, - searchApiRef, -} from '@backstage/plugin-search-react'; - -import { SearchBar } from './SearchBar'; - -jest.mock('@backstage/core-plugin-api', () => ({ - ...jest.requireActual('@backstage/core-plugin-api'), -})); - -describe('SearchBar', () => { - const initialState = { - term: '', - filters: {}, - types: ['*'], - pageCursor: '', - }; - - const query = jest.fn().mockResolvedValue({}); - const analyticsApiSpy = new MockAnalyticsApi(); - let apiRegistry: TestApiRegistry; - - apiRegistry = TestApiRegistry.from( - [ - configApiRef, - new ConfigReader({ - app: { title: 'Mock title' }, - }), - ], - [searchApiRef, { query }], - ); - - const name = 'Search'; - const term = 'term'; - - afterAll(() => { - jest.resetAllMocks(); - }); - - it('Renders without exploding', async () => { - render( - - - - - , - ); - - await waitFor(() => { - expect(screen.getByRole('textbox', { name })).toBeInTheDocument(); - expect( - screen.getByPlaceholderText('Search in Mock title'), - ).toBeInTheDocument(); - }); - }); - - it('Renders with custom placeholder', async () => { - render( - - - - - , - , - ); - - await waitFor(() => { - expect( - screen.getByPlaceholderText('This is a custom placeholder'), - ).toBeInTheDocument(); - }); - }); - - it('Renders based on initial search', async () => { - render( - - - - - , - , - ); - - await waitFor(() => { - expect(screen.getByRole('textbox', { name })).toHaveValue(term); - }); - }); - - it('Updates term state when text is entered', async () => { - const user = userEvent.setup({ delay: null }); - jest.useFakeTimers(); - const defaultDebounceTime = 200; - - render( - - - - - , - , - ); - - const textbox = screen.getByRole('textbox', { name }); - - const value = 'value'; - - await user.type(textbox, value); - - act(() => { - jest.advanceTimersByTime(defaultDebounceTime); - }); - - await waitFor(() => { - expect(textbox).toHaveValue(value); - }); - - expect(query).toHaveBeenLastCalledWith( - expect.objectContaining({ term: value }), - ); - jest.useRealTimers(); - }); - - it('Clear button clears term state', async () => { - render( - - - - - , - ); - - await waitFor(() => { - expect(screen.getByRole('textbox', { name })).toHaveValue(term); - }); - - await userEvent.click(screen.getByRole('button', { name: 'Clear' })); - - await waitFor(() => { - expect(screen.getByRole('textbox', { name })).toHaveValue(''); - }); - - expect(query).toHaveBeenLastCalledWith( - expect.objectContaining({ term: '' }), - ); - }); - - it('Should not show clear button', async () => { - render( - - - - - , - ); - - await waitFor(() => { - expect( - screen.queryByRole('button', { name: 'Clear' }), - ).not.toBeInTheDocument(); - }); - }); - - it('Adheres to provided debounceTime', async () => { - const user = userEvent.setup({ delay: null }); - jest.useFakeTimers(); - - const debounceTime = 600; - - render( - - - - - , - , - ); - - await waitFor(() => { - expect(screen.getByRole('textbox', { name })).toBeInTheDocument(); - }); - - const textbox = screen.getByRole('textbox', { name }); - - const value = 'value'; - - await user.type(textbox, value); - - expect(query).not.toHaveBeenLastCalledWith( - expect.objectContaining({ term: value }), - ); - - act(() => { - jest.advanceTimersByTime(debounceTime); - }); - expect(textbox).toHaveValue(value); - - expect(query).toHaveBeenLastCalledWith( - expect.objectContaining({ term: value }), - ); - jest.useRealTimers(); - }); - - it('does not capture analytics event if not enabled in app', async () => { - const user = userEvent.setup({ delay: null }); - jest.useFakeTimers(); - - const debounceTime = 600; - - render( - - - - - , - , - ); - - await waitFor(() => { - expect(screen.getByRole('textbox', { name })).toBeInTheDocument(); - }); - - const textbox = screen.getByRole('textbox', { name }); - - const value = 'value'; - - await user.type(textbox, value); - - act(() => { - jest.advanceTimersByTime(debounceTime); - }); - - await waitFor(() => expect(textbox).toHaveValue(value)); - - expect(analyticsApiSpy.getEvents()).toHaveLength(0); - jest.useRealTimers(); - }); - - it('captures analytics events if enabled in app', async () => { - const user = userEvent.setup({ delay: null }); - jest.useFakeTimers(); - - const debounceTime = 600; - - apiRegistry = TestApiRegistry.from( - [analyticsApiRef, analyticsApiSpy], - [ - configApiRef, - new ConfigReader({ - app: { - title: 'Mock title', - analytics: { - ga: { - trackingId: 'xyz123', - }, - }, - }, - }), - ], - [searchApiRef, { query }], - ); - - render( - - - - - , - ); - - await waitFor(() => { - expect(screen.getByRole('textbox', { name })).toBeInTheDocument(); - }); - - const textbox = screen.getByRole('textbox', { name }); - - const value = 'value'; - - await user.type(textbox, value); - - expect(analyticsApiSpy.getEvents()).toHaveLength(0); - - act(() => { - jest.advanceTimersByTime(debounceTime); - }); - - await waitFor(() => expect(textbox).toHaveValue(value)); - - expect(analyticsApiSpy.getEvents()).toHaveLength(1); - expect(analyticsApiSpy.getEvents()[0]).toEqual({ - action: 'search', - context: { - extension: 'App', - pluginId: 'root', - routeRef: 'unknown', - searchTypes: 'software-catalog,techdocs', - }, - subject: 'value', - }); - - await user.clear(textbox); - - // make sure new term is captured - await user.type(textbox, 'new value'); - - act(() => { - jest.advanceTimersByTime(debounceTime); - }); - - await waitFor(() => expect(textbox).toHaveValue('new value')); - - expect(analyticsApiSpy.getEvents()).toHaveLength(2); - expect(analyticsApiSpy.getEvents()[1]).toEqual({ - action: 'search', - context: { - extension: 'App', - pluginId: 'root', - routeRef: 'unknown', - searchTypes: 'software-catalog,techdocs', - }, - subject: 'new value', - }); - jest.useRealTimers(); - }); -}); diff --git a/plugins/search/src/components/SearchModal/SearchModal.test.tsx b/plugins/search/src/components/SearchModal/SearchModal.test.tsx index 842f5fb401..3ef9291585 100644 --- a/plugins/search/src/components/SearchModal/SearchModal.test.tsx +++ b/plugins/search/src/components/SearchModal/SearchModal.test.tsx @@ -21,7 +21,10 @@ import userEvent from '@testing-library/user-event'; import { configApiRef } from '@backstage/core-plugin-api'; import { ApiProvider, ConfigReader } from '@backstage/core-app-api'; import { rootRouteRef } from '../../plugin'; -import { searchApiRef } from '@backstage/plugin-search-react'; +import { + searchApiRef, + SearchContextProvider, +} from '@backstage/plugin-search-react'; import { SearchModal } from './SearchModal'; @@ -55,6 +58,52 @@ describe('SearchModal', () => { expect(query).toHaveBeenCalledTimes(1); }); + it('Should use parent search context if defined', async () => { + const initialState = { + term: 'term', + filters: { filter: '' }, + types: ['type'], + pageCursor: 'page cursor', + }; + + await renderInTestApp( + + + + , + { + mountedRoutes: { + '/search': rootRouteRef, + }, + }, + ); + + expect(screen.getByRole('dialog')).toBeInTheDocument(); + expect(query).toHaveBeenCalledWith(initialState); + }); + + it('Should create a local search context if a parent is not defined', async () => { + await renderInTestApp( + + , + { + mountedRoutes: { + '/search': rootRouteRef, + }, + }, + ); + + expect(screen.getByRole('dialog')).toBeInTheDocument(); + expect(query).toHaveBeenCalledWith({ + term: '', + filters: {}, + types: [], + pageCursor: undefined, + }); + }); + it('Should render a custom Modal correctly', async () => { await renderInTestApp( diff --git a/plugins/search/src/components/SearchModal/SearchModal.tsx b/plugins/search/src/components/SearchModal/SearchModal.tsx index 6c37f20001..dbb8100ec1 100644 --- a/plugins/search/src/components/SearchModal/SearchModal.tsx +++ b/plugins/search/src/components/SearchModal/SearchModal.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import React from 'react'; +import React, { PropsWithChildren } from 'react'; import { Dialog, DialogActions, @@ -35,6 +35,7 @@ import { SearchResult, SearchResultPager, useSearch, + useSearchContextCheck, } from '@backstage/plugin-search-react'; import { useRouteRef } from '@backstage/core-plugin-api'; import { Link, useContent } from '@backstage/core-components'; @@ -170,6 +171,15 @@ export const Modal = ({ toggleModal }: SearchModalProps) => { ); }; +const Context = ({ children }: PropsWithChildren<{}>) => { + // Checks if there is a parent context already defined and, if not, creates a new local context. + const hasParentContext = useSearchContextCheck(); + if (hasParentContext) { + return <>{children}; + } + return {children}; +}; + /** * @public */ @@ -194,11 +204,11 @@ export const SearchModal = ({ hidden={hidden} > {open && ( - + {(children && children({ toggleModal })) ?? ( )} - + )} ); diff --git a/plugins/sentry/CHANGELOG.md b/plugins/sentry/CHANGELOG.md index 1a469a83af..28903311c5 100644 --- a/plugins/sentry/CHANGELOG.md +++ b/plugins/sentry/CHANGELOG.md @@ -1,5 +1,34 @@ # @backstage/plugin-sentry +## 0.3.45-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## 0.3.45-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## 0.3.45-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + ## 0.3.44 ### Patch Changes diff --git a/plugins/sentry/package.json b/plugins/sentry/package.json index a75447f0ab..7b913fcefe 100644 --- a/plugins/sentry/package.json +++ b/plugins/sentry/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-sentry", "description": "A Backstage plugin that integrates towards Sentry", - "version": "0.3.44", + "version": "0.3.45-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,11 +35,11 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", - "@backstage/core-components": "^0.9.5", + "@backstage/catalog-model": "^1.1.0-next.2", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/plugin-catalog-react": "^1.1.1", - "@backstage/theme": "^0.2.15", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", + "@backstage/theme": "^0.2.16-next.1", "@material-table/core": "^3.1.0", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -53,10 +53,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", @@ -65,7 +65,7 @@ "@types/node": "^16.11.26", "@types/react": "^16.13.1 || ^17.0.0", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist", diff --git a/plugins/shortcuts/CHANGELOG.md b/plugins/shortcuts/CHANGELOG.md index 4513e09dab..c32e53638c 100644 --- a/plugins/shortcuts/CHANGELOG.md +++ b/plugins/shortcuts/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-shortcuts +## 0.2.8-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + +## 0.2.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/theme@0.2.16-next.0 + +## 0.2.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + ## 0.2.7 ### Patch Changes diff --git a/plugins/shortcuts/package.json b/plugins/shortcuts/package.json index d1d3f9fba4..2acbd5db5d 100644 --- a/plugins/shortcuts/package.json +++ b/plugins/shortcuts/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-shortcuts", "description": "A Backstage plugin that provides a shortcuts feature to the sidebar", - "version": "0.2.7", + "version": "0.2.8-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -24,9 +24,9 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.9.5", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/theme": "^0.2.15", + "@backstage/theme": "^0.2.16-next.1", "@backstage/types": "^1.0.0", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -42,17 +42,17 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/jest": "^26.0.7", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/sonarqube/CHANGELOG.md b/plugins/sonarqube/CHANGELOG.md index 2b3d6840da..072979d537 100644 --- a/plugins/sonarqube/CHANGELOG.md +++ b/plugins/sonarqube/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-sonarqube +## 0.3.7-next.2 + +### Patch Changes + +- 15201b1032: Updated dependency `rc-progress` to `3.4.0`. +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## 0.3.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## 0.3.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + ## 0.3.6 ### Patch Changes diff --git a/plugins/sonarqube/package.json b/plugins/sonarqube/package.json index d9310ffdde..beca17ae35 100644 --- a/plugins/sonarqube/package.json +++ b/plugins/sonarqube/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-sonarqube", "description": "", - "version": "0.3.6", + "version": "0.3.7-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -36,33 +36,33 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", - "@backstage/core-components": "^0.9.5", + "@backstage/catalog-model": "^1.1.0-next.2", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/plugin-catalog-react": "^1.1.1", - "@backstage/theme": "^0.2.15", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", "@material-ui/styles": "^4.10.0", "cross-fetch": "^3.1.5", - "rc-progress": "3.3.3", + "rc-progress": "3.4.0", "react-use": "^17.2.4" }, "peerDependencies": { "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/jest": "^26.0.7", "@types/node": "^16.11.26", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist", diff --git a/plugins/splunk-on-call/CHANGELOG.md b/plugins/splunk-on-call/CHANGELOG.md index e65afb1285..c48e6acab2 100644 --- a/plugins/splunk-on-call/CHANGELOG.md +++ b/plugins/splunk-on-call/CHANGELOG.md @@ -1,5 +1,34 @@ # @backstage/plugin-splunk-on-call +## 0.3.31-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## 0.3.31-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## 0.3.31-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + ## 0.3.30 ### Patch Changes diff --git a/plugins/splunk-on-call/package.json b/plugins/splunk-on-call/package.json index baecd2f9c5..6d0b2ac632 100644 --- a/plugins/splunk-on-call/package.json +++ b/plugins/splunk-on-call/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-splunk-on-call", "description": "A Backstage plugin that integrates towards Splunk On-Call", - "version": "0.3.30", + "version": "0.3.31-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,11 +34,11 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", - "@backstage/core-components": "^0.9.5", + "@backstage/catalog-model": "^1.1.0-next.2", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/plugin-catalog-react": "^1.1.1", - "@backstage/theme": "^0.2.15", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -51,10 +51,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", @@ -62,7 +62,7 @@ "@types/luxon": "^2.0.4", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "configSchema": "config.d.ts", "files": [ diff --git a/plugins/stack-overflow-backend/CHANGELOG.md b/plugins/stack-overflow-backend/CHANGELOG.md index 9f3a2d98a3..6c19f2bfe4 100644 --- a/plugins/stack-overflow-backend/CHANGELOG.md +++ b/plugins/stack-overflow-backend/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-stack-overflow-backend +## 0.1.3-next.0 + +### Patch Changes + +- 52b4f796e3: app-config is now picked up properly. +- Updated dependencies + - @backstage/plugin-search-common@0.3.6-next.0 + ## 0.1.2 ### Patch Changes diff --git a/plugins/stack-overflow-backend/config.d.ts b/plugins/stack-overflow-backend/config.d.ts index 7e7211ca33..2c39d61bfb 100644 --- a/plugins/stack-overflow-backend/config.d.ts +++ b/plugins/stack-overflow-backend/config.d.ts @@ -18,11 +18,11 @@ export interface Config { /** * Configuration options for the stack overflow plugin */ - stackoverflow: { + stackoverflow?: { /** * The base url of the Stack Overflow API used for the plugin * @visibility backend */ - baseUrl: string; + baseUrl?: string; }; } diff --git a/plugins/stack-overflow-backend/package.json b/plugins/stack-overflow-backend/package.json index cc41da042e..07cdbfb242 100644 --- a/plugins/stack-overflow-backend/package.json +++ b/plugins/stack-overflow-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-stack-overflow-backend", - "version": "0.1.2", + "version": "0.1.3-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,7 +33,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/plugin-search-common": "^0.3.5", + "@backstage/plugin-search-common": "^0.3.6-next.0", "@backstage/config": "^1.0.1", "qs": "^6.9.4", "cross-fetch": "^3.1.5", @@ -41,6 +41,7 @@ }, "files": [ "dist", - "config" - ] + "config.d.ts" + ], + "configSchema": "config.d.ts" } diff --git a/plugins/stack-overflow/CHANGELOG.md b/plugins/stack-overflow/CHANGELOG.md index d0f5f39f4b..bbba0a273d 100644 --- a/plugins/stack-overflow/CHANGELOG.md +++ b/plugins/stack-overflow/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-stack-overflow +## 0.1.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-home@0.4.23-next.2 + +## 0.1.3-next.1 + +### Patch Changes + +- 52b4f796e3: app-config is now picked up properly. +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/plugin-home@0.4.23-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-search-common@0.3.6-next.0 + +## 0.1.3-next.0 + +### Patch Changes + +- 12ae3eed2f: - Publicly exports `StackOverflowIcon`. + - `HomePageStackOverflowQuestions` accepts optional icon property. +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-home@0.4.23-next.0 + ## 0.1.2 ### Patch Changes diff --git a/plugins/stack-overflow/README.md b/plugins/stack-overflow/README.md index 6beb843c7d..96a8f524e3 100644 --- a/plugins/stack-overflow/README.md +++ b/plugins/stack-overflow/README.md @@ -23,6 +23,8 @@ This stack overflow frontend plugin is primarily responsible for the following: #### Use specific search result list item for Stack Overflow Question +> Note: For Stack Overflow specific search results to be returned, it needs to be indexed. Use the [stack-overflow-backend plugin](https://github.com/backstage/backstage/blob/master/plugins/stack-overflow-backend/README.md) to index Stack Overflow Questions to search. + When you have your `packages/app/src/components/search/SearchPage.tsx` file ready to make modifications, add the following code snippet to add the `StackOverflowSearchResultListItem` when the type of the search results are `stack-overflow`. ```tsx diff --git a/plugins/stack-overflow/api-report.md b/plugins/stack-overflow/api-report.md index 277b0272d1..e4912fcd18 100644 --- a/plugins/stack-overflow/api-report.md +++ b/plugins/stack-overflow/api-report.md @@ -16,6 +16,9 @@ export const HomePageStackOverflowQuestions: ( } & StackOverflowQuestionsContentProps, ) => JSX.Element; +// @public +export const StackOverflowIcon: () => JSX.Element; + // @public export const stackOverflowPlugin: BackstagePlugin<{}, {}>; @@ -31,6 +34,7 @@ export type StackOverflowQuestion = { // @public export type StackOverflowQuestionsContentProps = { requestParams: StackOverflowQuestionsRequestParams; + icon?: React.ReactNode; }; // @public diff --git a/plugins/stack-overflow/config.d.ts b/plugins/stack-overflow/config.d.ts index 811893231e..c0638e3c19 100644 --- a/plugins/stack-overflow/config.d.ts +++ b/plugins/stack-overflow/config.d.ts @@ -18,11 +18,11 @@ export interface Config { /** * Configuration options for the stack overflow plugin */ - stackoverflow: { + stackoverflow?: { /** * The base url of the Stack Overflow API used for the plugin * @visibility frontend */ - baseUrl: string; + baseUrl?: string; }; } diff --git a/plugins/stack-overflow/package.json b/plugins/stack-overflow/package.json index 1438ddcd50..e1245b743a 100644 --- a/plugins/stack-overflow/package.json +++ b/plugins/stack-overflow/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-stack-overflow", - "version": "0.1.2", + "version": "0.1.3-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -24,11 +24,11 @@ }, "dependencies": { "@backstage/config": "^1.0.1", - "@backstage/core-components": "^0.9.5", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/plugin-home": "^0.4.22", - "@backstage/plugin-search-common": "^0.3.5", - "@backstage/theme": "^0.2.15", + "@backstage/plugin-home": "^0.4.23-next.2", + "@backstage/plugin-search-common": "^0.3.6-next.0", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@testing-library/jest-dom": "^5.10.1", @@ -42,18 +42,19 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/jest": "^26.0.7", "@types/node": "^16.11.26", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist", - "config" - ] + "config.d.ts" + ], + "configSchema": "config.d.ts" } diff --git a/plugins/stack-overflow/src/home/StackOverflowQuestions/Content.tsx b/plugins/stack-overflow/src/home/StackOverflowQuestions/Content.tsx index c347399474..fbc3a90a9d 100644 --- a/plugins/stack-overflow/src/home/StackOverflowQuestions/Content.tsx +++ b/plugins/stack-overflow/src/home/StackOverflowQuestions/Content.tsx @@ -22,6 +22,7 @@ import { ListItem, ListItemText, ListItemSecondaryAction, + ListItemIcon, } from '@material-ui/core'; import OpenInNewIcon from '@material-ui/icons/OpenInNew'; import useAsync from 'react-use/lib/useAsync'; @@ -68,8 +69,9 @@ export const Content = (props: StackOverflowQuestionsContentProps) => { return ( {value.map(question => ( - - + + + {props.icon && {props.icon}} {
- - + + ))} ); diff --git a/plugins/stack-overflow/src/home/StackOverflowQuestions/StackOverflowQuestions.stories.tsx b/plugins/stack-overflow/src/home/StackOverflowQuestions/StackOverflowQuestions.stories.tsx index e19e0f807b..35ace44c14 100644 --- a/plugins/stack-overflow/src/home/StackOverflowQuestions/StackOverflowQuestions.stories.tsx +++ b/plugins/stack-overflow/src/home/StackOverflowQuestions/StackOverflowQuestions.stories.tsx @@ -20,6 +20,7 @@ import { configApiRef } from '@backstage/core-plugin-api'; import { ConfigReader } from '@backstage/config'; import { Grid } from '@material-ui/core'; import React, { ComponentType } from 'react'; +import { StackOverflowIcon } from '../../icons'; export default { title: 'Plugins/Home/Components/StackOverflow', @@ -60,3 +61,18 @@ export const Default = () => {
); }; + +export const WithIcon = () => { + return ( + + } + /> + + ); +}; diff --git a/plugins/stack-overflow/src/icons/StackOverflowIcon.tsx b/plugins/stack-overflow/src/icons/StackOverflowIcon.tsx new file mode 100644 index 0000000000..8befe53177 --- /dev/null +++ b/plugins/stack-overflow/src/icons/StackOverflowIcon.tsx @@ -0,0 +1,38 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; + +/** + * Stack Overflow Icon + * @public + */ +export const StackOverflowIcon = () => { + return ( + + + + + ); +}; diff --git a/plugins/stack-overflow/src/icons/index.ts b/plugins/stack-overflow/src/icons/index.ts new file mode 100644 index 0000000000..141d87d7b1 --- /dev/null +++ b/plugins/stack-overflow/src/icons/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export * from './StackOverflowIcon'; diff --git a/plugins/stack-overflow/src/index.ts b/plugins/stack-overflow/src/index.ts index 264a0d5d7c..5965d66983 100644 --- a/plugins/stack-overflow/src/index.ts +++ b/plugins/stack-overflow/src/index.ts @@ -18,11 +18,13 @@ * * @packageDocumentation */ + export { stackOverflowPlugin, StackOverflowSearchResultListItem, HomePageStackOverflowQuestions, } from './plugin'; +export { StackOverflowIcon } from './icons'; export type { StackOverflowQuestion, StackOverflowQuestionsContentProps, diff --git a/plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/StackOverflowSearchResultListItem.stories.tsx b/plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/StackOverflowSearchResultListItem.stories.tsx index 1239cabcbe..df5b8038b0 100644 --- a/plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/StackOverflowSearchResultListItem.stories.tsx +++ b/plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/StackOverflowSearchResultListItem.stories.tsx @@ -17,6 +17,7 @@ import { StackOverflowSearchResultListItem } from '../../plugin'; import { wrapInTestApp } from '@backstage/test-utils'; import React, { ComponentType } from 'react'; +import { StackOverflowIcon } from '../../icons'; export default { title: 'Plugins/Search/StackOverflowResultListItem', @@ -37,3 +38,18 @@ export const Default = () => { /> ); }; + +export const WithIcon = () => { + return ( + } + /> + ); +}; diff --git a/plugins/stack-overflow/src/types.ts b/plugins/stack-overflow/src/types.ts index c3fa08cc4f..8f2d8847ec 100644 --- a/plugins/stack-overflow/src/types.ts +++ b/plugins/stack-overflow/src/types.ts @@ -34,6 +34,7 @@ export type StackOverflowQuestion = { */ export type StackOverflowQuestionsContentProps = { requestParams: StackOverflowQuestionsRequestParams; + icon?: React.ReactNode; }; /** diff --git a/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md b/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md index ba2392b5ee..4be66cb389 100644 --- a/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md +++ b/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-tech-insights-backend-module-jsonfc +## 0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + +## 0.1.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/plugin-tech-insights-node@0.3.2-next.0 + ## 0.1.17 ### Patch Changes diff --git a/plugins/tech-insights-backend-module-jsonfc/package.json b/plugins/tech-insights-backend-module-jsonfc/package.json index a6782c57fb..d0b3626ac5 100644 --- a/plugins/tech-insights-backend-module-jsonfc/package.json +++ b/plugins/tech-insights-backend-module-jsonfc/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-tech-insights-backend-module-jsonfc", - "version": "0.1.17", + "version": "0.1.18-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,11 +34,11 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", + "@backstage/backend-common": "^0.14.1-next.1", "@backstage/config": "^1.0.1", - "@backstage/errors": "^1.0.0", + "@backstage/errors": "^1.1.0-next.0", "@backstage/plugin-tech-insights-common": "^0.2.4", - "@backstage/plugin-tech-insights-node": "^0.3.1", + "@backstage/plugin-tech-insights-node": "^0.3.2-next.0", "ajv": "^8.10.0", "json-rules-engine": "^6.1.2", "lodash": "^4.17.21", @@ -46,7 +46,7 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.17.2" + "@backstage/cli": "^0.18.0-next.1" }, "files": [ "dist" diff --git a/plugins/tech-insights-backend/CHANGELOG.md b/plugins/tech-insights-backend/CHANGELOG.md index 9e496d9046..9a08f51d33 100644 --- a/plugins/tech-insights-backend/CHANGELOG.md +++ b/plugins/tech-insights-backend/CHANGELOG.md @@ -1,5 +1,42 @@ # @backstage/plugin-tech-insights-backend +## 0.5.0-next.2 + +### Minor Changes + +- 818fa28d71: Allow FactRetrieverRegistry to be injected into buildTechInsightsContext so that we can override default registry implementation. + +### Patch Changes + +- 679b32172e: Updated dependency `knex` to `^2.0.0`. +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/backend-common@0.14.1-next.2 + - @backstage/backend-tasks@0.3.3-next.2 + +## 0.4.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/backend-tasks@0.3.3-next.1 + - @backstage/catalog-client@1.0.4-next.1 + +## 0.4.2-next.0 + +### Patch Changes + +- 2ef58ab539: TechInsightsBackend: Added missing 'scheduler' to code examples +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/backend-tasks@0.3.3-next.0 + - @backstage/plugin-tech-insights-node@0.3.2-next.0 + - @backstage/catalog-client@1.0.4-next.0 + ## 0.4.1 ### Patch Changes diff --git a/plugins/tech-insights-backend/README.md b/plugins/tech-insights-backend/README.md index e88d150393..c5c6e66270 100644 --- a/plugins/tech-insights-backend/README.md +++ b/plugins/tech-insights-backend/README.md @@ -106,6 +106,7 @@ const builder = buildTechInsightsContext({ database: env.database, discovery: env.discovery, tokenManager: env.tokenManager, + scheduler: env.scheduler, - factRetrievers: [], + factRetrievers: [myFactRetrieverRegistration], }); @@ -122,6 +123,7 @@ const builder = buildTechInsightsContext({ database: env.database, discovery: env.discovery, tokenManager: env.tokenManager, + scheduler: env.scheduler, - factRetrievers: [], + factRetrievers: process.env.MAIN_FACT_RETRIEVER_INSTANCE ? [myFactRetrieverRegistration] : [], }); @@ -281,6 +283,7 @@ export default async function createPlugin( database: env.database, discovery: env.discovery, tokenManager: env.tokenManager, + scheduler: env.scheduler, factRetrievers: [ createFactRetrieverRegistration({ cadence: '0 */6 * * *', // Run every 6 hours - https://crontab.guru/#0_*/6_*_*_* diff --git a/plugins/tech-insights-backend/api-report.md b/plugins/tech-insights-backend/api-report.md index 9fee3be281..32d45f8afd 100644 --- a/plugins/tech-insights-backend/api-report.md +++ b/plugins/tech-insights-backend/api-report.md @@ -11,6 +11,7 @@ import { FactCheckerFactory } from '@backstage/plugin-tech-insights-node'; import { FactLifecycle } from '@backstage/plugin-tech-insights-node'; import { FactRetriever } from '@backstage/plugin-tech-insights-node'; import { FactRetrieverRegistration } from '@backstage/plugin-tech-insights-node'; +import { FactSchema } from '@backstage/plugin-tech-insights-node'; import { Logger } from 'winston'; import { PluginDatabaseManager } from '@backstage/backend-common'; import { PluginEndpointDiscovery } from '@backstage/backend-common'; @@ -51,6 +52,22 @@ export type FactRetrieverRegistrationOptions = { lifecycle?: FactLifecycle; }; +// @public (undocumented) +export interface FactRetrieverRegistry { + // (undocumented) + get(retrieverReference: string): FactRetrieverRegistration; + // (undocumented) + getSchemas(): FactSchema[]; + // (undocumented) + listRegistrations(): FactRetrieverRegistration[]; + // (undocumented) + listRetrievers(): FactRetriever[]; + // (undocumented) + register(registration: FactRetrieverRegistration): void; + // (undocumented) + readonly retrievers: Map; +} + // @public export type PersistenceContext = { techInsightsStore: TechInsightsStore; @@ -91,7 +108,8 @@ export interface TechInsightsOptions< // (undocumented) discovery: PluginEndpointDiscovery; factCheckerFactory?: FactCheckerFactory; - factRetrievers: FactRetrieverRegistration[]; + factRetrieverRegistry?: FactRetrieverRegistry; + factRetrievers?: FactRetrieverRegistration[]; // (undocumented) logger: Logger; // (undocumented) diff --git a/plugins/tech-insights-backend/package.json b/plugins/tech-insights-backend/package.json index 5ae890ae1b..0ecdb6b6e8 100644 --- a/plugins/tech-insights-backend/package.json +++ b/plugins/tech-insights-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-tech-insights-backend", - "version": "0.4.1", + "version": "0.5.0-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,18 +34,18 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", - "@backstage/backend-tasks": "^0.3.2", - "@backstage/catalog-client": "^1.0.3", - "@backstage/catalog-model": "^1.0.3", + "@backstage/backend-common": "^0.14.1-next.2", + "@backstage/backend-tasks": "^0.3.3-next.2", + "@backstage/catalog-client": "^1.0.4-next.1", + "@backstage/catalog-model": "^1.1.0-next.2", "@backstage/config": "^1.0.1", - "@backstage/errors": "^1.0.0", + "@backstage/errors": "^1.1.0-next.0", "@backstage/plugin-tech-insights-common": "^0.2.4", - "@backstage/plugin-tech-insights-node": "^0.3.1", + "@backstage/plugin-tech-insights-node": "^0.3.2-next.0", "@types/express": "^4.17.6", "express": "^4.17.1", "express-promise-router": "^4.1.0", - "knex": "^1.0.2", + "knex": "^2.0.0", "lodash": "^4.17.21", "luxon": "^2.0.2", "semver": "^7.3.5", @@ -54,8 +54,8 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/backend-test-utils": "^0.1.25", - "@backstage/cli": "^0.17.2", + "@backstage/backend-test-utils": "^0.1.26-next.2", + "@backstage/cli": "^0.18.0-next.2", "@types/supertest": "^2.0.8", "@types/semver": "^7.3.8", "supertest": "^6.1.3", diff --git a/plugins/tech-insights-backend/src/index.ts b/plugins/tech-insights-backend/src/index.ts index 82fda47367..66180b1006 100644 --- a/plugins/tech-insights-backend/src/index.ts +++ b/plugins/tech-insights-backend/src/index.ts @@ -25,5 +25,6 @@ export type { export type { PersistenceContext } from './service/persistence/persistenceContext'; export { createFactRetrieverRegistration } from './service/fact/createFactRetriever'; +export type { FactRetrieverRegistry } from './service/fact/FactRetrieverRegistry'; export type { FactRetrieverRegistrationOptions } from './service/fact/createFactRetriever'; export * from './service/fact/factRetrievers'; diff --git a/plugins/tech-insights-backend/src/service/fact/FactRetrieverRegistry.ts b/plugins/tech-insights-backend/src/service/fact/FactRetrieverRegistry.ts index b122f52f0a..504d561f17 100644 --- a/plugins/tech-insights-backend/src/service/fact/FactRetrieverRegistry.ts +++ b/plugins/tech-insights-backend/src/service/fact/FactRetrieverRegistry.ts @@ -21,8 +21,21 @@ import { } from '@backstage/plugin-tech-insights-node'; import { ConflictError, NotFoundError } from '@backstage/errors'; -export class FactRetrieverRegistry { - private readonly retrievers = new Map(); +/** + * @public + * + */ +export interface FactRetrieverRegistry { + readonly retrievers: Map; + register(registration: FactRetrieverRegistration): void; + get(retrieverReference: string): FactRetrieverRegistration; + listRetrievers(): FactRetriever[]; + listRegistrations(): FactRetrieverRegistration[]; + getSchemas(): FactSchema[]; +} + +export class DefaultFactRetrieverRegistry implements FactRetrieverRegistry { + readonly retrievers = new Map(); constructor(retrievers: FactRetrieverRegistration[]) { retrievers.forEach(it => { diff --git a/plugins/tech-insights-backend/src/service/techInsightsContextBuilder.test.ts b/plugins/tech-insights-backend/src/service/techInsightsContextBuilder.test.ts new file mode 100644 index 0000000000..82f504c8a8 --- /dev/null +++ b/plugins/tech-insights-backend/src/service/techInsightsContextBuilder.test.ts @@ -0,0 +1,91 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { buildTechInsightsContext } from './techInsightsContextBuilder'; +import { + DatabaseManager, + getVoidLogger, + PluginDatabaseManager, + ServerTokenManager, +} from '@backstage/backend-common'; +import { ConfigReader } from '@backstage/config'; +import { TaskScheduler } from '@backstage/backend-tasks'; +import { DefaultFactRetrieverRegistry } from './fact/FactRetrieverRegistry'; +import { Knex } from 'knex'; + +jest.mock('./fact/FactRetrieverRegistry'); +jest.mock('./fact/FactRetrieverEngine', () => ({ + FactRetrieverEngine: { + create: jest.fn().mockResolvedValue({ + schedule: jest.fn(), + }), + }, +})); + +describe('buildTechInsightsContext', () => { + const pluginDatabase: PluginDatabaseManager = { + getClient: () => { + return Promise.resolve({ + migrate: { + latest: () => {}, + }, + }) as unknown as Promise; + }, + }; + const databaseManager: Partial = { + forPlugin: () => pluginDatabase, + }; + const manager = databaseManager as DatabaseManager; + const discoveryMock = { + getBaseUrl: (_: string) => Promise.resolve('http://mock.url'), + getExternalBaseUrl: (_: string) => Promise.resolve('http://mock.url'), + }; + const scheduler = new TaskScheduler(manager, getVoidLogger()).forPlugin( + 'tech-insights', + ); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('constructs the default FactRetrieverRegistry if factRetrievers but no factRetrieverRegistry are passed', () => { + buildTechInsightsContext({ + database: pluginDatabase, + logger: getVoidLogger(), + factRetrievers: [], + scheduler: scheduler, + config: ConfigReader.fromConfigs([]), + discovery: discoveryMock, + tokenManager: ServerTokenManager.noop(), + }); + expect(DefaultFactRetrieverRegistry).toHaveBeenCalledTimes(1); + }); + + it('uses factRetrieverRegistry implementation instead of the default FactRetrieverRegistry if it is passed in', () => { + const factRetrieverRegistryMock = {} as DefaultFactRetrieverRegistry; + + buildTechInsightsContext({ + database: pluginDatabase, + logger: getVoidLogger(), + factRetrievers: [], + factRetrieverRegistry: factRetrieverRegistryMock, + scheduler: scheduler, + config: ConfigReader.fromConfigs([]), + discovery: discoveryMock, + tokenManager: ServerTokenManager.noop(), + }); + expect(DefaultFactRetrieverRegistry).not.toHaveBeenCalled(); + }); +}); diff --git a/plugins/tech-insights-backend/src/service/techInsightsContextBuilder.ts b/plugins/tech-insights-backend/src/service/techInsightsContextBuilder.ts index e22bfbd253..008acf192d 100644 --- a/plugins/tech-insights-backend/src/service/techInsightsContextBuilder.ts +++ b/plugins/tech-insights-backend/src/service/techInsightsContextBuilder.ts @@ -16,7 +16,10 @@ import { FactRetrieverEngine } from './fact/FactRetrieverEngine'; import { Logger } from 'winston'; -import { FactRetrieverRegistry } from './fact/FactRetrieverRegistry'; +import { + DefaultFactRetrieverRegistry, + FactRetrieverRegistry, +} from './fact/FactRetrieverRegistry'; import { Config } from '@backstage/config'; import { PluginDatabaseManager, @@ -49,16 +52,25 @@ export interface TechInsightsOptions< CheckResultType extends CheckResult, > { /** - * A collection of FactRetrieverRegistrations. + * Optional collection of FactRetrieverRegistrations (required if no factRetrieverRegistry passed in). * Used to register FactRetrievers and their schemas and schedule an execution loop for them. + * + * Not needed if passing in your own FactRetrieverRegistry implementation. Required otherwise. */ - factRetrievers: FactRetrieverRegistration[]; + factRetrievers?: FactRetrieverRegistration[]; /** * Optional factory exposing a `construct` method to initialize a FactChecker implementation */ factCheckerFactory?: FactCheckerFactory; + /** + * Optional FactRetrieverRegistry implementation that replaces the default one. + * + * If passing this in you don't need to pass in factRetrievers also. + */ + factRetrieverRegistry?: FactRetrieverRegistry; + logger: Logger; config: Config; discovery: PluginEndpointDiscovery; @@ -109,7 +121,19 @@ export const buildTechInsightsContext = async < tokenManager, } = options; - const factRetrieverRegistry = new FactRetrieverRegistry(factRetrievers); + const buildFactRetrieverRegistry = (): FactRetrieverRegistry => { + if (!options.factRetrieverRegistry) { + if (!factRetrievers) { + throw new Error( + 'Failed to build FactRetrieverRegistry because no factRetrievers found', + ); + } + return new DefaultFactRetrieverRegistry(factRetrievers); + } + return options.factRetrieverRegistry; + }; + + const factRetrieverRegistry = buildFactRetrieverRegistry(); const persistenceContext = await initializePersistenceContext( await database.getClient(), diff --git a/plugins/tech-insights-common/package.json b/plugins/tech-insights-common/package.json index bc9bbcd792..14ec147bb9 100644 --- a/plugins/tech-insights-common/package.json +++ b/plugins/tech-insights-common/package.json @@ -38,7 +38,7 @@ "@backstage/types": "^1.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2-next.0" + "@backstage/cli": "^0.18.0-next.1" }, "files": [ "dist" diff --git a/plugins/tech-insights-node/CHANGELOG.md b/plugins/tech-insights-node/CHANGELOG.md index c6af55abd5..64d150d275 100644 --- a/plugins/tech-insights-node/CHANGELOG.md +++ b/plugins/tech-insights-node/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-tech-insights-node +## 0.3.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + ## 0.3.1 ### Patch Changes diff --git a/plugins/tech-insights-node/package.json b/plugins/tech-insights-node/package.json index 904f149d6c..3139865ddf 100644 --- a/plugins/tech-insights-node/package.json +++ b/plugins/tech-insights-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-tech-insights-node", - "version": "0.3.1", + "version": "0.3.2-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,7 +33,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", + "@backstage/backend-common": "^0.14.1-next.1", "@backstage/config": "^1.0.1", "@backstage/plugin-tech-insights-common": "^0.2.4", "@backstage/types": "^1.0.0", @@ -42,7 +42,7 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.17.2" + "@backstage/cli": "^0.18.0-next.1" }, "files": [ "dist" diff --git a/plugins/tech-insights/CHANGELOG.md b/plugins/tech-insights/CHANGELOG.md index 867f639067..68e60fd0d1 100644 --- a/plugins/tech-insights/CHANGELOG.md +++ b/plugins/tech-insights/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-tech-insights +## 0.2.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## 0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## 0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + ## 0.2.2 ### Patch Changes diff --git a/plugins/tech-insights/package.json b/plugins/tech-insights/package.json index 0956db7cf3..75308d67bc 100644 --- a/plugins/tech-insights/package.json +++ b/plugins/tech-insights/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-tech-insights", - "version": "0.2.2", + "version": "0.2.3-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -28,13 +28,13 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", - "@backstage/core-components": "^0.9.5", + "@backstage/catalog-model": "^1.1.0-next.2", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/errors": "^1.0.0", - "@backstage/plugin-catalog-react": "^1.1.1", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", "@backstage/plugin-tech-insights-common": "^0.2.4", - "@backstage/theme": "^0.2.15", + "@backstage/theme": "^0.2.16-next.1", "@backstage/types": "^1.0.0", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -47,17 +47,17 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/jest": "^26.0.7", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/tech-radar/CHANGELOG.md b/plugins/tech-radar/CHANGELOG.md index 049a1b9c4c..99d537779f 100644 --- a/plugins/tech-radar/CHANGELOG.md +++ b/plugins/tech-radar/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-tech-radar +## 0.5.14-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + +## 0.5.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/theme@0.2.16-next.0 + +## 0.5.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + ## 0.5.13 ### Patch Changes diff --git a/plugins/tech-radar/package.json b/plugins/tech-radar/package.json index de2eab6fd1..421297fcca 100644 --- a/plugins/tech-radar/package.json +++ b/plugins/tech-radar/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-tech-radar", "description": "A Backstage plugin that lets you display a Tech Radar for your organization", - "version": "0.5.13", + "version": "0.5.14-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,9 +34,9 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/core-components": "^0.9.5", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/theme": "^0.2.15", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -49,10 +49,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", @@ -62,7 +62,7 @@ "@types/node": "^16.11.26", "@types/react": "^16.13.1 || ^17.0.0", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/techdocs-addons-test-utils/CHANGELOG.md b/plugins/techdocs-addons-test-utils/CHANGELOG.md index aabdec8922..667c189a99 100644 --- a/plugins/techdocs-addons-test-utils/CHANGELOG.md +++ b/plugins/techdocs-addons-test-utils/CHANGELOG.md @@ -1,5 +1,45 @@ # @backstage/plugin-techdocs-addons-test-utils +## 1.0.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/plugin-search-react@0.2.2-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-techdocs@1.2.1-next.2 + - @backstage/plugin-catalog@1.4.0-next.2 + - @backstage/integration-react@1.1.2-next.2 + - @backstage/plugin-techdocs-react@1.0.2-next.1 + +## 1.0.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/plugin-catalog@1.3.1-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-techdocs@1.2.1-next.1 + - @backstage/integration-react@1.1.2-next.1 + - @backstage/test-utils@1.1.2-next.1 + - @backstage/plugin-search-react@0.2.2-next.1 + +## 1.0.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-techdocs-react@1.0.2-next.0 + - @backstage/plugin-catalog@1.3.1-next.0 + - @backstage/core-app-api@1.0.4-next.0 + - @backstage/plugin-techdocs@1.2.1-next.0 + - @backstage/integration-react@1.1.2-next.0 + - @backstage/plugin-search-react@0.2.2-next.0 + - @backstage/test-utils@1.1.2-next.0 + ## 1.0.1 ### Patch Changes diff --git a/plugins/techdocs-addons-test-utils/package.json b/plugins/techdocs-addons-test-utils/package.json index 35d176566e..34580c7475 100644 --- a/plugins/techdocs-addons-test-utils/package.json +++ b/plugins/techdocs-addons-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-addons-test-utils", - "version": "1.0.1", + "version": "1.0.2-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,16 +32,16 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/core-components": "^0.9.5", - "@backstage/core-app-api": "^1.0.3", + "@backstage/core-components": "^0.10.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/integration-react": "^1.1.1", - "@backstage/plugin-catalog": "^1.3.0", - "@backstage/plugin-search-react": "^0.2.1", - "@backstage/plugin-techdocs": "^1.2.0", - "@backstage/plugin-techdocs-react": "^1.0.1", - "@backstage/test-utils": "^1.1.1", - "@backstage/theme": "^0.2.15", + "@backstage/integration-react": "^1.1.2-next.2", + "@backstage/plugin-catalog": "^1.4.0-next.2", + "@backstage/plugin-search-react": "^0.2.2-next.2", + "@backstage/plugin-techdocs": "^1.2.1-next.2", + "@backstage/plugin-techdocs-react": "^1.0.2-next.1", + "@backstage/test-utils": "^1.1.2-next.1", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.9.13", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -56,14 +56,14 @@ "react-dom": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/dev-utils": "^1.0.3", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/dev-utils": "^1.0.4-next.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/jest": "^26.0.7", "@types/node": "^16.11.26", - "msw": "^0.42.0", + "msw": "^0.43.0", "cross-fetch": "^3.1.5" }, "files": [ diff --git a/plugins/techdocs-backend/CHANGELOG.md b/plugins/techdocs-backend/CHANGELOG.md index 861bf37bef..3039a7c50c 100644 --- a/plugins/techdocs-backend/CHANGELOG.md +++ b/plugins/techdocs-backend/CHANGELOG.md @@ -1,5 +1,47 @@ # @backstage/plugin-techdocs-backend +## 1.2.0-next.2 + +### Patch Changes + +- 679b32172e: Updated dependency `knex` to `^2.0.0`. +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/backend-common@0.14.1-next.2 + - @backstage/integration@1.2.2-next.2 + - @backstage/plugin-techdocs-node@1.2.0-next.2 + +## 1.2.0-next.1 + +### Minor Changes + +- 860765ff45: Added local publishing target directory `config`: `techdocs.publisher.local.publishDirectory` + +### Patch Changes + +- 726577958f: Add sample headings on the documented component homepage. +- Updated dependencies + - @backstage/plugin-techdocs-node@1.2.0-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/catalog-client@1.0.4-next.1 + - @backstage/integration@1.2.2-next.1 + - @backstage/plugin-catalog-common@1.0.4-next.0 + - @backstage/plugin-permission-common@0.6.3-next.0 + - @backstage/plugin-search-common@0.3.6-next.0 + +## 1.1.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/plugin-techdocs-node@1.1.3-next.0 + - @backstage/catalog-client@1.0.4-next.0 + ## 1.1.2 ### Patch Changes diff --git a/plugins/techdocs-backend/config.d.ts b/plugins/techdocs-backend/config.d.ts index c64a001f5f..fdacc9cfbc 100644 --- a/plugins/techdocs-backend/config.d.ts +++ b/plugins/techdocs-backend/config.d.ts @@ -66,6 +66,13 @@ export interface Config { publisher?: | { type: 'local'; + + local?: { + /** + * Directory to store generated static files. + */ + publishDirectory?: string; + }; } | { type: 'awsS3'; diff --git a/plugins/techdocs-backend/examples/documented-component/docs/index.md b/plugins/techdocs-backend/examples/documented-component/docs/index.md index 48a903445a..5a3d7508cd 100644 --- a/plugins/techdocs-backend/examples/documented-component/docs/index.md +++ b/plugins/techdocs-backend/examples/documented-component/docs/index.md @@ -11,6 +11,20 @@ You can see also: ## Basic Markdown +Headings: + +# h1 + +## h2 + +### h3 + +#### h4 + +##### h5 + +###### h6 + Here is a bulleted list: - Item one diff --git a/plugins/techdocs-backend/package.json b/plugins/techdocs-backend/package.json index d7e9326fe5..deabdea689 100644 --- a/plugins/techdocs-backend/package.json +++ b/plugins/techdocs-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-techdocs-backend", "description": "The Backstage backend plugin that renders technical documentation for your components", - "version": "1.1.2", + "version": "1.2.0-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,33 +34,33 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", - "@backstage/catalog-client": "^1.0.3", - "@backstage/catalog-model": "^1.0.3", + "@backstage/backend-common": "^0.14.1-next.2", + "@backstage/catalog-client": "^1.0.4-next.1", + "@backstage/catalog-model": "^1.1.0-next.2", "@backstage/config": "^1.0.1", - "@backstage/errors": "^1.0.0", - "@backstage/integration": "^1.2.1", - "@backstage/plugin-catalog-common": "^1.0.3", - "@backstage/plugin-permission-common": "^0.6.2", - "@backstage/plugin-search-common": "^0.3.5", - "@backstage/plugin-techdocs-node": "^1.1.2", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/integration": "^1.2.2-next.2", + "@backstage/plugin-catalog-common": "^1.0.4-next.0", + "@backstage/plugin-permission-common": "^0.6.3-next.0", + "@backstage/plugin-search-common": "^0.3.6-next.0", + "@backstage/plugin-techdocs-node": "^1.2.0-next.2", "@types/express": "^4.17.6", "dockerode": "^3.3.1", "express": "^4.17.1", "express-promise-router": "^4.1.0", "fs-extra": "10.1.0", - "knex": "^1.0.2", + "knex": "^2.0.0", "lodash": "^4.17.21", "node-fetch": "^2.6.7", "p-limit": "^3.1.0", "winston": "^3.2.1" }, "devDependencies": { - "@backstage/backend-test-utils": "^0.1.25", - "@backstage/cli": "^0.17.2", - "@backstage/plugin-search-backend-node": "0.6.2", + "@backstage/backend-test-utils": "^0.1.26-next.2", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/plugin-search-backend-node": "0.6.3-next.1", "@types/dockerode": "^3.3.0", - "msw": "^0.42.0", + "msw": "^0.43.0", "supertest": "^6.1.3" }, "files": [ diff --git a/plugins/techdocs-module-addons-contrib/CHANGELOG.md b/plugins/techdocs-module-addons-contrib/CHANGELOG.md index 4219157392..049cf72493 100644 --- a/plugins/techdocs-module-addons-contrib/CHANGELOG.md +++ b/plugins/techdocs-module-addons-contrib/CHANGELOG.md @@ -1,5 +1,45 @@ # @backstage/plugin-techdocs-module-addons-contrib +## 1.0.2-next.2 + +### Patch Changes + +- e2d7b76f43: Upgrade git-url-parse to 12.0.0. + + Motivation for upgrade is transitively upgrading parse-url which is vulnerable + to several CVEs detected by Snyk. + + - SNYK-JS-PARSEURL-2935944 + - SNYK-JS-PARSEURL-2935947 + - SNYK-JS-PARSEURL-2936249 + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/integration@1.2.2-next.2 + - @backstage/integration-react@1.1.2-next.2 + - @backstage/plugin-techdocs-react@1.0.2-next.1 + +## 1.0.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/theme@0.2.16-next.0 + - @backstage/integration@1.2.2-next.1 + - @backstage/integration-react@1.1.2-next.1 + +## 1.0.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-techdocs-react@1.0.2-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/integration-react@1.1.2-next.0 + ## 1.0.1 ### Patch Changes diff --git a/plugins/techdocs-module-addons-contrib/package.json b/plugins/techdocs-module-addons-contrib/package.json index 92c0d8d4af..e089428dbe 100644 --- a/plugins/techdocs-module-addons-contrib/package.json +++ b/plugins/techdocs-module-addons-contrib/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-techdocs-module-addons-contrib", "description": "Plugin module for contributed TechDocs Addons", - "version": "1.0.1", + "version": "1.0.2-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,35 +34,35 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/core-components": "^0.9.5", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/integration": "^1.2.1", - "@backstage/integration-react": "^1.1.1", - "@backstage/plugin-techdocs-react": "^1.0.1", - "@backstage/theme": "^0.2.15", + "@backstage/integration": "^1.2.2-next.2", + "@backstage/integration-react": "^1.1.2-next.2", + "@backstage/plugin-techdocs-react": "^1.0.2-next.1", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.9.13", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", "@react-hookz/web": "^14.0.0", - "git-url-parse": "^11.6.0", + "git-url-parse": "^12.0.0", "react-use": "^17.2.4" }, "peerDependencies": { "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/plugin-techdocs-addons-test-utils": "^1.0.1", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/plugin-techdocs-addons-test-utils": "^1.0.2-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/jest": "^26.0.7", "@types/node": "^16.11.26", "@types/react": "^16.13.1 || ^17.0.0", - "msw": "^0.42.0", + "msw": "^0.43.0", "cross-fetch": "^3.1.5" }, "files": [ diff --git a/plugins/techdocs-node/CHANGELOG.md b/plugins/techdocs-node/CHANGELOG.md index 1902f80171..159966eaae 100644 --- a/plugins/techdocs-node/CHANGELOG.md +++ b/plugins/techdocs-node/CHANGELOG.md @@ -1,5 +1,48 @@ # @backstage/plugin-techdocs-node +## 1.2.0-next.2 + +### Patch Changes + +- e2d7b76f43: Upgrade git-url-parse to 12.0.0. + + Motivation for upgrade is transitively upgrading parse-url which is vulnerable + to several CVEs detected by Snyk. + + - SNYK-JS-PARSEURL-2935944 + - SNYK-JS-PARSEURL-2935947 + - SNYK-JS-PARSEURL-2936249 + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/backend-common@0.14.1-next.2 + - @backstage/integration@1.2.2-next.2 + +## 1.2.0-next.1 + +### Minor Changes + +- 860765ff45: Added local publishing target directory `config`: `techdocs.publisher.local.publishDirectory` + +### Patch Changes + +- a5d73da942: Fix the flag parsing for `legacyCopyReadmeMdToIndexMd` in `techdocs-cli generate` command, and decouple it's logic from the `techdocs-ref` flag. +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/integration@1.2.2-next.1 + - @backstage/plugin-search-common@0.3.6-next.0 + +## 1.1.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/integration@1.2.2-next.0 + ## 1.1.2 ### Patch Changes diff --git a/plugins/techdocs-node/package.json b/plugins/techdocs-node/package.json index 9cd737db80..24ca02de8a 100644 --- a/plugins/techdocs-node/package.json +++ b/plugins/techdocs-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-techdocs-node", "description": "Common node.js functionalities for TechDocs, to be shared between techdocs-backend plugin and techdocs-cli", - "version": "1.1.2", + "version": "1.2.0-next.2", "main": "src/index.ts", "types": "src/index.ts", "private": false, @@ -42,19 +42,19 @@ "dependencies": { "@azure/identity": "^2.0.1", "@azure/storage-blob": "^12.5.0", - "@backstage/backend-common": "^0.14.0", - "@backstage/catalog-model": "^1.0.3", + "@backstage/backend-common": "^0.14.1-next.2", + "@backstage/catalog-model": "^1.1.0-next.2", "@backstage/config": "^1.0.1", - "@backstage/errors": "^1.0.0", - "@backstage/integration": "^1.2.1", - "@backstage/plugin-search-common": "^0.3.5", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/integration": "^1.2.2-next.2", + "@backstage/plugin-search-common": "^0.3.6-next.0", "@google-cloud/storage": "^6.0.0", "@trendyol-js/openstack-swift-sdk": "^0.0.5", "@types/express": "^4.17.6", "aws-sdk": "^2.840.0", "express": "^4.17.1", "fs-extra": "10.1.0", - "git-url-parse": "^11.6.0", + "git-url-parse": "^12.0.0", "js-yaml": "^4.0.0", "json5": "^2.1.3", "mime-types": "^2.1.27", @@ -64,7 +64,7 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.17.2", + "@backstage/cli": "^0.18.0-next.2", "@types/fs-extra": "^9.0.5", "@types/js-yaml": "^4.0.0", "@types/mime-types": "^2.1.0", diff --git a/plugins/techdocs-node/src/stages/generate/techdocs.ts b/plugins/techdocs-node/src/stages/generate/techdocs.ts index 660b8e8cb5..e3debab526 100644 --- a/plugins/techdocs-node/src/stages/generate/techdocs.ts +++ b/plugins/techdocs-node/src/stages/generate/techdocs.ts @@ -111,10 +111,10 @@ export class TechdocsGenerator implements GeneratorBase { parsedLocationAnnotation, this.scmIntegrations, ); + } - if (this.options.legacyCopyReadmeMdToIndexMd) { - await patchIndexPreBuild({ inputDir, logger: childLogger, docsDir }); - } + if (this.options.legacyCopyReadmeMdToIndexMd) { + await patchIndexPreBuild({ inputDir, logger: childLogger, docsDir }); } if (!this.options.omitTechdocsCoreMkdocsPlugin) { diff --git a/plugins/techdocs-node/src/stages/publish/local.test.ts b/plugins/techdocs-node/src/stages/publish/local.test.ts index 0119def16d..ce2e0c3ccd 100644 --- a/plugins/techdocs-node/src/stages/publish/local.test.ts +++ b/plugins/techdocs-node/src/stages/publish/local.test.ts @@ -236,5 +236,32 @@ describe('local publisher', () => { ); expect(response.status).toBe(404); }); + + it('should work with a configured directory', async () => { + const customConfig = new ConfigReader({ + techdocs: { + publisher: { + local: { + publishDirectory: tmpDir, + }, + }, + }, + }); + mockFs({ + [tmpDir]: { + 'index.html': 'found it', + }, + }); + const legacyPublisher = LocalPublish.fromConfig( + customConfig, + logger, + testDiscovery, + ); + app = express().use(legacyPublisher.docsRouter()); + + const response = await request(app).get('/index.html'); + expect(response.status).toBe(200); + expect(response.text).toEqual('found it'); + }); }); }); diff --git a/plugins/techdocs-node/src/stages/publish/local.ts b/plugins/techdocs-node/src/stages/publish/local.ts index 11c6e6dd2b..1a02cb7eee 100644 --- a/plugins/techdocs-node/src/stages/publish/local.ts +++ b/plugins/techdocs-node/src/stages/publish/local.ts @@ -44,40 +44,27 @@ import { } from './helpers'; import { ForwardedError } from '@backstage/errors'; -// TODO: Use a more persistent storage than node_modules or /tmp directory. -// Make it configurable with techdocs.publisher.local.publishDirectory -let staticDocsDir = ''; -try { - staticDocsDir = resolvePackagePath( - '@backstage/plugin-techdocs-backend', - 'static/docs', - ); -} catch (err) { - // This will most probably never be used. - // The try/catch is introduced so that techdocs-cli can import @backstage/plugin-techdocs-node - // on CI/CD without installing techdocs backend plugin. - staticDocsDir = os.tmpdir(); -} - /** - * Local publisher which uses the local filesystem to store the generated static files. It uses a directory - * called "static" at the root of techdocs-backend plugin. + * Local publisher which uses the local filesystem to store the generated static files. It uses by default a + * directory called "static" at the root of techdocs-backend plugin unless a directory has been configured by + * "techdocs.publisher.local.publishDirectory". */ export class LocalPublish implements PublisherBase { private readonly legacyPathCasing: boolean; private readonly logger: Logger; private readonly discovery: PluginEndpointDiscovery; + private readonly staticDocsDir: string; - // TODO: Move the logic of setting staticDocsDir based on config over to - // fromConfig, and set the value as a class parameter. constructor(options: { logger: Logger; discovery: PluginEndpointDiscovery; legacyPathCasing: boolean; + staticDocsDir: string; }) { this.logger = options.logger; this.discovery = options.discovery; this.legacyPathCasing = options.legacyPathCasing; + this.staticDocsDir = options.staticDocsDir; } static fromConfig( @@ -90,10 +77,28 @@ export class LocalPublish implements PublisherBase { 'techdocs.legacyUseCaseSensitiveTripletPaths', ) || false; + let staticDocsDir = config.getOptionalString( + 'techdocs.publisher.local.publishDirectory', + ); + if (!staticDocsDir) { + try { + staticDocsDir = resolvePackagePath( + '@backstage/plugin-techdocs-backend', + 'static/docs', + ); + } catch (err) { + // This will most probably never be used. + // The try/catch is introduced so that techdocs-cli can import @backstage/plugin-techdocs-node + // on CI/CD without installing techdocs backend plugin. + staticDocsDir = os.tmpdir(); + } + } + return new LocalPublish({ logger, discovery, legacyPathCasing, + staticDocsDir, }); } @@ -144,7 +149,7 @@ export class LocalPublish implements PublisherBase { const techdocsApiUrl = await this.discovery.getBaseUrl('techdocs'); const publishedFilePaths = (await getFileTreeRecursively(publishDir)).map( abs => { - return abs.split(`${staticDocsDir}/`)[1]; + return abs.split(`${this.staticDocsDir}/`)[1]; }, ); @@ -222,9 +227,8 @@ export class LocalPublish implements PublisherBase { // Otherwise, redirect to the new path. return res.redirect(301, req.baseUrl + newPath); }); - router.use( - express.static(staticDocsDir, { + express.static(this.staticDocsDir, { // Handle content-type header the same as all other publishers. setHeaders: (res, filePath) => { const fileExtension = path.extname(filePath); @@ -275,13 +279,16 @@ export class LocalPublish implements PublisherBase { concurrency = 25, }): Promise { // Iterate through every file in the root of the publisher. - const files = await getFileTreeRecursively(staticDocsDir); + const files = await getFileTreeRecursively(this.staticDocsDir); const limit = createLimiter(concurrency); await Promise.all( files.map(f => limit(async file => { - const relativeFile = file.replace(`${staticDocsDir}${path.sep}`, ''); + const relativeFile = file.replace( + `${this.staticDocsDir}${path.sep}`, + '', + ); const newFile = lowerCaseEntityTripletInStoragePath(relativeFile); // If all parts are already lowercase, ignore. @@ -311,7 +318,7 @@ export class LocalPublish implements PublisherBase { * Utility wrapper around path.join(), used to control legacy case logic. */ protected staticEntityPathJoin(...allParts: string[]): string { - let staticEntityPath = staticDocsDir; + let staticEntityPath = this.staticDocsDir; allParts .map(part => part.split(path.sep)) diff --git a/plugins/techdocs-react/CHANGELOG.md b/plugins/techdocs-react/CHANGELOG.md index 904eacff26..aa839600c3 100644 --- a/plugins/techdocs-react/CHANGELOG.md +++ b/plugins/techdocs-react/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-techdocs-react +## 1.0.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + +## 1.0.2-next.0 + +### Patch Changes + +- c3cfc83af2: Updated JSDoc to be MDX compatible. +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + ## 1.0.1 ### Patch Changes diff --git a/plugins/techdocs-react/package.json b/plugins/techdocs-react/package.json index f4a51bfe42..042dd4c81b 100644 --- a/plugins/techdocs-react/package.json +++ b/plugins/techdocs-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-techdocs-react", "description": "Shared frontend utilities for TechDocs and Addons", - "version": "1.0.1", + "version": "1.0.2-next.1", "private": false, "publishConfig": { "access": "public", @@ -35,8 +35,8 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", - "@backstage/core-components": "^0.9.5", + "@backstage/catalog-model": "^1.1.0-next.2", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", "@backstage/version-bridge": "^1.0.1", "@material-ui/core": "^4.12.2", @@ -56,8 +56,8 @@ "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/react-hooks": "^8.0.0", - "@backstage/test-utils": "^1.1.1", - "@backstage/theme": "^0.2.15" + "@backstage/test-utils": "^1.1.2-next.1", + "@backstage/theme": "^0.2.16-next.1" }, "files": [ "alpha", diff --git a/plugins/techdocs/CHANGELOG.md b/plugins/techdocs/CHANGELOG.md index 91babd6fba..aad89b46cf 100644 --- a/plugins/techdocs/CHANGELOG.md +++ b/plugins/techdocs/CHANGELOG.md @@ -1,5 +1,59 @@ # @backstage/plugin-techdocs +## 1.2.1-next.2 + +### Patch Changes + +- e2d7b76f43: Upgrade git-url-parse to 12.0.0. + + Motivation for upgrade is transitively upgrading parse-url which is vulnerable + to several CVEs detected by Snyk. + + - SNYK-JS-PARSEURL-2935944 + - SNYK-JS-PARSEURL-2935947 + - SNYK-JS-PARSEURL-2936249 + +- 7739141ab2: Fix: When docs are shown in an entity page under the docs tab the sidebars start overlapping with the header and tabs in the page when you scroll the documentation content. +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/plugin-search-react@0.2.2-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/integration@1.2.2-next.2 + - @backstage/plugin-catalog-react@1.1.2-next.2 + - @backstage/integration-react@1.1.2-next.2 + - @backstage/plugin-techdocs-react@1.0.2-next.1 + +## 1.2.1-next.1 + +### Patch Changes + +- 726577958f: Remove the 60% factor from the font size calculation of headers to use the exact size defined in BackstageTheme. +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + - @backstage/integration@1.2.2-next.1 + - @backstage/integration-react@1.1.2-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.1 + - @backstage/plugin-search-common@0.3.6-next.0 + - @backstage/plugin-search-react@0.2.2-next.1 + +## 1.2.1-next.0 + +### Patch Changes + +- 3cbebf710e: Reorder browser tab title in Techdocs pages to have the site name first. +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-techdocs-react@1.0.2-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + - @backstage/integration-react@1.1.2-next.0 + - @backstage/plugin-search-react@0.2.2-next.0 + ## 1.2.0 ### Minor Changes diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index 45c6d98aec..55b4a7c707 100644 --- a/plugins/techdocs/package.json +++ b/plugins/techdocs/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-techdocs", "description": "The Backstage plugin that renders technical documentation for your components", - "version": "1.2.0", + "version": "1.2.1-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,25 +35,25 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", + "@backstage/catalog-model": "^1.1.0-next.2", "@backstage/config": "^1.0.1", - "@backstage/core-components": "^0.9.5", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/errors": "^1.0.0", - "@backstage/integration": "^1.2.1", - "@backstage/integration-react": "^1.1.1", - "@backstage/plugin-catalog-react": "^1.1.1", - "@backstage/plugin-search-common": "^0.3.5", - "@backstage/plugin-search-react": "^0.2.1", - "@backstage/plugin-techdocs-react": "^1.0.1", - "@backstage/theme": "^0.2.15", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/integration": "^1.2.2-next.2", + "@backstage/integration-react": "^1.1.2-next.2", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", + "@backstage/plugin-search-common": "^0.3.6-next.0", + "@backstage/plugin-search-react": "^0.2.2-next.2", + "@backstage/plugin-techdocs-react": "^1.0.2-next.1", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", "@material-ui/styles": "^4.10.0", "dompurify": "^2.2.9", "event-source-polyfill": "1.0.25", - "git-url-parse": "^11.6.0", + "git-url-parse": "^12.0.0", "jss": "~10.8.2", "lodash": "^4.17.21", "react-helmet": "6.1.0", @@ -67,10 +67,10 @@ "react-dom": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/react-hooks": "^8.0.0", @@ -81,7 +81,7 @@ "@types/node": "^16.11.26", "canvas": "^2.6.1", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist", diff --git a/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.tsx b/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.tsx index 6885957002..9f69dcb8d8 100644 --- a/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.tsx @@ -106,16 +106,18 @@ export const TechDocsReaderPage = (props: TechDocsReaderPageProps) => { return ( {({ metadata, entityMetadata, onReady }) => ( - - {children instanceof Function - ? children({ - entityRef, - techdocsMetadataValue: metadata.value, - entityMetadataValue: entityMetadata.value, - onReady, - }) - : children} - +
+ + {children instanceof Function + ? children({ + entityRef, + techdocsMetadataValue: metadata.value, + entityMetadataValue: entityMetadata.value, + onReady, + }) + : children} + +
)}
); diff --git a/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/dom.tsx b/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/dom.tsx index 9f561bfcd3..76b07c9d32 100644 --- a/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/dom.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/dom.tsx @@ -81,9 +81,17 @@ export const useTechDocsReaderDom = ( if (isMobileMedia) { element.style.top = '0px'; } else { - const domTop = dom.getBoundingClientRect().top ?? 0; + const page = document?.querySelector('.techdocs-reader-page'); + const pageTop = page?.getBoundingClientRect().top ?? 0; + let domTop = dom.getBoundingClientRect().top ?? 0; + const tabs = dom.querySelector('.md-container > .md-tabs'); const tabsHeight = tabs?.getBoundingClientRect().height ?? 0; + + // the sidebars should not scroll beyond the total height of the header and tabs + if (domTop < pageTop) { + domTop = pageTop; + } element.style.top = `${Math.max(domTop, 0) + tabsHeight}px`; } diff --git a/plugins/techdocs/src/reader/components/TechDocsReaderPageHeader/TechDocsReaderPageHeader.tsx b/plugins/techdocs/src/reader/components/TechDocsReaderPageHeader/TechDocsReaderPageHeader.tsx index 9cf3d15471..8826154eee 100644 --- a/plugins/techdocs/src/reader/components/TechDocsReaderPageHeader/TechDocsReaderPageHeader.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsReaderPageHeader/TechDocsReaderPageHeader.tsx @@ -91,7 +91,7 @@ export const TechDocsReaderPageHeader = ( }, [metadata, setTitle, setSubtitle]); const appTitle = configApi.getOptional('app.title') || 'Backstage'; - const tabTitle = [subtitle, title, appTitle].filter(Boolean).join(' | '); + const tabTitle = [title, subtitle, appTitle].filter(Boolean).join(' | '); const { locationMetadata, spec } = entityMetadata || {}; const lifecycle = spec?.lifecycle; diff --git a/plugins/techdocs/src/reader/transformers/styles/rules/typeset.ts b/plugins/techdocs/src/reader/transformers/styles/rules/typeset.ts index e24b61da83..6a3b0461ef 100644 --- a/plugins/techdocs/src/reader/transformers/styles/rules/typeset.ts +++ b/plugins/techdocs/src/reader/transformers/styles/rules/typeset.ts @@ -16,8 +16,14 @@ import { RuleOptions } from './types'; +type RuleTypography = RuleOptions['theme']['typography']; + +type BackstageTypography = RuleTypography & { + htmlFontSize?: number; +}; + type TypographyHeadings = Pick< - RuleOptions['theme']['typography'], + RuleTypography, 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' >; @@ -33,13 +39,15 @@ export default ({ theme }: RuleOptions) => ` } ${headings.reduce((style, heading) => { + const htmlFontSize = + (theme.typography as BackstageTypography).htmlFontSize ?? 16; const styles = theme.typography[heading]; const { lineHeight, fontFamily, fontWeight, fontSize } = styles; const calculate = (value: typeof fontSize) => { let factor: number | string = 1; if (typeof value === 'number') { - // 60% of the size defined because it is too big - factor = (value / 16) * 0.6; + // convert px to rem + factor = value / htmlFontSize; } if (typeof value === 'string') { factor = value.replace('rem', ''); diff --git a/plugins/todo-backend/CHANGELOG.md b/plugins/todo-backend/CHANGELOG.md index 8fc6adbfcb..005a900f20 100644 --- a/plugins/todo-backend/CHANGELOG.md +++ b/plugins/todo-backend/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/plugin-todo-backend +## 0.1.31-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/catalog-client@1.0.4-next.1 + - @backstage/integration@1.2.2-next.1 + +## 0.1.31-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/integration@1.2.2-next.0 + - @backstage/catalog-client@1.0.4-next.0 + ## 0.1.30 ### Patch Changes diff --git a/plugins/todo-backend/package.json b/plugins/todo-backend/package.json index 235e05a93b..a49bd6fae5 100644 --- a/plugins/todo-backend/package.json +++ b/plugins/todo-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-todo-backend", "description": "A Backstage backend plugin that lets you browse TODO comments in your source code", - "version": "0.1.30", + "version": "0.1.31-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -29,12 +29,12 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", - "@backstage/catalog-client": "^1.0.3", - "@backstage/catalog-model": "^1.0.3", + "@backstage/backend-common": "^0.14.1-next.1", + "@backstage/catalog-client": "^1.0.4-next.1", + "@backstage/catalog-model": "^1.1.0-next.1", "@backstage/config": "^1.0.1", - "@backstage/errors": "^1.0.0", - "@backstage/integration": "^1.2.1", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/integration": "^1.2.2-next.1", "@types/express": "^4.17.6", "express": "^4.17.1", "express-promise-router": "^4.1.0", @@ -43,9 +43,9 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", + "@backstage/cli": "^0.18.0-next.1", "@types/supertest": "^2.0.8", - "msw": "^0.42.0", + "msw": "^0.43.0", "supertest": "^6.1.3" }, "files": [ diff --git a/plugins/todo/CHANGELOG.md b/plugins/todo/CHANGELOG.md index 77eda64a68..a2892e3036 100644 --- a/plugins/todo/CHANGELOG.md +++ b/plugins/todo/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-todo +## 0.2.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## 0.2.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## 0.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + ## 0.2.8 ### Patch Changes diff --git a/plugins/todo/package.json b/plugins/todo/package.json index 7fbf79cd3a..255a58a0d5 100644 --- a/plugins/todo/package.json +++ b/plugins/todo/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-todo", "description": "A Backstage plugin that lets you browse TODO comments in your source code", - "version": "0.2.8", + "version": "0.2.9-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,12 +30,12 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", - "@backstage/core-components": "^0.9.5", + "@backstage/catalog-model": "^1.1.0-next.2", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/errors": "^1.0.0", - "@backstage/plugin-catalog-react": "^1.1.1", - "@backstage/theme": "^0.2.15", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -45,17 +45,17 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/jest": "^26.0.7", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.42.0", + "msw": "^0.43.0", "react-router": "6.0.0-beta.0" }, "files": [ diff --git a/plugins/user-settings/CHANGELOG.md b/plugins/user-settings/CHANGELOG.md index 81cc4a891f..a515a7572a 100644 --- a/plugins/user-settings/CHANGELOG.md +++ b/plugins/user-settings/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-user-settings +## 0.4.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + +## 0.4.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/theme@0.2.16-next.0 + +## 0.4.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + ## 0.4.5 ### Patch Changes diff --git a/plugins/user-settings/package.json b/plugins/user-settings/package.json index aa4335856e..e2527933ee 100644 --- a/plugins/user-settings/package.json +++ b/plugins/user-settings/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-user-settings", "description": "A Backstage plugin that provides a settings page", - "version": "0.4.5", + "version": "0.4.6-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,9 +34,9 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.9.5", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/theme": "^0.2.15", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -48,17 +48,17 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/jest": "^26.0.7", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/vault-backend/CHANGELOG.md b/plugins/vault-backend/CHANGELOG.md index 302b27afa8..6b1dba1bfa 100644 --- a/plugins/vault-backend/CHANGELOG.md +++ b/plugins/vault-backend/CHANGELOG.md @@ -1,5 +1,38 @@ # @backstage/plugin-vault-backend +## 0.2.0-next.2 + +### Patch Changes + +- 7ee4abdcc9: Added a path notion in addition to secret name to allow to differentiate secrets in sub-paths +- Updated dependencies + - @backstage/backend-common@0.14.1-next.2 + - @backstage/backend-tasks@0.3.3-next.2 + - @backstage/backend-test-utils@0.1.26-next.2 + +## 0.2.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/backend-tasks@0.3.3-next.1 + - @backstage/backend-test-utils@0.1.26-next.1 + +## 0.2.0-next.0 + +### Minor Changes + +- 5ebf2c7023: Throw exceptions instead of swallow them, remove some exported types from the `api-report`, small changes in the API responses & expose the vault `baseUrl` to the frontend as well + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.14.1-next.0 + - @backstage/backend-tasks@0.3.3-next.0 + - @backstage/backend-test-utils@0.1.26-next.0 + ## 0.1.0 ### Minor Changes diff --git a/plugins/vault-backend/api-report.md b/plugins/vault-backend/api-report.md index 1c7e669ef2..d2e9e1b177 100644 --- a/plugins/vault-backend/api-report.md +++ b/plugins/vault-backend/api-report.md @@ -12,13 +12,6 @@ import { TaskRunner } from '@backstage/backend-tasks'; // @public export function createRouter(options: RouterOptions): express.Router; -// @public -export type RenewTokenResponse = { - auth: { - client_token: string; - }; -}; - // @public export interface RouterOptions { // (undocumented) @@ -33,7 +26,7 @@ export interface RouterOptions { export interface VaultApi { getFrontendSecretsUrl(): string; listSecrets(secretPath: string): Promise; - renewToken?(): Promise; + renewToken?(): Promise; } // @public @@ -45,7 +38,6 @@ export class VaultBuilder { enableTokenRenew(schedule?: TaskRunner): Promise; // (undocumented) protected readonly env: VaultEnvironment; - protected renewToken(vaultClient: VaultClient): Promise; setVaultClient(vaultClient: VaultClient): this; } @@ -62,7 +54,7 @@ export class VaultClient implements VaultApi { // (undocumented) listSecrets(secretPath: string): Promise; // (undocumented) - renewToken(): Promise; + renewToken(): Promise; } // @public @@ -78,16 +70,10 @@ export interface VaultEnvironment { // @public export type VaultSecret = { name: string; + path: string; showUrl: string; editUrl: string; }; -// @public -export type VaultSecretList = { - data: { - keys: string[]; - }; -}; - // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/vault-backend/config.d.ts b/plugins/vault-backend/config.d.ts index b1f917463e..c7aac4db9d 100644 --- a/plugins/vault-backend/config.d.ts +++ b/plugins/vault-backend/config.d.ts @@ -19,6 +19,7 @@ export interface Config { vault?: { /** * The baseUrl for your Vault instance. + * @visibility frontend */ baseUrl: string; diff --git a/plugins/vault-backend/package.json b/plugins/vault-backend/package.json index 651b95f98c..df5d0f5fa6 100644 --- a/plugins/vault-backend/package.json +++ b/plugins/vault-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-vault-backend", "description": "A Backstage backend plugin that integrates towards Vault", - "version": "0.1.0", + "version": "0.2.0-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,11 +34,11 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/backend-common": "^0.14.0", - "@backstage/backend-tasks": "^0.3.2", - "@backstage/backend-test-utils": "^0.1.25", + "@backstage/backend-common": "^0.14.1-next.2", + "@backstage/backend-tasks": "^0.3.3-next.2", + "@backstage/backend-test-utils": "^0.1.26-next.2", "@backstage/config": "^1.0.1", - "@backstage/errors": "^1.0.0", + "@backstage/errors": "^1.1.0-next.0", "@types/express": "*", "compression": "^1.7.4", "cors": "^2.8.5", @@ -46,15 +46,16 @@ "express": "^4.17.1", "express-promise-router": "^4.1.0", "helmet": "^5.0.2", + "p-limit": "^3.1.0", "winston": "^3.7.2", "yn": "^5.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", + "@backstage/cli": "^0.18.0-next.2", "@types/compression": "^1.7.2", "@types/supertest": "^2.0.8", - "msw": "^0.42.0", - "supertest": "^4.0.2" + "msw": "^0.43.0", + "supertest": "^6.1.6" }, "files": [ "dist", diff --git a/plugins/vault-backend/src/service/VaultBuilder.tsx b/plugins/vault-backend/src/service/VaultBuilder.tsx index aa2858345f..67260f45ca 100644 --- a/plugins/vault-backend/src/service/VaultBuilder.tsx +++ b/plugins/vault-backend/src/service/VaultBuilder.tsx @@ -45,9 +45,6 @@ export type VaultBuilderReturn = { * @public */ export class VaultBuilder { - // private vaultTokenRefreshInterval: Duration = Duration.fromObject({ - // minutes: 60, - // }); private vaultClient?: VaultClient; /** @@ -118,26 +115,12 @@ export class VaultBuilder { fn: async () => { this.env.logger.info('Renewing Vault token'); const vaultClient = this.vaultClient ?? new VaultClient(this.env); - await this.renewToken(vaultClient); + await vaultClient.renewToken(); }, }); return this; } - /** - * Renews the token for vault using a defined client. - * - * @param vaultClient - The vault client used to renew the token - */ - protected async renewToken(vaultClient: VaultClient) { - const result = await vaultClient.renewToken(); - if (!result) { - this.env.logger.warn('Error renewing vault token'); - } else { - this.env.logger.info('Vault token renewed'); - } - } - /** * Builds the backend routes for Vault. * @@ -159,7 +142,7 @@ export class VaultBuilder { } const secrets = await vaultClient.listSecrets(path); - res.json(secrets); + res.json({ items: secrets }); }); return router; diff --git a/plugins/vault-backend/src/service/vaultApi.test.ts b/plugins/vault-backend/src/service/vaultApi.test.ts index 5a29633933..1fb869ef60 100644 --- a/plugins/vault-backend/src/service/vaultApi.test.ts +++ b/plugins/vault-backend/src/service/vaultApi.test.ts @@ -46,11 +46,13 @@ describe('VaultApi', () => { const mockSecretsResult: VaultSecret[] = [ { name: 'secret::one', + path: 'test/success', editUrl: `${mockBaseUrl}/ui/vault/secrets/secrets/edit/test/success/secret::one`, showUrl: `${mockBaseUrl}/ui/vault/secrets/secrets/show/test/success/secret::one`, }, { name: 'secret::two', + path: 'test/success', editUrl: `${mockBaseUrl}/ui/vault/secrets/secrets/edit/test/success/secret::two`, showUrl: `${mockBaseUrl}/ui/vault/secrets/secrets/show/test/success/secret::two`, }, @@ -93,8 +95,7 @@ describe('VaultApi', () => { it('should return success token renew', async () => { setupHandlers(); const api = new VaultClient({ config }); - const apiRenew = await api.renewToken(); - expect(apiRenew).toBeTruthy(); + expect(await api.renewToken()).toBe(undefined); }); it('should render frontend url', () => { diff --git a/plugins/vault-backend/src/service/vaultApi.ts b/plugins/vault-backend/src/service/vaultApi.ts index 0623780654..158778294a 100644 --- a/plugins/vault-backend/src/service/vaultApi.ts +++ b/plugins/vault-backend/src/service/vaultApi.ts @@ -15,12 +15,14 @@ */ import { Config } from '@backstage/config'; +import { NotFoundError } from '@backstage/errors'; import fetch from 'cross-fetch'; +import plimit from 'p-limit'; import { getVaultConfig, VaultConfig } from '../config'; /** * Object received as a response from the Vault API when fetching secrets - * @public + * @internal */ export type VaultSecretList = { data: { @@ -34,15 +36,15 @@ export type VaultSecretList = { */ export type VaultSecret = { name: string; + path: string; showUrl: string; editUrl: string; }; /** * Object received as response when the token is renewed using the Vault API - * @public */ -export type RenewTokenResponse = { +type RenewTokenResponse = { auth: { client_token: string; }; @@ -63,10 +65,10 @@ export interface VaultApi { */ listSecrets(secretPath: string): Promise; /** - * Optional, to renew the token used to list the secrets. Returns true - * if the action was successfull, false otherwise. + * Optional, to renew the token used to list the secrets. Throws an + * error if the token renewal went wrong. */ - renewToken?(): Promise; + renewToken?(): Promise; } /** @@ -75,6 +77,7 @@ export interface VaultApi { */ export class VaultClient implements VaultApi { private vaultConfig: VaultConfig; + private readonly limit = plimit(5); constructor({ config }: { config: Config }) { this.vaultConfig = getVaultConfig(config); @@ -84,7 +87,7 @@ export class VaultClient implements VaultApi { path: string, query: { [key in string]: any }, method: string = 'GET', - ): Promise { + ): Promise { const url = new URL(path, this.vaultConfig.baseUrl); const response = await fetch( `${url.toString()}?${new URLSearchParams(query).toString()}`, @@ -96,15 +99,14 @@ export class VaultClient implements VaultApi { }, }, ); - if (response.status === 200) { + if (response.ok) { return (await response.json()) as T; + } else if (response.status === 404) { + throw new NotFoundError(`No secrets found in path '${path}'`); } - return undefined; - } - - private isFolder(secretName: string): boolean { - const regex = /^.*\/$/gm; - return regex.test(secretName); + throw new Error( + `Unexpected error while fetching secrets from path '${path}'`, + ); } getFrontendSecretsUrl(): string { @@ -116,21 +118,24 @@ export class VaultClient implements VaultApi { this.vaultConfig.kvVersion === 2 ? `v1/${this.vaultConfig.secretEngine}/metadata/${secretPath}` : `v1/${this.vaultConfig.secretEngine}/${secretPath}`; - const result = await this.callApi(listUrl, { list: true }); - if (!result) { - return []; - } + const result = await this.limit(() => + this.callApi(listUrl, { list: true }), + ); const secrets: VaultSecret[] = []; + await Promise.all( result.data.keys.map(async secret => { - if (this.isFolder(secret)) { + if (secret.endsWith('/')) { secrets.push( - ...(await this.listSecrets(`${secretPath}/${secret.slice(0, -1)}`)), + ...(await this.limit(() => + this.listSecrets(`${secretPath}/${secret.slice(0, -1)}`), + )), ); } else { secrets.push({ name: secret, + path: secretPath, editUrl: `${this.vaultConfig.baseUrl}/ui/vault/secrets/${this.vaultConfig.secretEngine}/edit/${secretPath}/${secret}`, showUrl: `${this.vaultConfig.baseUrl}/ui/vault/secrets/${this.vaultConfig.secretEngine}/show/${secretPath}/${secret}`, }); @@ -141,17 +146,13 @@ export class VaultClient implements VaultApi { return secrets; } - async renewToken(): Promise { + async renewToken(): Promise { const result = await this.callApi( 'v1/auth/token/renew-self', {}, 'POST', ); - if (!result) { - return false; - } this.vaultConfig.token = result.auth.client_token; - return true; } } diff --git a/plugins/vault/CHANGELOG.md b/plugins/vault/CHANGELOG.md index 205b537dd4..317d6ae7d6 100644 --- a/plugins/vault/CHANGELOG.md +++ b/plugins/vault/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/plugin-vault +## 0.1.1-next.2 + +### Patch Changes + +- 7ee4abdcc9: Added a path notion in addition to secret name to allow to differentiate secrets in sub-paths +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/catalog-model@1.1.0-next.2 + - @backstage/theme@0.2.16-next.1 + - @backstage/plugin-catalog-react@1.1.2-next.2 + +## 0.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/catalog-model@1.1.0-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.1 + +## 0.1.1-next.0 + +### Patch Changes + +- 5ebf2c7023: Export missing parameters and added them to the api-report. Also adapted the API to the expected response from the backend +- Updated dependencies + - @backstage/catalog-model@1.1.0-next.0 + - @backstage/core-components@0.9.6-next.0 + - @backstage/plugin-catalog-react@1.1.2-next.0 + ## 0.1.0 ### Minor Changes diff --git a/plugins/vault/api-report.md b/plugins/vault/api-report.md index a0b5773c70..b347989800 100644 --- a/plugins/vault/api-report.md +++ b/plugins/vault/api-report.md @@ -5,13 +5,37 @@ ```ts /// +import { ApiRef } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/core-plugin-api'; +import { Entity } from '@backstage/catalog-model'; // @public export const EntityVaultCard: () => JSX.Element; +// @public +export function isVaultAvailable(entity: Entity): boolean; + +// @public (undocumented) +export const VAULT_SECRET_PATH_ANNOTATION = 'vault.io/secrets-path'; + +// @public +export interface VaultApi { + listSecrets(secretPath: string): Promise; +} + +// @public (undocumented) +export const vaultApiRef: ApiRef; + // @public export const vaultPlugin: BackstagePlugin<{}, {}>; +// @public +export type VaultSecret = { + name: string; + path: string; + showUrl: string; + editUrl: string; +}; + // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/vault/dev/index.tsx b/plugins/vault/dev/index.tsx index f5056cd057..8d902e14c5 100644 --- a/plugins/vault/dev/index.tsx +++ b/plugins/vault/dev/index.tsx @@ -45,11 +45,13 @@ const mockedApi: VaultApi = { return [ { name: 'a::b', + path: '', editUrl: 'https://example.com', showUrl: 'https://example.com', }, { name: 'c::d', + path: '', editUrl: 'https://example.com', showUrl: 'https://example.com', }, diff --git a/plugins/vault/package.json b/plugins/vault/package.json index 54fc7cfc90..43ac2fdb26 100644 --- a/plugins/vault/package.json +++ b/plugins/vault/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-vault", "description": "A Backstage plugin that integrates towards Vault", - "version": "0.1.0", + "version": "0.1.1-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,11 +34,12 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/catalog-model": "^1.0.3", - "@backstage/core-components": "^0.9.5", + "@backstage/catalog-model": "^1.1.0-next.2", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/plugin-catalog-react": "^1.1.1", - "@backstage/theme": "^0.2.15", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/plugin-catalog-react": "^1.1.2-next.2", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "^4.0.0-alpha.57", @@ -48,17 +49,17 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/jest": "*", "@types/node": "*", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/plugins/vault/src/api.test.ts b/plugins/vault/src/api.test.ts index 70c6a553df..4ce6f95c41 100644 --- a/plugins/vault/src/api.test.ts +++ b/plugins/vault/src/api.test.ts @@ -27,18 +27,22 @@ describe('api', () => { const mockBaseUrl = 'https://api-vault.com/api/vault'; const discoveryApi = UrlPatternDiscovery.compile(mockBaseUrl); - const mockSecretsResult: VaultSecret[] = [ - { - name: 'secret::one', - editUrl: `${mockBaseUrl}/ui/vault/secrets/secrets/edit/test/success/secret::one`, - showUrl: `${mockBaseUrl}/ui/vault/secrets/secrets/show/test/success/secret::one`, - }, - { - name: 'secret::two', - editUrl: `${mockBaseUrl}/ui/vault/secrets/secrets/edit/test/success/secret::two`, - showUrl: `${mockBaseUrl}/ui/vault/secrets/secrets/show/test/success/secret::two`, - }, - ]; + const mockSecretsResult: { items: VaultSecret[] } = { + items: [ + { + name: 'secret::one', + path: 'test/success', + editUrl: `${mockBaseUrl}/ui/vault/secrets/secrets/edit/test/success/secret::one`, + showUrl: `${mockBaseUrl}/ui/vault/secrets/secrets/show/test/success/secret::one`, + }, + { + name: 'secret::two', + path: 'test/success', + editUrl: `${mockBaseUrl}/ui/vault/secrets/secrets/edit/test/success/secret::two`, + showUrl: `${mockBaseUrl}/ui/vault/secrets/secrets/show/test/success/secret::two`, + }, + ], + }; const setupHandlers = () => { server.use( @@ -47,31 +51,33 @@ describe('api', () => { if (path === 'test/success') { return res(ctx.json(mockSecretsResult)); } else if (path === 'test/error') { - return res(ctx.json([])); + return res(ctx.json({ items: [] })); } return res(ctx.status(400)); }), + rest.get(`${mockBaseUrl}/v1/secrets/`, (_req, res, ctx) => { + return res(ctx.json(mockSecretsResult)); + }), ); }; it('should return secrets', async () => { setupHandlers(); const api = new VaultClient({ discoveryApi }); - const secrets = await api.listSecrets('test/success'); - expect(secrets).toEqual(mockSecretsResult); + expect(await api.listSecrets('test/success')).toEqual( + mockSecretsResult.items, + ); }); it('should return empty secret list', async () => { setupHandlers(); const api = new VaultClient({ discoveryApi }); expect(await api.listSecrets('test/error')).toEqual([]); - expect(await api.listSecrets('')).toEqual([]); }); - it('should return no secrets', async () => { + it('should return all the secrets if no path defined', async () => { setupHandlers(); const api = new VaultClient({ discoveryApi }); - const secrets = await api.listSecrets(''); - expect(secrets).toEqual([]); + expect(await api.listSecrets('')).toEqual(mockSecretsResult.items); }); }); diff --git a/plugins/vault/src/api.ts b/plugins/vault/src/api.ts index 74b212429f..bdd881e08c 100644 --- a/plugins/vault/src/api.ts +++ b/plugins/vault/src/api.ts @@ -14,21 +14,42 @@ * limitations under the License. */ import { DiscoveryApi, createApiRef } from '@backstage/core-plugin-api'; +import { NotFoundError } from '@backstage/errors'; +/** + * @public + */ export const vaultApiRef = createApiRef({ id: 'plugin.vault.service', }); +/** + * Object containing the secret name and some links. + * @public + */ export type VaultSecret = { name: string; + path: string; showUrl: string; editUrl: string; }; +/** + * Interface for the VaultApi. + * @public + */ export interface VaultApi { + /** + * Returns a list of secrets used to show in a table. + * @param secretPath - The path where the secrets are stored in Vault + */ listSecrets(secretPath: string): Promise; } +/** + * Default implementation of the VaultApi. + * @public + */ export class VaultClient implements VaultApi { private readonly discoveryApi: DiscoveryApi; @@ -39,7 +60,7 @@ export class VaultClient implements VaultApi { private async callApi( path: string, query: { [key in string]: any }, - ): Promise { + ): Promise { const apiUrl = `${await this.discoveryApi.getBaseUrl('vault')}`; const response = await fetch( `${apiUrl}/${path}?${new URLSearchParams(query).toString()}`, @@ -49,23 +70,21 @@ export class VaultClient implements VaultApi { }, }, ); - if (response.status === 200) { + if (response.ok) { return (await response.json()) as T; + } else if (response.status === 404) { + throw new NotFoundError(`No secrets found in path '${path}'`); } - return undefined; + throw new Error( + `Unexpected error while fetching secrets from path '${path}'`, + ); } async listSecrets(secretPath: string): Promise { - if (secretPath === '') { - return []; - } - const result = await this.callApi( + const result = await this.callApi<{ items: VaultSecret[] }>( `v1/secrets/${encodeURIComponent(secretPath)}`, {}, ); - if (!result) { - return []; - } - return result; + return result.items; } } diff --git a/plugins/vault/src/components/EntityVaultTable/EntityVaultTable.test.tsx b/plugins/vault/src/components/EntityVaultTable/EntityVaultTable.test.tsx index f2b181562a..82a90f23e1 100644 --- a/plugins/vault/src/components/EntityVaultTable/EntityVaultTable.test.tsx +++ b/plugins/vault/src/components/EntityVaultTable/EntityVaultTable.test.tsx @@ -68,18 +68,22 @@ describe('EntityVaultTable', () => { }, }; - const mockSecretsResult: VaultSecret[] = [ - { - name: 'secret::one', - editUrl: `${mockBaseUrl}/ui/vault/secrets/secrets/edit/test/success/secret::one`, - showUrl: `${mockBaseUrl}/ui/vault/secrets/secrets/show/test/success/secret::one`, - }, - { - name: 'secret::two', - editUrl: `${mockBaseUrl}/ui/vault/secrets/secrets/edit/test/success/secret::two`, - showUrl: `${mockBaseUrl}/ui/vault/secrets/secrets/show/test/success/secret::two`, - }, - ]; + const mockSecretsResult: { items: VaultSecret[] } = { + items: [ + { + name: 'secret::one', + path: 'test/success', + editUrl: `${mockBaseUrl}/ui/vault/secrets/secrets/edit/test/success/secret::one`, + showUrl: `${mockBaseUrl}/ui/vault/secrets/secrets/show/test/success/secret::one`, + }, + { + name: 'secret::two', + path: 'test/success', + editUrl: `${mockBaseUrl}/ui/vault/secrets/secrets/edit/test/success/secret::two`, + showUrl: `${mockBaseUrl}/ui/vault/secrets/secrets/show/test/success/secret::two`, + }, + ], + }; const setupHandlers = () => { server.use( diff --git a/plugins/vault/src/components/EntityVaultTable/EntityVaultTable.tsx b/plugins/vault/src/components/EntityVaultTable/EntityVaultTable.tsx index 197c82c5b8..efc345b07f 100644 --- a/plugins/vault/src/components/EntityVaultTable/EntityVaultTable.tsx +++ b/plugins/vault/src/components/EntityVaultTable/EntityVaultTable.tsx @@ -15,7 +15,7 @@ */ import React from 'react'; import { Entity } from '@backstage/catalog-model'; -import { Table, TableColumn } from '@backstage/core-components'; +import { Link, Table, TableColumn } from '@backstage/core-components'; import { useApi } from '@backstage/core-plugin-api'; import { Box, Typography } from '@material-ui/core'; import Edit from '@material-ui/icons/Edit'; @@ -27,7 +27,7 @@ import { VAULT_SECRET_PATH_ANNOTATION } from '../../constants'; export const vaultSecretPath = (entity: Entity) => { const secretPath = - entity.metadata.annotations?.[VAULT_SECRET_PATH_ANNOTATION] ?? ''; + entity.metadata.annotations?.[VAULT_SECRET_PATH_ANNOTATION]; return { secretPath }; }; @@ -35,6 +35,11 @@ export const vaultSecretPath = (entity: Entity) => { export const EntityVaultTable = ({ entity }: { entity: Entity }) => { const vaultApi = useApi(vaultApiRef); const { secretPath } = vaultSecretPath(entity); + if (!secretPath) { + throw Error( + `The secret path is undefined. Please, define the annotation ${VAULT_SECRET_PATH_ANNOTATION}`, + ); + } const { value, loading, error } = useAsync(async (): Promise< VaultSecret[] > => { @@ -48,25 +53,29 @@ export const EntityVaultTable = ({ entity }: { entity: Entity }) => { ]; const data = (value || []).map(secret => { + const secretName = `${secret.path.replace(`${secretPath}/`, '')}/${ + secret.name + }`; + return { - secret: secret.name, + secret: secretName, view: ( - - + ), edit: ( - - + ), }; }); diff --git a/plugins/vault/src/conditions.ts b/plugins/vault/src/conditions.ts index 0ce34085e0..091c7117c2 100644 --- a/plugins/vault/src/conditions.ts +++ b/plugins/vault/src/conditions.ts @@ -16,6 +16,12 @@ import { Entity } from '@backstage/catalog-model'; import { VAULT_SECRET_PATH_ANNOTATION } from './constants'; +/** + * Checks if an entity contains the annotation for Vault. + * @param entity - The entity to check if the annotation exists + * @returns If the annotation exists or not + * @public + */ export function isVaultAvailable(entity: Entity): boolean { return Boolean( entity.metadata.annotations?.hasOwnProperty(VAULT_SECRET_PATH_ANNOTATION), diff --git a/plugins/vault/src/constants.ts b/plugins/vault/src/constants.ts index 1ac8b80b73..0d99c261d4 100644 --- a/plugins/vault/src/constants.ts +++ b/plugins/vault/src/constants.ts @@ -13,4 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +/** + * @public + */ export const VAULT_SECRET_PATH_ANNOTATION = 'vault.io/secrets-path'; diff --git a/plugins/vault/src/index.ts b/plugins/vault/src/index.ts index c2d1fc3419..f69a787963 100644 --- a/plugins/vault/src/index.ts +++ b/plugins/vault/src/index.ts @@ -14,3 +14,7 @@ * limitations under the License. */ export { vaultPlugin, EntityVaultCard } from './plugin'; +export { isVaultAvailable } from './conditions'; +export { VAULT_SECRET_PATH_ANNOTATION } from './constants'; +export { vaultApiRef } from './api'; +export type { VaultApi, VaultSecret } from './api'; diff --git a/plugins/xcmetrics/CHANGELOG.md b/plugins/xcmetrics/CHANGELOG.md index 01d99a138f..a8ac7904a0 100644 --- a/plugins/xcmetrics/CHANGELOG.md +++ b/plugins/xcmetrics/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-xcmetrics +## 0.2.27-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.0-next.2 + - @backstage/theme@0.2.16-next.1 + +## 0.2.27-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.1 + - @backstage/errors@1.1.0-next.0 + - @backstage/theme@0.2.16-next.0 + +## 0.2.27-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.9.6-next.0 + ## 0.2.26 ### Patch Changes diff --git a/plugins/xcmetrics/package.json b/plugins/xcmetrics/package.json index 1c93a9c8cb..67a63f0342 100644 --- a/plugins/xcmetrics/package.json +++ b/plugins/xcmetrics/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-xcmetrics", "description": "A Backstage plugin that shows XCode build metrics for your components", - "version": "0.2.26", + "version": "0.2.27-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -24,10 +24,10 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.9.5", + "@backstage/core-components": "^0.10.0-next.2", "@backstage/core-plugin-api": "^1.0.3", - "@backstage/errors": "^1.0.0", - "@backstage/theme": "^0.2.15", + "@backstage/errors": "^1.1.0-next.0", + "@backstage/theme": "^0.2.16-next.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -40,10 +40,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.17.2", - "@backstage/core-app-api": "^1.0.3", - "@backstage/dev-utils": "^1.0.3", - "@backstage/test-utils": "^1.1.1", + "@backstage/cli": "^0.18.0-next.2", + "@backstage/core-app-api": "^1.0.4-next.0", + "@backstage/dev-utils": "^1.0.4-next.2", + "@backstage/test-utils": "^1.1.2-next.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", @@ -51,7 +51,7 @@ "@types/luxon": "^2.0.4", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.42.0" + "msw": "^0.43.0" }, "files": [ "dist" diff --git a/scripts/api-extractor.ts b/scripts/api-extractor.ts index 2ca7aef17f..21a307b65a 100644 --- a/scripts/api-extractor.ts +++ b/scripts/api-extractor.ts @@ -23,7 +23,7 @@ import { dirname, join, } from 'path'; -import { spawnSync } from 'child_process'; +import { spawnSync, execFile } from 'child_process'; import prettier from 'prettier'; import fs from 'fs-extra'; import { @@ -197,18 +197,6 @@ ApiReportGenerator.generateReviewFileContent = const PACKAGE_ROOTS = ['packages', 'plugins']; -const SKIPPED_PACKAGES = [ - join('packages', 'app'), - join('packages', 'backend'), - join('packages', 'cli'), - join('packages', 'codemods'), - join('packages', 'create-app'), - join('packages', 'e2e-test'), - join('packages', 'techdocs-cli-embedded-app'), - join('packages', 'storybook'), - join('packages', 'techdocs-cli'), -]; - const ALLOW_WARNINGS = [ 'packages/core-components', 'plugins/allure', @@ -231,8 +219,6 @@ const ALLOW_WARNINGS = [ 'plugins/circleci', 'plugins/cloudbuild', 'plugins/code-climate', - 'plugins/code-coverage', - 'plugins/code-coverage-backend', 'plugins/config-schema', 'plugins/cost-insights', 'plugins/dynatrace', @@ -303,9 +289,6 @@ async function findSpecificPackageDirs(unresolvedPackageDirs: string[]) { if (!packageDir) { throw new Error(`'${unresolvedPackageDir}' is not a valid package path`); } - if (SKIPPED_PACKAGES.includes(packageDir)) { - throw new Error(`'${packageDir}' does not have an API report`); - } packageDirs.push(packageDir); } @@ -328,9 +311,7 @@ async function findPackageDirs() { continue; } - if (!SKIPPED_PACKAGES.includes(packageDir)) { - packageDirs.push(packageDir); - } + packageDirs.push(packageDir); } } @@ -1065,6 +1046,252 @@ async function buildDocs({ documenter.generateFiles(); } +async function categorizePackageDirs(projectRoot, packageDirs) { + const dirs = packageDirs.slice(); + const tsPackageDirs = new Array(); + const cliPackageDirs = new Array(); + + await Promise.all( + Array(10) + .fill(0) + .map(async () => { + for (;;) { + const dir = dirs.pop(); + if (!dir) { + return; + } + + const pkgJson = await fs + .readJson(resolvePath(projectRoot, dir, 'package.json')) + .catch(error => { + if (error.code === 'ENOENT') { + return undefined; + } + throw error; + }); + const role = pkgJson?.backstage?.role; + if (!role) { + throw new Error(`No backstage.role in ${dir}/package.json`); + } + if (role === 'cli') { + cliPackageDirs.push(dir); + } else if (role !== 'frontend' && role !== 'backend') { + tsPackageDirs.push(dir); + } + } + }), + ); + + return { tsPackageDirs, cliPackageDirs }; +} + +function createBinRunner(cwd: string, path: string) { + return async (...command: string[]) => + new Promise((resolve, reject) => { + execFile( + 'node', + [path, ...command], + { + cwd, + shell: true, + timeout: 60000, + maxBuffer: 1024 * 1024, + }, + (err, stdout, stderr) => { + if (err) { + reject(new Error(`${err.message}\n${stderr}`)); + } else if (stderr) { + reject(new Error(`Command printed error output: ${stderr}`)); + } else { + resolve(stdout); + } + }, + ); + }); +} + +function parseHelpPage(helpPageContent: string) { + const [, usage] = helpPageContent.match(/^\s*Usage: (.*)$/im) ?? []; + const lines = helpPageContent.split(/\r?\n/); + + let options = new Array(); + let commands = new Array(); + + while (lines.length > 0) { + while (lines.length > 0 && !lines[0].endsWith(':')) { + lines.shift(); + } + if (lines.length > 0) { + // Start of a new section, e.g. "Options:" + const sectionName = lines.shift(); + // Take lines until we hit the next section or the end + const sectionEndIndex = lines.findIndex( + line => line && !line.match(/^\s/), + ); + const sectionLines = lines.slice(0, sectionEndIndex); + lines.splice(0, sectionLines.length); + + // Trim away documentation + const sectionItems = sectionLines + .map(line => line.match(/^\s{1,8}(.*?)\s\s+/)?.[1]) + .filter(Boolean); + + if (sectionName.toLocaleLowerCase('en-US') === 'options:') { + options = sectionItems; + } else if (sectionName.toLocaleLowerCase('en-US') === 'commands:') { + commands = sectionItems; + } else { + throw new Error(`Unknown CLI section: ${sectionName}`); + } + } + } + + return { + usage, + options, + commands, + }; +} + +// Represents the help page os a CLI command +interface CliHelpPage { + // Path of commands to reach this page + path: string[]; + // Parsed content + usage: string | undefined; + options: string[]; + commands: string[]; +} + +async function exploreCliHelpPages( + run: (...args: string[]) => Promise, +): Promise { + const helpPages = new Array(); + + async function exploreHelpPage(...path: string[]) { + const content = await run(...path, '--help'); + const parsed = parseHelpPage(content); + helpPages.push({ path, ...parsed }); + + await Promise.all( + parsed.commands.map(async fullCommand => { + const command = fullCommand.split(/[|\s]/)[0]; + if (command !== 'help') { + await exploreHelpPage(...path, command); + } + }), + ); + } + + await exploreHelpPage(); + + helpPages.sort((a, b) => a.path.join(' ').localeCompare(b.path.join(' '))); + + return helpPages; +} + +// The API model for a CLI entry point +interface CliModel { + name: string; + helpPages: CliHelpPage[]; +} + +function generateCliReport(name: string, models: CliModel[]): string { + const content = [ + `## CLI Report file for "${name}"`, + '', + '> Do not edit this file. It is a report generated by `yarn build:api-reports`', + '', + ]; + + for (const model of models) { + for (const helpPage of model.helpPages) { + content.push( + `### \`${[model.name, ...helpPage.path].join(' ')}\``, + '', + '```', + `Usage: ${helpPage.usage ?? ''}`, + ); + + if (helpPage.options.length > 0) { + content.push('', 'Options:', ...helpPage.options.map(l => ` ${l}`)); + } + + if (helpPage.commands.length > 0) { + content.push('', 'Commands:', ...helpPage.commands.map(l => ` ${l}`)); + } + content.push('```', ''); + } + } + + return content.join('\n'); +} + +interface CliExtractionOptions { + projectRoot: string; + packageDirs: string[]; + isLocalBuild: boolean; +} + +async function runCliExtraction({ + projectRoot, + packageDirs, + isLocalBuild, +}: CliExtractionOptions) { + for (const packageDir of packageDirs) { + console.log(`## Processing ${packageDir}`); + const fullDir = resolvePath(projectRoot, packageDir); + const pkgJson = await fs.readJson(resolvePath(fullDir, 'package.json')); + + if (!pkgJson.bin) { + throw new Error(`CLI Package in ${packageDir} has no bin field`); + } + const models = new Array(); + for (const [name, path] of Object.entries(pkgJson.bin)) { + const run = createBinRunner(fullDir, path); + const helpPages = await exploreCliHelpPages(run); + models.push({ name, helpPages }); + } + + const report = generateCliReport(pkgJson.name, models); + + const reportPath = resolvePath(fullDir, 'cli-report.md'); + const existingReport = await fs + .readFile(reportPath, 'utf8') + .catch(error => { + if (error.code === 'ENOENT') { + return undefined; + } + throw error; + }); + + if (existingReport !== report) { + if (isLocalBuild) { + console.warn(`CLI report changed for ${packageDir}`); + await fs.writeFile(reportPath, report); + } else { + logApiReportInstructions(); + + if (existingReport) { + console.log(''); + console.log( + `The conflicting file is ${relativePath( + projectRoot, + reportPath, + )}, expecting the following content:`, + ); + console.log(''); + + console.log(report); + + logApiReportInstructions(); + } + throw new Error(`CLI report changed for ${packageDir}, `); + } + } + } +} + async function main() { const projectRoot = resolvePath(__dirname, '..'); const isCiBuild = process.argv.includes('--ci'); @@ -1121,13 +1348,28 @@ async function main() { const packageDirs = selectedPackageDirs ?? (await findPackageDirs()); - console.log('# Generating package API reports'); - await runApiExtraction({ + const { tsPackageDirs, cliPackageDirs } = await categorizePackageDirs( + projectRoot, packageDirs, - outputDir: tmpDir, - isLocalBuild: !isCiBuild, - tsconfigFilePath, - }); + ); + + if (tsPackageDirs.length > 0) { + console.log('# Generating package API reports'); + await runApiExtraction({ + packageDirs: tsPackageDirs, + outputDir: tmpDir, + isLocalBuild: !isCiBuild, + tsconfigFilePath, + }); + } + if (cliPackageDirs.length > 0) { + console.log('# Generating package CLI reports'); + await runCliExtraction({ + projectRoot, + packageDirs: cliPackageDirs, + isLocalBuild: !isCiBuild, + }); + } if (isDocsBuild) { console.log('# Generating package documentation'); diff --git a/scripts/create-release-tag.js b/scripts/create-release-tag.js index 637467f285..a2706c578f 100755 --- a/scripts/create-release-tag.js +++ b/scripts/create-release-tag.js @@ -57,22 +57,7 @@ async function createGitTag(octokit, commitSha, tagName) { } } -async function dispatchReleaseWorkflows(octokit, releaseVersion) { - console.log('Dispatching release manifest sync'); - await octokit.actions.createWorkflowDispatch({ - owner: 'backstage', - repo: 'backstage', - workflow_id: 'sync_release-manifest.yml', - ref: 'master', - inputs: { - version: releaseVersion, - }, - }); -} - async function main() { - const shouldDispatch = process.argv.includes('--dispatch-workflows'); - if (!process.env.GITHUB_SHA) { throw new Error('GITHUB_SHA is not set'); } @@ -90,11 +75,7 @@ async function main() { await createGitTag(octokit, commitSha, tagName); console.log(`::set-output name=tag_name::${tagName}`); - - if (shouldDispatch) { - console.log(`Dispatching release workflows for ${tagName}`); - await dispatchReleaseWorkflows(octokit, releaseVersion); - } + console.log(`::set-output name=version::${releaseVersion}`); } main().catch(error => { diff --git a/scripts/generate-changeset-feedback.js b/scripts/generate-changeset-feedback.js index b614459a0e..b34147798d 100644 --- a/scripts/generate-changeset-feedback.js +++ b/scripts/generate-changeset-feedback.js @@ -42,7 +42,7 @@ function isPublishedPath(path) { return false; } // API report changes by themselves don't count - if (path === 'api-report.md') { + if (path === 'api-report.md' || path === 'cli-report.md') { return false; } // Lint changes don't count diff --git a/scripts/goalie-labels.js b/scripts/goalie-labels.js deleted file mode 100644 index e0a5b966d0..0000000000 --- a/scripts/goalie-labels.js +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright 2022 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -const Codeowners = require('codeowners'); - -const getRepoEvents = async ({ github, context, pull_number }) => { - const commits = await github.paginate(github.rest.pulls.listCommits, { - owner: context.repo.owner, - repo: context.repo.repo, - pull_number, - }); - - const reviews = await github.paginate(github.rest.pulls.listReviews, { - owner: context.repo.owner, - repo: context.repo.repo, - pull_number, - }); - - const pullComments = await github.paginate( - 'GET /repos/{owner}/{repo}/pulls/{pull_number}/comments', - { - owner: context.repo.owner, - repo: context.repo.repo, - pull_number, - }, - ); - - const comments = await github.paginate(github.rest.issues.listComments, { - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: pull_number, - }); - - const events = [ - ...reviews.map(({ user, submitted_at }) => ({ - user, - updated_at: submitted_at, - type: 'review', - })), - ...commits.map(({ commit, author, committer }) => ({ - user: author || committer, - updated_at: commit.author.date || commit.committer.date, - type: 'commit', - })), - ...pullComments.map(({ user, updated_at }) => ({ - user, - updated_at, - type: 'pr_comment', - })), - ...comments.map(({ user, updated_at }) => ({ - user, - updated_at, - type: 'pr_comment', - })), - ]; - - return events - .sort((a, b) => new Date(a.updated_at) - new Date(b.updated_at)) - .filter(({ user }) => (user ? !user.login.includes('[bot]') : false)); -}; - -module.exports = async ({ github, context, core }) => { - // first get all open pull requests - const allPullRequests = await github.paginate(github.rest.pulls.list, { - owner: context.repo.owner, - repo: context.repo.repo, - state: 'open', - }); - - const { data: teams } = await github.request('GET /orgs/{org}/teams', { - org: context.repo.owner, - }); - - const groupMembers = await Promise.all( - teams.map(async team => { - const { data } = await github.rest.teams.listMembersInOrg({ - org: context.repo.owner, - team_slug: team.slug, - }); - - return { team: `@backstage/${team.slug}`, data }; - }), - ); - - const codeowners = new Codeowners(); - - for (const pullRequest of allPullRequests) { - // Go through each file changed and get the codeowners for that file. - // Find the group in the group list that matches the codeowner. - // If it does match push the owner to a list of reviewers - // check to see the reviews and if there is at least one matching reviewer from those group - - const changedFiles = await github.paginate(github.rest.pulls.listFiles, { - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: pullRequest.number, - }); - - const allReviews = await github.paginate(github.rest.pulls.listReviews, { - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: pullRequest.number, - }); - - const expectedReviewers = new Set(); - - for (const file of changedFiles) { - expectedReviewers.add(...codeowners.getOwner(file.filename)); - } - - const hasReviewed = new Set(); - - // For each reviewer in the group, check to see if they have a review set - for (const reviewer of expectedReviewers) { - const members = groupMembers.find(member => member.team === reviewer); - if (members) { - // then we are dealing with a group - const hasMemberReview = allReviews.some(review => - members.data.some(member => member.login === review.user.login), - ); - if (hasMemberReview) { - hasReviewed.add(reviewer); - } - } else { - // reviewer is a person - const hasReview = allReviews.some( - review => reviewer === `@${review.user.login}`, - ); - if (hasReview) { - hasReviewed.add(reviewer); - } - } - } - - // if all required reviewers have reviewed - if (hasReviewed.size === expectedReviewers.size) { - const repoEvents = await getRepoEvents({ - github, - context, - pull_number: pullRequest.number, - }); - // if the last event for the issue is not by the author, remove the label - if ( - repoEvents[repoEvents.length - 1].user.login !== pullRequest.user.login - ) { - await github.rest.issues - .removeLabel({ - issue_number: pullRequest.number, - owner: context.repo.owner, - repo: context.repo.repo, - name: 'awaiting-review', - }) - .catch(e => { - console.error(e); - }); - } - // add the awaiting-review label to tell us that the PR is waiting on reviews - } else { - await github.rest.issues - .addLabels({ - issue_number: pullRequest.number, - owner: context.repo.owner, - repo: context.repo.repo, - labels: ['awaiting-review'], - }) - .catch(e => { - console.error(e); - }); - } - } -}; diff --git a/storybook/.storybook/main.js b/storybook/.storybook/main.js index f493bd2de6..d2e22abee7 100644 --- a/storybook/.storybook/main.js +++ b/storybook/.storybook/main.js @@ -9,6 +9,7 @@ const BACKSTAGE_CORE_STORIES = [ 'packages/app', 'plugins/org', 'plugins/search', + 'plugins/search-react', 'plugins/home', 'plugins/stack-overflow', ]; diff --git a/storybook/yarn.lock b/storybook/yarn.lock index 91530cccf6..cf6ecae523 100644 --- a/storybook/yarn.lock +++ b/storybook/yarn.lock @@ -18,9 +18,9 @@ "@babel/highlight" "^7.16.7" "@babel/compat-data@^7.13.11", "@babel/compat-data@^7.17.10": - version "7.17.10" - resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.10.tgz#711dc726a492dfc8be8220028b1b92482362baab" - integrity sha512-GZt/TCsG70Ms19gfZO1tM4CVnXsPgEPBCpJu+Qz3L0LUDsY5nZqFZglIoPC1kIYOtNBZlrnFT+klg12vFGZXrw== + version "7.18.5" + resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.5.tgz#acac0c839e317038c73137fbb6ef71a1d6238471" + integrity sha512-BxhE40PVCBxVEJsSBhB6UWyAuqJRxGsAw8BdHMJ3AKGydcwuWW4kOO3HmqBQAdcq/OP+/DlTVxLvsCzRTnZuGg== "@babel/core@7.12.9": version "7.12.9" @@ -45,9 +45,9 @@ source-map "^0.5.0" "@babel/core@^7.12.10", "@babel/core@^7.7.5": - version "7.18.2" - resolved "https://registry.npmjs.org/@babel/core/-/core-7.18.2.tgz#87b2fcd7cce9becaa7f5acebdc4f09f3dd19d876" - integrity sha512-A8pri1YJiC5UnkdrWcmfZTJTV85b4UXTAfImGmCfYmax4TR9Cw8sDS0MOk++Gp2mE/BefVJ5nwy5yzqNJbP/DQ== + version "7.18.5" + resolved "https://registry.npmjs.org/@babel/core/-/core-7.18.5.tgz#c597fa680e58d571c28dda9827669c78cdd7f000" + integrity sha512-MGY8vg3DxMnctw0LdvSEojOsumc70g0t18gNyUdAZqB1Rpd1Bqo/svHGvt+UJ6JcGX+DIekGFDxxIWofBxLCnQ== dependencies: "@ampproject/remapping" "^2.1.0" "@babel/code-frame" "^7.16.7" @@ -55,10 +55,10 @@ "@babel/helper-compilation-targets" "^7.18.2" "@babel/helper-module-transforms" "^7.18.0" "@babel/helpers" "^7.18.2" - "@babel/parser" "^7.18.0" + "@babel/parser" "^7.18.5" "@babel/template" "^7.16.7" - "@babel/traverse" "^7.18.2" - "@babel/types" "^7.18.2" + "@babel/traverse" "^7.18.5" + "@babel/types" "^7.18.4" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.2" @@ -299,10 +299,10 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.12.11", "@babel/parser@^7.12.7", "@babel/parser@^7.16.7", "@babel/parser@^7.18.0": - version "7.18.4" - resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.18.4.tgz#6774231779dd700e0af29f6ad8d479582d7ce5ef" - integrity sha512-FDge0dFazETFcxGw/EXzOkN8uJp0PC7Qbm+Pe9T+av2zlBpOgunFHkQPPn+eRuClU73JF+98D531UgayY89tow== +"@babel/parser@^7.12.11", "@babel/parser@^7.12.7", "@babel/parser@^7.16.7", "@babel/parser@^7.18.5": + version "7.18.5" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.18.5.tgz#337062363436a893a2d22faa60be5bb37091c83c" + integrity sha512-YZWVaglMiplo7v8f1oMQ5ZPQr0vn7HPeZXxXWsxXJRjGVrzUFn9OxFQl1sb5wzfootjA/yChhW84BV+383FSOw== "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.17.12": version "7.17.12" @@ -763,9 +763,9 @@ babel-plugin-dynamic-import-node "^2.3.3" "@babel/plugin-transform-modules-systemjs@^7.18.0": - version "7.18.4" - resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.18.4.tgz#3d6fd9868c735cce8f38d6ae3a407fb7e61e6d46" - integrity sha512-lH2UaQaHVOAeYrUUuZ8i38o76J/FnO8vu21OE+tD1MyP9lxdZoSfz+pDbWkq46GogUrdrMz3tiz/FYGB+bVThg== + version "7.18.5" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.18.5.tgz#87f11c44fbfd3657be000d4897e192d9cb535996" + integrity sha512-SEewrhPpcqMF1V7DhnEbhVJLrC+nnYfe1E0piZMZXBpxi9WvZqWGwpsk7JYP7wPWeqaBh4gyKlBhHJu3uz5g4Q== dependencies: "@babel/helper-hoist-variables" "^7.16.7" "@babel/helper-module-transforms" "^7.18.0" @@ -790,9 +790,9 @@ "@babel/helper-plugin-utils" "^7.17.12" "@babel/plugin-transform-new-target@^7.17.12": - version "7.17.12" - resolved "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.17.12.tgz#10842cd605a620944e81ea6060e9e65c265742e3" - integrity sha512-CaOtzk2fDYisbjAD4Sd1MTKGVIpRtx9bWLyj24Y/k6p4s4gQ3CqDGJauFJxt8M/LEx003d0i3klVqnN73qvK3w== + version "7.18.5" + resolved "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.5.tgz#8c228c4a07501dd12c95c5f23d1622131cc23931" + integrity sha512-TuRL5uGW4KXU6OsRj+mLp9BM7pO8e7SGNTEokQRRxHFkXYMFiy2jlKSZPFtI/mKORDzciH+hneskcSOp0gU8hg== dependencies: "@babel/helper-plugin-utils" "^7.17.12" @@ -1075,10 +1075,10 @@ "@babel/parser" "^7.16.7" "@babel/types" "^7.16.7" -"@babel/traverse@^7.1.6", "@babel/traverse@^7.12.11", "@babel/traverse@^7.12.9", "@babel/traverse@^7.13.0", "@babel/traverse@^7.16.8", "@babel/traverse@^7.18.0", "@babel/traverse@^7.18.2": - version "7.18.2" - resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.2.tgz#b77a52604b5cc836a9e1e08dca01cba67a12d2e8" - integrity sha512-9eNwoeovJ6KH9zcCNnENY7DMFwTU9JdGCFtqNLfUAqtUHRCOsTOqWoffosP8vKmNYeSBUv3yVJXjfd8ucwOjUA== +"@babel/traverse@^7.1.6", "@babel/traverse@^7.12.11", "@babel/traverse@^7.12.9", "@babel/traverse@^7.13.0", "@babel/traverse@^7.16.8", "@babel/traverse@^7.18.0", "@babel/traverse@^7.18.2", "@babel/traverse@^7.18.5": + version "7.18.5" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.5.tgz#94a8195ad9642801837988ab77f36e992d9a20cd" + integrity sha512-aKXj1KT66sBj0vVzk6rEeAO6Z9aiiQ68wfDgge3nHhA/my6xMM/7HGQUNumKZaoa2qUPQ5whJG9aAifsxUKfLA== dependencies: "@babel/code-frame" "^7.16.7" "@babel/generator" "^7.18.2" @@ -1086,12 +1086,12 @@ "@babel/helper-function-name" "^7.17.9" "@babel/helper-hoist-variables" "^7.16.7" "@babel/helper-split-export-declaration" "^7.16.7" - "@babel/parser" "^7.18.0" - "@babel/types" "^7.18.2" + "@babel/parser" "^7.18.5" + "@babel/types" "^7.18.4" debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.12.11", "@babel/types@^7.12.7", "@babel/types@^7.16.0", "@babel/types@^7.16.7", "@babel/types@^7.16.8", "@babel/types@^7.17.0", "@babel/types@^7.17.12", "@babel/types@^7.18.0", "@babel/types@^7.18.2", "@babel/types@^7.2.0", "@babel/types@^7.4.4": +"@babel/types@^7.12.11", "@babel/types@^7.12.7", "@babel/types@^7.16.0", "@babel/types@^7.16.7", "@babel/types@^7.16.8", "@babel/types@^7.17.0", "@babel/types@^7.17.12", "@babel/types@^7.18.0", "@babel/types@^7.18.2", "@babel/types@^7.18.4", "@babel/types@^7.2.0", "@babel/types@^7.4.4": version "7.18.4" resolved "https://registry.npmjs.org/@babel/types/-/types-7.18.4.tgz#27eae9b9fd18e9dccc3f9d6ad051336f307be354" integrity sha512-ThN1mBcMq5pG/Vm2IcBmPPfyPXbd8S02rS+OBIDENdufvqC7Z/jHPCv9IcP01277aKtDI8g/2XysBN4hA8niiw== @@ -1273,18 +1273,18 @@ source-map "^0.7.3" "@storybook/addon-a11y@^6.4.21": - version "6.5.8" - resolved "https://registry.npmjs.org/@storybook/addon-a11y/-/addon-a11y-6.5.8.tgz#90ecf3490f0e7e2096ae04d6d6386bae5182fb94" - integrity sha512-nBP8t7wADsKoDLqeH4S4YbxuE+t9Xw9T+XpeG94xn9oJPE1Tj4A0x0X91sTIPbi/FF07lCiaUP+eq92Y1bAV+Q== + version "6.5.9" + resolved "https://registry.npmjs.org/@storybook/addon-a11y/-/addon-a11y-6.5.9.tgz#191fb8ea9be4feee67fd11553b98ab56ecfc1295" + integrity sha512-jRiuJ2xlN8quVq2lOqpxqyuwAj8xLcgVBPy+Mf220u7AZmmbS/0sONyHKROfEBjJoHQAQYqn2vSAeuQZuTWyVA== dependencies: - "@storybook/addons" "6.5.8" - "@storybook/api" "6.5.8" - "@storybook/channels" "6.5.8" - "@storybook/client-logger" "6.5.8" - "@storybook/components" "6.5.8" - "@storybook/core-events" "6.5.8" + "@storybook/addons" "6.5.9" + "@storybook/api" "6.5.9" + "@storybook/channels" "6.5.9" + "@storybook/client-logger" "6.5.9" + "@storybook/components" "6.5.9" + "@storybook/core-events" "6.5.9" "@storybook/csf" "0.0.2--canary.4566f4d.1" - "@storybook/theming" "6.5.8" + "@storybook/theming" "6.5.9" axe-core "^4.2.0" core-js "^3.8.2" global "^4.4.0" @@ -1295,17 +1295,17 @@ util-deprecate "^1.0.2" "@storybook/addon-actions@^6.4.21": - version "6.5.8" - resolved "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-6.5.8.tgz#c1f544acc016a4a0d5dcb373535dc991b5737c5f" - integrity sha512-9ciR1iWBTzQNBDlq0iQs9+TV7gng+FbQxW5mHNxNvT9SxY1dt02wCPHZeVE/5la61wBXZs/zpEepZA93VzVBDw== + version "6.5.9" + resolved "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-6.5.9.tgz#d50d65631403e1a5b680961429d9c0d7bd383e68" + integrity sha512-wDYm3M1bN+zcYZV3Q24M03b/P8DDpvj1oSoY6VLlxDAi56h8qZB/voeIS2I6vWXOB79C5tbwljYNQO0GsufS0g== dependencies: - "@storybook/addons" "6.5.8" - "@storybook/api" "6.5.8" - "@storybook/client-logger" "6.5.8" - "@storybook/components" "6.5.8" - "@storybook/core-events" "6.5.8" + "@storybook/addons" "6.5.9" + "@storybook/api" "6.5.9" + "@storybook/client-logger" "6.5.9" + "@storybook/components" "6.5.9" + "@storybook/core-events" "6.5.9" "@storybook/csf" "0.0.2--canary.4566f4d.1" - "@storybook/theming" "6.5.8" + "@storybook/theming" "6.5.9" core-js "^3.8.2" fast-deep-equal "^3.1.3" global "^4.4.0" @@ -1320,33 +1320,33 @@ uuid-browser "^3.1.0" "@storybook/addon-controls@^6.4.22": - version "6.5.8" - resolved "https://registry.npmjs.org/@storybook/addon-controls/-/addon-controls-6.5.8.tgz#779407655d990f88e1d3bb734cf116bc419ab6ba" - integrity sha512-fB6p5DgVHUnJKUzOlT2mtvaSCincnO+vuYLyf++f+l4BlYK1Es9HNl/puaRoMgdW+LoGJjXPTIMcMByeHVIt6Q== + version "6.5.9" + resolved "https://registry.npmjs.org/@storybook/addon-controls/-/addon-controls-6.5.9.tgz#8f6ef939c87b3dbad98f8bda7e124f0b34f668d2" + integrity sha512-VvjkgK32bGURKyWU2No6Q2B0RQZjLZk8D3neVNCnrWxwrl1G82StegxjRPn/UZm9+MZVPvTvI46nj1VdgOktnw== dependencies: - "@storybook/addons" "6.5.8" - "@storybook/api" "6.5.8" - "@storybook/client-logger" "6.5.8" - "@storybook/components" "6.5.8" - "@storybook/core-common" "6.5.8" + "@storybook/addons" "6.5.9" + "@storybook/api" "6.5.9" + "@storybook/client-logger" "6.5.9" + "@storybook/components" "6.5.9" + "@storybook/core-common" "6.5.9" "@storybook/csf" "0.0.2--canary.4566f4d.1" - "@storybook/node-logger" "6.5.8" - "@storybook/store" "6.5.8" - "@storybook/theming" "6.5.8" + "@storybook/node-logger" "6.5.9" + "@storybook/store" "6.5.9" + "@storybook/theming" "6.5.9" core-js "^3.8.2" lodash "^4.17.21" ts-dedent "^2.0.0" "@storybook/addon-links@^6.4.21": - version "6.5.8" - resolved "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-6.5.8.tgz#ec4b640bf89dbb653592e6f05968ba771bb10b4a" - integrity sha512-UxzEPnT1PLPsuy3tt+o3UJTbI4Kihec+/yzpzzGKreUnCC8EWTsOhtMQAVVit2t4BMl4vNrxKO0mKSc8saT3Gw== + version "6.5.9" + resolved "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-6.5.9.tgz#91cbca0c044796badf2498723fdd10dacea5748b" + integrity sha512-4BYC7pkxL3NLRnEgTA9jpIkObQKril+XFj1WtmY/lngF90vvK0Kc/TtvTA2/5tSgrHfxEuPevIdxMIyLJ4ejWQ== dependencies: - "@storybook/addons" "6.5.8" - "@storybook/client-logger" "6.5.8" - "@storybook/core-events" "6.5.8" + "@storybook/addons" "6.5.9" + "@storybook/client-logger" "6.5.9" + "@storybook/core-events" "6.5.9" "@storybook/csf" "0.0.2--canary.4566f4d.1" - "@storybook/router" "6.5.8" + "@storybook/router" "6.5.9" "@types/qs" "^6.9.5" core-js "^3.8.2" global "^4.4.0" @@ -1356,17 +1356,17 @@ ts-dedent "^2.0.0" "@storybook/addon-storysource@^6.4.21": - version "6.5.8" - resolved "https://registry.npmjs.org/@storybook/addon-storysource/-/addon-storysource-6.5.8.tgz#6754b19b714fc19e6601fe5385fcf05c648a8f36" - integrity sha512-BujH4Xdhvegi4WvI1foBfrnUGnyJ18sLn47xJ2D26kQQXgC3qiGaUiQuEfGeETYgDuIxoxTkv5N4Y1ocjoOSkA== + version "6.5.9" + resolved "https://registry.npmjs.org/@storybook/addon-storysource/-/addon-storysource-6.5.9.tgz#8e5fb76b9314a69831a3b5e08e8570407c39de75" + integrity sha512-7KLw03mE1JJSJQrqNDftoVVp2BBq8wltd0qo7WHkpRVfir9dMO3g7Wy6S6UPsrb9th47ZjonwBJEc28GwAq0yg== dependencies: - "@storybook/addons" "6.5.8" - "@storybook/api" "6.5.8" - "@storybook/client-logger" "6.5.8" - "@storybook/components" "6.5.8" - "@storybook/router" "6.5.8" - "@storybook/source-loader" "6.5.8" - "@storybook/theming" "6.5.8" + "@storybook/addons" "6.5.9" + "@storybook/api" "6.5.9" + "@storybook/client-logger" "6.5.9" + "@storybook/components" "6.5.9" + "@storybook/router" "6.5.9" + "@storybook/source-loader" "6.5.9" + "@storybook/theming" "6.5.9" core-js "^3.8.2" estraverse "^5.2.0" loader-utils "^2.0.0" @@ -1374,35 +1374,35 @@ react-syntax-highlighter "^15.4.5" regenerator-runtime "^0.13.7" -"@storybook/addons@6.5.8", "@storybook/addons@^6.4.21": - version "6.5.8" - resolved "https://registry.npmjs.org/@storybook/addons/-/addons-6.5.8.tgz#c529a2989830a09d26308277a3e356228479053d" - integrity sha512-L3LmbsYP9tDHHvpr/yv8YuEkzym7SXp/jZ0km31tpG3EuZmgGu7MXPrZ2ymEw4PkAhQzztgRr23VTfKobGUojA== +"@storybook/addons@6.5.9", "@storybook/addons@^6.4.21": + version "6.5.9" + resolved "https://registry.npmjs.org/@storybook/addons/-/addons-6.5.9.tgz#5a9d7395c579a9cbc44dfc122362fb3c95dfb9d5" + integrity sha512-adwdiXg+mntfPocLc1KXjZXyLgGk7Aac699Fwe+OUYPEC5tW347Rm/kFatcE556d42o5czcRiq3ZSIGWnm9ieQ== dependencies: - "@storybook/api" "6.5.8" - "@storybook/channels" "6.5.8" - "@storybook/client-logger" "6.5.8" - "@storybook/core-events" "6.5.8" + "@storybook/api" "6.5.9" + "@storybook/channels" "6.5.9" + "@storybook/client-logger" "6.5.9" + "@storybook/core-events" "6.5.9" "@storybook/csf" "0.0.2--canary.4566f4d.1" - "@storybook/router" "6.5.8" - "@storybook/theming" "6.5.8" + "@storybook/router" "6.5.9" + "@storybook/theming" "6.5.9" "@types/webpack-env" "^1.16.0" core-js "^3.8.2" global "^4.4.0" regenerator-runtime "^0.13.7" -"@storybook/api@6.5.8": - version "6.5.8" - resolved "https://registry.npmjs.org/@storybook/api/-/api-6.5.8.tgz#8bd400b8a5b18ec6bff5d35a898593d9c1c630f9" - integrity sha512-/MueV+wLCvy9gFA3ih4g7QYjDmn14i+D2ydonfaEC7R+agFGXxXwJGPKkz3yBNrRpNkBwcbY9mAmv8lE2AqgqQ== +"@storybook/api@6.5.9": + version "6.5.9" + resolved "https://registry.npmjs.org/@storybook/api/-/api-6.5.9.tgz#303733214c9de0422d162f7c54ae05d088b89bf9" + integrity sha512-9ylztnty4Y+ALU/ehW3BML9czjCAFsWvrwuCi6UgcwNjswwjSX3VRLhfD1KT3pl16ho//95LgZ0LnSwROCcPOA== dependencies: - "@storybook/channels" "6.5.8" - "@storybook/client-logger" "6.5.8" - "@storybook/core-events" "6.5.8" + "@storybook/channels" "6.5.9" + "@storybook/client-logger" "6.5.9" + "@storybook/core-events" "6.5.9" "@storybook/csf" "0.0.2--canary.4566f4d.1" - "@storybook/router" "6.5.8" + "@storybook/router" "6.5.9" "@storybook/semver" "^7.3.2" - "@storybook/theming" "6.5.8" + "@storybook/theming" "6.5.9" core-js "^3.8.2" fast-deep-equal "^3.1.3" global "^4.4.0" @@ -1414,28 +1414,28 @@ ts-dedent "^2.0.0" util-deprecate "^1.0.2" -"@storybook/builder-webpack4@6.5.8": - version "6.5.8" - resolved "https://registry.npmjs.org/@storybook/builder-webpack4/-/builder-webpack4-6.5.8.tgz#adfb4b91bd442c2f256d93649d50ca138c30663a" - integrity sha512-4/CVp/AlOxCeWZ/DF1TVS/TuzHao4l9KCq7DhL+utFEVl9c/dpgoZXc0Gy2FfHa2RXHKckrH/VUfV2KQk4TNSw== +"@storybook/builder-webpack4@6.5.9": + version "6.5.9" + resolved "https://registry.npmjs.org/@storybook/builder-webpack4/-/builder-webpack4-6.5.9.tgz#4b37e1fa23a25aa4bfeaba640e5d318fcd511f95" + integrity sha512-YOeA4++9uRZ8Hog1wC60yjaxBOiI1FRQNtax7b9E7g+kP8UlSCPCGcv4gls9hFmzbzTOPfQTWnToA9Oa6jzRVw== dependencies: "@babel/core" "^7.12.10" - "@storybook/addons" "6.5.8" - "@storybook/api" "6.5.8" - "@storybook/channel-postmessage" "6.5.8" - "@storybook/channels" "6.5.8" - "@storybook/client-api" "6.5.8" - "@storybook/client-logger" "6.5.8" - "@storybook/components" "6.5.8" - "@storybook/core-common" "6.5.8" - "@storybook/core-events" "6.5.8" - "@storybook/node-logger" "6.5.8" - "@storybook/preview-web" "6.5.8" - "@storybook/router" "6.5.8" + "@storybook/addons" "6.5.9" + "@storybook/api" "6.5.9" + "@storybook/channel-postmessage" "6.5.9" + "@storybook/channels" "6.5.9" + "@storybook/client-api" "6.5.9" + "@storybook/client-logger" "6.5.9" + "@storybook/components" "6.5.9" + "@storybook/core-common" "6.5.9" + "@storybook/core-events" "6.5.9" + "@storybook/node-logger" "6.5.9" + "@storybook/preview-web" "6.5.9" + "@storybook/router" "6.5.9" "@storybook/semver" "^7.3.2" - "@storybook/store" "6.5.8" - "@storybook/theming" "6.5.8" - "@storybook/ui" "6.5.8" + "@storybook/store" "6.5.9" + "@storybook/theming" "6.5.9" + "@storybook/ui" "6.5.9" "@types/node" "^14.0.10 || ^16.0.0" "@types/webpack" "^4.41.26" autoprefixer "^9.8.6" @@ -1467,51 +1467,51 @@ webpack-hot-middleware "^2.25.1" webpack-virtual-modules "^0.2.2" -"@storybook/channel-postmessage@6.5.8": - version "6.5.8" - resolved "https://registry.npmjs.org/@storybook/channel-postmessage/-/channel-postmessage-6.5.8.tgz#989af9a55eba391b64487640f6b5b0cfd1fde2f9" - integrity sha512-6IkIKk+UMYKk05vN8gWHvvOV/EZNXpQG/5gesGDALjkCyvRmcktHak1a9tHpoihZ3L7/gDwXOZraCZmuy8vBcQ== +"@storybook/channel-postmessage@6.5.9": + version "6.5.9" + resolved "https://registry.npmjs.org/@storybook/channel-postmessage/-/channel-postmessage-6.5.9.tgz#9cf4530f0364cee0d5e58f92d6fb5ce98e10257b" + integrity sha512-pX/0R8UW7ezBhCrafRaL20OvMRcmESYvQQCDgjqSzJyHkcG51GOhsd6Ge93eJ6QvRMm9+w0Zs93N2VKjVtz0Qw== dependencies: - "@storybook/channels" "6.5.8" - "@storybook/client-logger" "6.5.8" - "@storybook/core-events" "6.5.8" + "@storybook/channels" "6.5.9" + "@storybook/client-logger" "6.5.9" + "@storybook/core-events" "6.5.9" core-js "^3.8.2" global "^4.4.0" qs "^6.10.0" telejson "^6.0.8" -"@storybook/channel-websocket@6.5.8": - version "6.5.8" - resolved "https://registry.npmjs.org/@storybook/channel-websocket/-/channel-websocket-6.5.8.tgz#722743619f86ebc9325bbff026acf6eba13b21ca" - integrity sha512-lAtvgO0FWsyS3u7uFbsGIYp2aSWJfWU/LOtc3x1K5c84JJAd9fncYkyZMwP1gMbdNgYxJoxe8HXtVtfeNegPuQ== +"@storybook/channel-websocket@6.5.9": + version "6.5.9" + resolved "https://registry.npmjs.org/@storybook/channel-websocket/-/channel-websocket-6.5.9.tgz#6b7a0127fec58ee5be4f6aebcf460adc564f2f34" + integrity sha512-xtHvSNwuOhkgALwVshKWsoFhDmuvcosdYfxcfFGEiYKXIu46tRS5ZXmpmgEC/0JAVkVoFj5nL8bV7IY5np6oaA== dependencies: - "@storybook/channels" "6.5.8" - "@storybook/client-logger" "6.5.8" + "@storybook/channels" "6.5.9" + "@storybook/client-logger" "6.5.9" core-js "^3.8.2" global "^4.4.0" telejson "^6.0.8" -"@storybook/channels@6.5.8": - version "6.5.8" - resolved "https://registry.npmjs.org/@storybook/channels/-/channels-6.5.8.tgz#e85ffd2076813b67336b1b9b274c37aa5f1b80e0" - integrity sha512-fNql1lEIvWlI1NiRtwFMWOOvfW6qxgeSP6xoqiAJ0b+QYegEFG9UxJDuEvVHq++S81FulgQ5U+p+5R9XSV19tQ== +"@storybook/channels@6.5.9": + version "6.5.9" + resolved "https://registry.npmjs.org/@storybook/channels/-/channels-6.5.9.tgz#abfab89a6587a2688e9926d4aafeb11c9d8b2e79" + integrity sha512-FvGA35nV38UPXWOl9ERapFTJaxwSTamQ339s2Ev7E9riyRG+GRkgTWzf5kECJgS1PAYKd/7m/RqKJT9BVv6A5g== dependencies: core-js "^3.8.2" ts-dedent "^2.0.0" util-deprecate "^1.0.2" -"@storybook/client-api@6.5.8": - version "6.5.8" - resolved "https://registry.npmjs.org/@storybook/client-api/-/client-api-6.5.8.tgz#cf1b3d4a71a3a156636a9b6b51acc4239b259d86" - integrity sha512-mdU+qQ4+T2OUbEnl+3MWRKxEPju/EOIUg66hMgmif8c5u7YFYBFulUMUYLICMjll8Jlu+37+g+qO3K2eEz6CEw== +"@storybook/client-api@6.5.9": + version "6.5.9" + resolved "https://registry.npmjs.org/@storybook/client-api/-/client-api-6.5.9.tgz#3e4a8ec1d277fd81325c5d959c553161a85fa182" + integrity sha512-pc7JKJoWLesixUKvG2nV36HukUuYoGRyAgD3PpIV7qSBS4JixqZ3VAHFUtqV1UzfOSQTovLSl4a0rIRnpie6gA== dependencies: - "@storybook/addons" "6.5.8" - "@storybook/channel-postmessage" "6.5.8" - "@storybook/channels" "6.5.8" - "@storybook/client-logger" "6.5.8" - "@storybook/core-events" "6.5.8" + "@storybook/addons" "6.5.9" + "@storybook/channel-postmessage" "6.5.9" + "@storybook/channels" "6.5.9" + "@storybook/client-logger" "6.5.9" + "@storybook/core-events" "6.5.9" "@storybook/csf" "0.0.2--canary.4566f4d.1" - "@storybook/store" "6.5.8" + "@storybook/store" "6.5.9" "@types/qs" "^6.9.5" "@types/webpack-env" "^1.16.0" core-js "^3.8.2" @@ -1526,44 +1526,45 @@ ts-dedent "^2.0.0" util-deprecate "^1.0.2" -"@storybook/client-logger@6.5.8": - version "6.5.8" - resolved "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-6.5.8.tgz#551f818c4448ef6e6adf9c3ad256e1ae61e2d75c" - integrity sha512-dH6HSaVuOIMHy1+rpsqcD3SJxVZEEbuEtsNpdUGwLJaIuduhUJJpM2xQfUW0siZDyrgwoa+znll+G0YNUbv7sg== +"@storybook/client-logger@6.5.9": + version "6.5.9" + resolved "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-6.5.9.tgz#dc1669abe8c45af1cc38f74c6f4b15ff33e63014" + integrity sha512-DOHL6p0uiDd3gV/Sb2FR+Vh6OiPrrf8BrA06uvXWsMRIIvEEvnparxv9EvPg7FlmUX0T3nq7d3juwjx4F8Wbcg== dependencies: core-js "^3.8.2" global "^4.4.0" -"@storybook/components@6.5.8": - version "6.5.8" - resolved "https://registry.npmjs.org/@storybook/components/-/components-6.5.8.tgz#eb18cfcc4e88b7f4081b20b8a81b92d7ae9eaeac" - integrity sha512-YE+LZ1/GXoqertxodsf+L9ehcohbICRAxgE/iNqc7MZfk95SD3XRSUbxhCpGe8QTIZJpzs1tK4LFZ3Fg5w/+Lg== +"@storybook/components@6.5.9": + version "6.5.9" + resolved "https://registry.npmjs.org/@storybook/components/-/components-6.5.9.tgz#97e07ffe11ab76c01ccee380888991bd161f75b2" + integrity sha512-BhfX980O9zn/1J4FNMeDo8ZvL1m5Ml3T4HRpfYmEBnf8oW5b5BeF6S2K2cwFStZRjWqm1feUcwNpZxCBVMkQnQ== dependencies: - "@storybook/client-logger" "6.5.8" + "@storybook/client-logger" "6.5.9" "@storybook/csf" "0.0.2--canary.4566f4d.1" - "@storybook/theming" "6.5.8" + "@storybook/theming" "6.5.9" "@types/react-syntax-highlighter" "11.0.5" core-js "^3.8.2" + memoizerific "^1.11.3" qs "^6.10.0" react-syntax-highlighter "^15.4.5" regenerator-runtime "^0.13.7" util-deprecate "^1.0.2" -"@storybook/core-client@6.5.8": - version "6.5.8" - resolved "https://registry.npmjs.org/@storybook/core-client/-/core-client-6.5.8.tgz#4be4ce024a74b51c0650d346f1f3a11a0f921952" - integrity sha512-8x8qKQ2clvpfDcoWrNBmQ8Xt9z/i32TFIBp4PEZMcbB7eqo517nzfllLiXDipiJgO7BGxKtY5CRHQ9pAU9G27A== +"@storybook/core-client@6.5.9": + version "6.5.9" + resolved "https://registry.npmjs.org/@storybook/core-client/-/core-client-6.5.9.tgz#ea6035d1c90d2c68e860e3cf629979491856cd88" + integrity sha512-LY0QbhShowO+PQx3gao3wdVjpKMH1AaSLmuI95FrcjoMmSXGf96jVLKQp9mJRGeHIsAa93EQBYuCihZycM3Kbg== dependencies: - "@storybook/addons" "6.5.8" - "@storybook/channel-postmessage" "6.5.8" - "@storybook/channel-websocket" "6.5.8" - "@storybook/client-api" "6.5.8" - "@storybook/client-logger" "6.5.8" - "@storybook/core-events" "6.5.8" + "@storybook/addons" "6.5.9" + "@storybook/channel-postmessage" "6.5.9" + "@storybook/channel-websocket" "6.5.9" + "@storybook/client-api" "6.5.9" + "@storybook/client-logger" "6.5.9" + "@storybook/core-events" "6.5.9" "@storybook/csf" "0.0.2--canary.4566f4d.1" - "@storybook/preview-web" "6.5.8" - "@storybook/store" "6.5.8" - "@storybook/ui" "6.5.8" + "@storybook/preview-web" "6.5.9" + "@storybook/store" "6.5.9" + "@storybook/ui" "6.5.9" airbnb-js-shims "^2.2.1" ansi-to-html "^0.6.11" core-js "^3.8.2" @@ -1575,10 +1576,10 @@ unfetch "^4.2.0" util-deprecate "^1.0.2" -"@storybook/core-common@6.5.8": - version "6.5.8" - resolved "https://registry.npmjs.org/@storybook/core-common/-/core-common-6.5.8.tgz#6972c7109477914f9ed72bedbe3769cec0eb8c56" - integrity sha512-ELGKLMx1d0oEA2LT+fsmo85X2RNE1EO+It7B1bw//g7jyf1hmZ7t3lXMZUCqt7eml1qy1N72LDkfmmU+H9H6ww== +"@storybook/core-common@6.5.9": + version "6.5.9" + resolved "https://registry.npmjs.org/@storybook/core-common/-/core-common-6.5.9.tgz#7ca8258ea2634b1d64695c1e4262f71cc7457989" + integrity sha512-NxOK0mrOCo0TWZ7Npc5HU66EKoRHlrtg18/ZixblLDWQMIqY9XCck8K1kJ8QYpYCHla+aHIsYUArFe2vhlEfZA== dependencies: "@babel/core" "^7.12.10" "@babel/plugin-proposal-class-properties" "^7.12.1" @@ -1602,7 +1603,7 @@ "@babel/preset-react" "^7.12.10" "@babel/preset-typescript" "^7.12.7" "@babel/register" "^7.12.1" - "@storybook/node-logger" "6.5.8" + "@storybook/node-logger" "6.5.9" "@storybook/semver" "^7.3.2" "@types/node" "^14.0.10 || ^16.0.0" "@types/pretty-hrtime" "^1.0.0" @@ -1631,30 +1632,30 @@ util-deprecate "^1.0.2" webpack "4" -"@storybook/core-events@6.5.8": - version "6.5.8" - resolved "https://registry.npmjs.org/@storybook/core-events/-/core-events-6.5.8.tgz#bc405d37d0ed1a6eafa2682fc085b2a7a992233c" - integrity sha512-lzG4Lg65WFYvjs2k/E3CP4+eyPexEGrDyRMO9Pbj9H9x+eosYptauEbT/wXF83bmUWZKLWWVUAZX7hDcxBO8cw== +"@storybook/core-events@6.5.9": + version "6.5.9" + resolved "https://registry.npmjs.org/@storybook/core-events/-/core-events-6.5.9.tgz#5b0783c7d22a586c0f5e927a61fe1b1223e19637" + integrity sha512-tXt7a3ZvJOCeEKpNa/B5rQM5VI7UJLlOh3IHOImWn4HqoBRrZvbourmac+PRZAtXpos0h3c6554Hjapj/Sny5Q== dependencies: core-js "^3.8.2" -"@storybook/core-server@6.5.8": - version "6.5.8" - resolved "https://registry.npmjs.org/@storybook/core-server/-/core-server-6.5.8.tgz#3ef53c4b0437e83c310f9e545607a0b1ce512ab6" - integrity sha512-ti7+MW1xzD9O0JLwgZTwulxhJx5YGPNu+hRpGhJSjKrqGX1h6K6ilmkBSHvyLqpiE+F4mxvqb5Rx3KBIEdEgbw== +"@storybook/core-server@6.5.9": + version "6.5.9" + resolved "https://registry.npmjs.org/@storybook/core-server/-/core-server-6.5.9.tgz#749a881c1a81d7cf1a69f3782c06a7f0c39a505c" + integrity sha512-YeePGUrd5fQPvGzMhowh124KrcZURFpFXg1VB0Op3ESqCIsInoMZeObci4Gc+binMXC7vcv7aw3EwSLU37qJzQ== dependencies: "@discoveryjs/json-ext" "^0.5.3" - "@storybook/builder-webpack4" "6.5.8" - "@storybook/core-client" "6.5.8" - "@storybook/core-common" "6.5.8" - "@storybook/core-events" "6.5.8" + "@storybook/builder-webpack4" "6.5.9" + "@storybook/core-client" "6.5.9" + "@storybook/core-common" "6.5.9" + "@storybook/core-events" "6.5.9" "@storybook/csf" "0.0.2--canary.4566f4d.1" - "@storybook/csf-tools" "6.5.8" - "@storybook/manager-webpack4" "6.5.8" - "@storybook/node-logger" "6.5.8" + "@storybook/csf-tools" "6.5.9" + "@storybook/manager-webpack4" "6.5.9" + "@storybook/node-logger" "6.5.9" "@storybook/semver" "^7.3.2" - "@storybook/store" "6.5.8" - "@storybook/telemetry" "6.5.8" + "@storybook/store" "6.5.9" + "@storybook/telemetry" "6.5.9" "@types/node" "^14.0.10 || ^16.0.0" "@types/node-fetch" "^2.5.7" "@types/pretty-hrtime" "^1.0.0" @@ -1689,18 +1690,18 @@ ws "^8.2.3" x-default-browser "^0.4.0" -"@storybook/core@6.5.8": - version "6.5.8" - resolved "https://registry.npmjs.org/@storybook/core/-/core-6.5.8.tgz#cbe6acaf587e9ef66963bb104a067c213aeea990" - integrity sha512-+Fv4n1E5N4Avty9GcRbz4vB2IWH//se2OUU+RTT3vneCOGjyus5bj0Or6GU5wef5UGuvHF78mHg/frhWpguzsw== +"@storybook/core@6.5.9": + version "6.5.9" + resolved "https://registry.npmjs.org/@storybook/core/-/core-6.5.9.tgz#da4f237391d99aed1228323f24b335cafbdf3499" + integrity sha512-Mt3TTQnjQt2/pa60A+bqDsAOrYpohapdtt4DDZEbS8h0V6u11KyYYh3w7FCySlL+sPEyogj63l5Ec76Jah3l2w== dependencies: - "@storybook/core-client" "6.5.8" - "@storybook/core-server" "6.5.8" + "@storybook/core-client" "6.5.9" + "@storybook/core-server" "6.5.9" -"@storybook/csf-tools@6.5.8": - version "6.5.8" - resolved "https://registry.npmjs.org/@storybook/csf-tools/-/csf-tools-6.5.8.tgz#5788aa1e862ee613d11d6528f27c8e267e4dd3a7" - integrity sha512-4VrjIMxKcp29OFSMDub52aQOMP4EvtZ5eWZkPeORRNQoJsnQaxhF9GGf71QdSaAQZhMoxdvmpA47ehrFk8Rnfw== +"@storybook/csf-tools@6.5.9": + version "6.5.9" + resolved "https://registry.npmjs.org/@storybook/csf-tools/-/csf-tools-6.5.9.tgz#8e01df2305b53e228229f0b45ada3720e6e42a1c" + integrity sha512-RAdhsO2XmEDyWy0qNQvdKMLeIZAuyfD+tYlUwBHRU6DbByDucvwgMOGy5dF97YNJFmyo93EUYJzXjUrJs3U1LQ== dependencies: "@babel/core" "^7.12.10" "@babel/generator" "^7.12.11" @@ -1724,33 +1725,33 @@ dependencies: lodash "^4.17.15" -"@storybook/docs-tools@6.5.8": - version "6.5.8" - resolved "https://registry.npmjs.org/@storybook/docs-tools/-/docs-tools-6.5.8.tgz#6189fd20fafa9eb2aa4a19e311d65295992dd105" - integrity sha512-CWMW+3LSstvQmHKV5ggPR1beQZTpwCXEhfysZ9u4Yp/4fcoDIuQ7DTOK5uNFynGCGl1FG3lATriEOhEZ3bZCvQ== +"@storybook/docs-tools@6.5.9": + version "6.5.9" + resolved "https://registry.npmjs.org/@storybook/docs-tools/-/docs-tools-6.5.9.tgz#5ff304f881e972ce14923a5ffcfed3f052094889" + integrity sha512-UoTaXLvec8x+q+4oYIk/t8DBju9C3ZTGklqOxDIt+0kS3TFAqEgI3JhKXqQOXgN5zDcvLVSxi8dbVAeSxk2ktA== dependencies: "@babel/core" "^7.12.10" "@storybook/csf" "0.0.2--canary.4566f4d.1" - "@storybook/store" "6.5.8" + "@storybook/store" "6.5.9" core-js "^3.8.2" doctrine "^3.0.0" lodash "^4.17.21" regenerator-runtime "^0.13.7" -"@storybook/manager-webpack4@6.5.8": - version "6.5.8" - resolved "https://registry.npmjs.org/@storybook/manager-webpack4/-/manager-webpack4-6.5.8.tgz#9e4d3dcebac9bd0b07abd630632dc15130ae03f1" - integrity sha512-qW5/L3cJHvtNi5ylDxObALZWaAHMsWQlPP8GRxm95NHpff4CfRo/qs7puY9ZeLmJSic0KchoHEH/8AScflLOgA== +"@storybook/manager-webpack4@6.5.9": + version "6.5.9" + resolved "https://registry.npmjs.org/@storybook/manager-webpack4/-/manager-webpack4-6.5.9.tgz#c75d2cced4550c8a786f00b0e57b203d613e706c" + integrity sha512-49LZlHqWc7zj9tQfOOANixPYmLxqWTTZceA6DSXnKd9xDiO2Gl23Y+l/CSPXNZGDB8QFAwpimwqyKJj/NLH45A== dependencies: "@babel/core" "^7.12.10" "@babel/plugin-transform-template-literals" "^7.12.1" "@babel/preset-react" "^7.12.10" - "@storybook/addons" "6.5.8" - "@storybook/core-client" "6.5.8" - "@storybook/core-common" "6.5.8" - "@storybook/node-logger" "6.5.8" - "@storybook/theming" "6.5.8" - "@storybook/ui" "6.5.8" + "@storybook/addons" "6.5.9" + "@storybook/core-client" "6.5.9" + "@storybook/core-common" "6.5.9" + "@storybook/node-logger" "6.5.9" + "@storybook/theming" "6.5.9" + "@storybook/ui" "6.5.9" "@types/node" "^14.0.10 || ^16.0.0" "@types/webpack" "^4.41.26" babel-loader "^8.0.0" @@ -1795,10 +1796,10 @@ prettier ">=2.2.1 <=2.3.0" ts-dedent "^2.0.0" -"@storybook/node-logger@6.5.8": - version "6.5.8" - resolved "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-6.5.8.tgz#d1244c846da5a296a7432444f8682f77853fb81e" - integrity sha512-BHdkSipgjnfsh4FRYbV2R0npM5gVx9JLRsDQ0KiTolRpN4SU98kT/6885zb9jZg6I0EY+UG9Qdr3fvL9VLpY1g== +"@storybook/node-logger@6.5.9": + version "6.5.9" + resolved "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-6.5.9.tgz#129cfe0d0f79cab4f6a2ba194d39516680b1626f" + integrity sha512-nZZNZG2Wtwv6Trxi3FrnIqUmB55xO+X/WQGPT5iKlqNjdRIu/T72mE7addcp4rbuWCQfZUhcDDGpBOwKtBxaGg== dependencies: "@types/npmlog" "^4.1.2" chalk "^4.1.0" @@ -1806,17 +1807,17 @@ npmlog "^5.0.1" pretty-hrtime "^1.0.3" -"@storybook/preview-web@6.5.8": - version "6.5.8" - resolved "https://registry.npmjs.org/@storybook/preview-web/-/preview-web-6.5.8.tgz#b1c86d56e99032c02ba47bab628c36d76a0385b6" - integrity sha512-jEEAgvTVZfFA0B20mRJfLW6dPA5mG5PxUJtjMx6wH4Yw4+i3Sld/U63hTRt7ktpKdrcu4lX9E+PuaRLPq7S2kg== +"@storybook/preview-web@6.5.9": + version "6.5.9" + resolved "https://registry.npmjs.org/@storybook/preview-web/-/preview-web-6.5.9.tgz#557d919e6df50d66259521aa36ebf4055bbd236e" + integrity sha512-4eMrO2HJyZUYyL/j+gUaDvry6iGedshwT5MQqe7J9FaA+Q2pNARQRB1X53f410w7S4sObRmYIAIluWPYdWym9w== dependencies: - "@storybook/addons" "6.5.8" - "@storybook/channel-postmessage" "6.5.8" - "@storybook/client-logger" "6.5.8" - "@storybook/core-events" "6.5.8" + "@storybook/addons" "6.5.9" + "@storybook/channel-postmessage" "6.5.9" + "@storybook/client-logger" "6.5.9" + "@storybook/core-events" "6.5.9" "@storybook/csf" "0.0.2--canary.4566f4d.1" - "@storybook/store" "6.5.8" + "@storybook/store" "6.5.9" ansi-to-html "^0.6.11" core-js "^3.8.2" global "^4.4.0" @@ -1842,23 +1843,23 @@ tslib "^2.0.0" "@storybook/react@^6.4.21": - version "6.5.8" - resolved "https://registry.npmjs.org/@storybook/react/-/react-6.5.8.tgz#8a9e15416a18ceb5c11c89ffe9f38357d442efa9" - integrity sha512-LdObfhhPb9gAFBtRNb3awYJe1qMiYeda1ppkj0ZvccbV04YrmbW5bzYvfOCvU6D34ugbQJhJyWuvraO/0EJK6w== + version "6.5.9" + resolved "https://registry.npmjs.org/@storybook/react/-/react-6.5.9.tgz#687ec1f6b785822a392b7ac115b61800f69fb7cd" + integrity sha512-Rp+QaTQAzxJhwuzJXVd49mnIBLQRlF8llTxPT2YoGHdrGkku/zl/HblQ6H2yzEf15367VyzaAv/BpLsO9Jlfxg== dependencies: "@babel/preset-flow" "^7.12.1" "@babel/preset-react" "^7.12.10" "@pmmmwh/react-refresh-webpack-plugin" "^0.5.3" - "@storybook/addons" "6.5.8" - "@storybook/client-logger" "6.5.8" - "@storybook/core" "6.5.8" - "@storybook/core-common" "6.5.8" + "@storybook/addons" "6.5.9" + "@storybook/client-logger" "6.5.9" + "@storybook/core" "6.5.9" + "@storybook/core-common" "6.5.9" "@storybook/csf" "0.0.2--canary.4566f4d.1" - "@storybook/docs-tools" "6.5.8" - "@storybook/node-logger" "6.5.8" + "@storybook/docs-tools" "6.5.9" + "@storybook/node-logger" "6.5.9" "@storybook/react-docgen-typescript-plugin" "1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0" "@storybook/semver" "^7.3.2" - "@storybook/store" "6.5.8" + "@storybook/store" "6.5.9" "@types/estree" "^0.0.51" "@types/node" "^14.14.20 || ^16.0.0" "@types/webpack-env" "^1.16.0" @@ -1882,13 +1883,15 @@ util-deprecate "^1.0.2" webpack ">=4.43.0 <6.0.0" -"@storybook/router@6.5.8": - version "6.5.8" - resolved "https://registry.npmjs.org/@storybook/router/-/router-6.5.8.tgz#241e3842bdd174e0eeeb9d1de6adb2975615884d" - integrity sha512-tseNJpZ2ZzVYowjekUMpGJVVRMrwOkttieD9mRbHrhh+2n7b+SoMKnuLi3ow0xeOyPL8ZDng2FgRjQzQHXA5Sw== +"@storybook/router@6.5.9": + version "6.5.9" + resolved "https://registry.npmjs.org/@storybook/router/-/router-6.5.9.tgz#4740248f8517425b2056273fb366ace8a17c65e8" + integrity sha512-G2Xp/2r8vU2O34eelE+G5VbEEVFDeHcCURrVJEROh6dq2asFJAPbzslVXSeCqgOTNLSpRDJ2NcN5BckkNqmqJg== dependencies: - "@storybook/client-logger" "6.5.8" + "@storybook/client-logger" "6.5.9" core-js "^3.8.2" + memoizerific "^1.11.3" + qs "^6.10.0" regenerator-runtime "^0.13.7" "@storybook/semver@^7.3.2": @@ -1899,13 +1902,13 @@ core-js "^3.6.5" find-up "^4.1.0" -"@storybook/source-loader@6.5.8": - version "6.5.8" - resolved "https://registry.npmjs.org/@storybook/source-loader/-/source-loader-6.5.8.tgz#106694fe821f5e42abc4e8e653e5f268a043e470" - integrity sha512-3bVxXKE2o6lS4WGga/S7WwgITxPQ96qsY+pQ1I7A+e4/cKSmZxlVWM9qfMW2ScmHTVoZE0Ujsmn6DWftxzCyrQ== +"@storybook/source-loader@6.5.9": + version "6.5.9" + resolved "https://registry.npmjs.org/@storybook/source-loader/-/source-loader-6.5.9.tgz#7b6f065c6a6108c4b4ca7e45bfd78707373d84ac" + integrity sha512-H03nFKaP6borfWMTTa9igBA+Jm2ph+FoVJImWC/X+LAmLSJYYSXuqSgmiZ/DZvbjxS4k8vccE2HXogne1IvaRA== dependencies: - "@storybook/addons" "6.5.8" - "@storybook/client-logger" "6.5.8" + "@storybook/addons" "6.5.9" + "@storybook/client-logger" "6.5.9" "@storybook/csf" "0.0.2--canary.4566f4d.1" core-js "^3.8.2" estraverse "^5.2.0" @@ -1915,14 +1918,14 @@ prettier ">=2.2.1 <=2.3.0" regenerator-runtime "^0.13.7" -"@storybook/store@6.5.8": - version "6.5.8" - resolved "https://registry.npmjs.org/@storybook/store/-/store-6.5.8.tgz#528bf9a2decf5121045fb0a19b8caf795b4a5647" - integrity sha512-5rhGjN/O0oLebRv947B0vgapq48qBBBYYOgq4krRUYU2ecS6LUgtAHR/kTa324o9aBO8cnIXHH78jZcSvMiJlQ== +"@storybook/store@6.5.9": + version "6.5.9" + resolved "https://registry.npmjs.org/@storybook/store/-/store-6.5.9.tgz#dc9963fc013636569082bd8f7200804866373735" + integrity sha512-80pcDTcCwK6wUA63aWOp13urI77jfipIVee9mpVvbNyfrNN8kGv1BS0z/JHDxuV6rC4g7LG1fb+BurR0yki7BA== dependencies: - "@storybook/addons" "6.5.8" - "@storybook/client-logger" "6.5.8" - "@storybook/core-events" "6.5.8" + "@storybook/addons" "6.5.9" + "@storybook/client-logger" "6.5.9" + "@storybook/core-events" "6.5.9" "@storybook/csf" "0.0.2--canary.4566f4d.1" core-js "^3.8.2" fast-deep-equal "^3.1.3" @@ -1936,13 +1939,13 @@ ts-dedent "^2.0.0" util-deprecate "^1.0.2" -"@storybook/telemetry@6.5.8": - version "6.5.8" - resolved "https://registry.npmjs.org/@storybook/telemetry/-/telemetry-6.5.8.tgz#2acf9734292d421f84f7f2ac6c17d887c2cb0df4" - integrity sha512-QnAhYF8CwcjC1bT2PK7Zqvo6E42TPl0MY6JS+H6qSZU/BmYeS0It8ZURNfPsA/OzVVLHUkQs96CisKh3N0WWaw== +"@storybook/telemetry@6.5.9": + version "6.5.9" + resolved "https://registry.npmjs.org/@storybook/telemetry/-/telemetry-6.5.9.tgz#8e1e0d4a89fc2387620045e5ea96c109d16a7247" + integrity sha512-JluoHCRhHAr4X0eUNVBSBi1JIBA92404Tu1TPdbN7x6gCZxHXXPTSUTAnspXp/21cTdMhY2x+kfZQ8fmlGK4MQ== dependencies: - "@storybook/client-logger" "6.5.8" - "@storybook/core-common" "6.5.8" + "@storybook/client-logger" "6.5.9" + "@storybook/core-common" "6.5.9" chalk "^4.1.0" core-js "^3.8.2" detect-package-manager "^2.0.1" @@ -1954,30 +1957,33 @@ read-pkg-up "^7.0.1" regenerator-runtime "^0.13.7" -"@storybook/theming@6.5.8": - version "6.5.8" - resolved "https://registry.npmjs.org/@storybook/theming/-/theming-6.5.8.tgz#240a3c83ea53a9c7b1f3a2c47d6324f38ecb8771" - integrity sha512-1VaKHqj38Ls1bJwDpg3+aEOlvVib/DCFkP6WYrP/AQtNAzxiyw5WkaoRlTVJZvCdu5TxjpG4O6/Ai5TI9QftIg== +"@storybook/theming@6.5.9": + version "6.5.9" + resolved "https://registry.npmjs.org/@storybook/theming/-/theming-6.5.9.tgz#13f60a3a3cd73ceb5caf9f188e1627e79f1891aa" + integrity sha512-KM0AMP5jMQPAdaO8tlbFCYqx9uYM/hZXGSVUhznhLYu7bhNAIK7ZVmXxyE/z/khM++8eUHzRoZGiO/cwCkg9Xw== dependencies: - "@storybook/client-logger" "6.5.8" + "@storybook/client-logger" "6.5.9" core-js "^3.8.2" + memoizerific "^1.11.3" regenerator-runtime "^0.13.7" -"@storybook/ui@6.5.8": - version "6.5.8" - resolved "https://registry.npmjs.org/@storybook/ui/-/ui-6.5.8.tgz#acd8dadd221c68f65c4963c4ab86b4a757860591" - integrity sha512-rL09kxgY9pCVbxr/VUK4b5FL5VbALfciZR+50sNT1EcTDb9k0OPeqx7a4Ptc+KNkgyPdSTxUGvhzVqH5PYrhZQ== +"@storybook/ui@6.5.9": + version "6.5.9" + resolved "https://registry.npmjs.org/@storybook/ui/-/ui-6.5.9.tgz#41e59279323cccc0d613974ec9782d797220c8a7" + integrity sha512-ryuPxJgtbb0gPXKGgGAUC+Z185xGAd1IvQ0jM5fJ0SisHXI8jteG3RaWhntOehi9qCg+64Vv6eH/cj9QYNHt1Q== dependencies: - "@storybook/addons" "6.5.8" - "@storybook/api" "6.5.8" - "@storybook/channels" "6.5.8" - "@storybook/client-logger" "6.5.8" - "@storybook/components" "6.5.8" - "@storybook/core-events" "6.5.8" - "@storybook/router" "6.5.8" + "@storybook/addons" "6.5.9" + "@storybook/api" "6.5.9" + "@storybook/channels" "6.5.9" + "@storybook/client-logger" "6.5.9" + "@storybook/components" "6.5.9" + "@storybook/core-events" "6.5.9" + "@storybook/router" "6.5.9" "@storybook/semver" "^7.3.2" - "@storybook/theming" "6.5.8" + "@storybook/theming" "6.5.9" core-js "^3.8.2" + memoizerific "^1.11.3" + qs "^6.10.0" regenerator-runtime "^0.13.7" resolve-from "^5.0.0" @@ -2070,14 +2076,14 @@ form-data "^3.0.0" "@types/node@*": - version "17.0.41" - resolved "https://registry.npmjs.org/@types/node/-/node-17.0.41.tgz#1607b2fd3da014ae5d4d1b31bc792a39348dfb9b" - integrity sha512-xA6drNNeqb5YyV5fO3OAEsnXLfO7uF0whiOfPTz5AeDo8KeZFmODKnvwPymMNO8qE/an8pVY/O50tig2SQCrGw== + version "17.0.44" + resolved "https://registry.npmjs.org/@types/node/-/node-17.0.44.tgz#16dd0bb5338f016d8ca10631789f0d0612fe5d5b" + integrity sha512-gWYiOlu6Y4oyLYBvsJAPlwHbC8H4tX+tLsHy6Ee976wedwwZKrG2hFl3Y/HiH6bIyLTbDWQexQF/ohwKkOpUCg== "@types/node@^14.0.10 || ^16.0.0", "@types/node@^14.14.20 || ^16.0.0": - version "16.11.39" - resolved "https://registry.npmjs.org/@types/node/-/node-16.11.39.tgz#07223cd2bc332ad9d92135e3a522eebdee3b060e" - integrity sha512-K0MsdV42vPwm9L6UwhIxMAOmcvH/1OoVkZyCgEtVu4Wx7sElGloy/W7kMBNe/oJ7V/jW9BVt1F6RahH6e7tPXw== + version "16.11.41" + resolved "https://registry.npmjs.org/@types/node/-/node-16.11.41.tgz#88eb485b1bfdb4c224d878b7832239536aa2f813" + integrity sha512-mqoYK2TnVjdkGk8qXAVGc/x9nSaTpSrFaGFm43BUH3IdoBV0nta6hYaGmdOvIMlbHJbUEVen3gvwpwovAZKNdQ== "@types/normalize-package-data@^2.4.0": version "2.4.1" @@ -2146,9 +2152,9 @@ integrity sha512-ipixuVrh2OdNmauvtT51o3d8z12p6LtFW9in7U79der/kwejjdNchQC5UMn5u/KxNoM7VHHOs/l8KS8uHxhODQ== "@types/uglify-js@*": - version "3.13.3" - resolved "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.13.3.tgz#556fd2ac75cc649aba21f87e0be7b1a7e9915bfe" - integrity sha512-9dmBYXt/rKxedUXfCvXSxyiPvpDXLkiRlv17DnqdhS+pRustL1967rI1jZVt1xysTO+xJGMoZzcy3cWC9+b6Tw== + version "3.16.0" + resolved "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.16.0.tgz#2cf74a0e6ebb6cd54c0d48e509d5bd91160a9602" + integrity sha512-0yeUr92L3r0GLRnBOvtYK1v2SjqMIqQDHMl7GLb+l2L8+6LSFWEEWEIgVsPdMn5ImLM8qzWT8xFPtQYpp8co0g== dependencies: source-map "^0.6.1" @@ -2604,7 +2610,7 @@ ansi-to-html@^0.6.11: any-promise@^1.0.0: version "1.3.0" resolved "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" - integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= + integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== anymatch@^2.0.0: version "2.0.0" @@ -3128,7 +3134,7 @@ browserify-zlib@^0.2.0: dependencies: pako "~1.0.5" -browserslist@^4.12.0, browserslist@^4.14.5, browserslist@^4.20.2, browserslist@^4.20.3: +browserslist@^4.12.0, browserslist@^4.14.5, browserslist@^4.20.2, browserslist@^4.20.4: version "4.20.4" resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.20.4.tgz#98096c9042af689ee1e0271333dbc564b8ce4477" integrity sha512-ok1d+1WpnU24XYN7oC3QWgTyMhY/avPJ/r9T00xxvUOIparA/gc+UPUMaod3i+G6s+nI2nUb9xZ5k794uIwShw== @@ -3306,9 +3312,9 @@ camelcase@^6.2.0: integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001349: - version "1.0.30001350" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001350.tgz#f0acc6472469d066a4357765eb73be5973eda918" - integrity sha512-NZBql38Pzd+rAu5SPXv+qmTWGQuFsRiemHCJCAPvkoDxWV19/xqL2YHF32fDJ9SDLdLqfax8+S0CO3ncDCp9Iw== + version "1.0.30001354" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001354.tgz#95c5efdb64148bb4870771749b9a619304755ce5" + integrity sha512-mImKeCkyGDAHNywYFA4bqnLAzTUvVkqPvhY4DV47X+Gl2c5Z8c3KNETnXp14GQt11LvxE8AwjzGxJ+rsikiOzg== case-sensitive-paths-webpack-plugin@^2.3.0: version "2.4.0" @@ -3649,22 +3655,22 @@ copy-descriptor@^0.1.0: integrity sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw== core-js-compat@^3.21.0, core-js-compat@^3.22.1, core-js-compat@^3.8.1: - version "3.22.8" - resolved "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.22.8.tgz#46fa34ce1ddf742acd7f95f575f66bbb21e05d62" - integrity sha512-pQnwg4xtuvc2Bs/5zYQPaEYYSuTxsF7LBWF0SvnVhthZo/Qe+rJpcEekrdNK5DWwDJ0gv0oI9NNX5Mppdy0ctg== + version "3.23.1" + resolved "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.23.1.tgz#23d44d9f209086e60dabf9130cea7719af6e199b" + integrity sha512-KeYrEc8t6FJsKYB2qnDwRHWaC0cJNaqlHfCpMe5q3j/W1nje3moib/txNklddLPCtGb+etcBIyJ8zuMa/LN5/A== dependencies: - browserslist "^4.20.3" + browserslist "^4.20.4" semver "7.0.0" core-js-pure@^3.8.1: - version "3.22.8" - resolved "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.22.8.tgz#f2157793b58719196ccf9673cc14f3683adc0957" - integrity sha512-bOxbZIy9S5n4OVH63XaLVXZ49QKicjowDx/UELyJ68vxfCRpYsbyh/WNZNfEfAk+ekA8vSjt+gCDpvh672bc3w== + version "3.23.1" + resolved "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.23.1.tgz#0b27e4c3ad46178b84e790dbbb81987218ab82ad" + integrity sha512-3qNgf6TqI3U1uhuSYRzJZGfFd4T+YlbyVPl+jgRiKjdZopvG4keZQwWZDAWpu1UH9nCgTpUzIV3GFawC7cJsqg== core-js@^3.0.4, core-js@^3.6.5, core-js@^3.8.2: - version "3.22.8" - resolved "https://registry.npmjs.org/core-js/-/core-js-3.22.8.tgz#23f860b1fe60797cc4f704d76c93fea8a2f60631" - integrity sha512-UoGQ/cfzGYIuiq6Z7vWL1HfkE9U9IZ4Ub+0XSiJTCzvbZzgPA69oDF2f+lgJ6dFFLEdjW5O6svvoKzXX23xFkA== + version "3.23.1" + resolved "https://registry.npmjs.org/core-js/-/core-js-3.23.1.tgz#9f9a9255115f62c512db56d567f636da32ca0b78" + integrity sha512-wfMYHWi1WQjpgZNC9kAlN4ut04TM9fUTdi7CqIoTVM7yaiOUQTklOzfb+oWH3r9edQcT3F887swuVmxrV+CC8w== core-util-is@~1.0.0: version "1.0.3" @@ -4083,9 +4089,9 @@ ee-first@1.1.1: integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== electron-to-chromium@^1.4.147: - version "1.4.148" - resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.148.tgz#437430e03c58ccd1d05701f66980afe54d2253ec" - integrity sha512-8MJk1bcQUAYkuvCyWZxaldiwoDG0E0AMzBGA6cv3WfuvJySiPgfidEPBFCRRH3cZm6SVZwo/oRlK1ehi1QNEIQ== + version "1.4.156" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.156.tgz#fc398e1bfbe586135351ebfaf198473a82923af5" + integrity sha512-/Wj5NC7E0wHaMCdqxWz9B0lv7CcycDTiHyXCtbbu3pXM9TV2AOp8BtMqkVuqvJNdEvltBG6LxT2Q+BxY4LUCIA== element-resize-detector@^1.2.2: version "1.2.4" @@ -7033,12 +7039,7 @@ pinkie@^2.0.0: resolved "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" integrity sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg== -pirates@^4.0.1: - version "4.0.4" - resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.4.tgz#07df81e61028e402735cdd49db701e4885b4e6e6" - integrity sha512-ZIrVPH+A52Dw84R0L3/VS9Op04PuQ2SEoJL6bkshmiTic/HldyW9Tf7oH5mhJZBK7NmDx27vSMrYEXPXclpDKw== - -pirates@^4.0.5: +pirates@^4.0.1, pirates@^4.0.5: version "4.0.5" resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== @@ -7396,9 +7397,9 @@ react-docgen-typescript@^2.1.1: integrity sha512-tvg2ZtOpOi6QDwsb3GZhOjDkkX0h8Z2gipvTg6OVMUyoYoURhEiRNePT8NZItTVCDh39JJHnLdfCOkzoLbFnTg== react-docgen@^5.0.0: - version "5.4.1" - resolved "https://registry.npmjs.org/react-docgen/-/react-docgen-5.4.1.tgz#867168accce39e25095a23a922eaa90722e9d182" - integrity sha512-TZqD1aApirw86NV6tHrmDoxUn8wlinkVyutFarzbdwuhEurAzDN0y5sSj64o+BrHLPqjwpH9tunpfwgy+3Uyww== + version "5.4.2" + resolved "https://registry.npmjs.org/react-docgen/-/react-docgen-5.4.2.tgz#697ec899e8dd493bb7ba0d50ec0aa5e49f41d3fa" + integrity sha512-4Z5XYpHsn2bbUfaflxoS30VhUvQLBe4GCwwM5v1e1FUOeDdaoJi6wUGSmYp6OdXYEISEAOEIaSPBk4iezNCKBw== dependencies: "@babel/core" "^7.7.5" "@babel/generator" "^7.12.11" @@ -8120,7 +8121,7 @@ source-map-url@^0.4.0: source-map@^0.5.0, source-map@^0.5.6: version "0.5.7" resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: version "0.6.1" @@ -8202,7 +8203,7 @@ state-toggle@^1.0.0: static-extend@^0.1.1: version "0.1.2" resolved "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" - integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= + integrity sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g== dependencies: define-property "^0.2.5" object-copy "^0.1.0" @@ -8333,7 +8334,7 @@ string_decoder@~1.1.1: strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + integrity sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg== dependencies: ansi-regex "^2.0.0" @@ -8347,7 +8348,7 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: strip-bom@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" - integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4= + integrity sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g== dependencies: is-utf8 "^0.2.0" @@ -8359,7 +8360,7 @@ strip-final-newline@^2.0.0: strip-indent@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" - integrity sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI= + integrity sha512-I5iQq6aFMM62fBEAIB/hXzwJD6EEZ0xEGCX2t7oXqaKPIRgt4WruAQ285BISgdkP+HLGWyeGmNJcpIwFeRYRUA== dependencies: get-stdin "^4.0.1" @@ -8386,9 +8387,9 @@ style-to-object@0.3.0, style-to-object@^0.3.0: inline-style-parser "0.1.1" sucrase@^3.21.0: - version "3.21.0" - resolved "https://registry.npmjs.org/sucrase/-/sucrase-3.21.0.tgz#6a5affdbe716b22e4dc99c57d366ad0d216444b9" - integrity sha512-FjAhMJjDcifARI7bZej0Bi1yekjWQHoEvWIXhLPwDhC6O4iZ5PtGb86WV56riW87hzpgB13wwBKO9vKAiWu5VQ== + version "3.23.0" + resolved "https://registry.npmjs.org/sucrase/-/sucrase-3.23.0.tgz#2a7fa80a04f055fb2e95d2aead03fec1dba52838" + integrity sha512-xgC1xboStzGhCnRywlBf/DLmkC+SkdAKqrNCDsxGrzM0phR5oUxoFKiQNrsc2D8wDdAm03iLbSZqjHDddo3IzQ== dependencies: commander "^4.0.0" glob "7.1.6" @@ -8525,9 +8526,9 @@ terser@^4.1.2, terser@^4.6.3: source-map-support "~0.5.12" terser@^5.3.4, terser@^5.7.2: - version "5.14.0" - resolved "https://registry.npmjs.org/terser/-/terser-5.14.0.tgz#eefeec9af5153f55798180ee2617f390bdd285e2" - integrity sha512-JC6qfIEkPBd9j1SMO3Pfn+A6w2kQV54tv+ABQLgZr7dA3k/DL/OBoYSWxzVpZev3J+bUHXfr55L8Mox7AaNo6g== + version "5.14.1" + resolved "https://registry.npmjs.org/terser/-/terser-5.14.1.tgz#7c95eec36436cb11cf1902cc79ac564741d19eca" + integrity sha512-+ahUAE+iheqBTDxXhTisdA8hgvbEG1hHOQ9xmNjeUJSoi6DU/gMrKNcfZjHkyY6Alnuyc+ikYJaxxfHkT3+WuQ== dependencies: "@jridgewell/source-map" "^0.3.2" acorn "^8.5.0" @@ -8546,7 +8547,7 @@ test-exclude@^6.0.0: thenify-all@^1.0.0: version "1.6.0" resolved "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" - integrity sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY= + integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA== dependencies: thenify ">= 3.1.0 < 4" @@ -8580,24 +8581,24 @@ timers-browserify@^2.0.4: to-arraybuffer@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" - integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= + integrity sha512-okFlQcoGTi4LQBG/PgSYblw9VOyptsz2KJZqc6qtgGdes8VktzUQkj4BI2blit072iS8VODNcMA+tvnS9dnuMA== to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== to-object-path@^0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" - integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= + integrity sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg== dependencies: kind-of "^3.0.2" to-regex-range@^2.1.0: version "2.1.1" resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" - integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= + integrity sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg== dependencies: is-number "^3.0.0" repeat-string "^1.6.1" @@ -8627,12 +8628,12 @@ toidentifier@1.0.1: tr46@~0.0.3: version "0.0.3" resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" - integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== trim-newlines@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" - integrity sha1-WIeWa7WCpFA6QetST301ARgVphM= + integrity sha512-Nm4cF79FhSTzrLKGDMi3I4utBtFv8qKy4sq1enftf2gMdpqI8oVQTAfySkTz5r49giVzDj88SVZXP4CeYQwjaw== trim-trailing-lines@^1.0.0: version "1.1.4" @@ -8642,7 +8643,7 @@ trim-trailing-lines@^1.0.0: trim@0.0.1: version "0.0.1" resolved "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz#5858547f6b290757ee95cccc666fb50084c460dd" - integrity sha1-WFhUf2spB1fulczMZm+1AITEYN0= + integrity sha512-YzQV+TZg4AxpKxaTHK3c3D+kRDCGVEE7LemdlQZoQXn0iennk10RsIoY6ikzAqJTc9Xjl9C1/waHom/J86ziAQ== trough@^1.0.0: version "1.0.5" @@ -8672,12 +8673,12 @@ tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3: tty-browserify@0.0.0: version "0.0.0" resolved "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" - integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= + integrity sha512-JVa5ijo+j/sOoHGjw0sxw734b1LhBkQ3bvUGNdxnVXDCX81Yx7TFgnZygxrIIWn23hbfTaMYLwRmAxFyDuFmIw== type-check@~0.3.2: version "0.3.2" resolved "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= + integrity sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg== dependencies: prelude-ls "~1.1.2" @@ -8707,7 +8708,7 @@ type-is@~1.6.18: typedarray@^0.0.6: version "0.0.6" resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= + integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== uglify-js@^3.1.4: version "3.16.0" @@ -8862,12 +8863,12 @@ universalify@^2.0.0: unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== unset-value@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" - integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= + integrity sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ== dependencies: has-value "^0.3.1" isobject "^3.0.0" @@ -8875,7 +8876,7 @@ unset-value@^1.0.0: untildify@^2.0.0: version "2.1.0" resolved "https://registry.npmjs.org/untildify/-/untildify-2.1.0.tgz#17eb2807987f76952e9c0485fc311d06a826a2e0" - integrity sha1-F+soB5h/dpUunASF/DEdBqgmouA= + integrity sha512-sJjbDp2GodvkB0FZZcn7k6afVisqX5BZD7Yq3xp4nN2O15BBK0cLm3Vwn2vQaF7UDS0UUsrQMkkplmDI5fskig== dependencies: os-homedir "^1.0.0" @@ -8894,7 +8895,7 @@ uri-js@^4.2.2: urix@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" - integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= + integrity sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg== url-loader@^4.1.1: version "4.1.1" @@ -8908,7 +8909,7 @@ url-loader@^4.1.1: url@^0.11.0: version "0.11.0" resolved "https://registry.npmjs.org/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" - integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= + integrity sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ== dependencies: punycode "1.3.2" querystring "0.2.0" @@ -8921,7 +8922,7 @@ use@^3.1.0: util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== util.promisify@1.0.0: version "1.0.0" @@ -8934,7 +8935,7 @@ util.promisify@1.0.0: util@0.10.3: version "0.10.3" resolved "https://registry.npmjs.org/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" - integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk= + integrity sha512-5KiHfsmkqacuKjkRkdV7SsfDJ2EGiPsK92s2MhNSY0craxjTdKTtqKsJaCWp4LW33ZZ0OPUv1WO/TFvNQRiQxQ== dependencies: inherits "2.0.1" @@ -8948,17 +8949,17 @@ util@^0.11.0: utila@~0.4: version "0.4.0" resolved "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" - integrity sha1-ihagXURWV6Oupe7MWxKk+lN5dyw= + integrity sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA== utils-merge@1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" - integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== uuid-browser@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/uuid-browser/-/uuid-browser-3.1.0.tgz#0f05a40aef74f9e5951e20efbf44b11871e56410" - integrity sha1-DwWkCu90+eWVHiDvv0SxGHHlZBA= + integrity sha512-dsNgbLaTrd6l3MMxTtouOCFw4CBFc/3a+GgYA2YyrJvyQ1u6q4pcu3ktLoUZ/VN/Aw9WsauazbgsgdfVWgAKQg== uuid@^3.3.2: version "3.4.0" @@ -8985,7 +8986,7 @@ validate-npm-package-license@^3.0.1: vary@~1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== vfile-location@^3.0.0, vfile-location@^3.2.0: version "3.2.0" @@ -9049,7 +9050,7 @@ web-namespaces@^1.0.0: webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" - integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== webpack-dev-middleware@^3.7.3: version "3.7.3" @@ -9167,7 +9168,7 @@ webpack@4: whatwg-url@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" - integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== dependencies: tr46 "~0.0.3" webidl-conversions "^3.0.0" @@ -9212,7 +9213,7 @@ word-wrap@~1.2.3: wordwrap@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= + integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== worker-farm@^1.7.0: version "1.7.0" @@ -9240,17 +9241,17 @@ wrap-ansi@^7.0.0: wrappy@1: version "1.0.2" resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== ws@^8.2.3: - version "8.7.0" - resolved "https://registry.npmjs.org/ws/-/ws-8.7.0.tgz#eaf9d874b433aa00c0e0d8752532444875db3957" - integrity sha512-c2gsP0PRwcLFzUiA8Mkr37/MI7ilIlHQxaEAtd0uNMbVMoy8puJyafRlm0bV9MbGSabUPeLrRRaqIBcFcA2Pqg== + version "8.8.0" + resolved "https://registry.npmjs.org/ws/-/ws-8.8.0.tgz#8e71c75e2f6348dbf8d78005107297056cb77769" + integrity sha512-JDAgSYQ1ksuwqfChJusw1LSJ8BizJ2e/vVu5Lxjq3YvNJNlROv1ui4i+c/kUUrPheBvQl4c5UbERhTwKa6QBJQ== x-default-browser@^0.4.0: version "0.4.0" resolved "https://registry.npmjs.org/x-default-browser/-/x-default-browser-0.4.0.tgz#70cf0da85da7c0ab5cb0f15a897f2322a6bdd481" - integrity sha1-cM8NqF2nwKtcsPFaiX8jIqa91IE= + integrity sha512-7LKo7RtWfoFN/rHx1UELv/2zHGMx8MkZKDq1xENmOCTkfIqZJ0zZ26NEJX8czhnPXVcqS0ARjjfJB+eJ0/5Cvw== optionalDependencies: default-browser-id "^1.0.4" diff --git a/yarn.lock b/yarn.lock index 0d8a9f0a80..b03b5fdf07 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,13 +2,6 @@ # yarn lockfile v1 -"@acuris/aws-es-connection@^2.2.0": - version "2.3.0" - resolved "https://registry.npmjs.org/@acuris/aws-es-connection/-/aws-es-connection-2.3.0.tgz#bfa736163bdfe2e7fc12f8529eead949fb4e73fe" - integrity sha512-k8jSkdNwpSPty7oautGaJXoAzzPjP7WKbmaAE9i+vJrKWg9n2UtjesHeDhOAPzV9MG8EzXofGozYjaLdeTP+Ug== - dependencies: - aws4 "^1.11.0" - "@ampproject/remapping@^2.1.0": version "2.1.2" resolved "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz#4edca94973ded9630d20101cd8559cedb8d8bd34" @@ -16,7 +9,7 @@ dependencies: "@jridgewell/trace-mapping" "^0.3.0" -"@apidevtools/json-schema-ref-parser@^9.0.6": +"@apidevtools/json-schema-ref-parser@9.0.6", "@apidevtools/json-schema-ref-parser@^9.0.6": version "9.0.6" resolved "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.6.tgz#5d9000a3ac1fd25404da886da6b266adcd99cf1c" integrity sha512-M3YgsLjI0lZxvrpeGVk9Ap032W6TPQkH6pRAZz81Ac3WUNF79VQooAFnp8umjvVzUmD93NkogxEwbSce7qMsUg== @@ -25,6 +18,29 @@ call-me-maybe "^1.0.1" js-yaml "^3.13.1" +"@apidevtools/openapi-schemas@^2.1.0": + version "2.1.0" + resolved "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz#9fa08017fb59d80538812f03fc7cac5992caaa17" + integrity sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ== + +"@apidevtools/swagger-methods@^3.0.2": + version "3.0.2" + resolved "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz#b789a362e055b0340d04712eafe7027ddc1ac267" + integrity sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg== + +"@apidevtools/swagger-parser@^10.1.0": + version "10.1.0" + resolved "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-10.1.0.tgz#a987d71e5be61feb623203be0c96e5985b192ab6" + integrity sha512-9Kt7EuS/7WbMAUv2gSziqjvxwDbFSg3Xeyfuj5laUODX8o/k/CpsAKiQ8W7/R88eXFTMbJYg6+7uAmOWNKmwnw== + dependencies: + "@apidevtools/json-schema-ref-parser" "9.0.6" + "@apidevtools/openapi-schemas" "^2.1.0" + "@apidevtools/swagger-methods" "^3.0.2" + "@jsdevtools/ono" "^7.1.3" + ajv "^8.6.3" + ajv-draft-04 "^1.0.0" + call-me-maybe "^1.0.1" + "@apollo/protobufjs@1.2.2": version "1.2.2" resolved "https://registry.npmjs.org/@apollo/protobufjs/-/protobufjs-1.2.2.tgz#4bd92cd7701ccaef6d517cdb75af2755f049f87c" @@ -49,6 +65,14 @@ resolved "https://registry.npmjs.org/@apollo/utils.dropunuseddefinitions/-/utils.dropunuseddefinitions-1.1.0.tgz#02b04006442eaf037f4c4624146b12775d70d929" integrity sha512-jU1XjMr6ec9pPoL+BFWzEPW7VHHulVdGKMkPAMiCigpVIT11VmCbnij0bWob8uS3ODJ65tZLYKAh/55vLw2rbg== +"@apollo/utils.keyvaluecache@^1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@apollo/utils.keyvaluecache/-/utils.keyvaluecache-1.0.1.tgz#46f310f859067efe9fa126156c6954f8381080d2" + integrity sha512-nLgYLomqjVimEzQ4cdvVQkcryi970NDvcRVPfd0OPeXhBfda38WjBq+WhQFk+czSHrmrSp34YHBxpat0EtiowA== + dependencies: + "@apollo/utils.logger" "^1.0.0" + lru-cache "^7.10.1" + "@apollo/utils.logger@^1.0.0": version "1.0.0" resolved "https://registry.npmjs.org/@apollo/utils.logger/-/utils.logger-1.0.0.tgz#6e3460a2250c2ef7c2c3b0be6b5e148a1596f12b" @@ -100,6 +124,29 @@ dependencies: xss "^1.0.8" +"@ardatan/relay-compiler@12.0.0": + version "12.0.0" + resolved "https://registry.npmjs.org/@ardatan/relay-compiler/-/relay-compiler-12.0.0.tgz#2e4cca43088e807adc63450e8cab037020e91106" + integrity sha512-9anThAaj1dQr6IGmzBMcfzOQKTa5artjuPmw8NYK/fiGEMjADbSguBY2FMDykt+QhilR3wc9VA/3yVju7JHg7Q== + dependencies: + "@babel/core" "^7.14.0" + "@babel/generator" "^7.14.0" + "@babel/parser" "^7.14.0" + "@babel/runtime" "^7.0.0" + "@babel/traverse" "^7.14.0" + "@babel/types" "^7.0.0" + babel-preset-fbjs "^3.4.0" + chalk "^4.0.0" + fb-watchman "^2.0.0" + fbjs "^3.0.0" + glob "^7.1.1" + immutable "~3.7.6" + invariant "^2.2.4" + nullthrows "^1.1.1" + relay-runtime "12.0.0" + signedsource "^1.0.0" + yargs "^15.3.1" + "@asyncapi/avro-schema-parser@^0.3.0": version "0.3.0" resolved "https://registry.npmjs.org/@asyncapi/avro-schema-parser/-/avro-schema-parser-0.3.0.tgz#6922acc559ef999c57e81297d78ffe680fc92b3c" @@ -127,10 +174,10 @@ node-fetch "^2.6.0" tiny-merge-patch "^0.1.2" -"@asyncapi/react-component@1.0.0-next.38": - version "1.0.0-next.38" - resolved "https://registry.npmjs.org/@asyncapi/react-component/-/react-component-1.0.0-next.38.tgz#33909f556f18870faca8d8a9e9827a7e341a90ea" - integrity sha512-Uq0wcVHqmKXfvYCa74OiCEgNz3CbpVodeeIjrIsKWqyb9H6QjEA0pIJSLbvEwA+YKVGDXb48R3zsMSmRaqnmnA== +"@asyncapi/react-component@1.0.0-next.39": + version "1.0.0-next.39" + resolved "https://registry.npmjs.org/@asyncapi/react-component/-/react-component-1.0.0-next.39.tgz#2aa236b1783f36249752b3c30e0c7e0125af8c1f" + integrity sha512-UQYmzbvKwDm3HVGjLL1znK35bOKlWNiTUw29oSe6Xdil/Y7RODLctGQrbwKSCeP0VwtsokhwivQ3QHuL3byjVw== dependencies: "@asyncapi/avro-schema-parser" "^0.3.0" "@asyncapi/openapi-schema-parser" "^2.0.0" @@ -248,9 +295,9 @@ tslib "^2.0.0" "@azure/identity@^2.0.1", "@azure/identity@^2.0.4": - version "2.0.4" - resolved "https://registry.npmjs.org/@azure/identity/-/identity-2.0.4.tgz#f5cfde0daf1b9ebaaff3ed6c504f50d7d7c939a5" - integrity sha512-ZgFubAsmo7dji63NLPaot6O7pmDfceAUPY57uphSCr0hmRj+Cakqb4SUz5SohCHFtscrhcmejRU903Fowz6iXg== + version "2.0.5" + resolved "https://registry.npmjs.org/@azure/identity/-/identity-2.0.5.tgz#4475f1222a3cbf5c5ddec644dd3fb293256703d3" + integrity sha512-fSQTu9dS0P+lw1Gfct6t7TuRYybULL/E3wJjXLc1xr6RQXpmenJspi0lKzq3XFjLP5MzBlToKY3ZkYoAXPz1zA== dependencies: "@azure/abort-controller" "^1.0.0" "@azure/core-auth" "^1.3.0" @@ -297,17 +344,17 @@ dependencies: debug "^4.1.1" -"@azure/msal-common@^6.4.0": - version "6.4.0" - resolved "https://registry.npmjs.org/@azure/msal-common/-/msal-common-6.4.0.tgz#434a55be9639cb5c7910c0cc1a46555ff0bc6c39" - integrity sha512-WZdgq9f9O8cbxGzdRwLLMM5xjmLJ2mdtuzgXeiGxIRkVVlJ9nZ6sWnDFKa2TX8j72UXD1IfL0p/RYNoTXYoGfg== +"@azure/msal-common@^7.1.0": + version "7.1.0" + resolved "https://registry.npmjs.org/@azure/msal-common/-/msal-common-7.1.0.tgz#b77dbf9ae581f1ed254f81d56422e3cdd6664b32" + integrity sha512-WyfqE5mY/rggjqvq0Q5DxLnA33KSb0vfsUjxa95rycFknI03L5GPYI4HTU9D+g0PL5TtsQGnV3xzAGq9BFCVJQ== "@azure/msal-node@^1.1.0", "@azure/msal-node@^1.3.0": - version "1.9.1" - resolved "https://registry.npmjs.org/@azure/msal-node/-/msal-node-1.9.1.tgz#86f130fa50a5409a0e47a0ba192c7cdec42bd34c" - integrity sha512-chr914ZuKPvKEW1JPNDRhgdrzbA9PkVknV+q01h+eVhFZvHfO0pIFoP4dOU96ZdBkMmdD5kAP1Snv1gAdVXMIg== + version "1.11.0" + resolved "https://registry.npmjs.org/@azure/msal-node/-/msal-node-1.11.0.tgz#d8bd3f15c1f05bf806ba6f9479c48c2eddd6a98d" + integrity sha512-KW/XEexfCrPzdYbjY7NVmhq9okZT3Jvck55CGXpz9W5asxeq3EtrP45p+ZXtQVEfko0YJdolpCNqWUyXvanWZg== dependencies: - "@azure/msal-common" "^6.4.0" + "@azure/msal-common" "^7.1.0" jsonwebtoken "^8.5.1" uuid "^8.3.0" @@ -409,7 +456,7 @@ jsesc "^2.5.1" source-map "^0.5.0" -"@babel/helper-annotate-as-pure@^7.16.7": +"@babel/helper-annotate-as-pure@^7.16.0", "@babel/helper-annotate-as-pure@^7.16.7": version "7.16.7" resolved "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz#bb2339a7534a9c128e3102024c60760a3a7f3862" integrity sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw== @@ -523,7 +570,7 @@ dependencies: "@babel/types" "^7.16.7" -"@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.16.7": +"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.16.0", "@babel/helper-module-imports@^7.16.7": version "7.16.7" resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437" integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg== @@ -656,7 +703,7 @@ "@babel/traverse" "^7.17.3" "@babel/types" "^7.17.0" -"@babel/highlight@^7.0.0", "@babel/highlight@^7.16.7": +"@babel/highlight@^7.0.0": version "7.16.10" resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz#744f2eb81579d6eea753c227b0f570ad785aba88" integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw== @@ -665,6 +712,15 @@ chalk "^2.0.0" js-tokens "^4.0.0" +"@babel/highlight@^7.16.7": + version "7.17.12" + resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.12.tgz#257de56ee5afbd20451ac0a75686b6b404257351" + integrity sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + chalk "^2.0.0" + js-tokens "^4.0.0" + "@babel/parser@^7.1.0", "@babel/parser@^7.13.16", "@babel/parser@^7.14.0", "@babel/parser@^7.14.7", "@babel/parser@^7.16.10", "@babel/parser@^7.16.12", "@babel/parser@^7.16.7", "@babel/parser@^7.16.8", "@babel/parser@^7.17.3", "@babel/parser@^7.17.8": version "7.17.9" resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.17.9.tgz#9c94189a6062f0291418ca021077983058e171ef" @@ -1401,13 +1457,27 @@ dependencies: regenerator-runtime "^0.13.4" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.1", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.4", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.14.6", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.1", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.14.6", "@babel/runtime@^7.15.4", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": version "7.17.7" resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.7.tgz#a5f3328dc41ff39d803f311cfe17703418cf9825" integrity sha512-L6rvG9GDxaLgFjg41K+5Yv9OMrU98sWe+Ykmc6FDJW/+vYZMhdOMKkISgzptMaERHvS2Y2lw9MDRm2gHhlQQoA== dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@^7.10.4": + version "7.18.3" + resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.3.tgz#c7b654b57f6f63cf7f8b418ac9ca04408c4579f4" + integrity sha512-38Y8f7YUhce/K7RMwTp7m0uCumpv9hZkitCbBClqQIow1qSbCvGkcegKOXpEWCQLfWmevgRiWokZ1GkpfhbZug== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/runtime@^7.18.3": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.6.tgz#6a1ef59f838debd670421f8c7f2cbb8da9751580" + integrity sha512-t9wi7/AW6XtKahAe20Yw0/mMljKq0B1r2fPdvaAdV/KPDZewFXdaaa6K7lxmZBZ8FBNpCiAT6iHPmd6QO9bKfQ== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/template@^7.16.7", "@babel/template@^7.3.3": version "7.16.7" resolved "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155" @@ -1465,6 +1535,225 @@ "@babel/helper-validator-identifier" "^7.16.7" to-fast-properties "^2.0.0" +"@backstage/catalog-client@^1.0.3": + version "1.0.3" + resolved "https://registry.npmjs.org/@backstage/catalog-client/-/catalog-client-1.0.3.tgz#cb91472ccc31df322f69e7e4e80939b3535660cd" + integrity sha512-35Es9jFB9jOZTEtEeCyZHES0bcQkfX4qbmY1GuC6e6ZtO120w+595kmKxc744d7X2WXUIWvhRubqc9/w5blKbg== + dependencies: + "@backstage/catalog-model" "^1.0.3" + "@backstage/errors" "^1.0.0" + cross-fetch "^3.1.5" + +"@backstage/catalog-model@^1.0.0", "@backstage/catalog-model@^1.0.3": + version "1.0.3" + resolved "https://registry.npmjs.org/@backstage/catalog-model/-/catalog-model-1.0.3.tgz#0d7bd832add56650871b95894878540fc41a4ef9" + integrity sha512-rbXdA/CI8EzpsthlSI4JonLd4RZoki7IN6tFvivjKDMlW8IVb63BJXWO4VnvHH+LLYzH4/OaL051YeoaicdqYw== + dependencies: + "@backstage/config" "^1.0.1" + "@backstage/errors" "^1.0.0" + "@backstage/types" "^1.0.0" + ajv "^8.10.0" + json-schema "^0.4.0" + lodash "^4.17.21" + uuid "^8.0.0" + +"@backstage/core-components@^0.9.0", "@backstage/core-components@^0.9.5": + version "0.9.5" + resolved "https://registry.npmjs.org/@backstage/core-components/-/core-components-0.9.5.tgz#5a0b34867aaee0549bfa67b39a69c09588fa3c7a" + integrity sha512-kfAdN70idiEqHeH9ZQryn6C0RxJEKiRc/7srYIz0CVV88zJfc0nmZ5C/S10Gkht2xWfm95tTSw2P1vEYIBbfxg== + dependencies: + "@backstage/config" "^1.0.1" + "@backstage/core-plugin-api" "^1.0.3" + "@backstage/errors" "^1.0.0" + "@backstage/theme" "^0.2.15" + "@backstage/version-bridge" "^1.0.1" + "@material-table/core" "^3.1.0" + "@material-ui/core" "^4.12.2" + "@material-ui/icons" "^4.9.1" + "@material-ui/lab" "4.0.0-alpha.57" + "@react-hookz/web" "^14.0.0" + "@types/react-sparklines" "^1.7.0" + "@types/react-text-truncate" "^0.14.0" + ansi-regex "^6.0.1" + classnames "^2.2.6" + d3-selection "^3.0.0" + d3-shape "^3.0.0" + d3-zoom "^3.0.0" + dagre "^0.8.5" + history "^5.0.0" + immer "^9.0.1" + lodash "^4.17.21" + pluralize "^8.0.0" + prop-types "^15.7.2" + qs "^6.9.4" + rc-progress "3.3.3" + react-helmet "6.1.0" + react-hook-form "^7.12.2" + react-markdown "^8.0.0" + react-router "6.0.0-beta.0" + react-router-dom "6.0.0-beta.0" + react-sparklines "^1.7.0" + react-syntax-highlighter "^15.4.5" + react-text-truncate "^0.19.0" + react-use "^17.3.2" + react-virtualized-auto-sizer "^1.0.6" + react-window "^1.8.6" + remark-gfm "^3.0.1" + zen-observable "^0.8.15" + zod "^3.11.6" + +"@backstage/errors@^1.0.0": + version "1.0.0" + resolved "https://registry.npmjs.org/@backstage/errors/-/errors-1.0.0.tgz#08ebf53afdeaca32362955ea8551e8ffa0bb3cd7" + integrity sha512-2SpjdhH9ZOQ4RGEeu3/A7ARkl/1E9E6uBGQZ2DZOU4azTK1UZG/HE1KBMOThp3jL/8is2vOIJZLBA3r3DxLfVw== + dependencies: + "@backstage/types" "^1.0.0" + cross-fetch "^3.1.5" + serialize-error "^8.0.1" + +"@backstage/integration-react@^1.0.0": + version "1.1.1" + resolved "https://registry.npmjs.org/@backstage/integration-react/-/integration-react-1.1.1.tgz#936fd1441c47709fa8825360ea14ada26046b910" + integrity sha512-vCXErMhj90eW74A9gQwgKrc0Go5RXSEyM1wQV6+S91CZHYc3fdQJAfrxcmmUybGFtX2a2Yrmm67K8owG9WaYnQ== + dependencies: + "@backstage/config" "^1.0.1" + "@backstage/core-components" "^0.9.5" + "@backstage/core-plugin-api" "^1.0.3" + "@backstage/integration" "^1.2.1" + "@backstage/theme" "^0.2.15" + "@material-ui/core" "^4.12.2" + "@material-ui/icons" "^4.9.1" + "@material-ui/lab" "4.0.0-alpha.57" + react-use "^17.2.4" + +"@backstage/integration@^1.2.1": + version "1.2.1" + resolved "https://registry.npmjs.org/@backstage/integration/-/integration-1.2.1.tgz#a1931d240c2fbd304f0b87d54272709f4ffe83ed" + integrity sha512-9rXD1iIGhKRCfowxWx9sRKxiv1JvDI6ucvtUeXIj1G27kT/Xy7uUcgB8CkVxsvSeog5Z1VdYkFkDmQbKQ6GPrg== + dependencies: + "@backstage/config" "^1.0.1" + "@backstage/errors" "^1.0.0" + "@octokit/auth-app" "^3.4.0" + "@octokit/rest" "^18.5.3" + cross-fetch "^3.1.5" + git-url-parse "^11.6.0" + lodash "^4.17.21" + luxon "^2.0.2" + +"@backstage/plugin-catalog-common@^1.0.3": + version "1.0.3" + resolved "https://registry.npmjs.org/@backstage/plugin-catalog-common/-/plugin-catalog-common-1.0.3.tgz#96b1de2847fec0533c49ee19f93781777eedfd0d" + integrity sha512-Sf5IQocTRQaTh9ofZUy4/szWwDl5Eek6odKVx6v33jrMot5i3grybOELrVM3/Kgcr+5/ixSSopgQPUFO/T9KBA== + dependencies: + "@backstage/plugin-permission-common" "^0.6.2" + "@backstage/plugin-search-common" "^0.3.5" + +"@backstage/plugin-catalog-react@^1.0.0", "@backstage/plugin-catalog-react@^1.1.1": + version "1.1.1" + resolved "https://registry.npmjs.org/@backstage/plugin-catalog-react/-/plugin-catalog-react-1.1.1.tgz#0441bcf1291349ad355ff51e28245d7ea26a3e01" + integrity sha512-HxowTsFaNmAp+TEb0YgBak/61SkwwRV3tUdF5O2dQugbgI3Ci8dMjN2J18LiOEFS13m6IlrCpNC1Db3QMRjwBA== + dependencies: + "@backstage/catalog-client" "^1.0.3" + "@backstage/catalog-model" "^1.0.3" + "@backstage/core-components" "^0.9.5" + "@backstage/core-plugin-api" "^1.0.3" + "@backstage/errors" "^1.0.0" + "@backstage/integration" "^1.2.1" + "@backstage/plugin-catalog-common" "^1.0.3" + "@backstage/plugin-permission-common" "^0.6.2" + "@backstage/plugin-permission-react" "^0.4.2" + "@backstage/theme" "^0.2.15" + "@backstage/types" "^1.0.0" + "@backstage/version-bridge" "^1.0.1" + "@material-ui/core" "^4.12.2" + "@material-ui/icons" "^4.9.1" + "@material-ui/lab" "4.0.0-alpha.57" + classnames "^2.2.6" + jwt-decode "^3.1.0" + lodash "^4.17.21" + qs "^6.9.4" + react-router "6.0.0-beta.0" + react-use "^17.2.4" + yaml "^1.10.0" + zen-observable "^0.8.15" + +"@backstage/plugin-home@^0.4.19", "@backstage/plugin-home@^0.4.22": + version "0.4.22" + resolved "https://registry.npmjs.org/@backstage/plugin-home/-/plugin-home-0.4.22.tgz#efc54ebffb83a2a36dcd43e65142c30be5d8559d" + integrity sha512-0LPCyz1/nJraVdq+vkpS8g+8rnVTqY9oz5a+tOEnA6Beldlnd1xGa/qYfaH7s/5jFjd+XQRYoNw7qvioHLC16Q== + dependencies: + "@backstage/catalog-model" "^1.0.3" + "@backstage/config" "^1.0.1" + "@backstage/core-components" "^0.9.5" + "@backstage/core-plugin-api" "^1.0.3" + "@backstage/plugin-catalog-react" "^1.1.1" + "@backstage/plugin-stack-overflow" "^0.1.2" + "@backstage/theme" "^0.2.15" + "@material-ui/core" "^4.12.2" + "@material-ui/icons" "^4.9.1" + "@material-ui/lab" "4.0.0-alpha.57" + lodash "^4.17.21" + react-router "6.0.0-beta.0" + react-use "^17.2.4" + +"@backstage/plugin-permission-common@^0.6.2": + version "0.6.2" + resolved "https://registry.npmjs.org/@backstage/plugin-permission-common/-/plugin-permission-common-0.6.2.tgz#2ab5cf3d8a4a3394edc0d552719df4f34804bfbb" + integrity sha512-tbKjm0xw6stoaFzeWL59XRz/yEEXxnBMgm3ioNbh0Qdbj44z8KivjkDjWPovI5DW6x0jFxzLQYCNMlZxOpqL6A== + dependencies: + "@backstage/config" "^1.0.1" + "@backstage/errors" "^1.0.0" + cross-fetch "^3.1.5" + uuid "^8.0.0" + zod "^3.11.6" + +"@backstage/plugin-permission-react@^0.4.2": + version "0.4.2" + resolved "https://registry.npmjs.org/@backstage/plugin-permission-react/-/plugin-permission-react-0.4.2.tgz#efc39619617e5800a68728871b87c772a0861711" + integrity sha512-isofTbK1gFgLTgr51efbFO0jWOkhQwzErL24pwY6gFVKnz7Z53AfGv1lHabxAWnNhEyTzLPMA/7s7lKuKEtOXw== + dependencies: + "@backstage/config" "^1.0.1" + "@backstage/core-plugin-api" "^1.0.3" + "@backstage/plugin-permission-common" "^0.6.2" + cross-fetch "^3.1.5" + react-router "6.0.0-beta.0" + react-use "^17.2.4" + swr "^1.1.2" + +"@backstage/plugin-search-common@^0.3.5": + version "0.3.5" + resolved "https://registry.npmjs.org/@backstage/plugin-search-common/-/plugin-search-common-0.3.5.tgz#6a374541f2bd7d9545e29abbaecc70e7ad1b5ea3" + integrity sha512-sq7IDjCLrgZQHBFi+lFVkna3lLRA5eldiTbit/rCUCO4Eq52lWdQHLrQAhsyuObmIWHDh6R2lp2qoL6aAC2AOg== + dependencies: + "@backstage/plugin-permission-common" "^0.6.2" + "@backstage/types" "^1.0.0" + +"@backstage/plugin-stack-overflow@^0.1.2": + version "0.1.2" + resolved "https://registry.npmjs.org/@backstage/plugin-stack-overflow/-/plugin-stack-overflow-0.1.2.tgz#bc140bb22d239a7106f91ea1d4c637551dc91ca5" + integrity sha512-6phLbR7E/iZjuNFFStsO2zcJYDijPTS8WEyxhM/rX1Q/OeliMgGBs8V4j1hfHgcjjLz4PPI+EDz/+eeDMi1c4w== + dependencies: + "@backstage/config" "^1.0.1" + "@backstage/core-components" "^0.9.5" + "@backstage/core-plugin-api" "^1.0.3" + "@backstage/plugin-home" "^0.4.22" + "@backstage/plugin-search-common" "^0.3.5" + "@backstage/theme" "^0.2.15" + "@material-ui/core" "^4.12.2" + "@material-ui/icons" "^4.9.1" + "@testing-library/jest-dom" "^5.10.1" + cross-fetch "^3.1.5" + lodash "^4.17.21" + qs "^6.9.4" + react-use "^17.2.4" + +"@backstage/theme@^0.2.15", "@backstage/theme@^0.2.6", "@backstage/theme@^0.2.7", "@backstage/theme@^0.2.9": + version "0.2.15" + resolved "https://registry.npmjs.org/@backstage/theme/-/theme-0.2.15.tgz#478491c9bca9dca85d5af08767ba512eabcd3669" + integrity sha512-Srl5q0X47tFofw6wuElkUqtlbYSfA3J3zlfN6jcQF4801mTrFRw+pVxZmrdxayt4gUzCN+me3mO7tij6F6xQUQ== + dependencies: + "@material-ui/core" "^4.12.2" + "@balena/dockerignore@^1.0.2": version "1.0.2" resolved "https://registry.npmjs.org/@balena/dockerignore/-/dockerignore-1.0.2.tgz#9ffe4726915251e8eb69f44ef3547e0da2c03e0d" @@ -1499,10 +1788,10 @@ resolve-from "^5.0.0" semver "^5.4.1" -"@changesets/assemble-release-plan@^5.1.2": - version "5.1.2" - resolved "https://registry.npmjs.org/@changesets/assemble-release-plan/-/assemble-release-plan-5.1.2.tgz#63ed3a00f62b5af08a82e83801a252ac9726c625" - integrity sha512-nOFyDw4APSkY/vh5WNwGEtThPgEjVShp03PKVdId6wZTJALVcAALCSLmDRfeqjE2z9EsGJb7hZdDlziKlnqZgw== +"@changesets/assemble-release-plan@^5.1.3": + version "5.1.3" + resolved "https://registry.npmjs.org/@changesets/assemble-release-plan/-/assemble-release-plan-5.1.3.tgz#b415c5db64e5a30c53aed8c1adc5ab4c4aaad283" + integrity sha512-I+TTkUoqvxBEuDLoJfJYKDXIJ+nyiTbVJ8KGhpXEsLq4N/ms/AStSbouJwF2d/p3cB+RCPr5+gXh31GSN4kA7w== dependencies: "@babel/runtime" "^7.10.4" "@changesets/errors" "^0.1.4" @@ -1519,18 +1808,18 @@ "@changesets/types" "^5.0.0" "@changesets/cli@^2.14.0": - version "2.22.0" - resolved "https://registry.npmjs.org/@changesets/cli/-/cli-2.22.0.tgz#3bdbfb4a7a81ef37f63114e77da84e23f906b763" - integrity sha512-4bA3YoBkd5cm5WUxmrR2N9WYE7EeQcM+R3bVYMUj2NvffkQVpU3ckAI+z8UICoojq+HRl2OEwtz+S5UBmYY4zw== + version "2.23.0" + resolved "https://registry.npmjs.org/@changesets/cli/-/cli-2.23.0.tgz#e325b2d1b0484188671f684773b8cd5d42d068f1" + integrity sha512-Gi3tMi0Vr6eNd8GX6q73tbOm9XOzGfuLEm4PYVeWG2neg5DlRGNOjYwrFULJ/An3N9MHtHn4r5h1Qvnju9Ijug== dependencies: "@babel/runtime" "^7.10.4" "@changesets/apply-release-plan" "^6.0.0" - "@changesets/assemble-release-plan" "^5.1.2" + "@changesets/assemble-release-plan" "^5.1.3" "@changesets/changelog-git" "^0.1.11" "@changesets/config" "^2.0.0" "@changesets/errors" "^0.1.4" "@changesets/get-dependents-graph" "^1.3.2" - "@changesets/get-release-plan" "^3.0.8" + "@changesets/get-release-plan" "^3.0.9" "@changesets/git" "^1.3.2" "@changesets/logger" "^0.0.5" "@changesets/pre" "^1.0.11" @@ -1540,6 +1829,7 @@ "@manypkg/get-packages" "^1.1.3" "@types/is-ci" "^3.0.0" "@types/semver" "^6.0.0" + ansi-colors "^4.1.3" chalk "^2.1.0" enquirer "^2.3.0" external-editor "^3.1.0" @@ -1554,7 +1844,7 @@ semver "^5.4.1" spawndamnit "^2.0.0" term-size "^2.1.0" - tty-table "^2.8.10" + tty-table "^4.1.5" "@changesets/config@^2.0.0": version "2.0.0" @@ -1587,13 +1877,13 @@ fs-extra "^7.0.1" semver "^5.4.1" -"@changesets/get-release-plan@^3.0.8": - version "3.0.8" - resolved "https://registry.npmjs.org/@changesets/get-release-plan/-/get-release-plan-3.0.8.tgz#2ac7c4f7903aedede3d27af66311ad1db7937e5d" - integrity sha512-TJYiWNuP0Lzu2dL/KHuk75w7TkiE5HqoYirrXF7SJIxkhlgH9toQf2C7IapiFTObtuF1qDN8HJAX1CuIOwXldg== +"@changesets/get-release-plan@^3.0.9": + version "3.0.9" + resolved "https://registry.npmjs.org/@changesets/get-release-plan/-/get-release-plan-3.0.9.tgz#d445660f3679cb65e05e02adfbca037a25b45943" + integrity sha512-5C1r4DcOjVxcCvPmXpymeyT6mdSTLCNiB2L+5uf19BRkDKndJdIQorH5Fe2XBR2nHUcZQFT+2TXDzCepat969w== dependencies: "@babel/runtime" "^7.10.4" - "@changesets/assemble-release-plan" "^5.1.2" + "@changesets/assemble-release-plan" "^5.1.3" "@changesets/config" "^2.0.0" "@changesets/pre" "^1.0.11" "@changesets/read" "^0.5.5" @@ -1678,97 +1968,84 @@ human-id "^1.0.2" prettier "^1.19.1" -"@codemirror/autocomplete@^0.20.0": - version "0.20.0" - resolved "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-0.20.0.tgz#390cc444ea36474e77117f2153caad84214f0edf" - integrity sha512-F6VOM8lImn5ApqxJcaWgdl7hhlw8B5yAfZJGlsQifcpNotkZOMND61mBFZ84OmSLWxtT8/smkSeLvJupKbjP9w== +"@codemirror/autocomplete@^6.0.0": + version "6.0.2" + resolved "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.0.2.tgz#119b9d147456418895de6fae09419465b58d7beb" + integrity sha512-9PDjnllmXan/7Uax87KGORbxerDJ/cu10SB+n4Jz0zXMEvIh3+TGgZxhIvDOtaQ4jDBQEM7kHYW4vLdQB0DGZQ== dependencies: - "@codemirror/language" "^0.20.0" - "@codemirror/state" "^0.20.0" - "@codemirror/view" "^0.20.0" - "@lezer/common" "^0.16.0" + "@codemirror/language" "^6.0.0" + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.0.0" + "@lezer/common" "^1.0.0" -"@codemirror/basic-setup@^0.20.0": - version "0.20.0" - resolved "https://registry.npmjs.org/@codemirror/basic-setup/-/basic-setup-0.20.0.tgz#ed331e0b2d29efc0a09317de9e10467b992b0c7b" - integrity sha512-W/ERKMLErWkrVLyP5I8Yh8PXl4r+WFNkdYVSzkXYPQv2RMPSkWpr2BgggiSJ8AHF/q3GuApncDD8I4BZz65fyg== +"@codemirror/commands@^6.0.0": + version "6.0.0" + resolved "https://registry.npmjs.org/@codemirror/commands/-/commands-6.0.0.tgz#9eaa4d53e9cdb2e13da52c8a03636a9f9ad45d2b" + integrity sha512-nVJDPiCQXWXj5AZxqNVXyIM3nOYauF4Dko9NGPSwgVdK+lXWJQhI5LGhS/AvdG5b7u7/pTQBkrQmzkLWRBF62A== dependencies: - "@codemirror/autocomplete" "^0.20.0" - "@codemirror/commands" "^0.20.0" - "@codemirror/language" "^0.20.0" - "@codemirror/lint" "^0.20.0" - "@codemirror/search" "^0.20.0" - "@codemirror/state" "^0.20.0" - "@codemirror/view" "^0.20.0" + "@codemirror/language" "^6.0.0" + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.0.0" + "@lezer/common" "^1.0.0" -"@codemirror/commands@^0.20.0": - version "0.20.0" - resolved "https://registry.npmjs.org/@codemirror/commands/-/commands-0.20.0.tgz#51405d442e6b8687b63e8fa27effc28179917c88" - integrity sha512-v9L5NNVA+A9R6zaFvaTbxs30kc69F6BkOoiEbeFw4m4I0exmDEKBILN6mK+GksJtvTzGBxvhAPlVFTdQW8GB7Q== +"@codemirror/language@^6.0.0": + version "6.2.0" + resolved "https://registry.npmjs.org/@codemirror/language/-/language-6.2.0.tgz#f8d103927bb61346e93781b1ca7d3f4ac3c9280b" + integrity sha512-tabB0Ef/BflwoEmTB4a//WZ9P90UQyne9qWB9YFsmeS4bnEqSys7UpGk/da1URMXhyfuzWCwp+AQNMhvu8SfnA== dependencies: - "@codemirror/language" "^0.20.0" - "@codemirror/state" "^0.20.0" - "@codemirror/view" "^0.20.0" - "@lezer/common" "^0.16.0" - -"@codemirror/language@^0.20.0": - version "0.20.2" - resolved "https://registry.npmjs.org/@codemirror/language/-/language-0.20.2.tgz#31c3712eac2251810986272dcd6a50510e0c1529" - integrity sha512-WB3Bnuusw0xhVvhBocieYKwJm04SOk5bPoOEYksVHKHcGHFOaYaw+eZVxR4gIqMMcGzOIUil0FsCmFk8yrhHpw== - dependencies: - "@codemirror/state" "^0.20.0" - "@codemirror/view" "^0.20.0" - "@lezer/common" "^0.16.0" - "@lezer/highlight" "^0.16.0" - "@lezer/lr" "^0.16.0" + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.0.0" + "@lezer/common" "^1.0.0" + "@lezer/highlight" "^1.0.0" + "@lezer/lr" "^1.0.0" style-mod "^4.0.0" -"@codemirror/legacy-modes@^0.20.0": - version "0.20.0" - resolved "https://registry.npmjs.org/@codemirror/legacy-modes/-/legacy-modes-0.20.0.tgz#a1cea5eed05fa09a0cac4a39f41e362a136da5ea" - integrity sha512-SYllodnzD8OI6Y6NoFzCv+77cU9aTdfqDO0Zn8j5PbjUIAD+pIofwHAvecd9/ePLAICr+EYCEuqUxldHAR+pLQ== +"@codemirror/legacy-modes@^6.1.0": + version "6.1.0" + resolved "https://registry.npmjs.org/@codemirror/legacy-modes/-/legacy-modes-6.1.0.tgz#f1c6d504069509c8d3d9220453132e559477400c" + integrity sha512-V/PgGpndkZeTn3Hdlg/gd8MLFdyvTCIX+iwJzjUw5iNziWiNsAY8X0jvf7m3gSfxnKkNzmid6l0g4rYSpiDaCw== dependencies: - "@codemirror/language" "^0.20.0" + "@codemirror/language" "^6.0.0" -"@codemirror/lint@^0.20.0": - version "0.20.1" - resolved "https://registry.npmjs.org/@codemirror/lint/-/lint-0.20.1.tgz#791c83642f76103bbf6b8bfdc8020eff2b78b5e2" - integrity sha512-aWbeicDiNe5tb2aZuXs7sKk3hQ89Z1YcUuUX8ngQu23tT6EY4kcY2cayDjizvkLn8iHkObNf97uSudjNmUon2Q== +"@codemirror/lint@^6.0.0": + version "6.0.0" + resolved "https://registry.npmjs.org/@codemirror/lint/-/lint-6.0.0.tgz#a249b021ac9933b94fe312d994d220f0ef11a157" + integrity sha512-nUUXcJW1Xp54kNs+a1ToPLK8MadO0rMTnJB8Zk4Z8gBdrN0kqV7uvUraU/T2yqg+grDNR38Vmy/MrhQN/RgwiA== dependencies: - "@codemirror/state" "^0.20.0" - "@codemirror/view" "^0.20.2" + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.0.0" crelt "^1.0.5" -"@codemirror/search@^0.20.0": - version "0.20.1" - resolved "https://registry.npmjs.org/@codemirror/search/-/search-0.20.1.tgz#9eba0514218a673e29501a889a4fcb7da7ce24ad" - integrity sha512-ROe6gRboQU5E4z6GAkNa2kxhXqsGNbeLEisbvzbOeB7nuDYXUZ70vGIgmqPu0tB+1M3F9yWk6W8k2vrFpJaD4Q== +"@codemirror/search@^6.0.0": + version "6.0.0" + resolved "https://registry.npmjs.org/@codemirror/search/-/search-6.0.0.tgz#43bd6341d9aff18869386d2fce27519850e919e3" + integrity sha512-rL0rd3AhI0TAsaJPUaEwC63KHLO7KL0Z/dYozXj6E7L3wNHRyx7RfE0/j5HsIf912EE5n2PCb4Vg0rGYmDv4UQ== dependencies: - "@codemirror/state" "^0.20.0" - "@codemirror/view" "^0.20.0" + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.0.0" crelt "^1.0.5" -"@codemirror/state@^0.20.0": - version "0.20.0" - resolved "https://registry.npmjs.org/@codemirror/state/-/state-0.20.0.tgz#3343d209169813b0152b77361cd78bea01549a73" - integrity sha512-R3XrAWCS5Xm9lx+4pDET4EUPEg+8bDfAa5zoOFIhx+VChsfew9Vy33dAjCXS5ES4Q8UecW4WM4UudmUFpZ+86A== +"@codemirror/state@^6.0.0": + version "6.0.1" + resolved "https://registry.npmjs.org/@codemirror/state/-/state-6.0.1.tgz#a1994f14c49e2f77cb9e26aef35f63a8b3707c6c" + integrity sha512-6vYgaXc4KjSY0BUfSVDJooGcoswg/RJZpq/ZGjsUYmY0KN1lmB8u03nv+jiG1ncUV5qoggyxFT5AGD5Ak+5Zrw== -"@codemirror/theme-one-dark@^0.20.0": - version "0.20.0" - resolved "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-0.20.0.tgz#112074e446d46931d1104405154ccbe8c8874009" - integrity sha512-iqTKaiOZddwlc2rYF+9D60Gfyz9EsSawVejSjyP2FCtOwZ1X0frG5/ByTKH5FBDD2+P7W8+h/OIG4r5dWq4bgA== +"@codemirror/theme-one-dark@^6.0.0": + version "6.0.0" + resolved "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.0.0.tgz#81a999a568217f68522bd8846cbf7210ca2a59df" + integrity sha512-jTCfi1I8QT++3m21Ui6sU8qwu3F/hLv161KLxfvkV1cYWSBwyUanmQFs89ChobQjBHi2x7s2k71wF9WYvE8fdw== dependencies: - "@codemirror/language" "^0.20.0" - "@codemirror/state" "^0.20.0" - "@codemirror/view" "^0.20.0" - "@lezer/highlight" "^0.16.0" + "@codemirror/language" "^6.0.0" + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.0.0" + "@lezer/highlight" "^1.0.0" -"@codemirror/view@^0.20.0", "@codemirror/view@^0.20.2": - version "0.20.7" - resolved "https://registry.npmjs.org/@codemirror/view/-/view-0.20.7.tgz#1d0acc740f71f92abef4b437c030d4e6c39ab6dc" - integrity sha512-pqEPCb9QFTOtHgAH5XU/oVy9UR/Anj6r+tG5CRmkNVcqSKEPmBU05WtN/jxJCFZBXf6HumzWC9ydE4qstO3TxQ== +"@codemirror/view@^6.0.0": + version "6.0.2" + resolved "https://registry.npmjs.org/@codemirror/view/-/view-6.0.2.tgz#27f4d08edd10a3678cf15390b4fba5e2a7220873" + integrity sha512-mnVT/q1JvKPjpmjXJNeCi/xHyaJ3abGJsumIVpdQ1nE1MXAyHf7GHWt8QpWMUvDiqF0j+inkhVR2OviTdFFX7Q== dependencies: - "@codemirror/state" "^0.20.0" + "@codemirror/state" "^6.0.0" style-mod "^4.0.0" w3c-keyname "^2.2.4" @@ -1858,10 +2135,10 @@ find-my-way "^4.3.3" into-stream "^6.0.0" -"@elastic/elasticsearch@7.13.0": - version "7.13.0" - resolved "https://registry.npmjs.org/@elastic/elasticsearch/-/elasticsearch-7.13.0.tgz#6dcf511dfa91187e22c81e54f41f4bd0fd96b4d6" - integrity sha512-WgwLWo2p9P2tdqzBGX9fHeG8p5IOTXprXNTECQG2mJ7z9n93N5AFBJpEw4d35tWWeCWi9jI13A2wzQZH7XZ/xw== +"@elastic/elasticsearch@^7.13.0": + version "7.17.0" + resolved "https://registry.npmjs.org/@elastic/elasticsearch/-/elasticsearch-7.17.0.tgz#589fb219234cf1b0da23744e82b1d25e2fe9a797" + integrity sha512-5QLPCjd0uLmLj1lSuKSThjNpq39f6NmlTy9ROLFwG5gjyTgpwSqufDeYG/Fm43Xs05uF7WcscoO7eguI3HuuYA== dependencies: debug "^4.3.1" hpagent "^0.1.1" @@ -1873,6 +2150,28 @@ resolved "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413" integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow== +"@emotion/is-prop-valid@^1.1.0": + version "1.1.2" + resolved "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.1.2.tgz#34ad6e98e871aa6f7a20469b602911b8b11b3a95" + integrity sha512-3QnhqeL+WW88YjYbQL5gUIkthuMw7a0NGbZ7wfFVk2kg/CK5w8w5FFa0RzWjyY1+sujN0NWbtSHH6OJmWHtJpQ== + dependencies: + "@emotion/memoize" "^0.7.4" + +"@emotion/memoize@^0.7.4": + version "0.7.5" + resolved "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.5.tgz#2c40f81449a4e554e9fc6396910ed4843ec2be50" + integrity sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ== + +"@emotion/stylis@^0.8.4": + version "0.8.5" + resolved "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz#deacb389bd6ee77d1e7fcaccce9e16c5c7e78e04" + integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ== + +"@emotion/unitless@^0.7.4": + version "0.7.5" + resolved "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" + integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== + "@endemolshinegroup/cosmiconfig-typescript-loader@3.0.2": version "3.0.2" resolved "https://registry.npmjs.org/@endemolshinegroup/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-3.0.2.tgz#eea4635828dde372838b0909693ebd9aafeec22d" @@ -1989,9 +2288,9 @@ xcase "^2.0.1" "@google-cloud/container@^4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@google-cloud/container/-/container-4.0.0.tgz#9bcfe2d404b739844766a91c0dd2b3fc63d014d1" - integrity sha512-nndrAVyZ34I9LykL1DIDONskl/hRmXmvtTbWrcm+Jep6Lm1bCJ0LkgMGg8yLS1tqWrdhIl73+xwcVfiY2dm7ig== + version "4.1.0" + resolved "https://registry.npmjs.org/@google-cloud/container/-/container-4.1.0.tgz#cf929184f668fc40ca8b864b7f638228ae67fc98" + integrity sha512-LpVT3wxG73iX/5deF4a2KIEZ7sULF2mksrzyA25OVGtyxFclSZT2Gs5uho5USSLkoKg/Ou+l+ekGMrgBQbLDag== dependencies: google-gax "^3.0.1" @@ -2013,10 +2312,10 @@ arrify "^2.0.0" extend "^3.0.2" -"@google-cloud/projectify@^2.0.0": - version "2.0.1" - resolved "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-2.0.1.tgz#13350ee609346435c795bbfe133a08dfeab78d65" - integrity sha512-ZDG38U/Yy6Zr21LaR3BTiiLtpJl6RkPS/JwoRT453G+6Q1DhlV0waNf8Lfu+YVYGIIxgKnLayJRfYlFJfiI8iQ== +"@google-cloud/projectify@^3.0.0": + version "3.0.0" + resolved "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-3.0.0.tgz#302b25f55f674854dce65c2532d98919b118a408" + integrity sha512-HRkZsNmjScY6Li8/kb70wjGlDDyLkVk3KvoEo9uIoxSjYLJasGiCch9+PqRVDOCGUFvEIqyogl+BeqILL4OJHA== "@google-cloud/promisify@^3.0.0": version "3.0.0" @@ -2024,12 +2323,12 @@ integrity sha512-91ArYvRgXWb73YvEOBMmOcJc0bDRs5yiVHnqkwoG0f3nm7nZuipllz6e7BvFESBvjkDTBC0zMD8QxedUwNLc1A== "@google-cloud/storage@^6.0.0": - version "6.1.0" - resolved "https://registry.npmjs.org/@google-cloud/storage/-/storage-6.1.0.tgz#f882a969c5637ff445764d7b172f68fd0d9e63f8" - integrity sha512-zqZwzpRWCJuPne7x9Vc2H79zANl0uh9bNPGis0xAuC88ZEvBXfQqYCAVyiL1YIxi7rf51l8wy9vBr1pONMfxxA== + version "6.2.2" + resolved "https://registry.npmjs.org/@google-cloud/storage/-/storage-6.2.2.tgz#1fd3ee85e5fea55a9696c98769d097b28ff4d775" + integrity sha512-KhAOxmGfmELKKn6cdvgGfAi/YBLi19hI1jX3QI7xQmbeajSFMgUKrIPbbyfMIxQPOEQ9vG0MQX1uganlA/HTRA== dependencies: "@google-cloud/paginator" "^3.0.7" - "@google-cloud/projectify" "^2.0.0" + "@google-cloud/projectify" "^3.0.0" "@google-cloud/promisify" "^3.0.0" abort-controller "^3.0.0" arrify "^2.0.0" @@ -2049,17 +2348,17 @@ teeny-request "^8.0.0" uuid "^8.0.0" -"@graphiql/react@^0.4.1": - version "0.4.1" - resolved "https://registry.npmjs.org/@graphiql/react/-/react-0.4.1.tgz#c424951f4e1b2ffa22aa514b18663d7a848ff31f" - integrity sha512-YeB26Sc223zfv6wSzygKRfeJ7JeXZW40c6vY4Om/POXuytRyrxuKynuP1Z3ueGYY4Rji8YMg6dPAjtTOUDLjZw== +"@graphiql/react@^0.4.3": + version "0.4.3" + resolved "https://registry.npmjs.org/@graphiql/react/-/react-0.4.3.tgz#29ca3125c7a349de5e9beb2aef660137fbcbde2e" + integrity sha512-MnH+7LqRqFnwo8YBDtgDfJOdeS5QqNTzH2gTvTbEYYWaNQW1+Vhbsyu2RKHnPSgKVQlfLzdjw6SAMtSb3q1Qog== dependencies: "@graphiql/toolkit" "^0.6.0" codemirror "^5.65.3" - codemirror-graphql "^1.3.1" + codemirror-graphql "^1.3.2" copy-to-clipboard "^3.2.0" escape-html "^1.0.3" - graphql-language-service "^5.0.5" + graphql-language-service "^5.0.6" markdown-it "^12.2.0" set-value "^4.1.0" @@ -2072,21 +2371,21 @@ meros "^1.1.4" "@graphql-codegen/cli@^2.3.1": - version "2.6.2" - resolved "https://registry.npmjs.org/@graphql-codegen/cli/-/cli-2.6.2.tgz#a9aa4656141ee0998cae8c7ad7d0bf9ca8e0c9ae" - integrity sha512-UO75msoVgvLEvfjCezM09cQQqp32+mR8Ma1ACsBpr7nroFvHbgcu2ulx1cMovg4sxDBCsvd9Eq/xOOMpARUxtw== + version "2.7.0" + resolved "https://registry.npmjs.org/@graphql-codegen/cli/-/cli-2.7.0.tgz#610f3cb2798d581fff3af8d8ba522113a1811fc5" + integrity sha512-qlBcS6jGfZ/xWXwqiyRLHGRuLC9gUdF8AwGHN7LdAYEP5MjL7pIXb02W5JuvMn47rrvr2Q22H9ECppZX65oSAg== dependencies: "@graphql-codegen/core" "2.5.1" "@graphql-codegen/plugin-helpers" "^2.4.1" - "@graphql-tools/apollo-engine-loader" "^7.0.5" + "@graphql-tools/apollo-engine-loader" "^7.3.1" "@graphql-tools/code-file-loader" "^7.0.6" "@graphql-tools/git-loader" "^7.0.5" "@graphql-tools/github-loader" "^7.0.5" "@graphql-tools/graphql-file-loader" "^7.0.5" "@graphql-tools/json-file-loader" "^7.1.2" "@graphql-tools/load" "^7.3.0" - "@graphql-tools/prisma-loader" "^7.0.6" - "@graphql-tools/url-loader" "^7.0.11" + "@graphql-tools/prisma-loader" "^7.2.2" + "@graphql-tools/url-loader" "^7.12.1" "@graphql-tools/utils" "^8.1.1" ansi-escapes "^4.3.1" chalk "^4.1.0" @@ -2095,10 +2394,7 @@ common-tags "^1.8.0" cosmiconfig "^7.0.0" debounce "^1.2.0" - dependency-graph "^0.11.0" detect-indent "^6.0.0" - glob "^7.1.6" - globby "^11.0.4" graphql-config "^4.1.0" inquirer "^8.0.0" is-glob "^4.0.1" @@ -2107,12 +2403,9 @@ listr "^0.14.3" listr-update-renderer "^0.5.0" log-symbols "^4.0.0" - minimatch "^4.0.0" mkdirp "^1.0.4" string-env-interpolation "^1.0.1" ts-log "^2.2.3" - tslib "~2.3.0" - valid-url "^1.0.9" wrap-ansi "^7.0.0" yaml "^1.10.0" yargs "^17.0.0" @@ -2128,13 +2421,13 @@ tslib "~2.3.0" "@graphql-codegen/graphql-modules-preset@^2.3.2": - version "2.3.12" - resolved "https://registry.npmjs.org/@graphql-codegen/graphql-modules-preset/-/graphql-modules-preset-2.3.12.tgz#e2e128eaab2ca5600bb137c8fec9e3f52c5f243b" - integrity sha512-Xz5RsiythN/6ivt+9n43ciHWZ6ngUK1mpBBG/0EYISfUUVaTBLBVKoAhqPHcquqrsByppE0Nclw5sUuOLQUjiA== + version "2.3.14" + resolved "https://registry.npmjs.org/@graphql-codegen/graphql-modules-preset/-/graphql-modules-preset-2.3.14.tgz#78afc5193707cba8a9ef6e2053e90eb9a9a3499c" + integrity sha512-6i2n3pGqvSniA8Qued0KUxMdAEWPREzD9nSMa+hC+r6u0k6V8nW+jWWeLNEi65Ctmt527KSYmGj8PH1RFRqhiw== dependencies: "@graphql-codegen/plugin-helpers" "^2.4.0" - "@graphql-codegen/visitor-plugin-common" "2.9.0" - "@graphql-tools/utils" "8.6.12" + "@graphql-codegen/visitor-plugin-common" "2.10.0" + "@graphql-tools/utils" "8.8.0" change-case-all "1.0.14" parse-filepath "^1.0.2" tslib "~2.4.0" @@ -2161,36 +2454,36 @@ tslib "~2.3.0" "@graphql-codegen/typescript-resolvers@^2.4.3": - version "2.6.5" - resolved "https://registry.npmjs.org/@graphql-codegen/typescript-resolvers/-/typescript-resolvers-2.6.5.tgz#f22635ae76218dbc12c39d32f84a3979a791c764" - integrity sha512-vzREbHyiYHhy/C90V8HKnfD7hnJIeioqZIYssX9WTQ5pVHqdeO/k4Gbw9ljcFe4OsP5d9GFHzhtU+/GnQlCyaA== + version "2.6.7" + resolved "https://registry.npmjs.org/@graphql-codegen/typescript-resolvers/-/typescript-resolvers-2.6.7.tgz#a6cadbd6822680678675fffbb826c7163ac60ca0" + integrity sha512-zdB4VuXzBRl2EbxQ/SZ9DRiRMcvCY3eZ2FPM2MnEidR7ggh3GdSg3Ewo6HgwRIHBxI0+DeoK0IM/Po0Rs3q0DA== dependencies: "@graphql-codegen/plugin-helpers" "^2.4.0" - "@graphql-codegen/typescript" "^2.5.0" - "@graphql-codegen/visitor-plugin-common" "2.9.0" + "@graphql-codegen/typescript" "^2.6.0" + "@graphql-codegen/visitor-plugin-common" "2.10.0" "@graphql-tools/utils" "^8.1.1" auto-bind "~4.0.0" tslib "~2.4.0" -"@graphql-codegen/typescript@^2.4.2", "@graphql-codegen/typescript@^2.5.0": - version "2.5.0" - resolved "https://registry.npmjs.org/@graphql-codegen/typescript/-/typescript-2.5.0.tgz#5ae121db92120fecb6badb34aa361ac464bc23d3" - integrity sha512-eCCebNyhV5NcNyfrNOdur1b4zPSyj2o89yaSliEMSShf4WolfFOv4aYpL4tFXjhkw3n2pR7MYFDUnrzmDpfmNw== +"@graphql-codegen/typescript@^2.4.2", "@graphql-codegen/typescript@^2.6.0": + version "2.6.0" + resolved "https://registry.npmjs.org/@graphql-codegen/typescript/-/typescript-2.6.0.tgz#75e7a54a25b29906ca4e462d1be6bf830f21b328" + integrity sha512-f36ilg8J+wui0OhmQglIZ+2z4Ybc08Y7r7BlBDqfJ1F5X0zau0SlC7Hp2iCoCA0ucqZYtiUU/0n+/R8m1cTrQQ== dependencies: "@graphql-codegen/plugin-helpers" "^2.4.0" "@graphql-codegen/schema-ast" "^2.4.1" - "@graphql-codegen/visitor-plugin-common" "2.9.0" + "@graphql-codegen/visitor-plugin-common" "2.10.0" auto-bind "~4.0.0" tslib "~2.4.0" -"@graphql-codegen/visitor-plugin-common@2.9.0": - version "2.9.0" - resolved "https://registry.npmjs.org/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-2.9.0.tgz#a13556c805e72b63ee9d80fb437b9ba2eb0a9fa2" - integrity sha512-w353lPpXlgsQT6dxfcHw3hQdodGnfSwsxofHVfROqrIBZIjH0kNiFHOt8rnewYkLGEa75bWDVaM1ofyXEaN+3w== +"@graphql-codegen/visitor-plugin-common@2.10.0": + version "2.10.0" + resolved "https://registry.npmjs.org/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-2.10.0.tgz#d886d8281dfc6e4b9729a5468ffe18ebaefc883f" + integrity sha512-nWoxHKUdwOJCWV96Ks1x4EwYCWsZDJXB+2j6EQz5j27DzdxmQInZ86degaDCd3EgbwhMQEMtiZiPGFFDrgBkHA== dependencies: "@graphql-codegen/plugin-helpers" "^2.4.0" "@graphql-tools/optimize" "^1.0.1" - "@graphql-tools/relay-operation-optimizer" "^6.3.7" + "@graphql-tools/relay-operation-optimizer" "^6.4.14" "@graphql-tools/utils" "^8.3.0" auto-bind "~4.0.0" change-case-all "1.0.14" @@ -2199,15 +2492,15 @@ parse-filepath "^1.0.2" tslib "~2.4.0" -"@graphql-tools/apollo-engine-loader@^7.0.5": - version "7.2.11" - resolved "https://registry.npmjs.org/@graphql-tools/apollo-engine-loader/-/apollo-engine-loader-7.2.11.tgz#c247eef8986ce259de6dd2da39daeaba7960ac33" - integrity sha512-0NmAlTd/lQl35OaP18dhxlcdu4w4K+auPfbkiaDfArzdhn6Duhq+ATqMvj6Fx5C23zlcvQ0AJnT5a5Yb55K/5w== +"@graphql-tools/apollo-engine-loader@^7.3.1": + version "7.3.1" + resolved "https://registry.npmjs.org/@graphql-tools/apollo-engine-loader/-/apollo-engine-loader-7.3.1.tgz#535cb259fa6e0dbf1cf960e7212d58b8294bb370" + integrity sha512-PJhX4gQeoPtR2BJFYHYVLdLYkqQHB94r9IC64GamFV+kxR+jzQYZJdDTgnFZxvpvGJ7rEgYKNjcfWS+r+CQisQ== dependencies: - "@graphql-tools/utils" "8.6.9" - cross-undici-fetch "^0.3.0" - sync-fetch "0.3.1" - tslib "~2.3.0" + "@graphql-tools/utils" "8.8.0" + cross-undici-fetch "^0.4.11" + sync-fetch "0.4.1" + tslib "^2.4.0" "@graphql-tools/batch-execute@8.4.6": version "8.4.6" @@ -2219,6 +2512,16 @@ tslib "~2.3.0" value-or-promise "1.0.11" +"@graphql-tools/batch-execute@8.5.0": + version "8.5.0" + resolved "https://registry.npmjs.org/@graphql-tools/batch-execute/-/batch-execute-8.5.0.tgz#2767a9abf4e2712871a69360a27ef13ada1c019e" + integrity sha512-S9/76X4uYIbVlJyRzXhCBbTJvVD0VvaWNqGiKgkITxlq4aBsTOHVuE84OSi3E1QKP3PTiJYrgMIn220iFOkyQw== + dependencies: + "@graphql-tools/utils" "8.8.0" + dataloader "2.1.0" + tslib "^2.4.0" + value-or-promise "1.0.11" + "@graphql-tools/code-file-loader@^7.0.6": version "7.2.14" resolved "https://registry.npmjs.org/@graphql-tools/code-file-loader/-/code-file-loader-7.2.14.tgz#b43ce0c682040b3969f1f785b18fc33c79341084" @@ -2243,6 +2546,18 @@ tslib "~2.3.0" value-or-promise "1.0.11" +"@graphql-tools/delegate@8.8.0": + version "8.8.0" + resolved "https://registry.npmjs.org/@graphql-tools/delegate/-/delegate-8.8.0.tgz#acd3e48e4ca82aace92cc3d920b5c727c35eaf7b" + integrity sha512-dbhfOI8rQXPcowXrbwHLOBY9oGi7qxtlrXF4RuRXmjqGTs2AgogdOE3Ep1+6wFD7qYTuFmHXZ8Cl0PmhoZUgrg== + dependencies: + "@graphql-tools/batch-execute" "8.5.0" + "@graphql-tools/schema" "8.5.0" + "@graphql-tools/utils" "8.8.0" + dataloader "2.1.0" + tslib "~2.4.0" + value-or-promise "1.0.11" + "@graphql-tools/git-loader@^7.0.5": version "7.1.13" resolved "https://registry.npmjs.org/@graphql-tools/git-loader/-/git-loader-7.1.13.tgz#95f4715f4caf290dde975813bc87e0a96a81095d" @@ -2325,6 +2640,14 @@ "@graphql-tools/utils" "8.6.9" tslib "~2.3.0" +"@graphql-tools/merge@8.3.0": + version "8.3.0" + resolved "https://registry.npmjs.org/@graphql-tools/merge/-/merge-8.3.0.tgz#d3a8ba10942f8598788c3e03f97cc1d0c0b055f8" + integrity sha512-xRa7RAQok/0DD2YnjuqikMrr7dUAxTpdGtZ7BkvUUGhYs3B3p7reCAfvOVr1DJAqVToP7hdlMk+S5+Ylk+AaqA== + dependencies: + "@graphql-tools/utils" "8.8.0" + tslib "^2.4.0" + "@graphql-tools/mock@^8.1.2": version "8.6.8" resolved "https://registry.npmjs.org/@graphql-tools/mock/-/mock-8.6.8.tgz#232a23c0c14dcfca88012886230b93e6fc2303e2" @@ -2342,13 +2665,13 @@ dependencies: tslib "~2.3.0" -"@graphql-tools/prisma-loader@^7.0.6": - version "7.1.13" - resolved "https://registry.npmjs.org/@graphql-tools/prisma-loader/-/prisma-loader-7.1.13.tgz#3b46e9d9414e71cfeb1a8284c945329eca77a190" - integrity sha512-rctgCI11ZjPJd4ncNTV7mmjV2WN2LRL3aTuTJWHjudO+iJPgoWyor0idl+aP0fOX2GnDK7zASmWwVShuGBJb9g== +"@graphql-tools/prisma-loader@^7.2.2": + version "7.2.2" + resolved "https://registry.npmjs.org/@graphql-tools/prisma-loader/-/prisma-loader-7.2.2.tgz#ee56371f75a4e82330b0e4915f57976bf0f4a16a" + integrity sha512-f5txUBRwwZmPQYL5g5CNdOjOglFE/abtnEVOvUCq+nET0BRuxcuxUD5vykfZnkql9sNvnCFAfrZuBVe5S2n3bA== dependencies: - "@graphql-tools/url-loader" "7.9.14" - "@graphql-tools/utils" "8.6.9" + "@graphql-tools/url-loader" "7.12.1" + "@graphql-tools/utils" "8.8.0" "@types/js-yaml" "^4.0.0" "@types/json-stable-stringify" "^1.0.32" "@types/jsonwebtoken" "^8.5.0" @@ -2365,19 +2688,19 @@ lodash "^4.17.20" replaceall "^0.1.6" scuid "^1.1.0" - tslib "~2.3.0" + tslib "^2.4.0" yaml-ast-parser "^0.0.43" -"@graphql-tools/relay-operation-optimizer@^6.3.7": - version "6.4.9" - resolved "https://registry.npmjs.org/@graphql-tools/relay-operation-optimizer/-/relay-operation-optimizer-6.4.9.tgz#f3e1960ac8e6429a09156836701a03ebf523f0e1" - integrity sha512-fHMR1bNyx+ryBnmtXWnYmxvQLEx0O3yIG0MTVB1Mp6GlsyKTGI3O9njvjv0EI2JmCszs1uakT/6BW0LO37E6tQ== +"@graphql-tools/relay-operation-optimizer@^6.4.14": + version "6.4.14" + resolved "https://registry.npmjs.org/@graphql-tools/relay-operation-optimizer/-/relay-operation-optimizer-6.4.14.tgz#812f32123a1351615a72b4e832852daac7bd64b3" + integrity sha512-vqch2M/sIUfMmlRJ4eCupiHlVPXWOPVpHX9yCZwRrpNg0Eaokyc57NSjJuKVV3KcvcJKf03qfMK2PxFbfDvN9A== dependencies: - "@graphql-tools/utils" "8.6.9" - relay-compiler "12.0.0" - tslib "~2.3.0" + "@ardatan/relay-compiler" "12.0.0" + "@graphql-tools/utils" "8.6.13" + tslib "^2.4.0" -"@graphql-tools/schema@8.3.10", "@graphql-tools/schema@^8.0.0", "@graphql-tools/schema@^8.1.1", "@graphql-tools/schema@^8.1.2", "@graphql-tools/schema@^8.3.1": +"@graphql-tools/schema@8.3.10", "@graphql-tools/schema@^8.0.0", "@graphql-tools/schema@^8.1.2", "@graphql-tools/schema@^8.3.1": version "8.3.10" resolved "https://registry.npmjs.org/@graphql-tools/schema/-/schema-8.3.10.tgz#c3e373e6ad854f533fc7e55859dd8f9e81de30dd" integrity sha512-tfhjSTi3OzheDrVzG7rkPZg2BbQjmZRLM2vvQoM2b1TnUwgUIbpAgcnf+AWDLRsoCOWlezeLgij1BLeAR0Q0jg== @@ -2387,7 +2710,38 @@ tslib "~2.3.0" value-or-promise "1.0.11" -"@graphql-tools/url-loader@7.9.14", "@graphql-tools/url-loader@^7.0.11", "@graphql-tools/url-loader@^7.4.2": +"@graphql-tools/schema@8.5.0": + version "8.5.0" + resolved "https://registry.npmjs.org/@graphql-tools/schema/-/schema-8.5.0.tgz#0332b3a2e674d16e9bf8a58dfd47432449ce2368" + integrity sha512-VeFtKjM3SA9/hCJJfr95aEdC3G0xIKM9z0Qdz4i+eC1g2fdZYnfWFt2ucW4IME+2TDd0enHlKzaV0qk2SLVUww== + dependencies: + "@graphql-tools/merge" "8.3.0" + "@graphql-tools/utils" "8.8.0" + tslib "^2.4.0" + value-or-promise "1.0.11" + +"@graphql-tools/url-loader@7.12.1", "@graphql-tools/url-loader@^7.12.1": + version "7.12.1" + resolved "https://registry.npmjs.org/@graphql-tools/url-loader/-/url-loader-7.12.1.tgz#931a65da4faced1a71ddc5af638b87140ff3dfb6" + integrity sha512-Fd3ZZLEEr9GGFHEbdrcaMHFQu01BLpFnNDBkISupvjokd497O5Uh0xZvsZGC6mxVt0WWQWpgaK2ef+oLuOdLqQ== + dependencies: + "@graphql-tools/delegate" "8.8.0" + "@graphql-tools/utils" "8.8.0" + "@graphql-tools/wrap" "8.5.0" + "@n1ru4l/graphql-live-query" "^0.9.0" + "@types/ws" "^8.0.0" + cross-undici-fetch "^0.4.11" + dset "^3.1.2" + extract-files "^11.0.0" + graphql-ws "^5.4.1" + isomorphic-ws "^5.0.0" + meros "^1.1.4" + sync-fetch "^0.4.0" + tslib "^2.4.0" + value-or-promise "^1.0.11" + ws "^8.3.0" + +"@graphql-tools/url-loader@^7.4.2": version "7.9.14" resolved "https://registry.npmjs.org/@graphql-tools/url-loader/-/url-loader-7.9.14.tgz#9f76af9a6c55a0cf2e87ccf9b3be15eeb6af188c" integrity sha512-7IXiqUYp0cHeM+qvgjM4jAq8uJhl3PDdQYkyIj5wzZ7XjrkdV3JjPt0cHj2IBIeEwQJOjEKNeFYXjOlg73guCQ== @@ -2409,12 +2763,12 @@ value-or-promise "^1.0.11" ws "^8.3.0" -"@graphql-tools/utils@8.6.12": - version "8.6.12" - resolved "https://registry.npmjs.org/@graphql-tools/utils/-/utils-8.6.12.tgz#0a550dc0331fd9b097fe7223d65cbbee720556e4" - integrity sha512-WQ91O40RC+UJgZ9K+IzevSf8oolR1QE+WQ21Oyc2fgDYYiqT0eSf+HVyhZr/8x9rVjn3N9HeqCsywbdmbljg0w== +"@graphql-tools/utils@8.6.13": + version "8.6.13" + resolved "https://registry.npmjs.org/@graphql-tools/utils/-/utils-8.6.13.tgz#2b4fb7f9f8a29b25eecd44551fb95974de32f969" + integrity sha512-FiVqrQzj4cgz0HcZ3CxUs8NtBGPZFpmsVyIgwmL6YCwIhjJQnT72h8G3/vk5zVfjfesht85YGp0inWWuoCKWzg== dependencies: - tslib "~2.4.0" + tslib "^2.4.0" "@graphql-tools/utils@8.6.9", "@graphql-tools/utils@^8.1.1", "@graphql-tools/utils@^8.3.0", "@graphql-tools/utils@^8.5.1", "@graphql-tools/utils@^8.5.2", "@graphql-tools/utils@^8.6.0": version "8.6.9" @@ -2423,6 +2777,13 @@ dependencies: tslib "~2.3.0" +"@graphql-tools/utils@8.8.0": + version "8.8.0" + resolved "https://registry.npmjs.org/@graphql-tools/utils/-/utils-8.8.0.tgz#8332ff80a1da9204ccf514750dd6f5c5cccf17dc" + integrity sha512-KJrtx05uSM/cPYFdTnGAS1doL5bftJLAiFCDMZ8Vkifztz3BFn3gpFiy/o4wDtM8s39G46mxmt2Km/RmeltfGw== + dependencies: + tslib "^2.4.0" + "@graphql-tools/wrap@8.4.16", "@graphql-tools/wrap@^8.3.1": version "8.4.16" resolved "https://registry.npmjs.org/@graphql-tools/wrap/-/wrap-8.4.16.tgz#87dce9ec623a921e5a62f44e75abc9655892724b" @@ -2434,6 +2795,17 @@ tslib "~2.3.0" value-or-promise "1.0.11" +"@graphql-tools/wrap@8.5.0": + version "8.5.0" + resolved "https://registry.npmjs.org/@graphql-tools/wrap/-/wrap-8.5.0.tgz#ce1b0d775e1fc3a17404df566f4d2196d31c6e20" + integrity sha512-I+x9dBNzC135WWPi04ejqurR/zDmhfeGbCftCaYKF4CvgWd+ZaJx4Uc74n1SBegQtrj+KDrOS4HgKwf9vAVR7A== + dependencies: + "@graphql-tools/delegate" "8.8.0" + "@graphql-tools/schema" "8.5.0" + "@graphql-tools/utils" "8.8.0" + tslib "^2.4.0" + value-or-promise "1.0.11" + "@graphql-typed-document-node/core@^3.1.0", "@graphql-typed-document-node/core@^3.1.1": version "3.1.1" resolved "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.1.1.tgz#076d78ce99822258cf813ecc1e7fa460fa74d052" @@ -2550,6 +2922,20 @@ resolved "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz#b32366c89b43c6f8cefbdefac778b9c828e3ba8c" integrity sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg== +"@improbable-eng/grpc-web@^0.14.0": + version "0.14.1" + resolved "https://registry.npmjs.org/@improbable-eng/grpc-web/-/grpc-web-0.14.1.tgz#f4662f64dc89c0f956a94bb8a3b576556c74589c" + integrity sha512-XaIYuunepPxoiGVLLHmlnVminUGzBTnXr8Wv7khzmLWbNw4TCwJKX09GSMJlKhu/TRk6gms0ySFxewaETSBqgw== + dependencies: + browser-headers "^0.4.1" + +"@improbable-eng/grpc-web@^0.15.0": + version "0.15.0" + resolved "https://registry.npmjs.org/@improbable-eng/grpc-web/-/grpc-web-0.15.0.tgz#3e47e9fdd90381a74abd4b7d26e67422a2a04bef" + integrity sha512-ERft9/0/8CmYalqOVnJnpdDry28q+j+nAlFFARdjyxXDJ+Mhgv9+F600QC8BR9ygOfrXRlAk6CvST2j+JCpQPg== + dependencies: + browser-headers "^0.4.1" + "@ioredis/commands@^1.1.1": version "1.1.1" resolved "https://registry.npmjs.org/@ioredis/commands/-/commands-1.1.1.tgz#2ba4299ea624a6bfac15b35f6df90b0015691ec3" @@ -3092,14 +3478,14 @@ integrity sha512-CtzORUwWTTOTqfVtHaKRJ0I1kNQd1bpn3sUh8I3nJDVY+5/M/Oe1DnEWzPQvqq/xPIIkzzzIP7mfCoAjFRvDhg== "@jridgewell/resolve-uri@^3.0.3": - version "3.0.7" - resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz#30cd49820a962aff48c8fffc5cd760151fca61fe" - integrity sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA== + version "3.0.8" + resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.8.tgz#687cc2bbf243f4e9a868ecf2262318e2658873a1" + integrity sha512-YK5G9LaddzGbcucK4c8h5tWFmMPBvRZ/uyWmN1/SbBdIvqGUdWGkJ5BAaccgs6XbzVLsqbPJrBSFwKv3kT9i7w== "@jridgewell/sourcemap-codec@^1.4.10": - version "1.4.13" - resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz#b6461fb0c2964356c469e115f504c95ad97ab88c" - integrity sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w== + version "1.4.14" + resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== "@jridgewell/trace-mapping@0.3.9": version "0.3.9" @@ -3136,11 +3522,11 @@ integrity sha512-zMM9Ds+SawiUkakS7y94Ymqx+S0ORzpG3frZirN3l+UlXUmSUR7hF4wxCVqW+ei94JzV5kt0uXBcoOEAuiydrw== "@keyv/redis@^2.2.3": - version "2.3.6" - resolved "https://registry.npmjs.org/@keyv/redis/-/redis-2.3.6.tgz#462991af60b5b35af4e9ac8d05ad99a08ae2cfc2" - integrity sha512-MKRAeWaKI7zpGb+lSgAAlznQi725NEN18I/Uj2CJysk1o6hBqyXyxCvyI+b9qKwoFAkzxoogdvONIpstzI7t/Q== + version "2.3.7" + resolved "https://registry.npmjs.org/@keyv/redis/-/redis-2.3.7.tgz#4f6f6d85be07668a976bb3c9d910c57d1ab12c70" + integrity sha512-aBxnl2Bt1D7JUXQwdO9dDOBJi3VmKO5yfIiwxvEr/hVSryho0Zn1EuWr3fi6UE8WYw5X8FPUyD6h5wuVQreQsA== dependencies: - ioredis "^5.0.4" + ioredis "^5.1.0" "@kubernetes/client-node@^0.16.0": version "0.16.3" @@ -3857,24 +4243,24 @@ npmlog "^4.1.2" write-file-atomic "^3.0.3" -"@lezer/common@^0.16.0": - version "0.16.0" - resolved "https://registry.npmjs.org/@lezer/common/-/common-0.16.0.tgz#b6023a0a682b0b7676d0e7f0e0838f71bde39fcd" - integrity sha512-H6sPCku+asKWYaNjwfQ1Uvcay9UP1Pdzu4qpy8GtRZ0cKT2AAGnj9MQGiRtY18MDntvhYRJxNGv7FNWOSV/e8A== +"@lezer/common@^1.0.0": + version "1.0.0" + resolved "https://registry.npmjs.org/@lezer/common/-/common-1.0.0.tgz#1c95ae53ec17706aa3cbcc88b52c23f22ed56096" + integrity sha512-ohydQe+Hb+w4oMDvXzs8uuJd2NoA3D8YDcLiuDsLqH+yflDTPEpgCsWI3/6rH5C3BAedtH1/R51dxENldQceEA== -"@lezer/highlight@^0.16.0": - version "0.16.0" - resolved "https://registry.npmjs.org/@lezer/highlight/-/highlight-0.16.0.tgz#95f7b7ee3c32c8a0f6ce499c085e8b1f927ffbdc" - integrity sha512-iE5f4flHlJ1g1clOStvXNLbORJoiW4Kytso6ubfYzHnaNo/eo5SKhxs4wv/rtvwZQeZrK3we8S9SyA7OGOoRKQ== +"@lezer/highlight@^1.0.0": + version "1.0.0" + resolved "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.0.0.tgz#1dc82300f5d39fbd67ae1194b5519b4c381878d3" + integrity sha512-nsCnNtim90UKsB5YxoX65v3GEIw3iCHw9RM2DtdgkiqAbKh9pCdvi8AWNwkYf10Lu6fxNhXPpkpHbW6mihhvJA== dependencies: - "@lezer/common" "^0.16.0" + "@lezer/common" "^1.0.0" -"@lezer/lr@^0.16.0": - version "0.16.1" - resolved "https://registry.npmjs.org/@lezer/lr/-/lr-0.16.1.tgz#abe8c538d3f1a811ce5731847e3d0470c7709dcd" - integrity sha512-RuRD84dWY9If8BanfaaWNe0YhRdYWtni92GpB4C4/7JgHyAIfdkJz7miBjgILm3gOsBjJsJh56vb1ckxSQEWBg== +"@lezer/lr@^1.0.0": + version "1.0.0" + resolved "https://registry.npmjs.org/@lezer/lr/-/lr-1.0.0.tgz#89e30c1e710b8715ac5c847ad063418c51d6e750" + integrity sha512-k6DEqBh4HxqO/cVGedb6Ern6LS7K6IOzfydJ5WaqCR26v6UR9sIFyb6PS+5rPUs/mXgnBR/QQCW7RkyjSCMoQA== dependencies: - "@lezer/common" "^0.16.0" + "@lezer/common" "^1.0.0" "@manypkg/find-root@^1.1.0": version "1.1.0" @@ -4052,9 +4438,9 @@ react-is "^16.8.0 || ^17.0.0" "@maxim_mazurok/gapi.client.calendar@^3.0.20220408": - version "3.0.20220603" - resolved "https://registry.npmjs.org/@maxim_mazurok/gapi.client.calendar/-/gapi.client.calendar-3.0.20220603.tgz#0a6378497d1460058d847afd3c1f0aa83878c83d" - integrity sha512-sLB2ZCevNiGBHWCAg8NVT2+61IwLn9JxEvLgDcLno1GTwPVye3MC8H5bTYeFpL0Pgv58NPc2FIkG0w53Ojp7uw== + version "3.0.20220624" + resolved "https://registry.npmjs.org/@maxim_mazurok/gapi.client.calendar/-/gapi.client.calendar-3.0.20220624.tgz#17817142e348ce811415dfb111299fbdac2450a0" + integrity sha512-5+x4A6l8GY+dojvXUBQGc0Y4JOm9lBY1YZfCAEEZPjBcXkx0vs/CenPnmAu/fwQgGSrQLipxFV+pS6RL3L28mg== dependencies: "@types/gapi.client" "*" @@ -4099,9 +4485,9 @@ typescript "~4.6.3" "@microsoft/microsoft-graph-types@^2.6.0": - version "2.20.0" - resolved "https://registry.npmjs.org/@microsoft/microsoft-graph-types/-/microsoft-graph-types-2.20.0.tgz#fc532a5dc146c0b8a6f78a633fe930535f8cdc42" - integrity sha512-T1EPoYdH4124Rg+h261dvW2qAeSRAotHM/6lv10fDsYX4DWsppvresmfhGbPrLApK/lRTRj93bn4/Nwwmdv4Zg== + version "2.22.0" + resolved "https://registry.npmjs.org/@microsoft/microsoft-graph-types/-/microsoft-graph-types-2.22.0.tgz#7ceb222311770ed5b240d627b657d25b3979964e" + integrity sha512-iKc5L036hc/wu13DX5kGf//3/WqTAErAPTyYKG6zT3vG070xXaaP7PInODznfyZduhiOvavmrRlQb34ajeDTUA== "@microsoft/tsdoc-config@~0.16.1": version "0.16.1" @@ -4661,6 +5047,11 @@ resolved "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-11.2.0.tgz#b38d7fc3736d52a1e96b230c1ccd4a58a2f400a6" integrity sha512-PBsVO+15KSlGmiI8QAzaqvsNlZlrDlyAJYcrXBCvVUxCp7VnXjkwPoFHgjEJXx3WF9BAwkA6nfCUA7i9sODzKA== +"@octokit/openapi-types@^12.4.0": + version "12.4.0" + resolved "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.4.0.tgz#fd8bf5db72bd566c5ba2cb76754512a9ebe66e71" + integrity sha512-Npcb7Pv30b33U04jvcD7l75yLU0mxhuX2Xqrn51YyZ5WTkF04bpbxLaZ6GcaTqu03WZQHoO/Gbfp95NGRueDUA== + "@octokit/openapi-types@^7.3.2": version "7.3.2" resolved "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-7.3.2.tgz#065ce49b338043ec7f741316ce06afd4d459d944" @@ -4678,6 +5069,13 @@ dependencies: "@octokit/types" "^6.34.0" +"@octokit/plugin-paginate-rest@^2.18.0": + version "2.19.0" + resolved "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.19.0.tgz#b52eae6ecacfa1f5583dc2cc0985cfbed3ca78b0" + integrity sha512-hQ4Qysg2hNmEMuZeJkvyzM4eSZiTifOKqYAMsW8FnxFKowhuwWICSgBQ9Gn9GpUmgKB7qaf1hFvMjYaTAg5jQA== + dependencies: + "@octokit/types" "^6.36.0" + "@octokit/plugin-paginate-rest@^2.6.2": version "2.7.0" resolved "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.7.0.tgz#6bb7b043c246e0654119a6ec4e72a172c9e2c7f3" @@ -4711,6 +5109,14 @@ "@octokit/types" "^6.34.0" deprecation "^2.3.1" +"@octokit/plugin-rest-endpoint-methods@^5.14.0": + version "5.15.0" + resolved "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.15.0.tgz#6c8251b55c33315a6e53e5b55654f72023ed5049" + integrity sha512-Gsw9+Xm56jVhfbJoy4pt6eOOyf8/3K6CAnx1Sl7U2GhZWcg8MR6YgXWnpfdF69S2ViMXLA7nfvTDAsZpFlkLRw== + dependencies: + "@octokit/types" "^6.36.0" + deprecation "^2.3.1" + "@octokit/plugin-retry@^3.0.9": version "3.0.9" resolved "https://registry.npmjs.org/@octokit/plugin-retry/-/plugin-retry-3.0.9.tgz#ae625cca1e42b0253049102acd71c1d5134788fe" @@ -4782,31 +5188,38 @@ dependencies: "@octokit/openapi-types" "^7.3.2" -"@octokit/types@^6.26.0", "@octokit/types@^6.27.1", "@octokit/types@^6.34.0": +"@octokit/types@^6.27.1", "@octokit/types@^6.34.0": version "6.34.0" resolved "https://registry.npmjs.org/@octokit/types/-/types-6.34.0.tgz#c6021333334d1ecfb5d370a8798162ddf1ae8218" integrity sha512-s1zLBjWhdEI2zwaoSgyOFoKSl109CUcVBCc7biPJ3aAf6LGLU6szDvi31JPU7bxfla2lqfhjbbg/5DdFNxOwHw== dependencies: "@octokit/openapi-types" "^11.2.0" +"@octokit/types@^6.35.0", "@octokit/types@^6.36.0": + version "6.37.0" + resolved "https://registry.npmjs.org/@octokit/types/-/types-6.37.0.tgz#32eb78edb34cf5cea4ba5753ab8db75b776d617a" + integrity sha512-BXWQhFKRkjX4dVW5L2oYa0hzWOAqsEsujXsQLSdepPoDZfYdubrD1KDGpyNldGXtR8QM/WezDcxcIN1UKJMGPA== + dependencies: + "@octokit/openapi-types" "^12.4.0" + "@octokit/webhooks-methods@^2.0.0": version "2.0.0" resolved "https://registry.npmjs.org/@octokit/webhooks-methods/-/webhooks-methods-2.0.0.tgz#1108b9ea661ca6c81e4a8bfa63a09eb27d5bc2db" integrity sha512-35cfQ4YWlnZnmZKmIxlGPUPLtbkF8lr/A/1Sk1eC0ddLMwQN06dOuLc+dI3YLQS+T+MoNt3DIQ0NynwgKPilig== -"@octokit/webhooks-types@5.7.1": - version "5.7.1" - resolved "https://registry.npmjs.org/@octokit/webhooks-types/-/webhooks-types-5.7.1.tgz#26452dcd72fa77ac85bb188fda2a5980eb292932" - integrity sha512-zabCzfWvvquxDzj1lU7GhJQteACGfGXnHfROJD4A7LKhRjlkaggoSkE5cWQJJ6nW2t/UI51dSFrEA+A4mhqfPw== +"@octokit/webhooks-types@5.8.0": + version "5.8.0" + resolved "https://registry.npmjs.org/@octokit/webhooks-types/-/webhooks-types-5.8.0.tgz#b76d1a3e3ad82cec5680d3c6c3443a620047a6ef" + integrity sha512-8adktjIb76A7viIdayQSFuBEwOzwhDC+9yxZpKNHjfzrlostHCw0/N7JWpWMObfElwvJMk2fY2l1noENCk9wmw== "@octokit/webhooks@^9.0.1", "@octokit/webhooks@^9.14.1": - version "9.25.0" - resolved "https://registry.npmjs.org/@octokit/webhooks/-/webhooks-9.25.0.tgz#f1bd7815af59fb37892b87c86d2cb8625a570e9a" - integrity sha512-pyCraAmxHSnfTMe4K+QnNH/nSCJolCc++J2SAfYBwPFm6gg2WTGxWuegzuHul+Xm71+V9qL2NhIXX48U7MvTIA== + version "9.26.0" + resolved "https://registry.npmjs.org/@octokit/webhooks/-/webhooks-9.26.0.tgz#cf453bb313da3b66f1a90c84464d978e1c625cce" + integrity sha512-foZlsgrTDwAmD5j2Czn6ji10lbWjGDVsUxTIydjG9KTkAWKJrFapXJgO5SbGxRwfPd3OJdhK3nA2YPqVhxLXqA== dependencies: "@octokit/request-error" "^2.0.2" "@octokit/webhooks-methods" "^2.0.0" - "@octokit/webhooks-types" "5.7.1" + "@octokit/webhooks-types" "5.8.0" aggregate-error "^3.1.0" "@open-draft/until@^1.0.3": @@ -4843,6 +5256,16 @@ rxjs "7.5.5" tslib "2.0.3" +"@opensearch-project/opensearch@^1.1.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@opensearch-project/opensearch/-/opensearch-1.1.0.tgz#8b3c8b4cbcea01755ba092d2997bf0b4ca7f22f7" + integrity sha512-1TDw92JL8rD1b2QGluqBsIBLIiD5SGciIpz4qkrGAe9tcdfQ1ptub5e677rhWl35UULSjr6hP8M6HmISZ/M5HQ== + dependencies: + debug "^4.3.1" + hpagent "^0.1.1" + ms "^2.1.3" + secure-json-parse "^2.4.0" + "@opentelemetry/api@^1.0.1": version "1.0.4" resolved "https://registry.npmjs.org/@opentelemetry/api/-/api-1.0.4.tgz#a167e46c10d05a07ab299fc518793b0cff8f6924" @@ -4919,9 +5342,9 @@ "@react-hookz/deep-equal" "^1.0.1" "@react-hookz/web@^14.0.0": - version "14.2.2" - resolved "https://registry.npmjs.org/@react-hookz/web/-/web-14.2.2.tgz#eee0085f954e5b62d0a6c5b20d8786c28abfb9ad" - integrity sha512-6FeZHKV3FFOYnbSJMkkqXDoMuIX0HEFJlDF4LpHR7RsA3zrH2xzhtF8nSYZ+pG6fDIqYKID9yQuILFmbAWaqCQ== + version "14.7.1" + resolved "https://registry.npmjs.org/@react-hookz/web/-/web-14.7.1.tgz#5e39e6fc21331cc4ae95f36e8135ad763e6c29fb" + integrity sha512-kU1CccZDXvQ9G4vcCCpX3mDQqYKkuLXGFOtPMgmbZ9KrvkEduMRH4JqSVXp1nI/bGI1GJ0KAWm4UEb1x5eDGAg== dependencies: "@react-hookz/deep-equal" "^1.0.2" @@ -4994,9 +5417,9 @@ zustand "3.6.9" "@roadiehq/backstage-plugin-github-pull-requests@^2.0.0": - version "2.1.3" - resolved "https://registry.npmjs.org/@roadiehq/backstage-plugin-github-pull-requests/-/backstage-plugin-github-pull-requests-2.1.3.tgz#d37869c2ff5a51794d3d166e80260937e1d51e11" - integrity sha512-2/HVfFFbmSwRTweTYVh5TYEa7Rl2+TPI2nVPps9yse6DBYPpo26XBvhnRT8O8OdJIJ0D4IQe1mZxpeFiDPZQpA== + version "2.2.0" + resolved "https://registry.npmjs.org/@roadiehq/backstage-plugin-github-pull-requests/-/backstage-plugin-github-pull-requests-2.2.0.tgz#6c62c965842819bae185f96e1fbd1c26cf64c564" + integrity sha512-UNpfVMEx3WmUqIpIWPvf8uEZzCClff5H2krT/8iS3yaEP1ng9ZfLQPV7JgF8Bvaad37M08mCuvdmurtL6L3xSw== dependencies: "@backstage/catalog-model" "^1.0.0" "@backstage/core-components" "^0.9.0" @@ -5039,9 +5462,9 @@ react-use "^17.2.4" "@rollup/plugin-commonjs@^22.0.0": - version "22.0.0" - resolved "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-22.0.0.tgz#f4d87016e2fbf187a593ab9f46626fe05b59e8bd" - integrity sha512-Ktvf2j+bAO+30awhbYoCaXpBcyPmJbaEUYClQns/+6SNCYFURbvBiNbWgHITEsIgDDWCDUclWRKEuf8cwZCFoQ== + version "22.0.1" + resolved "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-22.0.1.tgz#f7cb777d20de3eeeaf994f39080115c336bef810" + integrity sha512-dGfEZvdjDHObBiP5IvwTKMVeq/tBZGMBHZFMdIV1ClMM/YoWS34xrHFGfag9SN2ZtMgNZRFruqvxZQEa70O6nQ== dependencies: "@rollup/pluginutils" "^3.1.0" commondir "^1.0.1" @@ -5058,7 +5481,7 @@ dependencies: "@rollup/pluginutils" "^3.0.8" -"@rollup/plugin-node-resolve@^13.0.0": +"@rollup/plugin-node-resolve@^13.0.6": version "13.3.0" resolved "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.3.0.tgz#da1c5c5ce8316cef96a2f823d111c1e4e498801c" integrity sha512-Lus8rbUo1eEcnS4yTFKLZrVumLPY+YayBdWXgFSHYhTT2iJbMhoaaBL3xl5NCdeRytErGr8tZ0L71BMRmnlwSw== @@ -5136,6 +5559,15 @@ dependencies: any-observable "^0.3.0" +"@short.io/opensearch-mock@^0.3.1": + version "0.3.1" + resolved "https://registry.npmjs.org/@short.io/opensearch-mock/-/opensearch-mock-0.3.1.tgz#41678404b94342ac60263a8df590f9b1efa80622" + integrity sha512-gwLTzxJrZNGVQNn+FHLhpw7at3jHb6tNczq2hvFPJ3C3nLaCBRkbP2IQHrIDzklLBVFV83Ug0Xgs73A5o9eLtg== + dependencies: + fast-deep-equal "^3.1.3" + find-my-way "^4.3.3" + into-stream "^6.0.0" + "@sideway/address@^4.1.0": version "4.1.1" resolved "https://registry.npmjs.org/@sideway/address/-/address-4.1.1.tgz#9e321e74310963fdf8eebfbee09c7bd69972de4d" @@ -5387,7 +5819,7 @@ lz-string "^1.4.4" pretty-format "^27.0.2" -"@testing-library/jest-dom@^5.10.1": +"@testing-library/jest-dom@^5.10.1", "@testing-library/jest-dom@^5.16.4": version "5.16.4" resolved "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.16.4.tgz#938302d7b8b483963a3ae821f1c0808f872245cd" integrity sha512-Gy+IoFutbMQcky0k+bqqumXZ1cTGswLsFqmNLzNdSKkU9KGV2u9oXhukCbbJ9/LRPKiqwxEE8VpV/+YZlfkPUA== @@ -5403,9 +5835,9 @@ redent "^3.0.0" "@testing-library/react-hooks@^8.0.0": - version "8.0.0" - resolved "https://registry.npmjs.org/@testing-library/react-hooks/-/react-hooks-8.0.0.tgz#7d0164bffce4647f506039de0a97f6fcbd20f4bf" - integrity sha512-uZqcgtcUUtw7Z9N32W13qQhVAD+Xki2hxbTR461MKax8T6Jr8nsUvZB+vcBTkzY2nFvsUet434CsgF0ncW2yFw== + version "8.0.1" + resolved "https://registry.npmjs.org/@testing-library/react-hooks/-/react-hooks-8.0.1.tgz#0924bbd5b55e0c0c0502d1754657ada66947ca12" + integrity sha512-Aqhl2IVmLt8IovEVarNDFuJDVWVvhnr9/GCU6UUnrYXwgDFF9h2L2o2P9KBni1AST5sT6riAyoukFLyjQUgD/g== dependencies: "@babel/runtime" "^7.12.5" react-error-boundary "^3.1.0" @@ -5420,9 +5852,9 @@ "@types/react-dom" "<18.0.0" "@testing-library/user-event@^14.0.0": - version "14.2.0" - resolved "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.2.0.tgz#8293560f8f80a00383d6c755ec3e0b918acb1683" - integrity sha512-+hIlG4nJS6ivZrKnOP7OGsDu9Fxmryj9vCl8x0ZINtTJcCHs2zLsYif5GzuRiBF2ck5GZG2aQr7Msg+EHlnYVQ== + version "14.2.1" + resolved "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.2.1.tgz#8c5ff2d004544bb2220e1d864f7267fe7eb6c556" + integrity sha512-HOr1QiODrq+0j9lKU5i10y9TbhxMBMRMGimNx10asdmau9cb8Xb1Vyg0GvTwyIL2ziQyh2kAloOtAQFBQVuecA== "@tokenizer/token@^0.3.0": version "0.3.0" @@ -5465,24 +5897,24 @@ path-browserify "^1.0.1" "@tsconfig/node10@^1.0.7": - version "1.0.8" - resolved "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9" - integrity sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg== + version "1.0.9" + resolved "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" + integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== "@tsconfig/node12@^1.0.7": - version "1.0.9" - resolved "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz#62c1f6dee2ebd9aead80dc3afa56810e58e1a04c" - integrity sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw== + version "1.0.11" + resolved "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" + integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== "@tsconfig/node14@^1.0.0": - version "1.0.1" - resolved "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz#95f2d167ffb9b8d2068b0b235302fafd4df711f2" - integrity sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg== + version "1.0.3" + resolved "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" + integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== "@tsconfig/node16@^1.0.2": - version "1.0.2" - resolved "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" - integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== + version "1.0.3" + resolved "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e" + integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ== "@types/accepts@^1.3.5": version "1.3.5" @@ -5860,7 +6292,7 @@ "@types/eslint" "*" "@types/estree" "*" -"@types/eslint@*", "@types/eslint@^7.28.2": +"@types/eslint@*": version "7.29.0" resolved "https://registry.npmjs.org/@types/eslint/-/eslint-7.29.0.tgz#e56ddc8e542815272720bb0b4ccc2aff9c3e1c78" integrity sha512-VNcvioYDH8/FxaeTKkM4/TiTwt6pBV9E3OfGmvaw8tPl0rrHCJ4Ll15HRT+pMiFAf/MLQvAzC+6RzUMEL9Ceng== @@ -5868,6 +6300,14 @@ "@types/estree" "*" "@types/json-schema" "*" +"@types/eslint@^7.29.0 || ^8.4.1": + version "8.4.3" + resolved "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.3.tgz#5c92815a3838b1985c90034cd85f26f59d9d0ece" + integrity sha512-YP1S7YJRMPs+7KZKDb9G63n8YejIwW9BALq7a5j2+H4yl6iOv9CB29edho+cuFRrvmJbbaH2yiVChKLJVysDGw== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + "@types/estree@*", "@types/estree@^0.0.51": version "0.0.51" resolved "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz#cfd70924a25a3fd32b218e5e420e6897e1ac4f40" @@ -5888,10 +6328,10 @@ resolved "https://registry.npmjs.org/@types/expect/-/expect-1.20.4.tgz#8288e51737bf7e3ab5d7c77bfa695883745264e5" integrity sha512-Q5Vn3yjTDyCMV50TB6VRIbQNxSE4OmZR86VSbGaNpfUolm0iePBB4KdEEHmxoY5sT2+2DIvXW0rvMDP2nHZ4Mg== -"@types/express-serve-static-core@*", "@types/express-serve-static-core@4.17.28", "@types/express-serve-static-core@^4.17.18", "@types/express-serve-static-core@^4.17.5": - version "4.17.28" - resolved "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz#c47def9f34ec81dc6328d0b1b5303d1ec98d86b8" - integrity sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig== +"@types/express-serve-static-core@*", "@types/express-serve-static-core@4.17.29", "@types/express-serve-static-core@^4.17.18", "@types/express-serve-static-core@^4.17.5": + version "4.17.29" + resolved "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.29.tgz#2a1795ea8e9e9c91b4a4bbe475034b20c1ec711c" + integrity sha512-uMd++6dMKS32EOuw1Uli3e3BPgdLIXmezcfHv7N4c1s3gkhikBplORPpMq3fuWkxncZN1reb16d5n8yhQ80x7Q== dependencies: "@types/node" "*" "@types/qs" "*" @@ -6059,9 +6499,9 @@ "@types/node" "*" "@types/jest-when@^3.5.0": - version "3.5.0" - resolved "https://registry.npmjs.org/@types/jest-when/-/jest-when-3.5.0.tgz#6a573cd521da131e6801f0991b4f1d4dee2ebab5" - integrity sha512-rNUuZ3Mn/HDzpImPXDeOtW18zqyerPoOS2aKU0zUFbirWgJ7sN7LnRv73RmbBQ/uzw28sxf/nUofxbhJ5DWB0w== + version "3.5.2" + resolved "https://registry.npmjs.org/@types/jest-when/-/jest-when-3.5.2.tgz#7e6225e827267d26f115dc97da6403a3b37556c5" + integrity sha512-1WP+wJDW7h4TYAVLoIebxRIVv8GPk66Qsq2nU7PkwKZ6usurnDQZgk0DfBNKAJ9gVzapCXSV53Vn/3nBHBNzAw== dependencies: "@types/jest" "*" @@ -6263,9 +6703,9 @@ "@types/through" "*" "@types/node-fetch@^2.5.0", "@types/node-fetch@^2.5.12", "@types/node-fetch@^2.5.7": - version "2.6.1" - resolved "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.1.tgz#8f127c50481db65886800ef496f20bbf15518975" - integrity sha512-oMqjURCaxoSIsHSr1E47QHzbmzNR5rK8McHuNb11BOM9cHcIK3Avy0s/b2JlXHoQGTYS3NsvWzV1M0iK7l0wbA== + version "2.6.2" + resolved "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz#d1a9c5fd049d9415dce61571557104dec3ec81da" + integrity sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A== dependencies: "@types/node" "*" form-data "^3.0.0" @@ -6301,9 +6741,9 @@ integrity sha512-qjd88DrCxupx/kJD5yQgZdcYKZKSIGBVDIBE1/LTGcNm3d2Np/jxojkdePDdfnBHJc5W7vSMpbJ1aB7p/Py69A== "@types/node@^16.0.0", "@types/node@^16.11.26", "@types/node@^16.9.2": - version "16.11.39" - resolved "https://registry.npmjs.org/@types/node/-/node-16.11.39.tgz#07223cd2bc332ad9d92135e3a522eebdee3b060e" - integrity sha512-K0MsdV42vPwm9L6UwhIxMAOmcvH/1OoVkZyCgEtVu4Wx7sElGloy/W7kMBNe/oJ7V/jW9BVt1F6RahH6e7tPXw== + version "16.11.43" + resolved "https://registry.npmjs.org/@types/node/-/node-16.11.43.tgz#555e5a743f76b6b897d47f945305b618525ddbe6" + integrity sha512-GqWykok+3uocgfAJM8imbozrqLnPyTrpFlrryURQlw1EesPUCx5XxTiucWDSFF9/NUEXDuD4bnvHm8xfVGWTpQ== "@types/normalize-package-data@^2.4.0": version "2.4.1" @@ -6388,9 +6828,9 @@ "@types/passport" "*" "@types/passport@*", "@types/passport@^1.0.3": - version "1.0.8" - resolved "https://registry.npmjs.org/@types/passport/-/passport-1.0.8.tgz#cc3ee653777365ac02f630c3c08fb755567b7387" - integrity sha512-Gdcvis7+7G/Mobm+25AeFi+oe5teBhHzpbCOFWeN10Bj8tnoEE1L5lkraQjzmDEKkJQuM7xSJUGIFGl/giyRfQ== + version "1.0.9" + resolved "https://registry.npmjs.org/@types/passport/-/passport-1.0.9.tgz#b32fa8f7485dace77a9b58e82d0c92908f6e8387" + integrity sha512-9+ilzUhmZQR4JP49GdC2O4UdDE3POPLwpmaTC/iLkW7l0TZCXOo1zsTnnlXPq6rP1UsUZPfbAV4IUdiwiXyC7g== dependencies: "@types/express" "*" @@ -6583,14 +7023,14 @@ integrity sha512-EaCxbanVeyxDRTQBkdLb3Bvl/HK7PBK6UJjsSixB0iHKoWxE5uu2Q/DgtpOhPIojN0Zl1whvOd7PoHs2P0s5eA== "@types/semver@^6.0.0": - version "6.2.1" - resolved "https://registry.npmjs.org/@types/semver/-/semver-6.2.1.tgz#a236185670a7860f1597cf73bea2e16d001461ba" - integrity sha512-+beqKQOh9PYxuHvijhVl+tIHvT6tuwOrE9m14zd+MT2A38KoKZhh7pYJ0SNleLtwDsiIxHDsIk9bv01oOxvSvA== + version "6.2.3" + resolved "https://registry.npmjs.org/@types/semver/-/semver-6.2.3.tgz#5798ecf1bec94eaa64db39ee52808ec0693315aa" + integrity sha512-KQf+QAMWKMrtBMsB8/24w53tEsxllMj6TuA80TT/5igJalLI/zm0L3oXRbIAl4Ohfc85gyHX/jhMwsVkmhLU4A== "@types/semver@^7.3.8": - version "7.3.9" - resolved "https://registry.npmjs.org/@types/semver/-/semver-7.3.9.tgz#152c6c20a7688c30b967ec1841d31ace569863fc" - integrity sha512-L/TMpyURfBkf+o/526Zb6kd/tchUP3iBDEPjqjb+U2MAJhVRxxrmr2fwpe08E7QsV7YLcpq0tUaQ9O9x97ZIxQ== + version "7.3.10" + resolved "https://registry.npmjs.org/@types/semver/-/semver-7.3.10.tgz#5f19ee40cbeff87d916eedc8c2bfe2305d957f73" + integrity sha512-zsv3fsC7S84NN6nPK06u79oWgrPVd0NvOyqgghV1haPaFcVxIrP4DLomRwGAXk0ui4HZA7mOcSFL98sMVW9viw== "@types/serve-handler@^6.1.0": version "6.1.1" @@ -6733,9 +7173,9 @@ "@types/node" "*" "@types/tern@*": - version "0.23.3" - resolved "https://registry.npmjs.org/@types/tern/-/tern-0.23.3.tgz#4b54538f04a88c9ff79de1f6f94f575a7f339460" - integrity sha512-imDtS4TAoTcXk0g7u4kkWqedB3E4qpjXzCpD2LU5M5NAXHzCDsypyvXSaG7mM8DKYkCRa7tFp4tS/lp/Wo7Q3w== + version "0.23.4" + resolved "https://registry.npmjs.org/@types/tern/-/tern-0.23.4.tgz#03926eb13dbeaf3ae0d390caf706b2643a0127fb" + integrity sha512-JAUw1iXGO1qaWwEOzxTKJZ/5JxVeON9kvGZ/osgZaJImBnyjyn0cjovPsf6FNLmyGY8Vw9DoXZCMlfMkMwHRWg== dependencies: "@types/estree" "*" @@ -6747,9 +7187,9 @@ terser-webpack-plugin "*" "@types/testing-library__jest-dom@^5.9.1": - version "5.14.3" - resolved "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.3.tgz#ee6c7ffe9f8595882ee7bda8af33ae7b8789ef17" - integrity sha512-oKZe+Mf4ioWlMuzVBaXQ9WDnEm1+umLx0InILg+yvZVBBDmzV5KfZyLrCvadtWcx8+916jLmHafcmqqffl+iIw== + version "5.14.5" + resolved "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.5.tgz#d113709c90b3c75fdb127ec338dad7d5f86c974f" + integrity sha512-SBwbxYoyPIvxHbeHxTZX2Pe/74F/tX2/D3mMvzabdeJ25bBojfW0TyB8BHrbq/9zaaKICJZjLP+8r6AeZMFCuQ== dependencies: "@types/jest" "*" @@ -6884,13 +7324,13 @@ integrity sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw== "@typescript-eslint/eslint-plugin@^5.9.0": - version "5.27.1" - resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.27.1.tgz#fdf59c905354139046b41b3ed95d1609913d0758" - integrity sha512-6dM5NKT57ZduNnJfpY81Phe9nc9wolnMCnknb1im6brWi1RYv84nbMS3olJa27B6+irUVV1X/Wb+Am0FjJdGFw== + version "5.30.5" + resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.5.tgz#e9a0afd6eb3b1d663db91cf1e7bc7584d394503d" + integrity sha512-lftkqRoBvc28VFXEoRgyZuztyVUQ04JvUnATSPtIRFAccbXTWL6DEtXGYMcbg998kXw1NLUJm7rTQ9eUt+q6Ig== dependencies: - "@typescript-eslint/scope-manager" "5.27.1" - "@typescript-eslint/type-utils" "5.27.1" - "@typescript-eslint/utils" "5.27.1" + "@typescript-eslint/scope-manager" "5.30.5" + "@typescript-eslint/type-utils" "5.30.5" + "@typescript-eslint/utils" "5.30.5" debug "^4.3.4" functional-red-black-tree "^1.0.1" ignore "^5.2.0" @@ -6911,13 +7351,13 @@ eslint-utils "^3.0.0" "@typescript-eslint/parser@^5.9.0": - version "5.27.1" - resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.27.1.tgz#3a4dcaa67e45e0427b6ca7bb7165122c8b569639" - integrity sha512-7Va2ZOkHi5NP+AZwb5ReLgNF6nWLGTeUJfxdkVUAPPSaAdbWNnFZzLZ4EGGmmiCTg+AwlbE1KyUYTBglosSLHQ== + version "5.30.5" + resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.30.5.tgz#f667c34e4e4c299d98281246c9b1e68c03a92522" + integrity sha512-zj251pcPXI8GO9NDKWWmygP6+UjwWmrdf9qMW/L/uQJBM/0XbU2inxe5io/234y/RCvwpKEYjZ6c1YrXERkK4Q== dependencies: - "@typescript-eslint/scope-manager" "5.27.1" - "@typescript-eslint/types" "5.27.1" - "@typescript-eslint/typescript-estree" "5.27.1" + "@typescript-eslint/scope-manager" "5.30.5" + "@typescript-eslint/types" "5.30.5" + "@typescript-eslint/typescript-estree" "5.30.5" debug "^4.3.4" "@typescript-eslint/scope-manager@5.20.0": @@ -6928,13 +7368,13 @@ "@typescript-eslint/types" "5.20.0" "@typescript-eslint/visitor-keys" "5.20.0" -"@typescript-eslint/scope-manager@5.27.1": - version "5.27.1" - resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.27.1.tgz#4d1504392d01fe5f76f4a5825991ec78b7b7894d" - integrity sha512-fQEOSa/QroWE6fAEg+bJxtRZJTH8NTskggybogHt4H9Da8zd4cJji76gA5SBlR0MgtwF7rebxTbDKB49YUCpAg== +"@typescript-eslint/scope-manager@5.30.5": + version "5.30.5" + resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.30.5.tgz#7f90b9d6800552c856a5f3644f5e55dd1469d964" + integrity sha512-NJ6F+YHHFT/30isRe2UTmIGGAiXKckCyMnIV58cE3JkHmaD6e5zyEYm5hBDv0Wbin+IC0T1FWJpD3YqHUG/Ydg== dependencies: - "@typescript-eslint/types" "5.27.1" - "@typescript-eslint/visitor-keys" "5.27.1" + "@typescript-eslint/types" "5.30.5" + "@typescript-eslint/visitor-keys" "5.30.5" "@typescript-eslint/scope-manager@5.9.0": version "5.9.0" @@ -6944,12 +7384,12 @@ "@typescript-eslint/types" "5.9.0" "@typescript-eslint/visitor-keys" "5.9.0" -"@typescript-eslint/type-utils@5.27.1": - version "5.27.1" - resolved "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.27.1.tgz#369f695199f74c1876e395ebea202582eb1d4166" - integrity sha512-+UC1vVUWaDHRnC2cQrCJ4QtVjpjjCgjNFpg8b03nERmkHv9JV9X5M19D7UFMd+/G7T/sgFwX2pGmWK38rqyvXw== +"@typescript-eslint/type-utils@5.30.5": + version "5.30.5" + resolved "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.30.5.tgz#7a9656f360b4b1daea635c4621dab053d08bf8a9" + integrity sha512-k9+ejlv1GgwN1nN7XjVtyCgE0BTzhzT1YsQF0rv4Vfj2U9xnslBgMYYvcEYAFVdvhuEscELJsB7lDkN7WusErw== dependencies: - "@typescript-eslint/utils" "5.27.1" + "@typescript-eslint/utils" "5.30.5" debug "^4.3.4" tsutils "^3.21.0" @@ -6958,10 +7398,10 @@ resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.20.0.tgz#fa39c3c2aa786568302318f1cb51fcf64258c20c" integrity sha512-+d8wprF9GyvPwtoB4CxBAR/s0rpP25XKgnOvMf/gMXYDvlUC3rPFHupdTQ/ow9vn7UDe5rX02ovGYQbv/IUCbg== -"@typescript-eslint/types@5.27.1": - version "5.27.1" - resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.27.1.tgz#34e3e629501349d38be6ae97841298c03a6ffbf1" - integrity sha512-LgogNVkBhCTZU/m8XgEYIWICD6m4dmEDbKXESCbqOXfKZxRKeqpiJXQIErv66sdopRKZPo5l32ymNqibYEH/xg== +"@typescript-eslint/types@5.30.5": + version "5.30.5" + resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.30.5.tgz#36a0c05a72af3623cdf9ee8b81ea743b7de75a98" + integrity sha512-kZ80w/M2AvsbRvOr3PjaNh6qEW1LFqs2pLdo2s5R38B2HYXG8Z0PP48/4+j1QHJFL3ssHIbJ4odPRS8PlHrFfw== "@typescript-eslint/types@5.9.0": version "5.9.0" @@ -6981,13 +7421,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/typescript-estree@5.27.1": - version "5.27.1" - resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.27.1.tgz#7621ee78607331821c16fffc21fc7a452d7bc808" - integrity sha512-DnZvvq3TAJ5ke+hk0LklvxwYsnXpRdqUY5gaVS0D4raKtbznPz71UJGnPTHEFo0GDxqLOLdMkkmVZjSpET1hFw== +"@typescript-eslint/typescript-estree@5.30.5": + version "5.30.5" + resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.5.tgz#c520e4eba20551c4ec76af8d344a42eb6c9767bb" + integrity sha512-qGTc7QZC801kbYjAr4AgdOfnokpwStqyhSbiQvqGBLixniAKyH+ib2qXIVo4P9NgGzwyfD9I0nlJN7D91E1VpQ== dependencies: - "@typescript-eslint/types" "5.27.1" - "@typescript-eslint/visitor-keys" "5.27.1" + "@typescript-eslint/types" "5.30.5" + "@typescript-eslint/visitor-keys" "5.30.5" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" @@ -7007,15 +7447,15 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/utils@5.27.1": - version "5.27.1" - resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.27.1.tgz#b4678b68a94bc3b85bf08f243812a6868ac5128f" - integrity sha512-mZ9WEn1ZLDaVrhRaYgzbkXBkTPghPFsup8zDbbsYTxC5OmqrFE7skkKS/sraVsLP3TcT3Ki5CSyEFBRkLH/H/w== +"@typescript-eslint/utils@5.30.5": + version "5.30.5" + resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.30.5.tgz#3999cbd06baad31b9e60d084f20714d1b2776765" + integrity sha512-o4SSUH9IkuA7AYIfAvatldovurqTAHrfzPApOZvdUq01hHojZojCFXx06D/aFpKCgWbMPRdJBWAC3sWp3itwTA== dependencies: "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.27.1" - "@typescript-eslint/types" "5.27.1" - "@typescript-eslint/typescript-estree" "5.27.1" + "@typescript-eslint/scope-manager" "5.30.5" + "@typescript-eslint/types" "5.30.5" + "@typescript-eslint/typescript-estree" "5.30.5" eslint-scope "^5.1.1" eslint-utils "^3.0.0" @@ -7039,12 +7479,12 @@ "@typescript-eslint/types" "5.20.0" eslint-visitor-keys "^3.0.0" -"@typescript-eslint/visitor-keys@5.27.1": - version "5.27.1" - resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.27.1.tgz#05a62666f2a89769dac2e6baa48f74e8472983af" - integrity sha512-xYs6ffo01nhdJgPieyk7HAOpjhTsx7r/oB9LWEhwAXgwn33tkr+W8DI2ChboqhZlC4q3TC6geDYPoiX8ROqyOQ== +"@typescript-eslint/visitor-keys@5.30.5": + version "5.30.5" + resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.5.tgz#d4bb969202019d5d5d849a0aaedc7370cc044b14" + integrity sha512-D+xtGo9HUMELzWIUqcQc0p2PO4NyvTrgIOK/VnSH083+8sq0tiLozNRKuLarwHYGRuA6TVBQSuuLwJUDWd3aaA== dependencies: - "@typescript-eslint/types" "5.27.1" + "@typescript-eslint/types" "5.30.5" eslint-visitor-keys "^3.3.0" "@typescript-eslint/visitor-keys@5.9.0": @@ -7055,16 +7495,14 @@ "@typescript-eslint/types" "5.9.0" eslint-visitor-keys "^3.0.0" -"@uiw/react-codemirror@^4.7.0": - version "4.7.0" - resolved "https://registry.npmjs.org/@uiw/react-codemirror/-/react-codemirror-4.7.0.tgz#cca6cb2e91f5c5c5e545b389cc55fb307087be75" - integrity sha512-gRBsIScecZzqj1/vqPZ6XxykccBkp+qv6wLFyTk2DxHzuPl4cDIQwqCBl81u80by5nCKambceRkTvpiQ6oJ2Ew== +"@uiw/react-codemirror@^4.9.3": + version "4.10.4" + resolved "https://registry.npmjs.org/@uiw/react-codemirror/-/react-codemirror-4.10.4.tgz#f26833d5cfc4c63de1858c587218efd9f85f18e2" + integrity sha512-eMl/Xtmhhjo1Hmx0P1NgwVlviOUCdjSYPKHn0bgUG6aLgZjCo1l0MJDDuLikGp8YlDrXcDKgiuXPt4GykBaUmg== dependencies: "@babel/runtime" ">=7.11.0" - "@codemirror/basic-setup" "^0.20.0" - "@codemirror/state" "^0.20.0" - "@codemirror/theme-one-dark" "^0.20.0" - "@codemirror/view" "^0.20.0" + "@codemirror/theme-one-dark" "^6.0.0" + codemirror "^6.0.0" "@webassemblyjs/ast@1.11.1": version "1.11.1" @@ -7213,9 +7651,9 @@ integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== "@yarnpkg/parsers@^3.0.0-rc.4": - version "3.0.0-rc.9" - resolved "https://registry.npmjs.org/@yarnpkg/parsers/-/parsers-3.0.0-rc.9.tgz#2d284e4e0c79b1c4e410465e217fa303d98b7be3" - integrity sha512-JMBE+6OJoNN9AXBzZ72u22/t9M25K8KgUWZIjvk8CU/NsE/m946l8D7SqMhbi3ZaUfYa5QitqCqVWTTFtysGJQ== + version "3.0.0-rc.11" + resolved "https://registry.npmjs.org/@yarnpkg/parsers/-/parsers-3.0.0-rc.11.tgz#4c2e69f3c904693eea58a8999ca9a189b0d78b41" + integrity sha512-qQ2EBj1lRA2iB1SwcyvGI53w5TlEBMgJ/hAR42ts+6bKK/am/xQoozQxtBiqodAyphIGVSm3sfQmQXN2pjMlNA== dependencies: js-yaml "^3.10.0" tslib "^1.13.0" @@ -7354,6 +7792,11 @@ aggregate-error@^3.0.0, aggregate-error@^3.1.0: clean-stack "^2.0.0" indent-string "^4.0.0" +ajv-draft-04@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz#3b64761b268ba0b9e668f0b41ba53fce0ad77fc8" + integrity sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw== + ajv-formats@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" @@ -7383,7 +7826,7 @@ ajv@^6.10.0, ajv@^6.10.1, ajv@^6.12.2, ajv@^6.12.4, ajv@^6.12.5, ajv@^6.5.5, ajv json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^8.0.0, ajv@^8.10.0, ajv@^8.8.0: +ajv@^8.0.0, ajv@^8.10.0, ajv@^8.6.3, ajv@^8.8.0: version "8.11.0" resolved "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f" integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg== @@ -7410,17 +7853,10 @@ anafanafo@2.0.0: dependencies: char-width-table-consumer "^1.0.0" -ansi-align@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz#b536b371cf687caaef236c18d3e21fe3797467cb" - integrity sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw== - dependencies: - string-width "^3.0.0" - -ansi-colors@^4.1.1: - version "4.1.1" - resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" - integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== +ansi-colors@^4.1.1, ansi-colors@^4.1.3: + version "4.1.3" + resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" + integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== ansi-escapes@^3.0.0: version "3.2.0" @@ -7516,12 +7952,12 @@ anymatch@^3.0.3, anymatch@~3.1.2: normalize-path "^3.0.0" picomatch "^2.0.4" -apollo-datasource@^3.3.1: - version "3.3.1" - resolved "https://registry.npmjs.org/apollo-datasource/-/apollo-datasource-3.3.1.tgz#a1168dd68371930de3ed4245ad12fa8600efe2cc" - integrity sha512-Z3a8rEUXVPIZ1p8xrFL8bcNhWmhOmovgDArvwIwmJOBnh093ZpRfO+ESJEDAN4KswmyzCLDAwjsW4zQOONdRUw== +apollo-datasource@^3.3.2: + version "3.3.2" + resolved "https://registry.npmjs.org/apollo-datasource/-/apollo-datasource-3.3.2.tgz#5711f8b38d4b7b53fb788cb4dbd4a6a526ea74c8" + integrity sha512-L5TiS8E2Hn/Yz7SSnWIVbZw0ZfEIXZCa5VUiVxD9P53JvSrf4aStvsFDlGWPvpIdCR+aly2CfoB79B9/JjKFqg== dependencies: - apollo-server-caching "^3.3.0" + "@apollo/utils.keyvaluecache" "^1.0.1" apollo-server-env "^4.2.1" apollo-reporting-protobuf@^3.3.1: @@ -7531,18 +7967,12 @@ apollo-reporting-protobuf@^3.3.1: dependencies: "@apollo/protobufjs" "1.2.2" -apollo-server-caching@^3.3.0: - version "3.3.0" - resolved "https://registry.npmjs.org/apollo-server-caching/-/apollo-server-caching-3.3.0.tgz#f501cbeb820a4201d98c2b768c085f22848d9dc5" - integrity sha512-Wgcb0ArjZ5DjQ7ID+tvxUcZ7Yxdbk5l1MxZL8D8gkyjooOkhPNzjRVQ7ubPoXqO54PrOMOTm1ejVhsF+AfIirQ== - dependencies: - lru-cache "^6.0.0" - -apollo-server-core@^3.8.2: - version "3.8.2" - resolved "https://registry.npmjs.org/apollo-server-core/-/apollo-server-core-3.8.2.tgz#a065e00220d6c709b11b824197520adee6d897d2" - integrity sha512-cbzG928HG27W+juMVCIL1O//iyAj/Q2hnOu6YwrGrcqeE75ZIJSgSBm/gPHK20cI7nEjK2IWACx8Hj1nGAQ5Zg== +apollo-server-core@^3.9.0: + version "3.9.0" + resolved "https://registry.npmjs.org/apollo-server-core/-/apollo-server-core-3.9.0.tgz#44b39e378314cfc0596be7003d3f1f1397c88eea" + integrity sha512-WS54C33cTriDaBIcj7ijWv/fgeJICcrQKlP1Cn6pnZp/eumpMraezLeJ3gFWAXprOuR2E3fZe64lNlup0fMu8w== dependencies: + "@apollo/utils.keyvaluecache" "^1.0.1" "@apollo/utils.logger" "^1.0.0" "@apollo/utils.usagereporting" "^1.0.0" "@apollographql/apollo-tools" "^0.5.3" @@ -7550,13 +7980,12 @@ apollo-server-core@^3.8.2: "@graphql-tools/mock" "^8.1.2" "@graphql-tools/schema" "^8.0.0" "@josephg/resolvable" "^1.0.0" - apollo-datasource "^3.3.1" + apollo-datasource "^3.3.2" apollo-reporting-protobuf "^3.3.1" - apollo-server-caching "^3.3.0" apollo-server-env "^4.2.1" apollo-server-errors "^3.3.1" - apollo-server-plugin-base "^3.6.0" - apollo-server-types "^3.6.0" + apollo-server-plugin-base "^3.6.1" + apollo-server-types "^3.6.1" async-retry "^1.2.1" fast-json-stable-stringify "^2.1.0" graphql-tag "^2.11.0" @@ -7578,48 +8007,48 @@ apollo-server-errors@^3.3.1: resolved "https://registry.npmjs.org/apollo-server-errors/-/apollo-server-errors-3.3.1.tgz#ba5c00cdaa33d4cbd09779f8cb6f47475d1cd655" integrity sha512-xnZJ5QWs6FixHICXHxUfm+ZWqqxrNuPlQ+kj5m6RtEgIpekOPssH/SD9gf2B4HuWV0QozorrygwZnux8POvyPA== -apollo-server-express@^3.0.0, apollo-server-express@^3.8.2: - version "3.8.2" - resolved "https://registry.npmjs.org/apollo-server-express/-/apollo-server-express-3.8.2.tgz#51285279f8a52eb7d88a4f4145261b6f69b12ba6" - integrity sha512-UIpjs0qwOGJ0U1IokrtfjgpQVoirr7E1w446mx6B0EqV8sIFgdEE253utxtHi80va37h/xuEIUuAZFRQaY6ClQ== +apollo-server-express@^3.0.0, apollo-server-express@^3.9.0: + version "3.9.0" + resolved "https://registry.npmjs.org/apollo-server-express/-/apollo-server-express-3.9.0.tgz#1ff3b53fe76e4e8be04b8477ea8a3d9586313af1" + integrity sha512-scSeHy9iB7W3OiF3uLQEzad9Jm9tEfDF8ACsJb2P+xX69uqg6zizsrQvj3qRhazCO7FKMcMu9zQFR0hy7zKbUA== dependencies: "@types/accepts" "^1.3.5" "@types/body-parser" "1.19.2" "@types/cors" "2.8.12" "@types/express" "4.17.13" - "@types/express-serve-static-core" "4.17.28" + "@types/express-serve-static-core" "4.17.29" accepts "^1.3.5" - apollo-server-core "^3.8.2" - apollo-server-types "^3.6.0" + apollo-server-core "^3.9.0" + apollo-server-types "^3.6.1" body-parser "^1.19.0" cors "^2.8.5" parseurl "^1.3.3" -apollo-server-plugin-base@^3.6.0: - version "3.6.0" - resolved "https://registry.npmjs.org/apollo-server-plugin-base/-/apollo-server-plugin-base-3.6.0.tgz#f85e19fa4a33866ef1b4235077397a63a9a7343e" - integrity sha512-GtXhczRGpTLQyFPWeWSnX1VcN2JaaAU7WT8PzoTQuJKYJ/Aj5mPebHbfG+PXQlDmI8IgyCKf7B1HIRnJqvAZbg== +apollo-server-plugin-base@^3.6.1: + version "3.6.1" + resolved "https://registry.npmjs.org/apollo-server-plugin-base/-/apollo-server-plugin-base-3.6.1.tgz#33e9f26433d5a8b8ed5d27e9fa88de9ef0c2c704" + integrity sha512-bFpxzWO0LTTtSAkGVBeaAtnQXJ5ZCi8eaLN/eMSju8RByifmF3Kr6gAqcOZhOH/geQEt3Y6G8n3bR0eHTGxljQ== dependencies: - apollo-server-types "^3.6.0" + apollo-server-types "^3.6.1" -apollo-server-types@^3.6.0: - version "3.6.0" - resolved "https://registry.npmjs.org/apollo-server-types/-/apollo-server-types-3.6.0.tgz#29fd8369aad99d42f72b760eb12bfe2c888da901" - integrity sha512-zISCkwXvwTHK2AysWSfLAUvDLSDJ0xj8pnfxDv34hqA+G9JqsLbykJdSL1Y1kT53HU4RWF6ymTuTwwOmmBiAWA== +apollo-server-types@^3.6.1: + version "3.6.1" + resolved "https://registry.npmjs.org/apollo-server-types/-/apollo-server-types-3.6.1.tgz#704e5309bd947306030df01f982e36d1d4753eaa" + integrity sha512-XOPlBlRdwP00PrG03OffGGWuzyei+J9t1rAnvyHsSdP0JCgQWigHJfvL1N9Bhgi4UTjl9JadKOJh1znLNlqIFQ== dependencies: + "@apollo/utils.keyvaluecache" "^1.0.1" "@apollo/utils.logger" "^1.0.0" apollo-reporting-protobuf "^3.3.1" - apollo-server-caching "^3.3.0" apollo-server-env "^4.2.1" apollo-server@^3.0.0: - version "3.8.2" - resolved "https://registry.npmjs.org/apollo-server/-/apollo-server-3.8.2.tgz#15a9263d56ac3a44a5c186d9aafed90c1c2687da" - integrity sha512-XBWTn9uMLKgob60qOlAphOIpY81dDfF5uonCvO154Qx5TJ6IRqER38StIgEgQLLRcR4RZ40uMvbwofZRHfXecA== + version "3.9.0" + resolved "https://registry.npmjs.org/apollo-server/-/apollo-server-3.9.0.tgz#391b60c4c24d37c65855cccc8aa886e684bc1776" + integrity sha512-g80gXDuK8fl2W0fQF/hEyeoO9AU+sO2gBzeJAYUyGLotYc+oL/Y3mTRk5GB8C7cXUXCg5uvWbUj8va0E5UZE7w== dependencies: "@types/express" "4.17.13" - apollo-server-core "^3.8.2" - apollo-server-express "^3.8.2" + apollo-server-core "^3.9.0" + apollo-server-express "^3.9.0" express "^4.17.1" aproba@^1.0.3: @@ -7770,7 +8199,7 @@ array-ify@^1.0.0: resolved "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece" integrity sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4= -array-includes@^3.1.2, array-includes@^3.1.3, array-includes@^3.1.4: +array-includes@^3.1.2, array-includes@^3.1.4: version "3.1.4" resolved "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz#f5b493162c760f3539631f005ba2bb46acb45ba9" integrity sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw== @@ -7814,6 +8243,16 @@ array-unique@^0.3.2: resolved "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= +array.prototype.flat@^1.2.3: + version "1.3.0" + resolved "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz#0b0c1567bf57b38b56b4c97b8aa72ab45e4adc7b" + integrity sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.2" + es-shim-unscopables "^1.0.0" + array.prototype.flat@^1.2.5: version "1.2.5" resolved "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz#07e0975d84bbc7c48cd1879d609e682598d33e13" @@ -7841,7 +8280,7 @@ arraybuffer.slice@~0.0.7: arrify@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" - integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= + integrity sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA== arrify@^2.0.0, arrify@^2.0.1: version "2.0.1" @@ -7960,6 +8399,13 @@ available-typed-arrays@^1.0.2: dependencies: array-filter "^1.0.0" +aws-os-connection@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/aws-os-connection/-/aws-os-connection-0.1.0.tgz#02c1be08cf63448c5bdc9d47b03b7ad3222b662c" + integrity sha512-WBN2S/5zgzfPpEiOTEW7IPJX+hlq+AQeAVKK4AL/Th0SfRRKu6a46i4aZKovQslBkKnmcSFvy+mHSJ299N8YWA== + dependencies: + aws4 "^1.11.0" + aws-sdk-mock@^5.2.1: version "5.7.0" resolved "https://registry.npmjs.org/aws-sdk-mock/-/aws-sdk-mock-5.7.0.tgz#b2a9454c78d008186c3f1a460b79cdb9cc9dfdc4" @@ -7970,9 +8416,9 @@ aws-sdk-mock@^5.2.1: traverse "^0.6.6" aws-sdk@^2.1122.0, aws-sdk@^2.840.0, aws-sdk@^2.948.0: - version "2.1151.0" - resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1151.0.tgz#8fcb41c3b919842a7b4e5c4cd9e124f6439b5b67" - integrity sha512-VvyzXAmWrX+klvwzA+9gSTY7blDnZOTl0UTKrqmFL4K7tOLieGLYTUkpUegcPxCjYgEg7JwvYolYUnUKiHa4oA== + version "2.1168.0" + resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1168.0.tgz#7936459edee0c999065f1ecf2ef0bea89ea056c1" + integrity sha512-9+WYoYTHHjLqeWdSSLbNpmc/NgnZpX4LGiyYjXenh4WNRBXshXI0XioTK8BQgDscVzB978EJV8kG1nZGE3USzw== dependencies: buffer "4.9.2" events "1.1.1" @@ -7994,10 +8440,10 @@ aws4@^1.11.0, aws4@^1.8.0: resolved "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== -axe-core@^4.3.5: - version "4.3.5" - resolved "https://registry.npmjs.org/axe-core/-/axe-core-4.3.5.tgz#78d6911ba317a8262bfee292aeafcc1e04b49cc5" - integrity sha512-WKTW1+xAzhMS5dJsxWkliixlO/PqC4VhmO9T4juNYcaTg9jzWiJsou6m5pxWYGfigWbwzJWeFY6z47a+4neRXA== +axe-core@^4.4.2: + version "4.4.2" + resolved "https://registry.npmjs.org/axe-core/-/axe-core-4.4.2.tgz#dcf7fb6dea866166c3eab33d68208afe4d5f670c" + integrity sha512-LVAaGp/wkkgYJcjmHsoKx4juT1aQvJyPcW09MLCjVTh3V2cc6PnyempiLMNH5iMdfIX/zdbjUx2KDjMLCTdPeA== axios-cached-dns-resolve@0.5.2: version "0.5.2" @@ -8109,6 +8555,22 @@ babel-plugin-polyfill-regenerator@^0.3.0: dependencies: "@babel/helper-define-polyfill-provider" "^0.3.1" +"babel-plugin-styled-components@>= 1.12.0": + version "2.0.7" + resolved "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-2.0.7.tgz#c81ef34b713f9da2b7d3f5550df0d1e19e798086" + integrity sha512-i7YhvPgVqRKfoQ66toiZ06jPNA3p6ierpfUuEWxNF+fV27Uv5gxBkf8KZLHUCc1nFA9j6+80pYoIpqCeyW3/bA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.0" + "@babel/helper-module-imports" "^7.16.0" + babel-plugin-syntax-jsx "^6.18.0" + lodash "^4.17.11" + picomatch "^2.3.0" + +babel-plugin-syntax-jsx@^6.18.0: + version "6.18.0" + resolved "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" + integrity sha512-qrPaCSo9c8RHNRHIotaufGbuOBN8rtdC4QrrFFc43vyWCCz7Kl7GL1PGaXtMGQZUXrkCjNEgxDfmAuAabr/rlw== + babel-plugin-syntax-trailing-function-commas@^7.0.0-beta.0: version "7.0.0-beta.0" resolved "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-7.0.0-beta.0.tgz#aa213c1435e2bffeb6fca842287ef534ad05d5cf" @@ -8322,6 +8784,11 @@ big.js@^5.2.2: resolved "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== +big.js@^6.1.1: + version "6.2.0" + resolved "https://registry.npmjs.org/big.js/-/big.js-6.2.0.tgz#39c60822aecb0f34a1d79a90fe9908a0ddf45e1d" + integrity sha512-paIKvJiAaOYdLt6MfnvxkDo64lTOV257XYJyX3oJnJQocIclUn+48k6ZerH/c5FxWE6DGJu1TKDYis7tqHg9kg== + bignumber.js@^9.0.0: version "9.0.1" resolved "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz#8d7ba124c882bfd8e43260c67475518d0689e4e5" @@ -8472,20 +8939,6 @@ bottleneck@^2.15.3: resolved "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz#5df0b90f59fd47656ebe63c78a98419205cadd91" integrity sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw== -boxen@^5.0.0: - version "5.1.2" - resolved "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz#788cb686fc83c1f486dfa8a40c68fc2b831d2b50" - integrity sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ== - dependencies: - ansi-align "^3.0.0" - camelcase "^6.2.0" - chalk "^4.1.0" - cli-boxes "^2.2.1" - string-width "^4.2.2" - type-fest "^0.20.2" - widest-line "^3.1.0" - wrap-ansi "^7.0.0" - brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -8550,6 +9003,11 @@ brorand@^1.0.1, brorand@^1.1.0: resolved "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= +browser-headers@^0.4.1: + version "0.4.1" + resolved "https://registry.npmjs.org/browser-headers/-/browser-headers-0.4.1.tgz#4308a7ad3b240f4203dbb45acedb38dc2d65dd02" + integrity sha512-CA9hsySZVo9371qEHjHZtYxV2cFtVj5Wj/ZHi8ooEsrtm4vOnl9Y9HmyYWk9q+05d7K3rdoAE0j3MVEFVvtQtg== + browser-process-hrtime@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" @@ -8681,7 +9139,7 @@ buffer@4.9.2, buffer@^4.3.0: ieee754 "^1.1.4" isarray "^1.0.0" -buffer@^5.2.0, buffer@^5.2.1, buffer@^5.5.0, buffer@^5.6.0, buffer@^5.7.0: +buffer@^5.2.0, buffer@^5.2.1, buffer@^5.5.0, buffer@^5.6.0, buffer@^5.7.0, buffer@^5.7.1: version "5.7.1" resolved "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== @@ -8724,6 +9182,13 @@ builtins@^5.0.0: dependencies: semver "^7.0.0" +busboy@^1.6.0: + version "1.6.0" + resolved "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893" + integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA== + dependencies: + streamsearch "^1.1.0" + byline@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/byline/-/byline-5.0.0.tgz#741c5216468eadc457b03410118ad77de8c1ddb1" @@ -8908,6 +9373,11 @@ camelcase@^6.2.0, camelcase@^6.3.0: resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== +camelize@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz#164a5483e630fa4321e5af07020e531831b2609b" + integrity sha512-W2lPwkBkMZwFlPCXhIlYgxu+7gC/NUlCtdK652DAJ1JdgV0sTrvuPFshNPrFa1TY2JOkLhgdeEBplB4ezEa+xg== + caniuse-api@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" @@ -8924,9 +9394,9 @@ caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001286: integrity sha512-5v7LFQU4Sb/qvkz7JcZkvtSH1Ko+1x2kgo3ocdBeMGZSOFpuE1kkm0kpTwLtWeFrw5qw08ulLxJjVIXIS8MkiQ== canvas@^2.6.1: - version "2.9.1" - resolved "https://registry.npmjs.org/canvas/-/canvas-2.9.1.tgz#58ec841cba36cef0675bc7a74ebd1561f0b476b0" - integrity sha512-vSQti1uG/2gjv3x6QLOZw7TctfufaerTWbVe+NSduHxxLGB+qf3kFgQ6n66DSnuoINtVUjrLLIK2R+lxrBG07A== + version "2.9.3" + resolved "https://registry.npmjs.org/canvas/-/canvas-2.9.3.tgz#8723c4f970442d4cdcedba5221579f9660a58bdb" + integrity sha512-WOUM7ghii5TV2rbhaZkh1youv/vW1/Canev6Yx6BG2W+1S07w8jKZqKkPnbiPpQEDsnJdN8ouDd7OvQEGXDcUw== dependencies: "@mapbox/node-pre-gyp" "^1.0.0" nan "^2.15.0" @@ -9131,9 +9601,9 @@ ci-info@^2.0.0: integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== ci-info@^3.1.0, ci-info@^3.2.0: - version "3.3.0" - resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz#b4ed1fb6818dea4803a55c623041f9165d2066b2" - integrity sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw== + version "3.3.2" + resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.3.2.tgz#6d2967ffa407466481c6c90b6e16b3098f080128" + integrity sha512-xmDt/QIAdeZ9+nfdPsaBCpMvHNLFiLdjj59qjqn+6iPe6YmHGQ35sBnQ8uslRBXFmXkiZQOJRjvQeoGppoTjjg== cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" @@ -9187,11 +9657,6 @@ clean-stack@^2.0.0: resolved "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== -cli-boxes@^2.2.1: - version "2.2.1" - resolved "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" - integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw== - cli-cursor@^2.0.0, cli-cursor@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" @@ -9317,7 +9782,7 @@ clone@2.x, clone@^2.1.1, clone@^2.1.2: clone@^1.0.2: version "1.0.4" resolved "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" - integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= + integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== cloneable-readable@^1.0.0: version "1.1.3" @@ -9367,18 +9832,31 @@ code-point-at@^1.0.0: resolved "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= -codemirror-graphql@^1.3.1: - version "1.3.1" - resolved "https://registry.npmjs.org/codemirror-graphql/-/codemirror-graphql-1.3.1.tgz#c852b12b6909783681a5e37d61d1627a78f9c7a6" - integrity sha512-jlLwTARoMeuYLR5sQYbh5uYewIoYUYAn+0lOIKXpaHudk9X1rOrP/WtOqfDza1ETnyfnlpLidBnpieIMKktriQ== +codemirror-graphql@^1.3.2: + version "1.3.2" + resolved "https://registry.npmjs.org/codemirror-graphql/-/codemirror-graphql-1.3.2.tgz#e9d1d18b4a160f0016a28465805284636ee42d2a" + integrity sha512-glwFsEVlH5TvxjSKGymZ1sNy37f3Mes58CB4fXOd0zy9+JzDL08Wti1b5ycy4vFZYghMDK1/Or/zRSjMAGtC2w== dependencies: - graphql-language-service "^5.0.5" + graphql-language-service "^5.0.6" codemirror@^5.65.3: version "5.65.3" resolved "https://registry.npmjs.org/codemirror/-/codemirror-5.65.3.tgz#2d029930d5a293bc5fb96ceea64654803c0d4ac7" integrity sha512-kCC0iwGZOVZXHEKW3NDTObvM7pTIyowjty4BUqeREROc/3I6bWbgZDA3fGDwlA+rbgRjvnRnfqs9SfXynel1AQ== +codemirror@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/codemirror/-/codemirror-6.0.0.tgz#48aac6370d188f0761807ad9c3b62da7e7f72446" + integrity sha512-c4XR9QtDn+NhKLM2FBsnRn9SFdRH7G6594DYC/fyKKIsTOcdLF0WNWRd+f6kNyd5j1vgYPucbIeq2XkywYCwhA== + dependencies: + "@codemirror/autocomplete" "^6.0.0" + "@codemirror/commands" "^6.0.0" + "@codemirror/language" "^6.0.0" + "@codemirror/lint" "^6.0.0" + "@codemirror/search" "^6.0.0" + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.0.0" + codeowners-utils@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/codeowners-utils/-/codeowners-utils-1.0.2.tgz#9d30148bf957c53d55f75df432cb1e3b4bc6ee28" @@ -9424,7 +9902,7 @@ color-convert@^2.0.1: color-name@1.1.3: version "1.1.3" resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== color-name@^1.0.0, color-name@^1.1.4, color-name@~1.1.4: version "1.1.4" @@ -9471,9 +9949,9 @@ colorette@2.0.16, colorette@^2.0.10: integrity sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g== colorette@^2.0.16, colorette@^2.0.17: - version "2.0.17" - resolved "https://registry.npmjs.org/colorette/-/colorette-2.0.17.tgz#5dd4c0d15e2984b7433cb4a9f2ead45063b80c47" - integrity sha512-hJo+3Bkn0NCHybn9Tu35fIeoOKGOk5OCC32y4Hz2It+qlCO2Q3DeQ1hRn/tDDMQKRYUEzqsl7jbF6dYKjlE60g== + version "2.0.19" + resolved "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798" + integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ== colors@1.0.3: version "1.0.3" @@ -9601,7 +10079,7 @@ component-emitter@1.2.1: resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= -component-emitter@^1.2.0, component-emitter@^1.2.1, component-emitter@^1.3.0, component-emitter@~1.3.0: +component-emitter@^1.2.1, component-emitter@^1.3.0, component-emitter@~1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== @@ -9705,14 +10183,14 @@ concurrently@6.5.1: yargs "^16.2.0" concurrently@^7.0.0: - version "7.2.1" - resolved "https://registry.npmjs.org/concurrently/-/concurrently-7.2.1.tgz#88b144060443403060aad46f837dd17451f7e55e" - integrity sha512-7cab/QyqipqghrVr9qZmoWbidu0nHsmxrpNqQ7r/67vfl1DWJElexehQnTH1p+87tDkihaAjM79xTZyBQh7HLw== + version "7.2.2" + resolved "https://registry.npmjs.org/concurrently/-/concurrently-7.2.2.tgz#4ad4a4dfd3945f668d727379de2a29502e6a531c" + integrity sha512-DcQkI0ruil5BA/g7Xy3EWySGrFJovF5RYAYxwGvv9Jf9q9B1v3jPFP2tl6axExNf1qgF30kjoNYrangZ0ey4Aw== dependencies: chalk "^4.1.0" date-fns "^2.16.1" lodash "^4.17.21" - rxjs "^6.6.3" + rxjs "^7.0.0" shell-quote "^1.7.3" spawn-command "^0.0.2-1" supports-color "^8.1.0" @@ -9727,22 +10205,10 @@ config-chain@^1.1.12: ini "^1.3.4" proto-list "~1.2.1" -configstore@^5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96" - integrity sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA== - dependencies: - dot-prop "^5.2.0" - graceful-fs "^4.1.2" - make-dir "^3.0.0" - unique-string "^2.0.0" - write-file-atomic "^3.0.0" - xdg-basedir "^4.0.0" - -connect-history-api-fallback@^1.6.0: - version "1.6.0" - resolved "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc" - integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg== +connect-history-api-fallback@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz#647264845251a0daf25b97ce87834cace0f5f1c8" + integrity sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA== consola@^2.15.0: version "2.15.3" @@ -9915,7 +10381,7 @@ cookie@0.5.0, cookie@~0.5.0: resolved "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== -cookiejar@^2.1.0, cookiejar@^2.1.3: +cookiejar@^2.1.3: version "2.1.3" resolved "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.3.tgz#fc7a6216e408e74414b90230050842dacda75acc" integrity sha512-JxbCBUdrfr6AQjOXrxoTvAMJO4HBTUIlBzslcJPAz+/KT8yk53fXun51u+RenNYvad/+Vc2DIz5o9UxlCDymFQ== @@ -9951,9 +10417,9 @@ core-js@^2.4.0, core-js@^2.5.0, core-js@^2.6.10: integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== core-js@^3.4.1, core-js@^3.6.5: - version "3.22.8" - resolved "https://registry.npmjs.org/core-js/-/core-js-3.22.8.tgz#23f860b1fe60797cc4f704d76c93fea8a2f60631" - integrity sha512-UoGQ/cfzGYIuiq6Z7vWL1HfkE9U9IZ4Ub+0XSiJTCzvbZzgPA69oDF2f+lgJ6dFFLEdjW5O6svvoKzXX23xFkA== + version "3.23.3" + resolved "https://registry.npmjs.org/core-js/-/core-js-3.23.3.tgz#3b977612b15da6da0c9cc4aec487e8d24f371112" + integrity sha512-oAKwkj9xcWNBAvGbT//WiCdOMpb9XQG92/Fe3ABFM/R16BsHgePG00mFOgKf7IsCtfj8tA1kHtf/VwErhriz5Q== core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" @@ -10069,9 +10535,9 @@ cron@^2.0.0: luxon "^1.23.x" cronstrue@^2.2.0: - version "2.9.0" - resolved "https://registry.npmjs.org/cronstrue/-/cronstrue-2.9.0.tgz#f63c376060c8e019d748564d6eb128d6cac76210" - integrity sha512-PZSsUZU7O+R0JdsquKMXlm41tm62oO5fVYoXi6QI/eRAYxgbkPJ/OcLrVxUM+JNRy5yv0QEI84YG1mUjEo4RLA== + version "2.11.0" + resolved "https://registry.npmjs.org/cronstrue/-/cronstrue-2.11.0.tgz#18ff1b95a836b9b4e06854f796db2dc8fa98ce41" + integrity sha512-iIBCSis5yqtFYWtJAmNOiwDveFWWIn+8uV5UYuPHYu/Aeu5CSSJepSbaHMyfc+pPFgnsCcGzfPQEo7LSGmWbTg== cross-env@^7.0.0: version "7.0.3" @@ -10090,7 +10556,7 @@ cross-fetch@3.1.5, cross-fetch@^3.0.4, cross-fetch@^3.0.6, cross-fetch@^3.1.3, c cross-spawn@^5.1.0: version "5.1.0" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" - integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= + integrity sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A== dependencies: lru-cache "^4.0.1" shebang-command "^1.2.0" @@ -10140,6 +10606,19 @@ cross-undici-fetch@^0.3.0: undici "^5.0.0" web-streams-polyfill "^3.2.0" +cross-undici-fetch@^0.4.11: + version "0.4.11" + resolved "https://registry.npmjs.org/cross-undici-fetch/-/cross-undici-fetch-0.4.11.tgz#bef38dc729a01db6e07c84fee6de1089b5d3d0a4" + integrity sha512-pRp+EWewyOPYIeUvwOqCIqylCFWqlBwwr6nlZB38v3PhWxS1RYfSgHUJApYTT8jm71SbL5p4qg5kUQv6ZyS24A== + dependencies: + abort-controller "^3.0.0" + busboy "^1.6.0" + form-data-encoder "^1.7.1" + formdata-node "^4.3.1" + node-fetch "^2.6.7" + undici "5.5.1" + web-streams-polyfill "^3.2.0" + crypto-browserify@^3.11.0: version "3.12.0" resolved "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" @@ -10157,11 +10636,6 @@ crypto-browserify@^3.11.0: randombytes "^2.0.0" randomfill "^1.0.3" -crypto-random-string@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" - integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== - css-box-model@^1.2.0: version "1.2.1" resolved "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz#59951d3b81fd6b2074a62d49444415b0d2b4d7c1" @@ -10178,6 +10652,11 @@ css-color-converter@^2.0.0: color-name "^1.1.4" css-unit-converter "^1.1.2" +css-color-keywords@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05" + integrity sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg== + css-declaration-sorter@^6.0.3: version "6.1.3" resolved "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.1.3.tgz#e9852e4cf940ba79f509d9425b137d1f94438dc2" @@ -10218,6 +10697,15 @@ css-select@^4.1.3: domutils "^2.6.0" nth-check "^2.0.0" +css-to-react-native@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.0.0.tgz#62dbe678072a824a689bcfee011fc96e02a7d756" + integrity sha512-Ro1yETZA813eoyUp2GDBhG2j+YggidUmzO1/v9eYBKR2EHVEniE2MI/NqpTQ954BMpTPZFsGNPm46qFB9dpaPQ== + dependencies: + camelize "^1.0.0" + css-color-keywords "^1.0.0" + postcss-value-parser "^4.0.2" + css-tree@^1.1.2, css-tree@^1.1.3: version "1.1.3" resolved "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d" @@ -10352,30 +10840,30 @@ csstype@^3.0.2, csstype@^3.0.6: resolved "https://registry.npmjs.org/csstype/-/csstype-3.0.7.tgz#2a5fb75e1015e84dd15692f71e89a1450290950b" integrity sha512-KxnUB0ZMlnUWCsx2Z8MUsr6qV6ja1w9ArPErJaJaF8a5SOWoHLIszeCTKGRGRgtLgYrs1E8CHkNSP1VZTTPc9g== -csv-generate@^3.2.4: - version "3.2.4" - resolved "https://registry.npmjs.org/csv-generate/-/csv-generate-3.2.4.tgz#440dab9177339ee0676c9e5c16f50e2b3463c019" - integrity sha512-qNM9eqlxd53TWJeGtY1IQPj90b563Zx49eZs8e0uMyEvPgvNVmX1uZDtdzAcflB3PniuH9creAzcFOdyJ9YGvA== +csv-generate@^3.4.3: + version "3.4.3" + resolved "https://registry.npmjs.org/csv-generate/-/csv-generate-3.4.3.tgz#bc42d943b45aea52afa896874291da4b9108ffff" + integrity sha512-w/T+rqR0vwvHqWs/1ZyMDWtHHSJaN06klRqJXBEpDJaM/+dZkso0OKh1VcuuYvK3XM53KysVNq8Ko/epCK8wOw== -csv-parse@^4.8.8: - version "4.12.0" - resolved "https://registry.npmjs.org/csv-parse/-/csv-parse-4.12.0.tgz#fd42d6291bbaadd51d3009f6cadbb3e53b4ce026" - integrity sha512-wPQl3H79vWLPI8cgKFcQXl0NBgYYEqVnT1i6/So7OjMpsI540oD7p93r3w6fDSyPvwkTepG05F69/7AViX2lXg== +csv-parse@^4.16.3: + version "4.16.3" + resolved "https://registry.npmjs.org/csv-parse/-/csv-parse-4.16.3.tgz#7ca624d517212ebc520a36873c3478fa66efbaf7" + integrity sha512-cO1I/zmz4w2dcKHVvpCr7JVRu8/FymG5OEpmvsZYlccYolPBLoVGKUHgNoc4ZGkFeFlWGEDmMyBM+TTqRdW/wg== -csv-stringify@^5.3.6: - version "5.5.1" - resolved "https://registry.npmjs.org/csv-stringify/-/csv-stringify-5.5.1.tgz#f42cdd379b0f7f142933a11f674b1a91ebd0fcd0" - integrity sha512-HM0/86Ks8OwFbaYLd495tqTs1NhscZL52dC4ieKYumy8+nawQYC0xZ63w1NqLf0M148T2YLYqowoImc1giPn0g== +csv-stringify@^5.6.5: + version "5.6.5" + resolved "https://registry.npmjs.org/csv-stringify/-/csv-stringify-5.6.5.tgz#c6d74badda4b49a79bf4e72f91cce1e33b94de00" + integrity sha512-PjiQ659aQ+fUTQqSrd1XEDnOr52jh30RBurfzkscaE2tPaFsDH5wOAHJiw8XAHphRknCwMUE9KRayc4K/NbO8A== -csv@^5.3.1: - version "5.3.2" - resolved "https://registry.npmjs.org/csv/-/csv-5.3.2.tgz#50b344e25dfbb8c62684a1bcec18c22468b2161e" - integrity sha512-odDyucr9OgJTdGM2wrMbJXbOkJx3nnUX3Pt8SFOwlAMOpsUQlz1dywvLMXJWX/4Ib0rjfOsaawuuwfI5ucqBGQ== +csv@^5.5.0: + version "5.5.3" + resolved "https://registry.npmjs.org/csv/-/csv-5.5.3.tgz#cd26c1e45eae00ce6a9b7b27dcb94955ec95207d" + integrity sha512-QTaY0XjjhTQOdguARF0lGKm5/mEq9PD9/VhZZegHDIBq2tQwgNpHc3dneD4mGo2iJs+fTKv5Bp0fZ+BRuY3Z0g== dependencies: - csv-generate "^3.2.4" - csv-parse "^4.8.8" - csv-stringify "^5.3.6" - stream-transform "^2.0.1" + csv-generate "^3.4.3" + csv-parse "^4.16.3" + csv-stringify "^5.6.5" + stream-transform "^2.1.3" cypress-plugin-snapshots@^1.4.4: version "1.4.4" @@ -10399,9 +10887,9 @@ cypress-plugin-snapshots@^1.4.4: unidiff "1.0.2" cypress@^10.0.0: - version "10.0.3" - resolved "https://registry.npmjs.org/cypress/-/cypress-10.0.3.tgz#889b4bef863b7d1ef1b608b85b964394ad350c5f" - integrity sha512-8C82XTybsEmJC9POYSNITGUhMLCRwB9LadP0x33H+52QVoBjhsWvIzrI+ybCe0+TyxaF0D5/9IL2kSTgjqCB9A== + version "10.3.0" + resolved "https://registry.npmjs.org/cypress/-/cypress-10.3.0.tgz#fae8d32f0822fcfb938e79c7c31ef344794336ae" + integrity sha512-txkQWKzvBVnWdCuKs5Xc08gjpO89W2Dom2wpZgT9zWZT5jXxqPIxqP/NC1YArtkpmp3fN5HW8aDjYBizHLUFvg== dependencies: "@cypress/request" "^2.88.10" "@cypress/xvfb" "^1.2.4" @@ -10666,10 +11154,10 @@ dagre@^0.8.5: graphlib "^2.1.8" lodash "^4.17.15" -damerau-levenshtein@^1.0.7: - version "1.0.7" - resolved "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.7.tgz#64368003512a1a6992593741a09a9d31a836f55d" - integrity sha512-VvdQIPGdWP0SqFXghj79Wf/5LArmreyMsGLa6FG6iC4t3j7j5s71TrwWmT/4akbDQIqjfACkLZmjXhA7g2oUZw== +damerau-levenshtein@^1.0.8: + version "1.0.8" + resolved "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7" + integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA== dargs@^7.0.0: version "7.0.0" @@ -10782,7 +11270,7 @@ debuglog@^1.0.1: decamelize-keys@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" - integrity sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk= + integrity sha512-ocLWuYzRPoS9bfiSdDd3cxvrzovVMZnRDVEzAs+hWIVXGDbHxWMECij2OBuyB/An0FFW/nLuq6Kv1i/YC5Qfzg== dependencies: decamelize "^1.1.0" map-obj "^1.0.0" @@ -10790,7 +11278,7 @@ decamelize-keys@^1.1.0: decamelize@^1.1.0, decamelize@^1.1.1, decamelize@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== decimal.js-light@^2.4.1: version "2.5.0" @@ -10865,7 +11353,7 @@ default-gateway@^6.0.3: defaults@^1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" - integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= + integrity sha512-s82itHOnYrN0Ib8r+z7laQz3sdE+4FP3d9Q7VLO7U+KRT+CR0GsWuyHxzdAY82I7cXv0G/twrqomTJLOssO5HA== dependencies: clone "^1.0.2" @@ -10884,14 +11372,7 @@ define-lazy-prop@^2.0.0: resolved "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== -define-properties@^1.1.3: - version "1.1.3" - resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" - integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== - dependencies: - object-keys "^1.0.12" - -define-properties@^1.1.4: +define-properties@^1.1.3, define-properties@^1.1.4: version "1.1.4" resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1" integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA== @@ -10999,9 +11480,9 @@ detect-indent@^5.0.0: integrity sha1-OHHMCmoALow+Wzz38zYmRnXwa50= detect-indent@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-6.0.0.tgz#0abd0f549f69fc6659a254fe96786186b6f528fd" - integrity sha512-oSyFlqaTHCItVRGK5RmrmjB+CmaMOW7IaNA/kdxqhoa6d17j/5ce9O9eWXmV/KEdRwqpQA+Vqe8a8Bsybu4YnA== + version "6.1.0" + resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz#592485ebbbf6b3b1ab2be175c8393d04ca0d57e6" + integrity sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA== detect-libc@^1.0.3: version "1.0.3" @@ -11036,10 +11517,10 @@ detect-port-alt@^1.1.6: address "^1.0.1" debug "^2.6.0" -devtools-protocol@0.0.1001819: - version "0.0.1001819" - resolved "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1001819.tgz#0a98f44cefdb02cc684f3d5e6bd898a1690231d9" - integrity sha512-G6OsIFnv/rDyxSqBa2lDLR6thp9oJioLsb2Gl+LbQlyoA9/OBAkrTU9jiCcQ8Pnh7z4d6slDiLaogR5hzgJLmQ== +devtools-protocol@0.0.1011705: + version "0.0.1011705" + resolved "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1011705.tgz#2582ed29f84848df83fba488122015540a744539" + integrity sha512-OKvTvu9n3swmgYshvsyVHYX0+aPzCoYUnyXUacfQMmFtBtBKewV/gT4I9jkAbpTqtTi2E4S9MXLlvzBDUlqg0Q== dezalgo@1.0.3, dezalgo@^1.0.0: version "1.0.3" @@ -11255,7 +11736,7 @@ dot-case@^3.0.4: no-case "^3.0.4" tslib "^2.0.3" -dot-prop@^5.1.0, dot-prop@^5.2.0: +dot-prop@^5.1.0: version "5.3.0" resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q== @@ -11279,7 +11760,7 @@ drange@^1.0.2: resolved "https://registry.npmjs.org/drange/-/drange-1.1.1.tgz#b2aecec2aab82fcef11dbbd7b9e32b83f8f6c0b8" integrity sha512-pYxfDYpued//QpnLIm4Avk7rsNtAtQkUES2cwAYSvD/wd2pKD71gN2Ebj3e7klzXwjocvE8c5vx/1fxwpqmSxA== -dset@^3.1.0, dset@^3.1.1: +dset@^3.1.0, dset@^3.1.1, dset@^3.1.2: version "3.1.2" resolved "https://registry.npmjs.org/dset/-/dset-3.1.2.tgz#89c436ca6450398396dc6538ea00abc0c54cd45a" integrity sha512-g/M9sqy3oHe477Ar4voQxWtaPIFw1jTdKZuomOjhCcBx9nHUNn0pu6NopuFFrTh/TRZIKEj+76vLWFu9BNKk+Q== @@ -11398,11 +11879,6 @@ emittery@^0.8.1: resolved "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz#bb23cc86d03b30aa75a7f734819dee2e1ba70860" integrity sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg== -emoji-regex@^7.0.1: - version "7.0.3" - resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" - integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== - emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" @@ -11551,7 +12027,7 @@ error@^10.4.0: resolved "https://registry.npmjs.org/error/-/error-10.4.0.tgz#6fcf0fd64bceb1e750f8ed9a3dd880f00e46a487" integrity sha512-YxIFEJuhgcICugOUvRx5th0UM+ActZ9sjY0QJmeVwsQdvosZ7kYzc9QqS0Da3R5iUmgU5meGIxh0xBeZpMVeLw== -es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2, es-abstract@^1.19.0, es-abstract@^1.19.1: +es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2, es-abstract@^1.19.1: version "1.19.1" resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3" integrity sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w== @@ -11577,7 +12053,7 @@ es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2, es-abstract@^1.19.0, es- string.prototype.trimstart "^1.0.4" unbox-primitive "^1.0.1" -es-abstract@^1.19.2, es-abstract@^1.19.5: +es-abstract@^1.19.0, es-abstract@^1.19.2, es-abstract@^1.19.5: version "1.20.1" resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz#027292cd6ef44bd12b1913b828116f54787d1814" integrity sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA== @@ -11632,75 +12108,75 @@ es6-error@^4.1.1: resolved "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg== -esbuild-android-64@0.14.43: - version "0.14.43" - resolved "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.43.tgz#59bf3edad6863c27aa92bbb5c1d83a9a5c981495" - integrity sha512-kqFXAS72K6cNrB6RiM7YJ5lNvmWRDSlpi7ZuRZ1hu1S3w0zlwcoCxWAyM23LQUyZSs1PbjHgdbbfYAN8IGh6xg== +esbuild-android-64@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.48.tgz#7e6394a0e517f738641385aaf553c7e4fb6d1ae3" + integrity sha512-3aMjboap/kqwCUpGWIjsk20TtxVoKck8/4Tu19rubh7t5Ra0Yrpg30Mt1QXXlipOazrEceGeWurXKeFJgkPOUg== -esbuild-android-arm64@0.14.43: - version "0.14.43" - resolved "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.43.tgz#0258704edf92ce2463af6d2900b844b5423bed63" - integrity sha512-bKS2BBFh+7XZY9rpjiHGRNA7LvWYbZWP87pLehggTG7tTaCDvj8qQGOU/OZSjCSKDYbgY7Q+oDw8RlYQ2Jt2BA== +esbuild-android-arm64@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.48.tgz#6877566be0f82dd5a43030c0007d06ece7f7c02f" + integrity sha512-vptI3K0wGALiDq+EvRuZotZrJqkYkN5282iAfcffjI5lmGG9G1ta/CIVauhY42MBXwEgDJkweiDcDMRLzBZC4g== -esbuild-darwin-64@0.14.43: - version "0.14.43" - resolved "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.43.tgz#72a47295678d4aa0656979baa8cf6d5c8c92656f" - integrity sha512-/3PSilx011ttoieRGkSZ0XV8zjBf2C9enV4ScMMbCT4dpx0mFhMOpFnCHkOK0pWGB8LklykFyHrWk2z6DENVUg== +esbuild-darwin-64@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.48.tgz#ea3caddb707d88f844b1aa1dea5ff3b0a71ef1fd" + integrity sha512-gGQZa4+hab2Va/Zww94YbshLuWteyKGD3+EsVon8EWTWhnHFRm5N9NbALNbwi/7hQ/hM1Zm4FuHg+k6BLsl5UA== -esbuild-darwin-arm64@0.14.43: - version "0.14.43" - resolved "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.43.tgz#5f5823170b8d85b888957f0794e186caac447aca" - integrity sha512-1HyFUKs8DMCBOvw1Qxpr5Vv/ThNcVIFb5xgXWK3pyT40WPvgYIiRTwJCvNs4l8i5qWF8/CK5bQxJVDjQvtv0Yw== +esbuild-darwin-arm64@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.48.tgz#4e5eaab54df66cc319b76a2ac0e8af4e6f0d9c2f" + integrity sha512-bFjnNEXjhZT+IZ8RvRGNJthLWNHV5JkCtuOFOnjvo5pC0sk2/QVk0Qc06g2PV3J0TcU6kaPC3RN9yy9w2PSLEA== -esbuild-freebsd-64@0.14.43: - version "0.14.43" - resolved "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.43.tgz#e4a48b08181053837e6cd9bda19ae0af94d493b0" - integrity sha512-FNWc05TPHYgaXjbPZO5/rJKSBslfG6BeMSs8GhwnqAKP56eEhvmzwnIz1QcC9cRVyO+IKqWNfmHFkCa1WJTULA== +esbuild-freebsd-64@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.48.tgz#47b5abc7426eae66861490ffbb380acc67af5b15" + integrity sha512-1NOlwRxmOsnPcWOGTB10JKAkYSb2nue0oM1AfHWunW/mv3wERfJmnYlGzL3UAOIUXZqW8GeA2mv+QGwq7DToqA== -esbuild-freebsd-arm64@0.14.43: - version "0.14.43" - resolved "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.43.tgz#386e780d36c1dedf3a1cdab79e0bbacd873274e6" - integrity sha512-amrYopclz3VohqisOPR6hA3GOWA3LZC1WDLnp21RhNmoERmJ/vLnOpnrG2P/Zao+/erKTCUqmrCIPVtj58DRoA== +esbuild-freebsd-arm64@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.48.tgz#e8c54c8637cd44feed967ea12338b0a4da3a7b11" + integrity sha512-gXqKdO8wabVcYtluAbikDH2jhXp+Klq5oCD5qbVyUG6tFiGhrC9oczKq3vIrrtwcxDQqK6+HDYK8Zrd4bCA9Gw== -esbuild-linux-32@0.14.43: - version "0.14.43" - resolved "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.43.tgz#040ed6b9ebf06d73acdf2acce7f1cd0c12fbc6a5" - integrity sha512-KoxoEra+9O3AKVvgDFvDkiuddCds6q71owSQEYwjtqRV7RwbPzKxJa6+uyzUulHcyGVq0g15K0oKG5CFBcvYDw== +esbuild-linux-32@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.48.tgz#229cf3246de2b7937c3ac13fac622d4d7a1344c5" + integrity sha512-ghGyDfS289z/LReZQUuuKq9KlTiTspxL8SITBFQFAFRA/IkIvDpnZnCAKTCjGXAmUqroMQfKJXMxyjJA69c/nQ== -esbuild-linux-64@0.14.43: - version "0.14.43" - resolved "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.43.tgz#8abbb7594ab6a008f2aae72d95d8a4fdc59d9000" - integrity sha512-EwINwGMyiJMgBby5/SbMqKcUhS5AYAZ2CpEBzSowsJPNBJEdhkCTtEjk757TN/wxgbu3QklqDM6KghY660QCUw== +esbuild-linux-64@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.48.tgz#7c0e7226c02c42aacc5656c36977493dc1e96c4f" + integrity sha512-vni3p/gppLMVZLghI7oMqbOZdGmLbbKR23XFARKnszCIBpEMEDxOMNIKPmMItQrmH/iJrL1z8Jt2nynY0bE1ug== -esbuild-linux-arm64@0.14.43: - version "0.14.43" - resolved "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.43.tgz#4e8e9ce77cbf7efec65e79e512b3d2fbd2da398f" - integrity sha512-UlSpjMWllAc70zYbHxWuDS3FJytyuR/gHJYBr8BICcTNb/TSOYVBg6U7b3jZ3mILTrgzwJUHwhEwK18FZDouUQ== +esbuild-linux-arm64@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.48.tgz#0af1eda474b5c6cc0cace8235b74d0cb8fcf57a7" + integrity sha512-3CFsOlpoxlKPRevEHq8aAntgYGYkE1N9yRYAcPyng/p4Wyx0tPR5SBYsxLKcgPB9mR8chHEhtWYz6EZ+H199Zw== -esbuild-linux-arm@0.14.43: - version "0.14.43" - resolved "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.43.tgz#9e41ee5e099c0ffdfd150da154330c2c0226cc96" - integrity sha512-e6YzQUoDxxtyamuF12eVzzRC7bbEFSZohJ6igQB9tBqnNmIQY3fI6Cns3z2wxtbZ3f2o6idkD2fQnlvs2902Dg== +esbuild-linux-arm@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.48.tgz#de4d1fa6b77cdcd00e2bb43dd0801e4680f0ab52" + integrity sha512-+VfSV7Akh1XUiDNXgqgY1cUP1i2vjI+BmlyXRfVz5AfV3jbpde8JTs5Q9sYgaoq5cWfuKfoZB/QkGOI+QcL1Tw== -esbuild-linux-mips64le@0.14.43: - version "0.14.43" - resolved "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.43.tgz#4b41f465a787f91cc4fe7dffa0dcabf655935a1a" - integrity sha512-f+v8cInPEL1/SDP//CfSYzcDNgE4CY3xgDV81DWm3KAPWzhvxARrKxB1Pstf5mB56yAslJDxu7ryBUPX207EZA== +esbuild-linux-mips64le@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.48.tgz#822c1778495f7868e990d4da47ad7281df28fd15" + integrity sha512-cs0uOiRlPp6ymknDnjajCgvDMSsLw5mST2UXh+ZIrXTj2Ifyf2aAP3Iw4DiqgnyYLV2O/v/yWBJx+WfmKEpNLA== -esbuild-linux-ppc64le@0.14.43: - version "0.14.43" - resolved "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.43.tgz#ca15934f5b46728dd9ac05270e783e7feaca9eaf" - integrity sha512-5wZYMDGAL/K2pqkdIsW+I4IR41kyfHr/QshJcNpUfK3RjB3VQcPWOaZmc+74rm4ZjVirYrtz+jWw0SgxtxRanA== +esbuild-linux-ppc64le@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.48.tgz#55de0a9ec4a48fedfe82a63e083164d001709447" + integrity sha512-+2F0vJMkuI0Wie/wcSPDCqXvSFEELH7Jubxb7mpWrA/4NpT+/byjxDz0gG6R1WJoeDefcrMfpBx4GFNN1JQorQ== -esbuild-linux-riscv64@0.14.43: - version "0.14.43" - resolved "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.43.tgz#70fce2b5a0605a67e58b5a357b0e00be1029836d" - integrity sha512-lYcAOUxp85hC7lSjycJUVSmj4/9oEfSyXjb/ua9bNl8afonaduuqtw7hvKMoKuYnVwOCDw4RSfKpcnIRDWq+Bw== +esbuild-linux-riscv64@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.48.tgz#cd2b7381880b2f4b21a5a598fb673492120f18a5" + integrity sha512-BmaK/GfEE+5F2/QDrIXteFGKnVHGxlnK9MjdVKMTfvtmudjY3k2t8NtlY4qemKSizc+QwyombGWTBDc76rxePA== -esbuild-linux-s390x@0.14.43: - version "0.14.43" - resolved "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.43.tgz#318d03b4f4ccc7fa44ac7562121cf4a4529e477a" - integrity sha512-27e43ZhHvhFE4nM7HqtUbMRu37I/4eNSUbb8FGZWszV+uLzMIsHDwLoBiJmw7G9N+hrehNPeQ4F5Ujad0DrUKQ== +esbuild-linux-s390x@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.48.tgz#4b319eca2a5c64637fc7397ffbd9671719cdb6bf" + integrity sha512-tndw/0B9jiCL+KWKo0TSMaUm5UWBLsfCKVdbfMlb3d5LeV9WbijZ8Ordia8SAYv38VSJWOEt6eDCdOx8LqkC4g== esbuild-loader@^2.18.0: version "2.19.0" @@ -11714,72 +12190,67 @@ esbuild-loader@^2.18.0: tapable "^2.2.0" webpack-sources "^2.2.0" -esbuild-netbsd-64@0.14.43: - version "0.14.43" - resolved "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.43.tgz#86130ce204ef0162a96e863b55851efecc92f423" - integrity sha512-2mH4QF6hHBn5zzAfxEI/2eBC0mspVsZ6UVo821LpAJKMvLJPBk3XJO5xwg7paDqSqpl7p6IRrAenW999AEfJhQ== +esbuild-netbsd-64@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.48.tgz#c27cde8b5cb55dcc227943a18ab078fb98d0adbf" + integrity sha512-V9hgXfwf/T901Lr1wkOfoevtyNkrxmMcRHyticybBUHookznipMOHoF41Al68QBsqBxnITCEpjjd4yAos7z9Tw== -esbuild-openbsd-64@0.14.43: - version "0.14.43" - resolved "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.43.tgz#0229dc2db2ded97b03bb93bba7646b30ffdf5d0d" - integrity sha512-ZhQpiZjvqCqO8jKdGp9+8k9E/EHSA+zIWOg+grwZasI9RoblqJ1QiZqqi7jfd6ZrrG1UFBNGe4m0NFxCFbMVbg== +esbuild-openbsd-64@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.48.tgz#af5ab2d1cb41f09064bba9465fc8bf1309150df1" + integrity sha512-+IHf4JcbnnBl4T52egorXMatil/za0awqzg2Vy6FBgPcBpisDWT2sVz/tNdrK9kAqj+GZG/jZdrOkj7wsrNTKA== -esbuild-sunos-64@0.14.43: - version "0.14.43" - resolved "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.43.tgz#17e316216eb9f1de25d52a9000356ae5b869e736" - integrity sha512-DgxSi9DaHReL9gYuul2rrQCAapgnCJkh3LSHPKsY26zytYppG0HgkgVF80zjIlvEsUbGBP/GHQzBtrezj/Zq1Q== +esbuild-sunos-64@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.48.tgz#db3ae20526055cf6fd5c4582676233814603ac54" + integrity sha512-77m8bsr5wOpOWbGi9KSqDphcq6dFeJyun8TA+12JW/GAjyfTwVtOnN8DOt6DSPUfEV+ltVMNqtXUeTeMAxl5KA== -esbuild-windows-32@0.14.43: - version "0.14.43" - resolved "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.43.tgz#a173757bc6dfd0f2656ff40b64f7f9290745778e" - integrity sha512-Ih3+2O5oExiqm0mY6YYE5dR0o8+AspccQ3vIAtRodwFvhuyGLjb0Hbmzun/F3Lw19nuhPMu3sW2fqIJ5xBxByw== +esbuild-windows-32@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.48.tgz#021ffceb0a3f83078262870da88a912293c57475" + integrity sha512-EPgRuTPP8vK9maxpTGDe5lSoIBHGKO/AuxDncg5O3NkrPeLNdvvK8oywB0zGaAZXxYWfNNSHskvvDgmfVTguhg== -esbuild-windows-64@0.14.43: - version "0.14.43" - resolved "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.43.tgz#c447b23126aad158c4fe6a394342cafd97926ed1" - integrity sha512-8NsuNfI8xwFuJbrCuI+aBqNTYkrWErejFO5aYM+yHqyHuL8mmepLS9EPzAzk8rvfaJrhN0+RvKWAcymViHOKEw== +esbuild-windows-64@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.48.tgz#a4d3407b580f9faac51f61eec095fa985fb3fee4" + integrity sha512-YmpXjdT1q0b8ictSdGwH3M8VCoqPpK1/UArze3X199w6u8hUx3V8BhAi1WjbsfDYRBanVVtduAhh2sirImtAvA== -esbuild-windows-arm64@0.14.43: - version "0.14.43" - resolved "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.43.tgz#3caed1b430d394d7a7836407b9d36c4750246e76" - integrity sha512-7ZlD7bo++kVRblJEoG+cepljkfP8bfuTPz5fIXzptwnPaFwGS6ahvfoYzY7WCf5v/1nX2X02HDraVItTgbHnKw== +esbuild-windows-arm64@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.48.tgz#762c0562127d8b09bfb70a3c816460742dd82880" + integrity sha512-HHaOMCsCXp0rz5BT2crTka6MPWVno121NKApsGs/OIW5QC0ggC69YMGs1aJct9/9FSUF4A1xNE/cLvgB5svR4g== esbuild@^0.14.1, esbuild@^0.14.10, esbuild@^0.14.39: - version "0.14.43" - resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.14.43.tgz#c227d585c512d3e0f23b88f50b8e16501147f647" - integrity sha512-Uf94+kQmy/5jsFwKWiQB4hfo/RkM9Dh7b79p8yqd1tshULdr25G2szLz631NoH3s2ujnKEKVD16RmOxvCNKRFA== + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.14.48.tgz#da5d8d25cd2d940c45ea0cfecdca727f7aee2b85" + integrity sha512-w6N1Yn5MtqK2U1/WZTX9ZqUVb8IOLZkZ5AdHkT6x3cHDMVsYWC7WPdiLmx19w3i4Rwzy5LqsEMtVihG3e4rFzA== optionalDependencies: - esbuild-android-64 "0.14.43" - esbuild-android-arm64 "0.14.43" - esbuild-darwin-64 "0.14.43" - esbuild-darwin-arm64 "0.14.43" - esbuild-freebsd-64 "0.14.43" - esbuild-freebsd-arm64 "0.14.43" - esbuild-linux-32 "0.14.43" - esbuild-linux-64 "0.14.43" - esbuild-linux-arm "0.14.43" - esbuild-linux-arm64 "0.14.43" - esbuild-linux-mips64le "0.14.43" - esbuild-linux-ppc64le "0.14.43" - esbuild-linux-riscv64 "0.14.43" - esbuild-linux-s390x "0.14.43" - esbuild-netbsd-64 "0.14.43" - esbuild-openbsd-64 "0.14.43" - esbuild-sunos-64 "0.14.43" - esbuild-windows-32 "0.14.43" - esbuild-windows-64 "0.14.43" - esbuild-windows-arm64 "0.14.43" + esbuild-android-64 "0.14.48" + esbuild-android-arm64 "0.14.48" + esbuild-darwin-64 "0.14.48" + esbuild-darwin-arm64 "0.14.48" + esbuild-freebsd-64 "0.14.48" + esbuild-freebsd-arm64 "0.14.48" + esbuild-linux-32 "0.14.48" + esbuild-linux-64 "0.14.48" + esbuild-linux-arm "0.14.48" + esbuild-linux-arm64 "0.14.48" + esbuild-linux-mips64le "0.14.48" + esbuild-linux-ppc64le "0.14.48" + esbuild-linux-riscv64 "0.14.48" + esbuild-linux-s390x "0.14.48" + esbuild-netbsd-64 "0.14.48" + esbuild-openbsd-64 "0.14.48" + esbuild-sunos-64 "0.14.48" + esbuild-windows-32 "0.14.48" + esbuild-windows-64 "0.14.48" + esbuild-windows-arm64 "0.14.48" escalade@^3.1.1: version "3.1.1" resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== -escape-goat@^2.0.0: - version "2.1.1" - resolved "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675" - integrity sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q== - escape-html@^1.0.3, escape-html@~1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" @@ -11788,7 +12259,7 @@ escape-html@^1.0.3, escape-html@~1.0.3: escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== escape-string-regexp@^2.0.0: version "2.0.0" @@ -11892,22 +12363,23 @@ eslint-plugin-jest@^26.1.2: "@typescript-eslint/utils" "^5.10.0" eslint-plugin-jsx-a11y@^6.5.1: - version "6.5.1" - resolved "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.5.1.tgz#cdbf2df901040ca140b6ec14715c988889c2a6d8" - integrity sha512-sVCFKX9fllURnXT2JwLN5Qgo24Ug5NF6dxhkmxsMEUZhXRcGg+X3e1JbJ84YePQKBl5E0ZjAH5Q4rkdcGY99+g== + version "6.6.0" + resolved "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.6.0.tgz#2c5ac12e013eb98337b9aa261c3b355275cc6415" + integrity sha512-kTeLuIzpNhXL2CwLlc8AHI0aFRwWHcg483yepO9VQiHzM9bZwJdzTkzBszbuPrbgGmq2rlX/FaT2fJQsjUSHsw== dependencies: - "@babel/runtime" "^7.16.3" + "@babel/runtime" "^7.18.3" aria-query "^4.2.2" - array-includes "^3.1.4" + array-includes "^3.1.5" ast-types-flow "^0.0.7" - axe-core "^4.3.5" + axe-core "^4.4.2" axobject-query "^2.2.0" - damerau-levenshtein "^1.0.7" + damerau-levenshtein "^1.0.8" emoji-regex "^9.2.2" has "^1.0.3" - jsx-ast-utils "^3.2.1" + jsx-ast-utils "^3.3.1" language-tags "^1.0.5" - minimatch "^3.0.4" + minimatch "^3.1.2" + semver "^6.3.0" eslint-plugin-monorepo@^0.3.2: version "0.3.2" @@ -11932,14 +12404,14 @@ eslint-plugin-notice@^0.9.10: metric-lcs "^0.1.2" eslint-plugin-react-hooks@^4.3.0: - version "4.5.0" - resolved "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.5.0.tgz#5f762dfedf8b2cf431c689f533c9d3fa5dcf25ad" - integrity sha512-8k1gRt7D7h03kd+SAAlzXkQwWK22BnK6GKZG+FJA6BAGy22CFvl8kCIXKpVux0cCxMWDQUPqSok0LKaZ0aOcCw== + version "4.6.0" + resolved "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz#4c3e697ad95b77e93f8646aaa1630c1ba607edd3" + integrity sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g== eslint-plugin-react@^7.28.0: - version "7.30.0" - resolved "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.30.0.tgz#8e7b1b2934b8426ac067a0febade1b13bd7064e3" - integrity sha512-RgwH7hjW48BleKsYyHK5vUAvxtE9SMPDKmcPRQgtRCYaZA0XQPt5FSkrU3nhz5ifzMZcA8opwmRJ2cmOO8tr5A== + version "7.30.1" + resolved "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.30.1.tgz#2be4ab23ce09b5949c6631413ba64b2810fd3e22" + integrity sha512-NbEvI9jtqO46yJA3wcRF9Mo0lF9T/jhdHqhCHXiXtD+Zcb98812wvokjWpU7Q4QH5edo6dmqrukxVvWWXHlsUg== dependencies: array-includes "^3.1.5" array.prototype.flatmap "^1.3.0" @@ -11990,20 +12462,20 @@ eslint-visitor-keys@^3.0.0, eslint-visitor-keys@^3.3.0: integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== eslint-webpack-plugin@^3.1.1: - version "3.1.1" - resolved "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-3.1.1.tgz#83dad2395e5f572d6f4d919eedaa9cf902890fcb" - integrity sha512-xSucskTN9tOkfW7so4EaiFIkulWLXwCB/15H917lR6pTv0Zot6/fetFucmENRb7J5whVSFKIvwnrnsa78SG2yg== + version "3.2.0" + resolved "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-3.2.0.tgz#1978cdb9edc461e4b0195a20da950cf57988347c" + integrity sha512-avrKcGncpPbPSUHX6B3stNGzkKFto3eL+DKM4+VyMrVnhPc3vRczVlCq3uhuFOdRvDHTVXuzwk1ZKUrqDQHQ9w== dependencies: - "@types/eslint" "^7.28.2" - jest-worker "^27.3.1" - micromatch "^4.0.4" + "@types/eslint" "^7.29.0 || ^8.4.1" + jest-worker "^28.0.2" + micromatch "^4.0.5" normalize-path "^3.0.0" - schema-utils "^3.1.1" + schema-utils "^4.0.0" eslint@^8.6.0: - version "8.17.0" - resolved "https://registry.npmjs.org/eslint/-/eslint-8.17.0.tgz#1cfc4b6b6912f77d24b874ca1506b0fe09328c21" - integrity sha512-gq0m0BTJfci60Fz4nczYxNAlED+sMcihltndR8t9t1evnU/azx53x3t2UHXC/uRjcbvRw/XctpaNygSTcQD+Iw== + version "8.19.0" + resolved "https://registry.npmjs.org/eslint/-/eslint-8.19.0.tgz#7342a3cbc4fbc5c106a1eefe0fd0b50b6b1a7d28" + integrity sha512-SXOPj3x9VKvPe81TjjUJCYlV4oJjQw68Uek+AM0X4p+33dj2HY5bpTZOgnQHcG2eAm1mtCU9uNMnJi7exU/kYw== dependencies: "@eslint/eslintrc" "^1.3.0" "@humanwhocodes/config-array" "^0.9.2" @@ -12161,63 +12633,63 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: safe-buffer "^5.1.1" "example-app@link:packages/app": - version "0.2.72" + version "0.2.73-next.2" dependencies: - "@backstage/app-defaults" "^1.0.3" - "@backstage/catalog-model" "^1.0.3" - "@backstage/cli" "^0.17.2" + "@backstage/app-defaults" "^1.0.4-next.2" + "@backstage/catalog-model" "^1.1.0-next.2" + "@backstage/cli" "^0.18.0-next.2" "@backstage/config" "^1.0.1" - "@backstage/core-app-api" "^1.0.3" - "@backstage/core-components" "^0.9.5" + "@backstage/core-app-api" "^1.0.4-next.0" + "@backstage/core-components" "^0.10.0-next.2" "@backstage/core-plugin-api" "^1.0.3" - "@backstage/integration-react" "^1.1.1" - "@backstage/plugin-airbrake" "^0.3.6" - "@backstage/plugin-apache-airflow" "^0.1.14" - "@backstage/plugin-api-docs" "^0.8.6" - "@backstage/plugin-azure-devops" "^0.1.22" - "@backstage/plugin-badges" "^0.2.30" - "@backstage/plugin-catalog" "^1.3.0" - "@backstage/plugin-catalog-common" "^1.0.3" - "@backstage/plugin-catalog-graph" "^0.2.18" - "@backstage/plugin-catalog-import" "^0.8.9" - "@backstage/plugin-catalog-react" "^1.1.1" - "@backstage/plugin-circleci" "^0.3.6" - "@backstage/plugin-cloudbuild" "^0.3.6" - "@backstage/plugin-code-coverage" "^0.1.33" - "@backstage/plugin-cost-insights" "^0.11.28" - "@backstage/plugin-dynatrace" "^0.1.0" - "@backstage/plugin-explore" "^0.3.37" - "@backstage/plugin-gcalendar" "^0.3.2" - "@backstage/plugin-gcp-projects" "^0.3.25" - "@backstage/plugin-github-actions" "^0.5.6" - "@backstage/plugin-gocd" "^0.1.12" - "@backstage/plugin-graphiql" "^0.2.38" - "@backstage/plugin-home" "^0.4.22" - "@backstage/plugin-jenkins" "^0.7.5" - "@backstage/plugin-kafka" "^0.3.6" - "@backstage/plugin-kubernetes" "^0.6.6" - "@backstage/plugin-lighthouse" "^0.3.6" - "@backstage/plugin-newrelic" "^0.3.24" - "@backstage/plugin-newrelic-dashboard" "^0.1.14" - "@backstage/plugin-org" "^0.5.6" - "@backstage/plugin-pagerduty" "0.4.0" - "@backstage/plugin-permission-react" "^0.4.2" - "@backstage/plugin-rollbar" "^0.4.6" - "@backstage/plugin-scaffolder" "^1.3.0" - "@backstage/plugin-search" "^0.9.0" - "@backstage/plugin-search-common" "^0.3.5" - "@backstage/plugin-search-react" "^0.2.1" - "@backstage/plugin-sentry" "^0.3.44" - "@backstage/plugin-shortcuts" "^0.2.7" - "@backstage/plugin-stack-overflow" "^0.1.2" - "@backstage/plugin-tech-insights" "^0.2.2" - "@backstage/plugin-tech-radar" "^0.5.13" - "@backstage/plugin-techdocs" "^1.2.0" - "@backstage/plugin-techdocs-module-addons-contrib" "^1.0.1" - "@backstage/plugin-techdocs-react" "^1.0.1" - "@backstage/plugin-todo" "^0.2.8" - "@backstage/plugin-user-settings" "^0.4.5" - "@backstage/theme" "^0.2.15" + "@backstage/integration-react" "^1.1.2-next.2" + "@backstage/plugin-airbrake" "^0.3.7-next.2" + "@backstage/plugin-apache-airflow" "^0.2.0-next.2" + "@backstage/plugin-api-docs" "^0.8.7-next.2" + "@backstage/plugin-azure-devops" "^0.1.23-next.2" + "@backstage/plugin-badges" "^0.2.31-next.2" + "@backstage/plugin-catalog" "^1.4.0-next.2" + "@backstage/plugin-catalog-common" "^1.0.4-next.0" + "@backstage/plugin-catalog-graph" "^0.2.19-next.2" + "@backstage/plugin-catalog-import" "^0.8.10-next.2" + "@backstage/plugin-catalog-react" "^1.1.2-next.2" + "@backstage/plugin-circleci" "^0.3.7-next.2" + "@backstage/plugin-cloudbuild" "^0.3.7-next.2" + "@backstage/plugin-code-coverage" "^0.1.34-next.2" + "@backstage/plugin-cost-insights" "^0.11.29-next.2" + "@backstage/plugin-dynatrace" "^0.1.1-next.2" + "@backstage/plugin-explore" "^0.3.38-next.2" + "@backstage/plugin-gcalendar" "^0.3.3-next.2" + "@backstage/plugin-gcp-projects" "^0.3.26-next.2" + "@backstage/plugin-github-actions" "^0.5.7-next.2" + "@backstage/plugin-gocd" "^0.1.13-next.2" + "@backstage/plugin-graphiql" "^0.2.39-next.2" + "@backstage/plugin-home" "^0.4.23-next.2" + "@backstage/plugin-jenkins" "^0.7.6-next.2" + "@backstage/plugin-kafka" "^0.3.7-next.2" + "@backstage/plugin-kubernetes" "^0.6.7-next.2" + "@backstage/plugin-lighthouse" "^0.3.7-next.2" + "@backstage/plugin-newrelic" "^0.3.25-next.2" + "@backstage/plugin-newrelic-dashboard" "^0.1.15-next.2" + "@backstage/plugin-org" "^0.5.7-next.2" + "@backstage/plugin-pagerduty" "0.5.0-next.2" + "@backstage/plugin-permission-react" "^0.4.3-next.0" + "@backstage/plugin-rollbar" "^0.4.7-next.2" + "@backstage/plugin-scaffolder" "^1.4.0-next.2" + "@backstage/plugin-search" "^0.9.1-next.2" + "@backstage/plugin-search-common" "^0.3.6-next.0" + "@backstage/plugin-search-react" "^0.2.2-next.2" + "@backstage/plugin-sentry" "^0.3.45-next.2" + "@backstage/plugin-shortcuts" "^0.2.8-next.2" + "@backstage/plugin-stack-overflow" "^0.1.3-next.2" + "@backstage/plugin-tech-insights" "^0.2.3-next.2" + "@backstage/plugin-tech-radar" "^0.5.14-next.2" + "@backstage/plugin-techdocs" "^1.2.1-next.2" + "@backstage/plugin-techdocs-module-addons-contrib" "^1.0.2-next.2" + "@backstage/plugin-techdocs-react" "^1.0.2-next.1" + "@backstage/plugin-todo" "^0.2.9-next.2" + "@backstage/plugin-user-settings" "^0.4.6-next.2" + "@backstage/theme" "^0.2.16-next.1" "@material-ui/core" "^4.12.2" "@material-ui/icons" "^4.9.1" "@material-ui/lab" "4.0.0-alpha.57" @@ -12360,9 +12832,9 @@ expect@^27.5.1: jest-message-util "^27.5.1" express-prom-bundle@^6.3.6: - version "6.4.1" - resolved "https://registry.npmjs.org/express-prom-bundle/-/express-prom-bundle-6.4.1.tgz#a688050b9e090f6969825c33143106d3e0e5a70e" - integrity sha512-Sg0svLQe/SS5z1tHDTVfZVjNumobiDlXM0jmemt5Dm9K6BX8z9yCwEr93zbko6fNMR4zKav77iPfxUWi6gAjNA== + version "6.5.0" + resolved "https://registry.npmjs.org/express-prom-bundle/-/express-prom-bundle-6.5.0.tgz#cdf28b29907618cae933ed14d5b727f7404e810b" + integrity sha512-paFAm0FK7TV1Ln6Blh9edDt2mJ4Pk6Py/fjhZDMcoMHENYryBjCpnXDXuCu8NE1kkvp58IrPcAAkNeNqdvZnnw== dependencies: on-finished "^2.3.0" url-value-parser "^2.0.0" @@ -12924,7 +13396,7 @@ form-data-encoder@^1.4.3, form-data-encoder@^1.7.1: resolved "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.1.tgz#ac80660e4f87ee0d3d3c3638b7da8278ddb8ec96" integrity sha512-EFRDrsMm/kyqbTQocNvRXMLjc7Es2Vk+IQFx/YW7hkUH1eBl4J1fqiP34l74Yt0pFLCNpc06fkbVk00008mzjg== -form-data@^2.3.1, form-data@^2.3.2, form-data@^2.5.0: +form-data@^2.3.2, form-data@^2.5.0: version "2.5.1" resolved "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz#f2cbec57b5e59e23716e128fe44d4e5dd23895f4" integrity sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA== @@ -12981,11 +13453,6 @@ formdata-node@^4.3.1: node-domexception "1.0.0" web-streams-polyfill "4.0.0-beta.1" -formidable@^1.2.0: - version "1.2.6" - resolved "https://registry.npmjs.org/formidable/-/formidable-1.2.6.tgz#d2a51d60162bbc9b4a055d8457a7c75315d1a168" - integrity sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ== - formidable@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/formidable/-/formidable-2.0.1.tgz#4310bc7965d185536f9565184dee74fbb75557ff" @@ -13235,6 +13702,14 @@ gcp-metadata@^5.0.0: gaxios "^5.0.0" json-bigint "^1.0.0" +gendocu-public-apis@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/gendocu-public-apis/-/gendocu-public-apis-1.0.0.tgz#ba9212207c6b4c9ba131b6cafb82deb07f068010" + integrity sha512-2XbY+joWdhBK2Z7b5NaP8+3NkOYZjHkqux83lpgdShp1QN9eu10s/MojCaJ7WiCTB7ZKIkfqUtWgWipDxDPjpw== + dependencies: + "@improbable-eng/grpc-web" "^0.14.0" + google-protobuf "^3.15.8" + generate-function@^2.3.1: version "2.3.1" resolved "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz#f069617690c10c868e73b8465746764f97c3479f" @@ -13265,13 +13740,13 @@ get-caller-file@^2.0.1, get-caller-file@^2.0.5: integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" - integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== + version "1.1.2" + resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz#336975123e05ad0b7ba41f152ee4aadbea6cf598" + integrity sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA== dependencies: function-bind "^1.1.1" has "^1.0.3" - has-symbols "^1.0.1" + has-symbols "^1.0.3" get-monorepo-packages@^1.1.0: version "1.2.0" @@ -13392,6 +13867,14 @@ git-up@^4.0.0: is-ssh "^1.3.0" parse-url "^5.0.0" +git-up@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/git-up/-/git-up-6.0.0.tgz#dbd6e4eee270338be847a0601e6d0763c90b74db" + integrity sha512-6RUFSNd1c/D0xtGnyWN2sxza2bZtZ/EmI9448n6rCZruFwV/ezeEn2fJP7XnUQGwf0RAtd/mmUCbtH6JPYA2SA== + dependencies: + is-ssh "^1.4.0" + parse-url "^7.0.2" + git-url-parse@^11.4.4, git-url-parse@^11.6.0: version "11.6.0" resolved "https://registry.npmjs.org/git-url-parse/-/git-url-parse-11.6.0.tgz#c634b8de7faa66498a2b88932df31702c67df605" @@ -13399,6 +13882,13 @@ git-url-parse@^11.4.4, git-url-parse@^11.6.0: dependencies: git-up "^4.0.0" +git-url-parse@^12.0.0: + version "12.0.0" + resolved "https://registry.npmjs.org/git-url-parse/-/git-url-parse-12.0.0.tgz#4ba70bc1e99138321c57e3765aaf7428e5abb793" + integrity sha512-I6LMWsxV87vysX1WfsoglXsXg6GjQRKq7+Dgiseo+h0skmp5Hp2rzmcEIRQot9CPA+uzU7x1x7jZdqvTFGnB+Q== + dependencies: + git-up "^6.0.0" + gitconfiglocal@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz#41d045f3851a5ea88f03f24ca1c6178114464b9b" @@ -13552,7 +14042,7 @@ globby@^7.1.1: pify "^3.0.0" slash "^1.0.0" -google-auth-library@^7.14.0, google-auth-library@^7.6.1: +google-auth-library@^7.14.0: version "7.14.1" resolved "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.14.1.tgz#e3483034162f24cc71b95c8a55a210008826213c" integrity sha512-5Rk7iLNDFhFeBYc3s8l1CqzbEBcdhwR193RlD4vSNFajIcINKI8W8P0JLmBpwymHqqWbX34pJDQu39cSy/6RsA== @@ -13567,10 +14057,10 @@ google-auth-library@^7.14.0, google-auth-library@^7.6.1: jws "^4.0.0" lru-cache "^6.0.0" -google-auth-library@^8.0.1, google-auth-library@^8.0.2: - version "8.0.2" - resolved "https://registry.npmjs.org/google-auth-library/-/google-auth-library-8.0.2.tgz#5fa0f2d3795c3e4019d2bb315ade4454cc9c30b5" - integrity sha512-HoG+nWFAThLovKpvcbYzxgn+nBJPTfAwtq0GxPN821nOO+21+8oP7MoEHfd1sbDulUFFGfcjJr2CnJ4YssHcyg== +google-auth-library@^8.0.0, google-auth-library@^8.0.1, google-auth-library@^8.0.2: + version "8.1.0" + resolved "https://registry.npmjs.org/google-auth-library/-/google-auth-library-8.1.0.tgz#879e8d2e90a9d47e6eab32fd1d5fd9ed52d7d441" + integrity sha512-J/fNXEnqLgbr3kmeUshZCtHQia6ZiNbbrebVzpt/+LTeY6Ka9CtbQvloTjVGVO7nyYbs0KYeuIwgUC/t2Gp1Jw== dependencies: arrify "^2.0.0" base64-js "^1.3.0" @@ -13578,7 +14068,7 @@ google-auth-library@^8.0.1, google-auth-library@^8.0.2: fast-text-encoding "^1.0.0" gaxios "^5.0.0" gcp-metadata "^5.0.0" - gtoken "^5.3.2" + gtoken "^6.0.0" jws "^4.0.0" lru-cache "^6.0.0" @@ -13627,14 +14117,19 @@ google-p12-pem@^3.0.3: dependencies: node-forge "^1.0.0" -google-p12-pem@^3.1.3: - version "3.1.4" - resolved "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.1.4.tgz#123f7b40da204de4ed1fbf2fd5be12c047fc8b3b" - integrity sha512-HHuHmkLgwjdmVRngf5+gSmpkyaRI6QmOg77J8tkNBHhNEI62sGHyw4/+UkgyZEI7h84NbWprXDJ+sa3xOYFvTg== +google-p12-pem@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-4.0.0.tgz#f46581add1dc6ea0b96160cda6ce37ee35ab8ca3" + integrity sha512-lRTMn5ElBdDixv4a86bixejPSRk1boRtUowNepeKEVvYiFlkLuAJUVpEz6PfObDHYEKnZWq/9a2zC98xu62A9w== dependencies: node-forge "^1.3.1" -got@11.8.3, got@^11.8.0: +google-protobuf@^3.15.8, google-protobuf@^3.19.1: + version "3.20.1" + resolved "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.20.1.tgz#1b255c2b59bcda7c399df46c65206aa3c7a0ce8b" + integrity sha512-XMf1+O32FjYIV3CYu6Tuh5PNbfNEU5Xu22X+Xkdb/DUexFlCzhvv7d5Iirm4AOwn8lv4al1YvIhzGrg2j9Zfzw== + +got@11.8.3: version "11.8.3" resolved "https://registry.npmjs.org/got/-/got-11.8.3.tgz#f496c8fdda5d729a90b4905d2b07dbd148170770" integrity sha512-7gtQ5KiPh1RtGS9/Jbv1ofDpBFuq42gyfEib+ejaRBJuj/3tQFeR5+gw57e4ipaU8c/rCjvX6fkQz2lyDlGAOg== @@ -13651,6 +14146,23 @@ got@11.8.3, got@^11.8.0: p-cancelable "^2.0.0" responselike "^2.0.0" +got@^11.8.0: + version "11.8.5" + resolved "https://registry.npmjs.org/got/-/got-11.8.5.tgz#ce77d045136de56e8f024bebb82ea349bc730046" + integrity sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ== + 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.2" + decompress-response "^6.0.0" + http2-wrapper "^1.0.0-beta.5.2" + lowercase-keys "^2.0.0" + p-cancelable "^2.0.0" + responselike "^2.0.0" + got@^9.6.0: version "9.6.0" resolved "https://registry.npmjs.org/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" @@ -13668,12 +14180,12 @@ got@^9.6.0: to-readable-stream "^1.0.0" url-parse-lax "^3.0.0" -graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.5, graceful-fs@^4.2.2, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: +graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.2.2, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: version "4.2.9" resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== -graceful-fs@^4.1.6, graceful-fs@^4.2.0: +graceful-fs@^4.1.2, graceful-fs@^4.1.5, graceful-fs@^4.1.6, graceful-fs@^4.2.0: version "4.2.10" resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== @@ -13684,14 +14196,14 @@ grapheme-splitter@^1.0.4: integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== graphiql@^1.5.12, graphiql@^1.8.8: - version "1.9.7" - resolved "https://registry.npmjs.org/graphiql/-/graphiql-1.9.7.tgz#2edadea4fbbd723f9ba27a1f464f4ff5b20866bd" - integrity sha512-rn0njwDkCpFn5GwDbSuzt7GwjiFLhYCdgiscYm4n8Oq9EeOyGrIxQK/PjUz1YaR/+T7lg1raIBuRAX/Nei9KcQ== + version "1.9.10" + resolved "https://registry.npmjs.org/graphiql/-/graphiql-1.9.10.tgz#ba7113ed8b1bc988d00d8d7cc51901b51b684bde" + integrity sha512-uYYK/zBTV9Y/IHw4uopGVRusbF2xmPnptx7OMFTnTHOTQOmzfIGRTn58WuPgevyEi+9zSLojM86lot9xvNA1/w== dependencies: - "@graphiql/react" "^0.4.1" + "@graphiql/react" "^0.4.3" "@graphiql/toolkit" "^0.6.0" entities "^2.0.0" - graphql-language-service "^5.0.5" + graphql-language-service "^5.0.6" markdown-it "^12.2.0" graphlib@^2.1.8: @@ -13723,23 +14235,23 @@ graphql-executor@0.0.23: resolved "https://registry.npmjs.org/graphql-executor/-/graphql-executor-0.0.23.tgz#205c1764b39ee0fcf611553865770f37b45851a2" integrity sha512-3Ivlyfjaw3BWmGtUSnMpP/a4dcXCp0mJtj0PiPG14OKUizaMKlSEX+LX2Qed0LrxwniIwvU6B4w/koVjEPyWJg== -graphql-language-service@^5.0.5: - version "5.0.5" - resolved "https://registry.npmjs.org/graphql-language-service/-/graphql-language-service-5.0.5.tgz#894c08bee50070c97cc53ae514847aeef41bc0ac" - integrity sha512-hekBLI73r6ghShWrIMJ7Pe4Z+yJrda/U+kLenNJLNswuCrR0XfFOv5pNtnSXLcjFZkQfY1bwGV0D8IVKZEOW5Q== +graphql-language-service@^5.0.6: + version "5.0.6" + resolved "https://registry.npmjs.org/graphql-language-service/-/graphql-language-service-5.0.6.tgz#7fd1e6479e5c3074b070c760fa961d9ad1ed7c72" + integrity sha512-FjE23aTy45Lr5metxCv3ZgSKEZOzN7ERR+OFC1isV5mHxI0Ob8XxayLTYjQKrs8b3kOpvgTYmSmu6AyXOzYslg== dependencies: nullthrows "^1.0.0" vscode-languageserver-types "^3.15.1" graphql-modules@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/graphql-modules/-/graphql-modules-2.0.0.tgz#5f710d86eb7295da83769c8cd6d61a049d999800" - integrity sha512-CM5CIJp428+ripgcLyrioBmAKB3ucvIEOgJG4WMjnOgScHY/eCZh/8I51cF8oc+pqebOgBCR3HH//IH5v7kv+w== + version "2.1.0" + resolved "https://registry.npmjs.org/graphql-modules/-/graphql-modules-2.1.0.tgz#d99692034b4b053fba3d0ebe49e4e66772ed2785" + integrity sha512-fOUc4i5xNLkRxqx234MIr+kolrxk1tZ2onTeRIcB73mCY4NeKxej7FMLb5St+UcNLzhqM4L6Mf47rN9MPVDmgA== dependencies: - "@graphql-tools/schema" "^8.1.1" + "@graphql-tools/schema" "^8.3.1" "@graphql-tools/wrap" "^8.3.1" "@graphql-typed-document-node/core" "^3.1.0" - ramda "^0.27.1" + ramda "^0.28.0" graphql-request@^4.0.0: version "4.2.0" @@ -13763,9 +14275,9 @@ graphql-type-json@^0.3.2: integrity sha512-J+vjof74oMlCWXSvt0DOf2APEdZOCdubEvGDUAlqH//VBYcOYsGgRW7Xzorr44LvkjiuvecWc8fChxuZZbChtg== graphql-ws@^5.4.1: - version "5.8.2" - resolved "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.8.2.tgz#800184b1addb20b3010dc06cb70877703a5fff20" - integrity sha512-hYo8kTGzxePFJtMGC7Y4cbypwifMphIJJ7n4TDcVUAfviRwQBnmZAbfZlC+XFwWDUaR7raEDQPxWctpccmE0JQ== + version "5.9.1" + resolved "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.9.1.tgz#9c0fa48ceb695d61d574ed3ab21b426729e87f2d" + integrity sha512-mL/SWGBwIT9Meq0NlfS55yXXTOeWPMbK7bZBEZhFu46bcGk1coTx2Sdtzxdk+9yHWngD+Fk1PZDWaAutQa9tpw== graphql@^16.0.0, graphql@^16.3.0: version "16.5.0" @@ -13777,6 +14289,26 @@ grouped-queue@^2.0.0: resolved "https://registry.npmjs.org/grouped-queue/-/grouped-queue-2.0.0.tgz#a2c6713f2171e45db2c300a3a9d7c119d694dac8" integrity sha512-/PiFUa7WIsl48dUeCvhIHnwNmAAzlI/eHoJl0vu3nsFA366JleY7Ff8EVTplZu5kO0MIdZjKTTnzItL61ahbnw== +grpc-docs@^1.0.6, grpc-docs@^1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/grpc-docs/-/grpc-docs-1.1.2.tgz#021d065f8a386bdc07d16f80a8ab604cddefba06" + integrity sha512-IUQJpDNgCgq5aL1OWkcvK2Yeky0tscEOI0rDLb4fNxXAOgamrsEI/14aNX+DRzGq3gs/NTF9xU7YqN2kj3OiFA== + dependencies: + "@improbable-eng/grpc-web" "^0.15.0" + "@types/minimatch" "^3.0.5" + gendocu-public-apis "^1.0.0" + google-protobuf "^3.19.1" + grpc-docs "^1.0.6" + js-yaml "^4.1.0" + minimatch "^3.0.4" + react-copy-to-clipboard "^5.0.4" + react-dom "^16.13.1" + react-is "^16.8.0" + react-syntax-highlighter "^15.4.5" + rollup "^0.60" + rollup-plugin-smart-asset "^2.1.2" + styled-components "^5.3.3" + gtoken@^5.0.4: version "5.1.0" resolved "https://registry.npmjs.org/gtoken/-/gtoken-5.1.0.tgz#4ba8d2fc9a8459098f76e7e8fd7beaa39fda9fe4" @@ -13787,13 +14319,13 @@ gtoken@^5.0.4: jws "^4.0.0" mime "^2.2.0" -gtoken@^5.3.2: - version "5.3.2" - resolved "https://registry.npmjs.org/gtoken/-/gtoken-5.3.2.tgz#deb7dc876abe002178e0515e383382ea9446d58f" - integrity sha512-gkvEKREW7dXWF8NV8pVrKfW7WqReAmjjkMBh6lNCCGOM4ucS0r0YyXXl0r/9Yj8wcW/32ISkfc8h5mPTDbtifQ== +gtoken@^6.0.0: + version "6.0.1" + resolved "https://registry.npmjs.org/gtoken/-/gtoken-6.0.1.tgz#1276371d51e93c4eface76e3f30f9e8f1cad3f1a" + integrity sha512-J0vebk6u6i4rLTM0lQq25SdusCLMvujYNZeAouyPvSbGlcjw7P8L3W9INIFnlXUx+AUD7TDoM1mgdhzH+XX7DQ== dependencies: gaxios "^4.0.0" - google-p12-pem "^3.1.3" + google-p12-pem "^4.0.0" jws "^4.0.0" gzip-size@^6.0.0: @@ -13850,12 +14382,7 @@ has-ansi@^2.0.0: dependencies: ansi-regex "^2.0.0" -has-bigints@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" - integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== - -has-bigints@^1.0.2: +has-bigints@^1.0.1, has-bigints@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== @@ -13875,7 +14402,7 @@ has-cors@1.1.0: has-flag@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== has-flag@^4.0.0: version "4.0.0" @@ -13889,12 +14416,7 @@ has-property-descriptors@^1.0.0: dependencies: get-intrinsic "^1.1.1" -has-symbols@^1.0.1, has-symbols@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" - integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== - -has-symbols@^1.0.3: +has-symbols@^1.0.1, has-symbols@^1.0.2, has-symbols@^1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== @@ -13942,11 +14464,6 @@ has-values@^1.0.0: is-number "^3.0.0" kind-of "^4.0.0" -has-yarn@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77" - integrity sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw== - has@^1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" @@ -14053,7 +14570,7 @@ hogan.js@^3.0.2: mkdirp "0.3.0" nopt "1.0.10" -hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: +hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: version "3.3.2" resolved "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== @@ -14411,9 +14928,9 @@ immer@9.0.7: integrity sha512-KGllzpbamZDvOIxnmJ0jI840g7Oikx58lBPWV0hUh7dtAyZpFqqrBZdKka5GlTwMTZ1Tjc/bKKW4VSFAt6BqMA== immer@^9.0.1, immer@^9.0.7: - version "9.0.14" - resolved "https://registry.npmjs.org/immer/-/immer-9.0.14.tgz#e05b83b63999d26382bb71676c9d827831248a48" - integrity sha512-ubBeqQutOSLIFCUBN03jGeOS6a3DoYlSYwYJTa+gSKEZKU5redJIqkIdZ3JVv/4RZpfcXdAWH5zCNLWPRv2WDw== + version "9.0.15" + resolved "https://registry.npmjs.org/immer/-/immer-9.0.15.tgz#0b9169e5b1d22137aba7d43f8a81a495dd1b62dc" + integrity sha512-2eB/sswms9AEUSkOm4SbV5Y7Vmt/bKRwByd52jfLkW4OLYeaTP3EEiJ9agqU0O/tq6Dk62Zfj+TJSqfm1rLVGQ== immutable@^3.x.x: version "3.8.2" @@ -14452,11 +14969,6 @@ import-from@^3.0.0: dependencies: resolve-from "^5.0.0" -import-lazy@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" - integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM= - import-lazy@~4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz#e8eb627483a0a43da3c03f3e35548be5cb0cc153" @@ -14670,10 +15182,10 @@ invert-kv@^1.0.0: resolved "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= -ioredis@^5.0.4: - version "5.0.4" - resolved "https://registry.npmjs.org/ioredis/-/ioredis-5.0.4.tgz#0d4abfd818adfc5ef5029fddac4b8f503a1433b7" - integrity sha512-qFJw3MnPNsJF1lcIOP3vztbsasOXK3nDdNAgjQj7t7/Bn/w10PGchTOpqylQNxjzPbLoYDu34LjeJtSWiKBntQ== +ioredis@^5.1.0: + version "5.1.0" + resolved "https://registry.npmjs.org/ioredis/-/ioredis-5.1.0.tgz#17bc0bc40f164ef26910ca6e56981c2a9bfdf57e" + integrity sha512-HYHnvwxFwefeUBj0hZFejLvd8Q/YNAfnZlZG/hSRxkRhXMs1H8soMEVccHd1WlLrKkynorXBsAtqDGskOdAfVQ== dependencies: "@ioredis/commands" "^1.1.1" cluster-key-slot "^1.1.0" @@ -14761,7 +15273,7 @@ is-arguments@^1.0.4: is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== is-arrayish@^0.3.1: version "0.3.2" @@ -14769,9 +15281,11 @@ is-arrayish@^0.3.1: integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== is-bigint@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.1.tgz#6923051dfcbc764278540b9ce0e6b3213aa5ebc2" - integrity sha512-J0ELF4yHFxHy0cmSxZuheDOz2luOdVvqjwmEcj8H/L1JHeuEDSDbeRP+Dk9kFVk5RTFzbucJ2Kb9F7ixY2QaCg== + version "1.0.4" + resolved "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" is-binary-path@~2.1.0: version "2.1.0" @@ -14781,11 +15295,12 @@ is-binary-path@~2.1.0: binary-extensions "^2.0.0" is-boolean-object@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.0.tgz#e2aaad3a3a8fca34c28f6eee135b156ed2587ff0" - integrity sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA== + version "1.1.2" + resolved "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== dependencies: - call-bind "^1.0.0" + call-bind "^1.0.2" + has-tostringtag "^1.0.0" is-buffer@^1.1.5: version "1.1.6" @@ -14823,14 +15338,14 @@ is-ci@^3.0.0, is-ci@^3.0.1: dependencies: ci-info "^3.2.0" -is-core-module@^2.1.0, is-core-module@^2.2.0, is-core-module@^2.8.0: +is-core-module@^2.1.0, is-core-module@^2.2.0: version "2.8.1" resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz#f59fdfca701d5879d0a6b100a40aa1560ce27211" integrity sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA== dependencies: has "^1.0.3" -is-core-module@^2.8.1: +is-core-module@^2.8.0, is-core-module@^2.8.1: version "2.9.0" resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz#e1c34429cd51c6dd9e09e0799e396e27b19a9c69" integrity sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A== @@ -14852,9 +15367,11 @@ is-data-descriptor@^1.0.0: kind-of "^6.0.0" is-date-object@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" - integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== + version "1.0.5" + resolved "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" is-decimal@^1.0.0: version "1.0.4" @@ -14973,7 +15490,7 @@ is-in-browser@^1.0.2, is-in-browser@^1.1.3: resolved "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz#56ff4db683a078c6082eb95dad7dc62e1d04f835" integrity sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU= -is-installed-globally@^0.4.0, is-installed-globally@~0.4.0: +is-installed-globally@~0.4.0: version "0.4.0" resolved "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz#9a0fd407949c30f86eb6959ef1b7994ed0b7b520" integrity sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ== @@ -15003,12 +15520,7 @@ is-module@^1.0.0: resolved "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" integrity sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE= -is-negative-zero@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" - integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== - -is-negative-zero@^2.0.2: +is-negative-zero@^2.0.1, is-negative-zero@^2.0.2: version "2.0.2" resolved "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== @@ -15018,15 +15530,12 @@ is-node-process@^1.0.1: resolved "https://registry.npmjs.org/is-node-process/-/is-node-process-1.0.1.tgz#4fc7ac3a91e8aac58175fe0578abbc56f2831b23" integrity sha512-5IcdXuf++TTNt3oGl9EBdkvndXA8gmc4bz/Y+mdEpWh3Mcn/+kOw6hI7LD5CocqJWMzeb0I0ClndRVNdEPuJXQ== -is-npm@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz#43e8d65cc56e1b67f8d47262cf667099193f45a8" - integrity sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA== - is-number-object@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.4.tgz#36ac95e741cf18b283fc1ddf5e83da798e3ec197" - integrity sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw== + version "1.0.7" + resolved "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" + integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== + dependencies: + has-tostringtag "^1.0.0" is-number@^3.0.0: version "3.0.0" @@ -15170,12 +15679,7 @@ is-scoped@^2.1.0: dependencies: scoped-regex "^2.0.0" -is-shared-array-buffer@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" - integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA== - -is-shared-array-buffer@^1.0.2: +is-shared-array-buffer@^1.0.1, is-shared-array-buffer@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== @@ -15189,6 +15693,13 @@ is-ssh@^1.3.0: dependencies: protocols "^1.1.0" +is-ssh@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/is-ssh/-/is-ssh-1.4.0.tgz#4f8220601d2839d8fa624b3106f8e8884f01b8b2" + integrity sha512-x7+VxdxOdlV3CYpjvRLBv5Lo9OJerlYanjwFrPR9fuGPjCiNiCzFgAWpiLAohSbsnH4ZAys3SBh+hq5rJosxUQ== + dependencies: + protocols "^2.0.1" + is-stream-ended@^0.1.4: version "0.1.4" resolved "https://registry.npmjs.org/is-stream-ended/-/is-stream-ended-0.1.4.tgz#f50224e95e06bce0e356d440a4827cd35b267eda" @@ -15217,18 +15728,18 @@ is-string@^1.0.5, is-string@^1.0.7: has-tostringtag "^1.0.0" is-subdir@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/is-subdir/-/is-subdir-1.1.1.tgz#423e66902f9c5f159b9cc4826c820df083059538" - integrity sha512-VYpq0S7gPBVkkmfwkvGnx1EL9UVIo87NQyNcgMiNUdQCws3CJm5wj2nB+XPL7zigvjxhuZgp3bl2yBcKkSIj1w== + version "1.2.0" + resolved "https://registry.npmjs.org/is-subdir/-/is-subdir-1.2.0.tgz#b791cd28fab5202e91a08280d51d9d7254fd20d4" + integrity sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw== dependencies: better-path-resolve "1.0.0" is-symbol@^1.0.2, is-symbol@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" - integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== + version "1.0.4" + resolved "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== dependencies: - has-symbols "^1.0.1" + has-symbols "^1.0.2" is-text-path@^1.0.1: version "1.0.1" @@ -15277,14 +15788,7 @@ is-utf8@^0.2.0, is-utf8@^0.2.1: resolved "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= -is-weakref@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.1.tgz#842dba4ec17fa9ac9850df2d6efbc1737274f2a2" - integrity sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ== - dependencies: - call-bind "^1.0.0" - -is-weakref@^1.0.2: +is-weakref@^1.0.1, is-weakref@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== @@ -15308,11 +15812,6 @@ is-wsl@^2.2.0: dependencies: is-docker "^2.0.0" -is-yarn-global@^0.3.0: - version "0.3.0" - resolved "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232" - integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw== - isarray@0.0.1: version "0.0.1" resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" @@ -15385,9 +15884,9 @@ isomorphic-form-data@^2.0.0: form-data "^2.3.2" isomorphic-git@^1.8.0: - version "1.17.3" - resolved "https://registry.npmjs.org/isomorphic-git/-/isomorphic-git-1.17.3.tgz#d4a4e7a2defc7e9c80d4d0bfd43c1e7d2bfb25ee" - integrity sha512-jEQtmg1lJ8ZiJLjJCCJDDIdXaeoHwqHFY7QCLgNw7GzZ6MktXLzKXnQsFRfIcm7sNYGt+w1/6FQTwO9zoHq/Fw== + version "1.18.3" + resolved "https://registry.npmjs.org/isomorphic-git/-/isomorphic-git-1.18.3.tgz#b2ef91688ac8f4315a8f3ce72f24a76c17bf61ad" + integrity sha512-CVTNt0uU5RQ4g626LxqUyShdoeD15uZppKA0tk7iY/PyikCbRG594a7BksU4JZcOC6RsqUkURdIlFyKhAfdbqg== dependencies: async-lock "^1.1.0" clean-git-ref "^2.0.1" @@ -15406,6 +15905,11 @@ isomorphic-ws@^4.0.1: resolved "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc" integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w== +isomorphic-ws@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz#e5529148912ecb9b451b46ed44d53dae1ce04bbf" + integrity sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw== + isstream@~0.1.2: version "0.1.2" resolved "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" @@ -15901,7 +16405,7 @@ jest-when@^3.1.0: resolved "https://registry.npmjs.org/jest-when/-/jest-when-3.5.1.tgz#33ab6f923661cf878cd08fe9df64b507934603db" integrity sha512-o+HiaIVCg1IC95sMDKHU9G5v5N5l3UHqXvJpf0PgAMThZeQo4Hf5Sgoj+wpCBRGg4/KtzSAZZZEKNiLqE0i4eQ== -jest-worker@^27.3.1, jest-worker@^27.4.5, jest-worker@^27.5.1: +jest-worker@^27.4.5, jest-worker@^27.5.1: version "27.5.1" resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== @@ -15910,6 +16414,15 @@ jest-worker@^27.3.1, jest-worker@^27.4.5, jest-worker@^27.5.1: merge-stream "^2.0.0" supports-color "^8.0.0" +jest-worker@^28.0.2: + version "28.1.1" + resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.1.tgz#3480c73247171dfd01eda77200f0063ab6a3bf28" + integrity sha512-Au7slXB08C6h+xbJPp7VIb6U0XX5Kc9uel/WFc6/rcTzGiaVCBRngBExSYuXSLFPULPSYU3cJ3ybS988lNFQhQ== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + jest@^27.5.1: version "27.5.1" resolved "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz#dadf33ba70a779be7a6fc33015843b51494f63fc" @@ -15970,9 +16483,9 @@ jose@^4.1.4: integrity sha512-GFcVFQwYQKbQTUOo2JlpFGXTkgBw26uzDsRMD2q1WgSKNSnpKS9Ug7bdQ8dS+p4sZHNH6iRPu6WK2jLIjspaMA== jose@^4.6.0: - version "4.8.1" - resolved "https://registry.npmjs.org/jose/-/jose-4.8.1.tgz#dc7c2660b115ba29b44880e588c5ac313c158247" - integrity sha512-+/hpTbRcCw9YC0TOfN1W47pej4a9lRmltdOVdRLz5FP5UvUq3CenhXjQK7u/8NdMIIShMXYAh9VLPhc7TjhvFw== + version "4.8.3" + resolved "https://registry.npmjs.org/jose/-/jose-4.8.3.tgz#5a754fb4aa5f2806608d083f438e6916b11087da" + integrity sha512-7rySkpW78d8LBp4YU70Wb7+OTgE3OwAALNVZxhoIhp4Kscp+p/fBkdpxGAMKxvCAMV4QfXBU9m6l9nX/vGwd2g== joycon@^3.0.1: version "3.1.0" @@ -16276,7 +16789,7 @@ jsonc-parser@^3.0.0: jsonfile@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= + integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== optionalDependencies: graceful-fs "^4.1.6" @@ -16444,12 +16957,12 @@ jss@~10.8.2: array-includes "^3.1.2" object.assign "^4.1.2" -jsx-ast-utils@^3.2.1: - version "3.2.1" - resolved "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz#720b97bfe7d901b927d87c3773637ae8ea48781b" - integrity sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA== +jsx-ast-utils@^3.3.1: + version "3.3.1" + resolved "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.1.tgz#a3e0f1cb7e230954eab4dcbce9f6288a78f8ba44" + integrity sha512-pxrjmNpeRw5wwVeWyEAk7QJu2GnBO3uzPFmHCKJJFPKK2Cy0cWL23krGtLdnMmbIi6/FjlrQpPyfQI19ByPOhQ== dependencies: - array-includes "^3.1.3" + array-includes "^3.1.5" object.assign "^4.1.2" just-diff-apply@^4.0.1: @@ -16506,10 +17019,10 @@ jwt-decode@*, jwt-decode@^3.1.0: resolved "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz#3fb319f3675a2df0c2895c8f5e9fa4b67b04ed59" integrity sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A== -kafkajs@^1.16.0-beta.6: - version "1.16.0" - resolved "https://registry.npmjs.org/kafkajs/-/kafkajs-1.16.0.tgz#bfcc3ae2b69265ca8435b53a01ee9e8787b9fee5" - integrity sha512-+Rcfu2hyQ/jv5skqRY8xA7Ra+mmRkDAzCaLDYbkGtgsNKpzxPWiLbk8ub0dgr4EbWrN1Zb4BCXHUkD6+zYfdWg== +kafkajs@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/kafkajs/-/kafkajs-2.1.0.tgz#32ede4e8080cc75586c5e4406eeb582fa73f7b1e" + integrity sha512-6IYiOdGWvFPbSbVB+AV3feT+A7vzw5sXm7Ze4QTfP7FRNdY8pGcpiNPvD2lfgYFD8Dm9KbMgBgTt2mf8KaIkzw== keyv-memcache@^1.2.5: version "1.2.9" @@ -16527,9 +17040,9 @@ keyv@^3.0.0: json-buffer "3.0.0" keyv@^4.0.0, keyv@^4.0.3: - version "4.3.0" - resolved "https://registry.npmjs.org/keyv/-/keyv-4.3.0.tgz#b4352e0e4fe7c94111947d6738a6d3fe7903027c" - integrity sha512-C30Un9+63J0CsR7Wka5quXKqYZsT6dcRQ2aOwGcSc3RiQ4HGWpTAHlCA+puNfw2jA/s11EsxA1nCXgZRuRKMQQ== + version "4.3.2" + resolved "https://registry.npmjs.org/keyv/-/keyv-4.3.2.tgz#e839df676a0c7ee594c8835e7c1c83742558e5c2" + integrity sha512-kn8WmodVBe12lmHpA6W8OY7SNh6wVR+Z+wZESF4iF5FCazaVXGWOtnbnvX0tMQ1bO+/TmOD9LziuYMvrIIs0xw== dependencies: compress-brotli "^1.3.8" json-buffer "3.0.1" @@ -16563,15 +17076,15 @@ kleur@^3.0.3: resolved "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== -kleur@^4.0.3: +kleur@^4.0.3, kleur@^4.1.4: version "4.1.4" resolved "https://registry.npmjs.org/kleur/-/kleur-4.1.4.tgz#8c202987d7e577766d039a8cd461934c01cda04d" integrity sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA== -knex@^1.0.2: - version "1.0.7" - resolved "https://registry.npmjs.org/knex/-/knex-1.0.7.tgz#965f4490efc451b140aac4c5c6efa39fd877597b" - integrity sha512-89jxuRATt4qJMb9ZyyaKBy0pQ4d5h7eOFRqiNFnUvsgU+9WZ2eIaZKrAPG1+F3mgu5UloPUnkVE5Yo2sKZUs6Q== +knex@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/knex/-/knex-2.1.0.tgz#9348aace3a08ff5be26eb1c8e838416ddf1aa216" + integrity sha512-vVsnD6UJdSJy55TvCXfFF9syfwyXNxfE9mvr2hJL/4Obciy2EPGoqjDpgRSlMruHuPWDOeYAG25nyrGvU+jJog== dependencies: colorette "2.0.16" commander "^9.1.0" @@ -16610,7 +17123,7 @@ language-tags@^1.0.5: dependencies: language-subtag-registry "~0.3.2" -latest-version@5.1.0, latest-version@^5.1.0: +latest-version@5.1.0: version "5.1.0" resolved "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face" integrity sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA== @@ -16761,9 +17274,9 @@ lilconfig@^2.0.3: integrity sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA== lines-and-columns@^1.1.6: - version "1.1.6" - resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" - integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= + version "1.2.4" + resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== linkify-it@^3.0.1: version "3.0.2" @@ -16773,9 +17286,9 @@ linkify-it@^3.0.1: uc.micro "^1.0.1" lint-staged@^13.0.0: - version "13.0.1" - resolved "https://registry.npmjs.org/lint-staged/-/lint-staged-13.0.1.tgz#899e78065ab29b88fdd922482411121664ef66be" - integrity sha512-Ykaf4QTi0a02BF7cnq7JIPGOJxH4TkNMWhSlJdH9wOekd0X+gog47Jfh/0L31DqZe5AiydLGC7LkPqpaNm+Kvg== + version "13.0.3" + resolved "https://registry.npmjs.org/lint-staged/-/lint-staged-13.0.3.tgz#d7cdf03a3830b327a2b63c6aec953d71d9dc48c6" + integrity sha512-9hmrwSCFroTSYLjflGI8Uk+GWAwMB4OlpU4bMJEAT5d/llQwtYKoim4bLOyLCuWFAhWEupE0vkIFqtw/WIsPug== dependencies: cli-truncate "^3.1.0" colorette "^2.0.17" @@ -17144,7 +17657,7 @@ lodash.sortby@^4.7.0: lodash.startcase@^4.4.0: version "4.4.0" resolved "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz#9436e34ed26093ed7ffae1936144350915d9add8" - integrity sha1-lDbjTtJgk+1/+uGTYUQ1CRXZrdg= + integrity sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg== lodash.template@^4.5.0: version "4.5.0" @@ -17176,7 +17689,7 @@ lodash.uniq@^4.5.0: resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -lodash@4.17.21, lodash@^4.17.10, lodash@^4.17.13, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.7.0, lodash@~4.17.0, lodash@~4.17.15, lodash@~4.17.4: +lodash@4.17.21, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.7.0, lodash@~4.17.0, lodash@~4.17.15, lodash@~4.17.4: version "4.17.21" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -17216,9 +17729,9 @@ log-update@^4.0.0: wrap-ansi "^6.2.0" logform@^2.3.2, logform@^2.4.0: - version "2.4.0" - resolved "https://registry.npmjs.org/logform/-/logform-2.4.0.tgz#131651715a17d50f09c2a2c1a524ff1a4164bcfe" - integrity sha512-CPSJw4ftjf517EhXZGGvTHHkYobo7ZCc0kvwUoOYcjfR2UVrI66RHj8MCrfAdEitdmFqbu2BYdYs8FHHZSb6iw== + version "2.4.1" + resolved "https://registry.npmjs.org/logform/-/logform-2.4.1.tgz#512c9eaef738044d1c619790ba0f806c80d9d3a9" + integrity sha512-7XB/tqc3VRbri9pRjU6E97mQ8vC27ivJ3lct4jhyT+n0JNDd4YKldFl0D75NqDp46hk8RC7Ma1Vjv/UPf67S+A== dependencies: "@colors/colors" "1.5.0" fecha "^4.2.0" @@ -17302,16 +17815,16 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +lru-cache@^7.10.1, lru-cache@^7.4.4, lru-cache@^7.5.1, lru-cache@^7.7.1: + version "7.10.1" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-7.10.1.tgz#db577f42a94c168f676b638d15da8fb073448cab" + integrity sha512-BQuhQxPuRl79J5zSXRP+uNzPOyZw2oFI9JLRQ80XswSvg21KMKNtQza9eF42rfI/3Z40RvzBdXgziEkudzjo8A== + 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-cache@^7.4.4, lru-cache@^7.5.1, lru-cache@^7.7.1: - version "7.10.1" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-7.10.1.tgz#db577f42a94c168f676b638d15da8fb073448cab" - integrity sha512-BQuhQxPuRl79J5zSXRP+uNzPOyZw2oFI9JLRQ80XswSvg21KMKNtQza9eF42rfI/3Z40RvzBdXgziEkudzjo8A== - lunr@^2.3.9: version "2.3.9" resolved "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz#18b123142832337dd6e964df1a5a7707b25d35e1" @@ -17473,7 +17986,7 @@ map-cache@^0.2.0, map-cache@^0.2.2: map-obj@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" - integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= + integrity sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg== map-obj@^4.0.0, map-obj@^4.1.0: version "4.3.0" @@ -17509,9 +18022,9 @@ markdown-table@^3.0.0: integrity sha512-CBbaYXKSGnE1uLRpKA1SWgIRb2PQrpkllNWpZtZe6VojOJ4ysqiq7/2glYcmKsOYN09QgH/HEBX5hIshAeiK6A== marked@^4.0.14: - version "4.0.16" - resolved "https://registry.npmjs.org/marked/-/marked-4.0.16.tgz#9ec18fc1a723032eb28666100344d9428cf7a264" - integrity sha512-wahonIQ5Jnyatt2fn8KqF/nIqZM8mh3oRu2+l5EANGMhu6RFjiSG52QNE2eWzFMI94HqYSgN184NurgNG6CztA== + version "4.0.17" + resolved "https://registry.npmjs.org/marked/-/marked-4.0.17.tgz#1186193d85bb7882159cdcfc57d1dfccaffb3fe9" + integrity sha512-Wfk0ATOK5iPxM4ptrORkFemqroz0ZDxp5MWfYA7H/F+wO17NRWV5Ypxi6p3g2Xmw2bKeiYOl6oVnLHKxBA0VhA== match-sorter@^6.0.2: version "6.3.1" @@ -17806,7 +18319,7 @@ meros@^1.1.4: resolved "https://registry.npmjs.org/meros/-/meros-1.1.4.tgz#c17994d3133db8b23807f62bec7f0cb276cfd948" integrity sha512-E9ZXfK9iQfG9s73ars9qvvvbSIkJZF5yOo9j4tcwM5tN8mUKfj/EKN5PzOr3ZH0y5wL7dLAHw3RVEfpQV9Q7VQ== -methods@^1.0.0, methods@^1.1.1, methods@^1.1.2, methods@~1.1.2: +methods@^1.0.0, methods@^1.1.2, methods@~1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= @@ -18145,12 +18658,12 @@ mime-types@^2.0.8, mime-types@^2.1.12, mime-types@^2.1.27, mime-types@^2.1.31, m dependencies: mime-db "1.52.0" -mime@1.6.0, mime@^1.3.4, mime@^1.4.1: +mime@1.6.0, mime@^1.3.4: version "1.6.0" resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== -mime@^2.2.0, mime@^2.5.0: +mime@2.6.0, mime@^2.2.0, mime@^2.5.2: version "2.6.0" resolved "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== @@ -18198,14 +18711,14 @@ min-document@^2.19.0: dom-walk "^0.1.0" min-indent@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/min-indent/-/min-indent-1.0.0.tgz#cfc45c37e9ec0d8f0a0ec3dd4ef7f7c3abe39256" - integrity sha1-z8RcN+nsDY8KDsPdTvf3w6vjklY= + version "1.0.1" + resolved "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" + integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== mini-css-extract-plugin@^2.4.2: - version "2.6.0" - resolved "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.0.tgz#578aebc7fc14d32c0ad304c2c34f08af44673f5e" - integrity sha512-ndG8nxCEnAemsg4FSgS+yNyHKgkTB4nPKqCOgh65j3/30qqC5RaSQQXMm++Y6sb6E1zRSxPkztj9fqxhS1Eo6w== + version "2.6.1" + resolved "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.1.tgz#9a1251d15f2035c342d99a468ab9da7a0451b71e" + integrity sha512-wd+SD57/K6DiV7jIR34P+s3uckTRuQvx0tKPcvjFlrEylk6P4mQ2KSWk1hblj1Kxaqok7LogKOieygXqBczNlg== dependencies: schema-utils "^4.0.0" @@ -18240,13 +18753,6 @@ minimatch@^3.0.2, minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" -minimatch@^4.0.0: - version "4.2.1" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz#40d9d511a46bdc4e563c22c3080cde9c0d8299b4" - integrity sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g== - dependencies: - brace-expansion "^1.1.7" - minimist-options@4.1.0, minimist-options@^4.0.2: version "4.1.0" resolved "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" @@ -18466,10 +18972,10 @@ msw@^0.39.2: type-fest "^1.2.2" yargs "^17.3.1" -msw@^0.42.0: - version "0.42.1" - resolved "https://registry.npmjs.org/msw/-/msw-0.42.1.tgz#2496d3e191754b68686e2530de459a2e102f85c4" - integrity sha512-LZZuz7VddL45gCBgfBWHyXj6a4W7OTJY0mZPoipJ3P/xwbuJwrtwB3IJrWlqBM8aink/eTKlRxwzmtIAwCj5yQ== +msw@^0.43.0: + version "0.43.0" + resolved "https://registry.npmjs.org/msw/-/msw-0.43.0.tgz#10c6fc3fb1752c0a144179e5ab04c6a512cc9959" + integrity sha512-XJylZP0qW3D5WUGWh9FFefJEl3MGG4y1I+/8a833d0eedm6B+GaPm6wPVZNcnlS2YVTagvEgShVJ7ZtY66tTRQ== dependencies: "@mswjs/cookies" "^0.2.0" "@mswjs/interceptors" "^0.16.3" @@ -18763,9 +19269,9 @@ node-releases@^2.0.1: integrity sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA== nodemon@^2.0.2: - version "2.0.16" - resolved "https://registry.npmjs.org/nodemon/-/nodemon-2.0.16.tgz#d71b31bfdb226c25de34afea53486c8ef225fdef" - integrity sha512-zsrcaOfTWRuUzBn3P44RDliLlp263Z/76FPoHFr3cFFkOz0lTPAcIw8dCzfdVIx/t3AtDYCZRCDkoCojJqaG3w== + version "2.0.19" + resolved "https://registry.npmjs.org/nodemon/-/nodemon-2.0.19.tgz#cac175f74b9cb8b57e770d47841995eebe4488bd" + integrity sha512-4pv1f2bMDj0Eeg/MhGqxrtveeQ5/G/UVe9iO6uTZzjnRluSA4PVWf8CW99LUPwGB3eNIA7zUFoP77YuI7hOc0A== dependencies: chokidar "^3.5.2" debug "^3.2.7" @@ -18773,10 +19279,10 @@ nodemon@^2.0.2: minimatch "^3.0.4" pstree.remy "^1.1.8" semver "^5.7.1" + simple-update-notifier "^1.0.7" supports-color "^5.5.0" touch "^3.1.0" undefsafe "^2.0.5" - update-notifier "^5.1.0" nopt@1.0.10, nopt@~1.0.10: version "1.0.10" @@ -18844,7 +19350,7 @@ normalize-url@^4.1.0: resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== -normalize-url@^6.0.1: +normalize-url@^6.0.1, normalize-url@^6.1.0: version "6.1.0" resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== @@ -18914,9 +19420,9 @@ npm-packlist@^3.0.0: npm-normalize-package-bin "^1.0.1" npm-packlist@^5.0.0, npm-packlist@^5.1.0: - version "5.1.0" - resolved "https://registry.npmjs.org/npm-packlist/-/npm-packlist-5.1.0.tgz#f3fd52903a021009913a133732022132eb355ce7" - integrity sha512-a04sqF6FbkyOAFA19AA0e94gS7Et5T2/IMj3VOT9nOF2RaRdVPQ1Q17Fb/HaDRFs+gbC7HOmhVZ29adpWgmDZg== + version "5.1.1" + resolved "https://registry.npmjs.org/npm-packlist/-/npm-packlist-5.1.1.tgz#79bcaf22a26b6c30aa4dd66b976d69cc286800e0" + integrity sha512-UfpSvQ5YKwctmodvPPkK6Fwk603aoVsf8AEbmVKAEECrfvL8SSe1A2YIwrJ6xmTHAITKPwwZsWo7WwEbNk0kxw== dependencies: glob "^8.0.1" ignore-walk "^5.0.1" @@ -19108,17 +19614,12 @@ object-hash@^2.0.1: resolved "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz#5ad518581eefc443bd763472b8ff2e9c2c0d54a5" integrity sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw== -object-inspect@^1.11.0, object-inspect@^1.9.0: - version "1.12.0" - resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0" - integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g== - -object-inspect@^1.12.0, object-inspect@^1.12.2: +object-inspect@^1.11.0, object-inspect@^1.12.0, object-inspect@^1.12.2, object-inspect@^1.9.0: version "1.12.2" resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== -object-keys@^1.0.12, object-keys@^1.1.1: +object-keys@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== @@ -19193,25 +19694,25 @@ obuf@^1.0.0, obuf@^1.1.2: integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== octokit-plugin-create-pull-request@^3.10.0: - version "3.11.0" - resolved "https://registry.npmjs.org/octokit-plugin-create-pull-request/-/octokit-plugin-create-pull-request-3.11.0.tgz#11f496176111eaa04955fb2bb7e4d953501423d0" - integrity sha512-ZD025HTrm/KoBMRmPYbcCw3tfGomOdAYFB6/K1xiMW+/NFsOyDOeFrEGBbL82b57dhNsPRibs0eL64lpJ3xyvw== + version "3.12.2" + resolved "https://registry.npmjs.org/octokit-plugin-create-pull-request/-/octokit-plugin-create-pull-request-3.12.2.tgz#eaced840587a2f7176c563d94ca6112a93f29da2" + integrity sha512-DwY+vPq7dd2zSiIJw2lN1bYUKEuvjLmBTErTJOQEQd+ujQompN8qjpixeheMZetkJmSNzpWhxxqgZyCMuVnZlQ== dependencies: "@octokit/types" "^6.8.2" octokit@^1.7.1: - version "1.7.2" - resolved "https://registry.npmjs.org/octokit/-/octokit-1.7.2.tgz#c5f11699c39ba5526ff170cbfcb7eaa291ddf11a" - integrity sha512-C+iwOeUMWwbvHxGbLX5rAde5WuEVGe/hNQniU1haZAPMHqUz1+ppffvkP4v/2R3dkSLJnzceUG+ir0klNmEoBA== + version "1.8.1" + resolved "https://registry.npmjs.org/octokit/-/octokit-1.8.1.tgz#399b0032e89e058084a1a1922e40a02e87d4cd61" + integrity sha512-xBLKFIivbl7wnLwxzLYuDO/JDNYxdyxoSjFrl/QMrY/fwGGQYYklvKUDTUyGMU0aXPrQtJ0IZnG3BXpCkDQzWg== dependencies: "@octokit/app" "^12.0.4" "@octokit/core" "^3.5.1" "@octokit/oauth-app" "^3.5.1" - "@octokit/plugin-paginate-rest" "^2.16.8" - "@octokit/plugin-rest-endpoint-methods" "^5.12.0" + "@octokit/plugin-paginate-rest" "^2.18.0" + "@octokit/plugin-rest-endpoint-methods" "^5.14.0" "@octokit/plugin-retry" "^3.0.9" "@octokit/plugin-throttling" "^3.5.1" - "@octokit/types" "^6.26.0" + "@octokit/types" "^6.35.0" oidc-token-hash@^5.0.1: version "5.0.1" @@ -19294,6 +19795,11 @@ openapi-sampler@^1.2.1: "@types/json-schema" "^7.0.7" json-pointer "0.6.2" +openapi-types@^12.0.0: + version "12.0.0" + resolved "https://registry.npmjs.org/openapi-types/-/openapi-types-12.0.0.tgz#458a99d048f9eae1c067e15d56a8bfb3726041f1" + integrity sha512-6Wd9k8nmGQHgCbehZCP6wwWcfXcvinhybUTBatuhjRsCxUIujuYFZc9QnGeae75CyHASewBtxs0HX/qwREReUw== + openid-client@^4.1.1: version "4.9.0" resolved "https://registry.npmjs.org/openid-client/-/openid-client-4.9.0.tgz#bdfc9194435316df419f759ce177635146b43074" @@ -19308,9 +19814,9 @@ openid-client@^4.1.1: oidc-token-hash "^5.0.1" openid-client@^5.1.3: - version "5.1.6" - resolved "https://registry.npmjs.org/openid-client/-/openid-client-5.1.6.tgz#e5eb2032ecfdcfc108660b5c525910a14e352f11" - integrity sha512-HTFaXWdUHvLFw4GaEMgC0jXYBgpjgzQQNHW1pZsSqJorSgrXzxJ+4u/LWCGaClDEse5HLjXRV+zU5Bn3OefiZw== + version "5.1.8" + resolved "https://registry.npmjs.org/openid-client/-/openid-client-5.1.8.tgz#3a24910288b32c32f548fb6e391f44178ce6370f" + integrity sha512-EPxJY6bT7YIYQEXSGxRC5flQ3GUhLy98ufdto6+BVBrFGPmwjUpy4xBcYuU/Wt9nPkO/3EgljBrr6Ezx4lp1RQ== dependencies: jose "^4.1.4" lru-cache "^6.0.0" @@ -19379,7 +19885,7 @@ os-name@^3.1.0: os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== ospath@^1.2.2: version "1.2.2" @@ -19437,13 +19943,20 @@ p-limit@^1.1.0: dependencies: p-try "^1.0.0" -p-limit@^2.0.0, p-limit@^2.2.0: +p-limit@^2.0.0: version "2.2.2" resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz#61279b67721f5287aa1c13a9a7fbbc48c9291b1e" integrity sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ== dependencies: p-try "^2.0.0" +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + p-limit@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz#914af6544ed32bfa54670b061cafcbd04984b644" @@ -19738,17 +20251,7 @@ parse-json@^4.0.0: error-ex "^1.3.1" json-parse-better-errors "^1.0.1" -parse-json@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz#73e5114c986d143efa3712d4ea24db9a4266f60f" - integrity sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw== - dependencies: - "@babel/code-frame" "^7.0.0" - error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" - lines-and-columns "^1.1.6" - -parse-json@^5.2.0: +parse-json@^5.0.0, parse-json@^5.2.0: version "5.2.0" resolved "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== @@ -19771,6 +20274,13 @@ parse-path@^4.0.0: is-ssh "^1.3.0" protocols "^1.4.0" +parse-path@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/parse-path/-/parse-path-5.0.0.tgz#f933152f3c6d34f4cf36cfc3d07b138ac113649d" + integrity sha512-qOpH55/+ZJ4jUu/oLO+ifUKjFPNZGfnPJtzvGzKN/4oLMil5m9OH4VpOj6++9/ytJcfks4kzH2hhi87GL/OU9A== + dependencies: + protocols "^2.0.0" + parse-url@^5.0.0: version "5.0.1" resolved "https://registry.npmjs.org/parse-url/-/parse-url-5.0.1.tgz#99c4084fc11be14141efa41b3d117a96fcb9527f" @@ -19781,6 +20291,16 @@ parse-url@^5.0.0: parse-path "^4.0.0" protocols "^1.4.0" +parse-url@^7.0.2: + version "7.0.2" + resolved "https://registry.npmjs.org/parse-url/-/parse-url-7.0.2.tgz#d21232417199b8d371c6aec0cedf1406fd6393f0" + integrity sha512-PqO4Z0eCiQ08Wj6QQmrmp5YTTxpYfONdOEamrtvK63AmzXpcavIVQubGHxOEwiIoDZFb8uDOoQFS0NCcjqIYQg== + dependencies: + is-ssh "^1.4.0" + normalize-url "^6.1.0" + parse-path "^5.0.0" + protocols "^2.0.1" + parse5@6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" @@ -19942,10 +20462,10 @@ path-case@^3.0.4: dot-case "^3.0.4" tslib "^2.0.3" -path-equal@1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/path-equal/-/path-equal-1.1.2.tgz#260e7c449c4c2022f68cc5fa6e617e892858250d" - integrity sha512-p5kxPPwCdbf5AdXzT1bUBJomhgBlEjRBavYNr1XUpMFIE4Hnf2roueCMXudZK5tnaAu1tTmp3GPzqwJK45IHEA== +path-equal@^1.1.2: + version "1.2.2" + resolved "https://registry.npmjs.org/path-equal/-/path-equal-1.2.2.tgz#fa2997f0a829de22ec8f5f86461ca5590d49b832" + integrity sha512-AUJvbcle1Zgb1TgtftHYknlrgrSYyI1ytrYgSbKUHSybwqUDnbD2cw9PIWivuMvsN+GTXmr/DRN4VBXpHG6aGg== path-exists@^2.0.0: version "2.1.0" @@ -20163,7 +20683,7 @@ picocolors@^1.0.0: resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.2.3, picomatch@^2.3.1: +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.2.3, picomatch@^2.3.0, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== @@ -20675,9 +21195,9 @@ prettier@^1.16.4, prettier@^1.19.1: integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== prettier@^2.2.1: - version "2.6.2" - resolved "https://registry.npmjs.org/prettier/-/prettier-2.6.2.tgz#e26d71a18a74c3d0f0597f55f01fb6c06c206032" - integrity sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew== + version "2.7.1" + resolved "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64" + integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== pretty-bytes@^5.3.0, pretty-bytes@^5.6.0: version "5.6.0" @@ -20773,6 +21293,11 @@ promise-all-reject-late@^1.0.0: resolved "https://registry.npmjs.org/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz#f8ebf13483e5ca91ad809ccc2fcf25f26f8643c2" integrity sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw== +promise-any-polyfill@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/promise-any-polyfill/-/promise-any-polyfill-1.0.1.tgz#563872dd0abd370bfa8039e63980469b4b8b0d53" + integrity sha512-51Tj+hOoV3LOeCHItmWBklN9FYkyV53uIIjjzgIchitGneTvl6+ivOxWXhxraeUzzS3YFRpXRPPbv7+KD3NzYQ== + promise-call-limit@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/promise-call-limit/-/promise-call-limit-1.0.1.tgz#4bdee03aeb85674385ca934da7114e9bcd3c6e24" @@ -20894,6 +21419,11 @@ protocols@^1.1.0, protocols@^1.4.0: resolved "https://registry.npmjs.org/protocols/-/protocols-1.4.7.tgz#95f788a4f0e979b291ffefcf5636ad113d037d32" integrity sha512-Fx65lf9/YDn3hUX08XUc0J8rSux36rEsyiv21ZGUC1mOyeM3lTRpZLcrm8aAolzS4itwVfm7TAPyxC2E5zd6xg== +protocols@^2.0.0, protocols@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/protocols/-/protocols-2.0.1.tgz#8f155da3fc0f32644e83c5782c8e8212ccf70a86" + integrity sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q== + proxy-addr@~2.0.7: version "2.0.7" resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" @@ -20922,7 +21452,7 @@ ps-tree@1.2.0: pseudomap@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" - integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= + integrity sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ== psl@^1.1.28, psl@^1.1.33: version "1.8.0" @@ -20978,21 +21508,14 @@ punycode@^2.1.0, punycode@^2.1.1: resolved "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== -pupa@^2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz#f5e8fd4afc2c5d97828faa523549ed8744a20d62" - integrity sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A== - dependencies: - escape-goat "^2.0.0" - -puppeteer@^14.0.0: - version "14.3.0" - resolved "https://registry.npmjs.org/puppeteer/-/puppeteer-14.3.0.tgz#0099cabf97767461aca02486313e84fcfc776af6" - integrity sha512-pDtg1+vyw1UPIhUjh2/VW1HUdQnaZJHfMacrJciR3AVm+PBiqdCEcFeFb3UJ/CDEQlHOClm3/WFa7IjY25zIGg== +puppeteer@^15.0.0: + version "15.3.1" + resolved "https://registry.npmjs.org/puppeteer/-/puppeteer-15.3.1.tgz#0ff9b433a8fc3798f5ec82ea4b31ec47857219cf" + integrity sha512-Z+SpYBiS1zUzMXV7Wnhe2pyuVCFAFRTq1UrUWHB2CkLos5v7bXvXYuZ3Fn5pSN5IObxijyx4opNYKTCRnGni6Q== dependencies: cross-fetch "3.1.5" debug "4.3.4" - devtools-protocol "0.0.1001819" + devtools-protocol "0.0.1011705" extract-zip "2.0.1" https-proxy-agent "5.0.1" pkg-dir "4.2.0" @@ -21001,14 +21524,14 @@ puppeteer@^14.0.0: rimraf "3.0.2" tar-fs "2.1.1" unbzip2-stream "1.4.3" - ws "8.7.0" + ws "8.8.0" q@^1.5.1: version "1.5.1" resolved "https://registry.npmjs.org/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= -qs@6.10.3, qs@^6.10.1, qs@^6.10.2, qs@^6.10.3, qs@^6.5.1, qs@^6.9.1, qs@^6.9.4, qs@^6.9.6: +qs@6.10.3, qs@^6.10.1, qs@^6.10.2, qs@^6.10.3, qs@^6.9.1, qs@^6.9.4, qs@^6.9.6: version "6.10.3" resolved "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz#d6cde1b2ffca87b5aa57889816c5f81535e22e8e" integrity sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ== @@ -21082,10 +21605,10 @@ raf@^3.4.0: dependencies: performance-now "^2.1.0" -ramda@^0.27.1: - version "0.27.2" - resolved "https://registry.npmjs.org/ramda/-/ramda-0.27.2.tgz#84463226f7f36dc33592f6f4ed6374c48306c3f1" - integrity sha512-SbiLPU40JuJniHexQSAgad32hfwd+DRUdwF2PlVuI5RZD0/vahUco7R8vD86J/tcEKKF9vZrUVwgtmGCqlCKyA== +ramda@^0.28.0: + version "0.28.0" + resolved "https://registry.npmjs.org/ramda/-/ramda-0.28.0.tgz#acd785690100337e8b063cab3470019be427cc97" + integrity sha512-9QnLuG/kPVgWvMQ4aODhsBUFKOUmnbUnsSXACv+NCQZcHbeb+v8Lodp8OVxtRULN1/xOyYLLaL6npE6dMq5QTA== randexp@^0.5.3: version "0.5.3" @@ -21154,6 +21677,15 @@ rc-progress@3.3.3: classnames "^2.2.6" rc-util "^5.16.1" +rc-progress@3.4.0: + version "3.4.0" + resolved "https://registry.npmjs.org/rc-progress/-/rc-progress-3.4.0.tgz#80a33c25c9675f5836ba25a87cd8dc310aad72b1" + integrity sha512-ZuMyOzzTkZnn+EKqGQ7YHzrvGzBtcCCVjx1McC/E/pMTvr6GWVfVRSawDlWsscxsJs7MkqSTwCO6Lu4IeoY2zQ== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.6" + rc-util "^5.16.1" + rc-util@^5.16.1: version "5.16.1" resolved "https://registry.npmjs.org/rc-util/-/rc-util-5.16.1.tgz#374db7cb735512f05165ddc3d6b2c61c21b8b4e3" @@ -21194,6 +21726,14 @@ react-copy-to-clipboard@5.0.4: copy-to-clipboard "^3" prop-types "^15.5.8" +react-copy-to-clipboard@^5.0.4: + version "5.1.0" + resolved "https://registry.npmjs.org/react-copy-to-clipboard/-/react-copy-to-clipboard-5.1.0.tgz#09aae5ec4c62750ccb2e6421a58725eabc41255c" + integrity sha512-k61RsNgAayIJNoy9yDsYzDe/yAZAzEbEgcz3DZMhF686LEyukcE1hzurxe85JandPUG+yTfGVFzuEw3xt8WP/A== + dependencies: + copy-to-clipboard "^3.3.1" + prop-types "^15.8.1" + react-debounce-input@=3.2.4: version "3.2.4" resolved "https://registry.npmjs.org/react-debounce-input/-/react-debounce-input-3.2.4.tgz#8204373a6498776536a2fcc7e467d054c3b729d4" @@ -21232,6 +21772,16 @@ react-dev-utils@^12.0.0-next.60: strip-ansi "^6.0.1" text-table "^0.2.0" +react-dom@^16.13.1: + version "16.14.0" + resolved "https://registry.npmjs.org/react-dom/-/react-dom-16.14.0.tgz#7ad838ec29a777fb3c75c3a190f661cf92ab8b89" + integrity sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.2" + scheduler "^0.19.1" + react-dom@^17.0.2: version "17.0.2" resolved "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" @@ -21264,9 +21814,9 @@ react-fast-compare@^3.1.1: integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA== react-ga@^3.3.0: - version "3.3.0" - resolved "https://registry.npmjs.org/react-ga/-/react-ga-3.3.0.tgz#c91f407198adcb3b49e2bc5c12b3fe460039b3ca" - integrity sha512-o8RScHj6Lb8cwy3GMrVH6NJvL+y0zpJvKtc0+wmH7Bt23rszJmnqEQxRbyrqUzk9DTJIHoP42bfO5rswC9SWBQ== + version "3.3.1" + resolved "https://registry.npmjs.org/react-ga/-/react-ga-3.3.1.tgz#d8e1f4e05ec55ed6ff944dcb14b99011dfaf9504" + integrity sha512-4Vc0W5EvXAXUN/wWyxvsAKDLLgtJ3oLmhYYssx+YzphJpejtOst6cbIHCIyF50Fdxuf5DDKqRYny24yJ2y7GFQ== react-helmet@6.1.0: version "6.1.0" @@ -21279,9 +21829,9 @@ react-helmet@6.1.0: react-side-effect "^2.1.0" react-hook-form@^7.12.2, react-hook-form@^7.13.0: - version "7.31.3" - resolved "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.31.3.tgz#b61bafb9a7435f91695351a7a9f714d8c4df0121" - integrity sha512-NVZdCWViIWXXXlQ3jxVQH0NuNfwPf8A/0KvuCxrM9qxtP1qYosfR2ZudarziFrVOC7eTUbWbm1T4OyYCwv9oSQ== + version "7.32.2" + resolved "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.32.2.tgz#58ec2ab0239ce97969baa2faa03ced13fae913ac" + integrity sha512-F1A6n762xaRhvtQH5SkQQhMr19cCkHZYesTcKJJeNmrphiZp/cYFTIzC05FnQry0SspM54oPJ9tXFXlzya8VNQ== react-hot-loader@^4.13.0: version "4.13.0" @@ -21952,29 +22502,6 @@ relateurl@^0.2.7: resolved "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk= -relay-compiler@12.0.0: - version "12.0.0" - resolved "https://registry.npmjs.org/relay-compiler/-/relay-compiler-12.0.0.tgz#9f292d483fb871976018704138423a96c8a45439" - integrity sha512-SWqeSQZ+AMU/Cr7iZsHi1e78Z7oh00I5SvR092iCJq79aupqJ6Ds+I1Pz/Vzo5uY5PY0jvC4rBJXzlIN5g9boQ== - dependencies: - "@babel/core" "^7.14.0" - "@babel/generator" "^7.14.0" - "@babel/parser" "^7.14.0" - "@babel/runtime" "^7.0.0" - "@babel/traverse" "^7.14.0" - "@babel/types" "^7.0.0" - babel-preset-fbjs "^3.4.0" - chalk "^4.0.0" - fb-watchman "^2.0.0" - fbjs "^3.0.0" - glob "^7.1.1" - immutable "~3.7.6" - invariant "^2.2.4" - nullthrows "^1.1.1" - relay-runtime "12.0.0" - signedsource "^1.0.0" - yargs "^15.3.1" - relay-runtime@12.0.0: version "12.0.0" resolved "https://registry.npmjs.org/relay-runtime/-/relay-runtime-12.0.0.tgz#1e039282bdb5e0c1b9a7dc7f6b9a09d4f4ff8237" @@ -22117,7 +22644,7 @@ request@^2.88.0: require-directory@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== require-from-string@^2.0.2: version "2.0.2" @@ -22181,7 +22708,7 @@ resolve.exports@^1.1.0: resolved "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz#5ce842b94b05146c0e03076985d1d0e7e48c90c9" integrity sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ== -resolve@^1.1.6, resolve@^1.10.0, resolve@^1.14.2, resolve@^1.17.0, resolve@^1.19.0, resolve@^1.20.0: +resolve@^1.1.6, resolve@^1.14.2, resolve@^1.17.0, resolve@^1.19.0, resolve@^1.20.0: version "1.21.0" resolved "https://registry.npmjs.org/resolve/-/resolve-1.21.0.tgz#b51adc97f3472e6a5cf4444d34bc9d6b9037591f" integrity sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA== @@ -22190,7 +22717,7 @@ resolve@^1.1.6, resolve@^1.10.0, resolve@^1.14.2, resolve@^1.17.0, resolve@^1.19 path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -resolve@^1.22.0: +resolve@^1.10.0, resolve@^1.22.0: version "1.22.0" resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198" integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw== @@ -22390,6 +22917,17 @@ rollup-plugin-postcss@*, rollup-plugin-postcss@^4.0.0: safe-identifier "^0.4.2" style-inject "^0.3.0" +rollup-plugin-smart-asset@^2.1.2: + version "2.1.2" + resolved "https://registry.npmjs.org/rollup-plugin-smart-asset/-/rollup-plugin-smart-asset-2.1.2.tgz#08c171122395b848c0c342eb344d2ffcd87261bc" + integrity sha512-Y/gD3abliw3F20uY6ILpmH6sokXKntuTFKvDdLEJxHFcyQRsTb12u2KbsapqPZDa4JN/Nxx7BslYlZ/KmYAtPg== + dependencies: + big.js "^6.1.1" + magic-string "^0.25.7" + mime "^2.5.2" + mkdirp "^1.0.4" + rollup-pluginutils "^2.8.2" + rollup-pluginutils@^2.8.2: version "2.8.2" resolved "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz#72f2af0748b592364dbd3389e600e5a9444a351e" @@ -22397,6 +22935,14 @@ rollup-pluginutils@^2.8.2: dependencies: estree-walker "^0.6.1" +rollup@^0.60: + version "0.60.7" + resolved "https://registry.npmjs.org/rollup/-/rollup-0.60.7.tgz#2b62ef9306f719b1ab85a7814b3e6596ac51fae8" + integrity sha512-Uj5I1A2PnDgA79P+v1dsNs1IHVydNgeJdKWRfoEJJdNMmyx07TRYqUtPUINaZ/gDusncFy1SZsT3lJnBBI8CGw== + dependencies: + "@types/estree" "0.0.39" + "@types/node" "*" + rollup@^0.63.4: version "0.63.5" resolved "https://registry.npmjs.org/rollup/-/rollup-0.63.5.tgz#5543eecac9a1b83b7e1be598b5be84c9c0a089db" @@ -22406,9 +22952,9 @@ rollup@^0.63.4: "@types/node" "*" rollup@^2.60.2: - version "2.75.6" - resolved "https://registry.npmjs.org/rollup/-/rollup-2.75.6.tgz#ac4dc8600f95942a0180f61c7c9d6200e374b439" - integrity sha512-OEf0TgpC9vU6WGROJIk1JA3LR5vk/yvqlzxqdrE2CzzXnqKXNzbAwlWUXis8RS3ZPe7LAq+YUxsRa0l3r27MLA== + version "2.75.7" + resolved "https://registry.npmjs.org/rollup/-/rollup-2.75.7.tgz#221ff11887ae271e37dcc649ba32ce1590aaa0b9" + integrity sha512-VSE1iy0eaAYNCxEXaleThdFXqZJ42qDBatAwrfnPlENEZ8erQ+0LYX4JXOLPceWfZpV1VtZwZ3dFCuOZiSyFtQ== optionalDependencies: fsevents "~2.3.2" @@ -22431,12 +22977,12 @@ run-parallel@^1.1.9: resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679" integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q== -run-script-webpack-plugin@^0.0.14: - version "0.0.14" - resolved "https://registry.npmjs.org/run-script-webpack-plugin/-/run-script-webpack-plugin-0.0.14.tgz#fe2362b32c1dab7a8af7a6f1246fc043690cedd7" - integrity sha512-DXe6lzzEVXjBr/74zd4m4yOfmz5P6GMjzhQxDDsViOmwG7cap8UCE6RgD5rT7zf4wM83a+ToHnpB3v4efUv5IA== +run-script-webpack-plugin@^0.1.0: + version "0.1.1" + resolved "https://registry.npmjs.org/run-script-webpack-plugin/-/run-script-webpack-plugin-0.1.1.tgz#dad3114be32eb864d2160306e4d9c52a2c1cfd59" + integrity sha512-PrxBRLv1K9itDKMlootSCyGhdTU+KbKGJ2wF6/k0eyo6M0YGPC58HYbS/J/QsDiwM0t7G99WcuCqto0J7omOXA== -rxjs@7.5.5, rxjs@^7.1.0, rxjs@^7.2.0, rxjs@^7.5.1, rxjs@^7.5.5: +rxjs@7.5.5, rxjs@^7.0.0, rxjs@^7.1.0, rxjs@^7.2.0, rxjs@^7.5.1, rxjs@^7.5.5: version "7.5.5" resolved "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz#2ebad89af0f560f460ad5cc4213219e1f7dd4e9f" integrity sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw== @@ -22601,13 +23147,6 @@ semver-compare@^1.0.0: resolved "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" integrity sha1-De4hahyUGrN+nvsXiPavxf9VN/w= -semver-diff@^3.1.1: - version "3.1.1" - resolved "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz#05f77ce59f325e00e2706afd67bb506ddb1ca32b" - integrity sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg== - dependencies: - semver "^6.3.0" - semver-store@^0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/semver-store/-/semver-store-0.3.0.tgz#ce602ff07df37080ec9f4fb40b29576547befbe9" @@ -22618,7 +23157,7 @@ semver-store@^0.3.0: resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@7.0.0: +semver@7.0.0, semver@~7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== @@ -22797,7 +23336,7 @@ shallowequal@^1.1.0: shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + integrity sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg== dependencies: shebang-regex "^1.0.0" @@ -22811,7 +23350,7 @@ shebang-command@^2.0.0: shebang-regex@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + integrity sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ== shebang-regex@^3.0.0: version "3.0.0" @@ -22889,6 +23428,13 @@ simple-swizzle@^0.2.2: dependencies: is-arrayish "^0.3.1" +simple-update-notifier@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.0.7.tgz#7edf75c5bdd04f88828d632f762b2bc32996a9cc" + integrity sha512-BBKgR84BJQJm6WjWFMHgLVuo61FBDSj1z/xSFUIozqO6wO7ii0JxCqlIud7Enr/+LhlbNI0whErq96P2qHNWew== + dependencies: + semver "~7.0.0" + sinon@^13.0.2: version "13.0.2" resolved "https://registry.npmjs.org/sinon/-/sinon-13.0.2.tgz#c6a8ddd655dc1415bbdc5ebf0e5b287806850c3a" @@ -22952,11 +23498,12 @@ smart-buffer@^4.2.0: resolved "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== -smartwrap@^1.2.3: - version "1.2.5" - resolved "https://registry.npmjs.org/smartwrap/-/smartwrap-1.2.5.tgz#45ee3e09ac234e5f7f17c16e916f511834f3cd23" - integrity sha512-bzWRwHwu0RnWjwU7dFy7tF68pDAx/zMSu3g7xr9Nx5J0iSImYInglwEVExyHLxXljy6PWMjkSAbwF7t2mPnRmg== +smartwrap@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/smartwrap/-/smartwrap-2.0.2.tgz#7e25d3dd58b51c6ca4aba3a9e391650ea62698a4" + integrity sha512-vCsKNQxb7PnCNd2wY1WClWifAc2lwqsG8OaswpJkVJsvMGcnEntdTCDajZCkk93Ay1U3t/9puJmb525Rg5MZBA== dependencies: + array.prototype.flat "^1.2.3" breakword "^1.0.5" grapheme-splitter "^1.0.4" strip-ansi "^6.0.0" @@ -23199,7 +23746,7 @@ space-separated-tokens@^2.0.0: spawn-command@^0.0.2-1: version "0.0.2-1" resolved "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz#62f5e9466981c1b796dc5929937e11c9c6921bd0" - integrity sha1-YvXpRmmBwbeW3Fkpk34RycaSG9A= + integrity sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg== spawndamnit@^2.0.0: version "2.0.0" @@ -23210,30 +23757,30 @@ spawndamnit@^2.0.0: signal-exit "^3.0.2" spdx-correct@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" - integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q== + version "3.1.1" + resolved "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" + integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w== dependencies: spdx-expression-parse "^3.0.0" spdx-license-ids "^3.0.0" spdx-exceptions@^2.1.0: - version "2.2.0" - resolved "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977" - integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA== + version "2.3.0" + resolved "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" + integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== spdx-expression-parse@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" - integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== + version "3.0.1" + resolved "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== dependencies: spdx-exceptions "^2.1.0" spdx-license-ids "^3.0.0" spdx-license-ids@^3.0.0: - version "3.0.5" - resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654" - integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q== + version "3.0.11" + resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz#50c0d8c40a14ec1bf449bae69a0ea4685a9d9f95" + integrity sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g== spdy-transport@^3.0.0: version "3.0.0" @@ -23311,7 +23858,7 @@ sprintf-js@^1.1.2: sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== sqlstring@^2.3.2: version "2.3.2" @@ -23496,13 +24043,18 @@ stream-shift@^1.0.0: resolved "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== -stream-transform@^2.0.1: +stream-transform@^2.1.3: version "2.1.3" resolved "https://registry.npmjs.org/stream-transform/-/stream-transform-2.1.3.tgz#a1c3ecd72ddbf500aa8d342b0b9df38f5aa598e3" integrity sha512-9GHUiM5hMiCi6Y03jD2ARC1ettBXkQBoQAe7nJsPknnI0ow10aXjTnew8QtYQmLjzn974BnmWEAJgCY6ZP1DeQ== dependencies: mixme "^0.5.1" +streamsearch@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" + integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== + strict-event-emitter@^0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.2.0.tgz#78e2f75dc6ea502e5d8a877661065a1e2deedecd" @@ -23554,7 +24106,7 @@ 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 || 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: +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, 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== @@ -23571,15 +24123,6 @@ string-width@^2.1.1: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" -string-width@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" - integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== - dependencies: - emoji-regex "^7.0.1" - is-fullwidth-code-point "^2.0.0" - strip-ansi "^5.1.0" - string-width@^5.0.0: version "5.1.2" resolved "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" @@ -23603,15 +24146,7 @@ string.prototype.matchall@^4.0.7: regexp.prototype.flags "^1.4.1" side-channel "^1.0.4" -string.prototype.trimend@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" - integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - -string.prototype.trimend@^1.0.5: +string.prototype.trimend@^1.0.4, string.prototype.trimend@^1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz#914a65baaab25fbdd4ee291ca7dde57e869cb8d0" integrity sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog== @@ -23620,15 +24155,7 @@ string.prototype.trimend@^1.0.5: define-properties "^1.1.4" es-abstract "^1.19.5" -string.prototype.trimstart@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" - integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - -string.prototype.trimstart@^1.0.5: +string.prototype.trimstart@^1.0.4, string.prototype.trimstart@^1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz#5466d93ba58cfa2134839f81d7f42437e8c01fef" integrity sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg== @@ -23651,7 +24178,7 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -strip-ansi@5.2.0, strip-ansi@^5.1.0: +strip-ansi@5.2.0: version "5.2.0" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== @@ -23711,7 +24238,7 @@ strip-bom@^2.0.0: strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== strip-bom@^4.0.0: version "4.0.0" @@ -23794,6 +24321,22 @@ style-to-object@^0.3.0: dependencies: inline-style-parser "0.1.1" +styled-components@^5.3.3: + version "5.3.5" + resolved "https://registry.npmjs.org/styled-components/-/styled-components-5.3.5.tgz#a750a398d01f1ca73af16a241dec3da6deae5ec4" + integrity sha512-ndETJ9RKaaL6q41B69WudeqLzOpY1A/ET/glXkNZ2T7dPjPqpPCXXQjDFYZWwNnE5co0wX+gTCqx9mfxTmSIPg== + dependencies: + "@babel/helper-module-imports" "^7.0.0" + "@babel/traverse" "^7.4.5" + "@emotion/is-prop-valid" "^1.1.0" + "@emotion/stylis" "^0.8.4" + "@emotion/unitless" "^0.7.4" + babel-plugin-styled-components ">= 1.12.0" + css-to-react-native "^3.0.0" + hoist-non-react-statics "^3.0.0" + shallowequal "^1.1.0" + supports-color "^5.5.0" + stylehacks@^5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/stylehacks/-/stylehacks-5.0.1.tgz#323ec554198520986806388c7fdaebc38d2c06fb" @@ -23808,9 +24351,9 @@ stylis@^4.0.6: integrity sha512-OFFeUXFgwnGOKvEXaSv0D0KQ5ADP0n6g3SVONx6I/85JzNZ3u50FRwB3lVIk1QO2HNdI75tbVzc4Z66Gdp9voA== sucrase@^3.18.0, sucrase@^3.20.2: - version "3.21.0" - resolved "https://registry.npmjs.org/sucrase/-/sucrase-3.21.0.tgz#6a5affdbe716b22e4dc99c57d366ad0d216444b9" - integrity sha512-FjAhMJjDcifARI7bZej0Bi1yekjWQHoEvWIXhLPwDhC6O4iZ5PtGb86WV56riW87hzpgB13wwBKO9vKAiWu5VQ== + version "3.23.0" + resolved "https://registry.npmjs.org/sucrase/-/sucrase-3.23.0.tgz#2a7fa80a04f055fb2e95d2aead03fec1dba52838" + integrity sha512-xgC1xboStzGhCnRywlBf/DLmkC+SkdAKqrNCDsxGrzM0phR5oUxoFKiQNrsc2D8wDdAm03iLbSZqjHDddo3IzQ== dependencies: commander "^4.0.0" glob "7.1.6" @@ -23819,26 +24362,10 @@ sucrase@^3.18.0, sucrase@^3.20.2: pirates "^4.0.1" ts-interface-checker "^0.1.9" -superagent@^3.8.3: - version "3.8.3" - resolved "https://registry.npmjs.org/superagent/-/superagent-3.8.3.tgz#460ea0dbdb7d5b11bc4f78deba565f86a178e128" - integrity sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA== - dependencies: - component-emitter "^1.2.0" - cookiejar "^2.1.0" - debug "^3.1.0" - extend "^3.0.0" - form-data "^2.3.1" - formidable "^1.2.0" - methods "^1.1.1" - mime "^1.4.1" - qs "^6.5.1" - readable-stream "^2.3.5" - -superagent@^7.1.3: - version "7.1.3" - resolved "https://registry.npmjs.org/superagent/-/superagent-7.1.3.tgz#783ff8330e7c2dad6ad8f0095edc772999273b6b" - integrity sha512-WA6et4nAvgBCS73lJvv1D0ssI5uk5Gh+TGN/kNe+B608EtcVs/yzfl+OLXTzDs7tOBDIpvgh/WUs1K2OK1zTeQ== +superagent@^8.0.0: + version "8.0.0" + resolved "https://registry.npmjs.org/superagent/-/superagent-8.0.0.tgz#2ea4587df4b81ef023ec01ebc6e1bcb9e2344cb6" + integrity sha512-iudipXEel+SzlP9y29UBWGDjB+Zzag+eeA1iLosaR2YHBRr1Q1kC29iBrF2zIVD9fqVbpZnXkN/VJmwFMVyNWg== dependencies: component-emitter "^1.3.0" cookiejar "^2.1.3" @@ -23847,26 +24374,18 @@ superagent@^7.1.3: form-data "^4.0.0" formidable "^2.0.1" methods "^1.1.2" - mime "^2.5.0" + mime "2.6.0" qs "^6.10.3" readable-stream "^3.6.0" semver "^7.3.7" -supertest@^4.0.2: - version "4.0.2" - resolved "https://registry.npmjs.org/supertest/-/supertest-4.0.2.tgz#c2234dbdd6dc79b6f15b99c8d6577b90e4ce3f36" - integrity sha512-1BAbvrOZsGA3YTCWqbmh14L0YEq0EGICX/nBnfkfVJn7SrxQV1I3pMYjSzG9y/7ZU2V9dWqyqk2POwxlb09duQ== - dependencies: - methods "^1.1.2" - superagent "^3.8.3" - supertest@^6.1.3, supertest@^6.1.6: - version "6.2.3" - resolved "https://registry.npmjs.org/supertest/-/supertest-6.2.3.tgz#291b220126e5faa654d12abe1ada3658757c8c67" - integrity sha512-3GSdMYTMItzsSYjnIcljxMVZKPW1J9kYHZY+7yLfD0wpPwww97GeImZC1oOk0S5+wYl2niJwuFusBJqwLqYM3g== + version "6.2.4" + resolved "https://registry.npmjs.org/supertest/-/supertest-6.2.4.tgz#3dcebe42f7fd6f28dd7ac74c6cba881f7101b2f0" + integrity sha512-M8xVnCNv+q2T2WXVzxDECvL2695Uv2uUj2O0utxsld/HRyJvOU8W9f1gvsYxSNU4wmIe0/L/ItnpU4iKq0emDA== dependencies: methods "^1.1.2" - superagent "^7.1.3" + superagent "^8.0.0" supports-color@^2.0.0: version "2.0.0" @@ -24013,6 +24532,14 @@ sync-fetch@0.3.1, sync-fetch@^0.3.1: buffer "^5.7.0" node-fetch "^2.6.1" +sync-fetch@0.4.1, sync-fetch@^0.4.0: + version "0.4.1" + resolved "https://registry.npmjs.org/sync-fetch/-/sync-fetch-0.4.1.tgz#87b8684eef2fa25c96c4683ae308473a4e5c571f" + integrity sha512-JDtyFEvnKUzt1CxRtzzsGgkBanEv8XRmLyJo0F0nGkpCR8EjYmpOJJXz8GA/SWtlPU0nAYh0+CNMNnFworGyOA== + dependencies: + buffer "^5.7.1" + node-fetch "^2.6.1" + tapable@^1.0.0: version "1.1.3" resolved "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" @@ -24079,21 +24606,21 @@ tdigest@^0.1.1: bintrees "1.0.1" "techdocs-cli-embedded-app@link:packages/techdocs-cli-embedded-app": - version "0.2.71" + version "0.2.72-next.2" dependencies: - "@backstage/app-defaults" "^1.0.3" - "@backstage/catalog-model" "^1.0.3" - "@backstage/cli" "^0.17.2" + "@backstage/app-defaults" "^1.0.4-next.2" + "@backstage/catalog-model" "^1.1.0-next.2" + "@backstage/cli" "^0.18.0-next.2" "@backstage/config" "^1.0.1" - "@backstage/core-app-api" "^1.0.3" - "@backstage/core-components" "^0.9.5" + "@backstage/core-app-api" "^1.0.4-next.0" + "@backstage/core-components" "^0.10.0-next.2" "@backstage/core-plugin-api" "^1.0.3" - "@backstage/integration-react" "^1.1.1" - "@backstage/plugin-catalog" "^1.3.0" - "@backstage/plugin-techdocs" "^1.2.0" - "@backstage/plugin-techdocs-react" "^1.0.1" - "@backstage/test-utils" "^1.1.1" - "@backstage/theme" "^0.2.15" + "@backstage/integration-react" "^1.1.2-next.2" + "@backstage/plugin-catalog" "^1.4.0-next.2" + "@backstage/plugin-techdocs" "^1.2.1-next.2" + "@backstage/plugin-techdocs-react" "^1.0.2-next.1" + "@backstage/test-utils" "^1.1.2-next.1" + "@backstage/theme" "^0.2.16-next.1" "@material-ui/core" "^4.11.0" "@material-ui/icons" "^4.9.1" history "^5.0.0" @@ -24127,9 +24654,9 @@ temp@^0.8.4: rimraf "~2.6.2" term-size@^2.1.0: - version "2.2.0" - resolved "https://registry.npmjs.org/term-size/-/term-size-2.2.0.tgz#1f16adedfe9bdc18800e1776821734086fcc6753" - integrity sha512-a6sumDlzyHVJWb8+YofY4TW112G6p2FCPEAFk+59gIYHv3XHRhm9ltVQ9kli4hNWeQBwSpe8cRN25x0ROunMOw== + version "2.2.1" + resolved "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54" + integrity sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg== terminal-link@^2.0.0: version "2.1.1" @@ -24170,9 +24697,9 @@ test-exclude@^6.0.0: minimatch "^3.0.4" testcontainers@^8.1.2: - version "8.10.1" - resolved "https://registry.npmjs.org/testcontainers/-/testcontainers-8.10.1.tgz#2b3d1d25932f437ba4c46a1f32380ce7987629f8" - integrity sha512-MQFoWe6sJrbcZqXb+fM7uN2w9WnV2KZnNyI7Qc9pbxQZS6oLa/or5kgL4DADAuzYFxXJvL3f8inIGI+/1S+rvA== + version "8.11.0" + resolved "https://registry.npmjs.org/testcontainers/-/testcontainers-8.11.0.tgz#f19307557289b7e80c7e1d65b39ab0054a2b2549" + integrity sha512-sc9FA40waYXKVTp/Dm9qmcc8I5/TLyZd+JxtnYjIQDp1UvLzAckQPjSlGCDTdM00J2X4KDwG0+jY+8WprZbpnQ== dependencies: "@balena/dockerignore" "^1.0.2" "@types/archiver" "^5.3.1" @@ -24543,9 +25070,9 @@ ts-morph@^15.0.0: code-block-writer "^11.0.0" ts-node@^10.0.0, ts-node@^10.2.1, ts-node@^10.4.0: - version "10.8.1" - resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.8.1.tgz#ea2bd3459011b52699d7e88daa55a45a1af4f066" - integrity sha512-Wwsnao4DQoJsN034wePSg5nZiw4YKXf56mPIAeD6wVmiv+RytNSWqc2f3fKvcUoV+Yn2+yocD71VOfQHbmVX4g== + version "10.8.2" + resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.8.2.tgz#3185b75228cef116bf82ffe8762594f54b2a23f2" + integrity sha512-LYdGnoGddf1D6v8REPtIH+5iq/gTDuZqv2/UJUU7tKjuEU8xVZorBM+buCGNjj+pGEud+sOoM4CX3/YzINpENA== dependencies: "@cspotcode/source-map-support" "^0.8.0" "@tsconfig/node10" "^1.0.7" @@ -24598,7 +25125,7 @@ tslib@^1.13.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.1.0, tslib@~2.4.0: +tslib@^2.1.0, tslib@^2.4.0, tslib@~2.4.0: version "2.4.0" resolved "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== @@ -24615,17 +25142,18 @@ tty-browserify@0.0.0: resolved "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= -tty-table@^2.8.10: - version "2.8.13" - resolved "https://registry.npmjs.org/tty-table/-/tty-table-2.8.13.tgz#d484a416381973eaebbdf19c79136b390e5c6d70" - integrity sha512-eVV/+kB6fIIdx+iUImhXrO22gl7f6VmmYh0Zbu6C196fe1elcHXd7U6LcLXu0YoVPc2kNesWiukYcdK8ZmJ6aQ== +tty-table@^4.1.5: + version "4.1.6" + resolved "https://registry.npmjs.org/tty-table/-/tty-table-4.1.6.tgz#6bd58338f36c94cce478c3337934d8a65ab40a73" + integrity sha512-kRj5CBzOrakV4VRRY5kUWbNYvo/FpOsz65DzI5op9P+cHov3+IqPbo1JE1ZnQGkHdZgNFDsrEjrfqqy/Ply9fw== dependencies: - chalk "^3.0.0" - csv "^5.3.1" - smartwrap "^1.2.3" + chalk "^4.1.2" + csv "^5.5.0" + kleur "^4.1.4" + smartwrap "^2.0.2" strip-ansi "^6.0.0" wcwidth "^1.0.1" - yargs "^15.1.0" + yargs "^17.1.1" tunnel-agent@^0.6.0: version "0.6.0" @@ -24732,15 +25260,15 @@ typedarray@^0.0.6: resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript-json-schema@^0.53.0: - version "0.53.1" - resolved "https://registry.npmjs.org/typescript-json-schema/-/typescript-json-schema-0.53.1.tgz#9204547f3e145169b40928998366ff6d28b81d32" - integrity sha512-Hg+RnOKUd38MOzC0rDft03a8xvwO+gCcj1F77smw2tCoZYQpFoLtrXWBGdvCX+REliko5WYel2kux17HPFqjLQ== +typescript-json-schema@^0.54.0: + version "0.54.0" + resolved "https://registry.npmjs.org/typescript-json-schema/-/typescript-json-schema-0.54.0.tgz#b3fc42ad90df6a0f6ab57571ebc8b4d41125df4f" + integrity sha512-/MNhm1pjdxXiVspjjyRCrQAA1B768cRzHU83aIqN5vQqQEW2NgyyKOfcguiRIMM64lseIZIelegnHOHEu7YDCg== dependencies: "@types/json-schema" "^7.0.9" "@types/node" "^16.9.2" glob "^7.1.7" - path-equal "1.1.2" + path-equal "^1.1.2" safe-stable-stringify "^2.2.0" ts-node "^10.2.1" typescript "~4.6.0" @@ -24752,9 +25280,9 @@ typescript@~4.6.0, typescript@~4.6.3: integrity sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg== typescript@~4.7.0: - version "4.7.3" - resolved "https://registry.npmjs.org/typescript/-/typescript-4.7.3.tgz#8364b502d5257b540f9de4c40be84c98e23a129d" - integrity sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA== + version "4.7.4" + resolved "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235" + integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ== ua-parser-js@^0.7.18: version "0.7.28" @@ -24783,17 +25311,7 @@ uid2@0.0.3, uid2@0.0.x: resolved "https://registry.npmjs.org/uid2/-/uid2-0.0.3.tgz#483126e11774df2f71b8b639dcd799c376162b82" integrity sha1-SDEm4Rd03y9xuLY53NeZw3YWK4I= -unbox-primitive@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" - integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== - dependencies: - function-bind "^1.1.1" - has-bigints "^1.0.1" - has-symbols "^1.0.2" - which-boxed-primitive "^1.0.2" - -unbox-primitive@^1.0.2: +unbox-primitive@^1.0.1, unbox-primitive@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== @@ -24826,10 +25344,10 @@ underscore@^1.12.1, underscore@^1.9.1: resolved "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz#0c1c6bd2df54b6b69f2314066d65b6cde6fcf9d1" integrity sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g== -undici@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/undici/-/undici-5.0.0.tgz#3c1e08c7f0df90c485d5d8dbb0517e11e34f2090" - integrity sha512-VhUpiZ3No1DOPPQVQnsDZyfcbTTcHdcgWej1PdFnSvOeJmOVDgiOHkunJmBLfmjt4CqgPQddPVjSWW0dsTs5Yg== +undici@5.5.1, undici@^5.0.0: + version "5.5.1" + resolved "https://registry.npmjs.org/undici/-/undici-5.5.1.tgz#baaf25844a99eaa0b22e1ef8d205bffe587c8f43" + integrity sha512-MEvryPLf18HvlCbLSzCW0U00IMftKGI5udnjrQbC5D4P0Hodwffhv+iGfWuJwg16Y/TK11ZFK8i+BPVW2z/eAw== unicode-canonical-property-names-ecmascript@^1.0.4: version "1.0.4" @@ -24903,13 +25421,6 @@ unique-slug@^2.0.0: dependencies: imurmurhash "^0.1.4" -unique-string@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d" - integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg== - dependencies: - crypto-random-string "^2.0.0" - unist-builder@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/unist-builder/-/unist-builder-3.0.0.tgz#728baca4767c0e784e1e64bb44b5a5a753021a04" @@ -25057,26 +25568,6 @@ upath@^2.0.1: resolved "https://registry.npmjs.org/upath/-/upath-2.0.1.tgz#50c73dea68d6f6b990f51d279ce6081665d61a8b" integrity sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w== -update-notifier@^5.1.0: - version "5.1.0" - resolved "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz#4ab0d7c7f36a231dd7316cf7729313f0214d9ad9" - integrity sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw== - dependencies: - boxen "^5.0.0" - chalk "^4.1.0" - configstore "^5.0.1" - has-yarn "^2.1.0" - import-lazy "^2.1.0" - is-ci "^2.0.0" - is-installed-globally "^0.4.0" - is-npm "^5.0.0" - is-yarn-global "^0.3.0" - latest-version "^5.1.0" - pupa "^2.1.1" - semver "^7.3.4" - semver-diff "^3.1.1" - xdg-basedir "^4.0.0" - upper-case-first@^2.0.2: version "2.0.2" resolved "https://registry.npmjs.org/upper-case-first/-/upper-case-first-2.0.2.tgz#992c3273f882abd19d1e02894cc147117f844324" @@ -25258,11 +25749,6 @@ v8-to-istanbul@^8.1.0: convert-source-map "^1.6.0" source-map "^0.7.3" -valid-url@^1.0.9: - version "1.0.9" - resolved "https://registry.npmjs.org/valid-url/-/valid-url-1.0.9.tgz#1c14479b40f1397a75782f115e4086447433a200" - integrity sha1-HBRHm0DxOXp1eC8RXkCGRHQzogA= - validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.4: version "3.0.4" resolved "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" @@ -25393,9 +25879,9 @@ vm-browserify@^1.0.1: integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== vm2@^3.9.6: - version "3.9.9" - resolved "https://registry.npmjs.org/vm2/-/vm2-3.9.9.tgz#c0507bc5fbb99388fad837d228badaaeb499ddc5" - integrity sha512-xwTm7NLh/uOjARRBs8/95H0e8fT3Ukw5D/JJWhxMbhKzNh1Nu981jQKvkep9iKYNxzlVrdzD0mlBGkDKZWprlw== + version "3.9.10" + resolved "https://registry.npmjs.org/vm2/-/vm2-3.9.10.tgz#c66543096b5c44c8861a6465805c23c7cc996a44" + integrity sha512-AuECTSvwu2OHLAZYhG716YzwodKCIJxB6u1zG7PgSQwIgAlEaoXH52bxdcvT8GkGjnYK7r7yWDW0m0sOsPuBjQ== dependencies: acorn "^8.7.0" acorn-walk "^8.2.0" @@ -25511,9 +25997,9 @@ webpack-dev-middleware@^5.3.1: schema-utils "^4.0.0" webpack-dev-server@^4.7.3: - version "4.9.2" - resolved "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.9.2.tgz#c188db28c7bff12f87deda2a5595679ebbc3c9bc" - integrity sha512-H95Ns95dP24ZsEzO6G9iT+PNw4Q7ltll1GfJHV4fKphuHWgKFzGHWi4alTlTnpk1SPPk41X+l2RB7rLfIhnB9Q== + version "4.9.3" + resolved "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.9.3.tgz#2360a5d6d532acb5410a668417ad549ee3b8a3c9" + integrity sha512-3qp/eoboZG5/6QgiZ3llN8TUzkSpYg1Ko9khWX1h40MIEUNS2mDoIa8aXsPfskER+GbTvs/IJZ1QTBBhhuetSw== dependencies: "@types/bonjour" "^3.5.9" "@types/connect-history-api-fallback" "^1.3.5" @@ -25527,7 +26013,7 @@ webpack-dev-server@^4.7.3: chokidar "^3.5.3" colorette "^2.0.10" compression "^1.7.4" - connect-history-api-fallback "^1.6.0" + connect-history-api-fallback "^2.0.0" default-gateway "^6.0.3" express "^4.17.3" graceful-fs "^4.2.6" @@ -25665,7 +26151,7 @@ which-module@^1.0.0: which-module@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" - integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= + integrity sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q== which-pm@2.0.0: version "2.0.0" @@ -25709,13 +26195,6 @@ wide-align@^1.1.0, wide-align@^1.1.2, wide-align@^1.1.5: dependencies: string-width "^1.0.2 || 2 || 3 || 4" -widest-line@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca" - integrity sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg== - dependencies: - string-width "^4.0.0" - window-size@^0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" @@ -25738,9 +26217,9 @@ winston-transport@^4.5.0: triple-beam "^1.3.0" winston@^3.2.1, winston@^3.7.2: - version "3.7.2" - resolved "https://registry.npmjs.org/winston/-/winston-3.7.2.tgz#95b4eeddbec902b3db1424932ac634f887c400b1" - integrity sha512-QziIqtojHBoyzUOdQvQiar1DH0Xp9nF1A1y7NVy2DGEsz82SBDtOalS0ulTRGVT14xPX3WRWkCsdcJKqNflKng== + version "3.8.1" + resolved "https://registry.npmjs.org/winston/-/winston-3.8.1.tgz#76f15b3478cde170b780234e0c4cf805c5a7fb57" + integrity sha512-r+6YAiCR4uI3N8eQNOg8k3P3PqwAm20cLKlzVD9E66Ch39+LZC+VH1UKf9JemQj2B3QoUHfKD7Poewn0Pr3Y1w== dependencies: "@dabh/diagnostics" "^2.0.2" async "^3.2.3" @@ -25862,21 +26341,16 @@ write-pkg@^4.0.0: type-fest "^0.4.1" write-json-file "^3.2.0" -ws@8.7.0: - version "8.7.0" - resolved "https://registry.npmjs.org/ws/-/ws-8.7.0.tgz#eaf9d874b433aa00c0e0d8752532444875db3957" - integrity sha512-c2gsP0PRwcLFzUiA8Mkr37/MI7ilIlHQxaEAtd0uNMbVMoy8puJyafRlm0bV9MbGSabUPeLrRRaqIBcFcA2Pqg== +ws@8.8.0, ws@^8.0.0, ws@^8.3.0: + version "8.8.0" + resolved "https://registry.npmjs.org/ws/-/ws-8.8.0.tgz#8e71c75e2f6348dbf8d78005107297056cb77769" + integrity sha512-JDAgSYQ1ksuwqfChJusw1LSJ8BizJ2e/vVu5Lxjq3YvNJNlROv1ui4i+c/kUUrPheBvQl4c5UbERhTwKa6QBJQ== ws@^7.3.1, ws@^7.4.6: version "7.5.7" resolved "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz#9e0ac77ee50af70d58326ecff7e85eb3fa375e67" integrity sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A== -ws@^8.0.0, ws@^8.3.0: - version "8.8.0" - resolved "https://registry.npmjs.org/ws/-/ws-8.8.0.tgz#8e71c75e2f6348dbf8d78005107297056cb77769" - integrity sha512-JDAgSYQ1ksuwqfChJusw1LSJ8BizJ2e/vVu5Lxjq3YvNJNlROv1ui4i+c/kUUrPheBvQl4c5UbERhTwKa6QBJQ== - ws@^8.4.2: version "8.5.0" resolved "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f" @@ -25892,11 +26366,6 @@ xcase@^2.0.1: resolved "https://registry.npmjs.org/xcase/-/xcase-2.0.1.tgz#c7fa72caa0f440db78fd5673432038ac984450b9" integrity sha1-x/pyyqD0QNt4/VZzQyA4rJhEULk= -xdg-basedir@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" - integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== - xhr@^2.0.1: version "2.6.0" resolved "https://registry.npmjs.org/xhr/-/xhr-2.6.0.tgz#b69d4395e792b4173d6b7df077f0fc5e4e2b249d" @@ -26023,7 +26492,7 @@ y18n@^5.0.5: yallist@^2.1.2: version "2.1.2" resolved "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" - integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= + integrity sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A== yallist@^3.0.2: version "3.1.1" @@ -26111,7 +26580,7 @@ yargs@^16.2.0: y18n "^5.0.5" yargs-parser "^20.2.2" -yargs@^17.0.0, yargs@^17.1.1, yargs@^17.2.1: +yargs@^17.0.0, yargs@^17.2.1: version "17.3.1" resolved "https://registry.npmjs.org/yargs/-/yargs-17.3.1.tgz#da56b28f32e2fd45aefb402ed9c26f42be4c07b9" integrity sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA== @@ -26124,7 +26593,7 @@ yargs@^17.0.0, yargs@^17.1.1, yargs@^17.2.1: y18n "^5.0.5" yargs-parser "^21.0.0" -yargs@^17.3.1: +yargs@^17.1.1, yargs@^17.3.1: version "17.5.1" resolved "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz#e109900cab6fcb7fd44b1d8249166feb0b36e58e" integrity sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==